Return TypeFunction nameArguments
hzEcodehzHttpEvent::ProcessEvent(hzChain&,)

Declared in file: hzHttpServer.h
Defined in file : hzHttpServer.cpp

Function Logic:

0:START 1:!this 2:Fatal 3:!m_pLog 4:Fatal 5:!m_pCx 6:Fatal 7:hzChain::Size hzChain::Printf items 8:m_bHdrComplete 9:hzChain::BlkIter::Data hzChain::Printf 10:Goto stage_two 11:ZI.Size()<80 12:zi 13:!(*zi>='A'&&*zi<='Z')||zi==CONNECT 14:items hzIpConnex::ClientIP SetStatusIP 15:Return E_FORMAT 16:items 17:Return E_OK 18:hzIpConnex::ClientIP m_ClientIP hzXDate::SysDateTime 19:!m_nHeaderLen 20:hSofar nSnd nFst zi 21:!zi.eof()&&Head.Size() 22:*zi==(char)13&&zi==\r\n 23:items zi 24:hzChain::AddByte 25:hzChain::Size hSofar 26:!zi.eof()&&Head.Size() 27:*zi==(char)13&&zi==\r\n\r\n 28:items hzChain::Size m_nHeaderLen 29:zi==: 30:items items 31:nFst>nSnd 32:items 33:zi==\r\n 34:items 35:hzChain::AddByte 36:!m_nHeaderLen 37:hzChain::Printf hzHttpEvent::SendError 38:Return E_RANGE 39:m_nHeaderLen>=HZ_MAX_HTTP_HDR 40:hzChain::Printf hzHttpEvent::SendError 41:Return E_RANGE 42:hSofar<1024 43:hSofar 44:m_pBuf ph zi 45:zi==GET 46:zi m_eMethod 47:zi==HEAD 48:zi m_eMethod 49:zi==POST 50:zi m_eMethod 51:zi==OPTIONS 52:zi m_eMethod 53:zi==PUT 54:zi m_eMethod 55:zi==DELETE 56:zi m_eMethod 57:zi==TRACE 58:zi m_eMethod 59:zi==CONNECT 60:zi m_eMethod 61:bErr 62:!bErr 63:!zi.eof()&&*zi!=(char)32&&*zi!=(char)63&&*zi!=(char)35; 64:* 65:* 66:*zi==(char)63 67:items hzHttpEvent::_setnvpairs m_nQueryLen 68:*zi==(char)35 69:!zi.eof()&&*zi==(char)32; 70:* 71:* 72:*zi!=(char)32 73:bErr 74:!m_pReqPATH[0] 75:bErr 76:items 77:!bErr 78:zi!=HTTP/ 79:bErr 80:zi 81:zi==1.0\r\n 82:zi m_nVersion 83:zi==1.1\r\n 84:zi m_nVersion 85:zi==2.0\r\n 86:zi m_nVersion 87:bErr 88:!zi.eof()&&!bErr; 89:zi==\r\n 90:!zi.eof(); 91:*zi==(char)58&&zi[1]==(char)32 92:zi 0 len 93:!zi.eof(); 94:*zi==(char)13&&zi[1]==(char)10 95:mkC zi 96:!len 97:bErr 98:toupper(*mkA) 99:'A' 100:mkA.Equiv(Accept) 101:xi!=mkC; 102:* 103:* 104:mkA.Equiv(Accept-Charset) 105:xi!=mkC; 106:* 107:* 108:mkA.Equiv(Accept-Language) 109:xi!=mkC; 110:* 111:* 112:mkA.Equiv(Accept-Encoding) 113:xi!=mkC; 114:* 115:* 116:mkA.Equiv(Authorization: basic) 117:xi!=mkC; 118:* 119:* Base64Decode m_Auth 120:'C' 121:mkA.Equiv(Cache-Control) 122:xi!=mkC; 123:* 124:* 125:mkA.Equiv(Content-Type) 126:xi!=mkC; 127:* 128:* 129:mkA.Equiv(Client-ip) 130:xi!=mkC; 131:* 132:* 133:mkA.Equiv(Content-Length) 134:xi!=mkC; 135:* 136:* atoi m_nContentLen 137:mkA.Equiv(Connection) 138:hzChain::Iter::Equiv m_nConnection 139:mkA.Equiv(Cookie) 140:*xi; 141:xi==_hz_ 142:xi 143:*xi&&n<32&&*xi>(char)32&&*xi!=(char)59; 144:* 145:* IsHexnum m_CookieSub 146:'F' 147:mkA.Equiv(From) 148:xi!=mkC; 149:* 150:* 151:'H' 152:mkA.Equiv(Host) 153:*xi!=(char)58&&xi!=mkC; 154:* 155:* 156:xi==(char)58 157:xi!=mkC; 158:'I' 159:mkA.Equiv(If-Modified-Since) 160:xi!=mkC; 161:* 162:* m_LastMod 163:mkA.Equiv(If-None-Match) 164:xi!=mkC; 165:* 166:* 167:'K' 168:mkA.Equiv(Keep-Alive) 169:m_nConnection 170:'M' 171:mkA.Equiv(Max-Forwards) 172:xi!=mkC; 173:* 174:* atoi m_nMaxForwards 175:'P' 176:mkA.Equiv(Pragma) 177:xi!=mkC; 178:* 179:* 180:'R' 181:mkA.Equiv(Referer) 182:xi!=mkC; 183:* 184:* m_Referer 185:'U' 186:mkA.Equiv(User-Agent) 187:xi!=mkC; 188:* 189:* 190:mkA.Equiv(UA-CPU) 191:xi!=mkC; 192:* 193:* 194:'V' 195:mkA.Equiv(Via) 196:xi!=mkC; 197:* 198:* 199:'x' 200:'X' 201:mkA.Equiv(X-Forwarded-For) 202:xi!=mkC; 203:* 204:* 205:mkA.Equiv(X-ProxyUser-IP) 206:xi!=mkC; 207:* 208:* 209:mkA.Equiv(X-Forwarded-Host) 210:xi!=mkC; 211:* 212:* 213:mkA.Equiv(X-Forwarded-Server) 214:xi!=mkC; 215:* 216:*

Function body:

hzEcode hzHttpEvent::ProcessEvent (hzChain& ZI)
{
   _hzfunc("hzHttpEvent::ProcessEvent") ;
   hzChain::BlkIter    bi ;
   hzChain         Head ;
   hzChain         Word ;
   hzChain         deco ;
   chIter          zi ;
   chIter          xi ;
   chIter          mkA ;
   chIter          mkB ;
   chIter          mkC ;
   hzHttpFile      upload ;
   hzPair          Pair ;
   const char*     i ;
   char*           j ;
   char*           ph ;
   uint64_t        cookie ;
   hzString        S ;
   hzString        boundary ;
   uint32_t        nLine = 0;
   uint32_t        bErr = 0;
   uint32_t        hSofar ;
   uint32_t        n ;
   uint32_t        len ;
   uint32_t        nFst ;
   uint32_t        nSnd ;
   if (!this)      Fatal("No Instance\n") ;
   if (!m_pLog)    Fatal("Cannot process requests. No logfile\n") ;
   if (!m_pCx)     Fatal("Cannot process requests. No client info\n") ;
   m_Report.Printf("ProcessEvents: Input chain of %d bytes\n", ZI.Size()) ;
   m_Report << ZI ;
   if (m_bHdrComplete)
   {
           m_Report.Printf("HTTP HEADER COMPLETE: Goto stage 2 with Header of %d bytes (conn=%p)\n", bi.Data(), m_nHeaderLen, m_pCx) ;
       goto stage_two ;
   }
   if (ZI.Size() < 80)
   {
       zi = ZI ;
       if (!(*zi >&eq; ''A''&&*zi <&eq; ''Z'')||zi == "CONNECT ")
       {
           m_Report << "Invalid Header [" << ZI << "]\n" ;
           SetStatusIP(m_pCx->ClientIP(), HZ_IPSTATUS_BLACK_HTTP, 9000);
           return E_FORMAT ;
       }
       m_Report << "Incomplete Header [" << ZI << "]\n" ;
       return E_OK ;
   }
   m_ClientIP = m_pCx->ClientIP() ;
   m_Occur.SysDateTime() ;
   if (!m_nHeaderLen)
   {
       nFst = nSnd = hSofar = 0;
       for (zi = ZI ; !zi.eof() && Head.Size() < HZ_MAX_HTTP_HDR ; zi++)
       {
           if (*zi == CHAR_CR && zi == "\r\n")
               { Head << "\r\n" ; zi += 2; break ; }
           Head.AddByte(*zi) ;
       }
       hSofar = Head.Size() ;
       for (; !zi.eof() && Head.Size() < HZ_MAX_HTTP_HDR ; zi++)
       {
           if (*zi == CHAR_CR && zi == "\r\n\r\n")
               { Head << "\r\n\r\n" ; m_nHeaderLen = Head.Size() ; break ; }
           if (zi == ": ")
               { nFst++ ; hSofar++ ; }
           if (nFst > nSnd)
               hSofar++ ;
           if (zi == "\r\n")
               nSnd++ ;
           Head.AddByte(*zi) ;
       }
       if (!m_nHeaderLen)
       {
           m_Report.Printf("\n%s: REJECTED REQUEST (Excessive HTTP Header)\n", *m_Occur) ;
           SendError(HTTPMSG_NOTFOUND, "Excessive HTTP Header\n") ;
           return E_RANGE ;
       }
       if (m_nHeaderLen >&eq; HZ_MAX_HTTP_HDR)
       {
           m_Report.Printf("\n%s: REJECTED REQUEST (too large)\n", *m_Occur) ;
           SendError(HTTPMSG_ENTITY_TOO_LARGE, "Excessive HTTP Header\n") ;
           return E_RANGE ;
       }
       if (hSofar < 1024)
           hSofar = 1024;
       ph = m_pBuf = new char[hSofar] ;
       zi = Head ;
       if      (zi == "GET ")      { zi += 4; m_eMethod = HTTP_GET ; }
       else if (zi == "HEAD ")     { zi += 5; m_eMethod = HTTP_HEAD ; }
       else if (zi == "POST ")     { zi += 5; m_eMethod = HTTP_POST ; }
       else if (zi == "OPTIONS ")  { zi += 8; m_eMethod = HTTP_OPTIONS ; }
       else if (zi == "PUT ")      { zi += 4; m_eMethod = HTTP_PUT ; }
       else if (zi == "DELETE ")   { zi += 7; m_eMethod = HTTP_DELETE ; }
       else if (zi == "TRACE ")    { zi += 6; m_eMethod = HTTP_TRACE ; }
       else if (zi == "CONNECT ")  { zi += 8; m_eMethod = HTTP_CONNECT ; }
       else
           bErr |= 0x01;
       if (!bErr)
       {
           for (m_pReqPATH = ph ; !zi.eof() && *zi != CHAR_SPACE && *zi != CHAR_QUERY && *zi != CHAR_HASH ; ph++, zi++)
               *ph = *zi ;
           *ph++ = 0;
           if (*zi == CHAR_QUERY)
           {
               zi++ ;
               m_nQueryLen = _setnvpairs(zi) ;
           }
           if (*zi == CHAR_HASH)
           {
               for (m_pReqFRAG = ph ; !zi.eof() && *zi == CHAR_SPACE ; ph++, zi++)
                   *ph = *zi ;
               *ph++ = 0;
           }
           if (*zi != CHAR_SPACE)
               bErr |= 0x02;
           if (!m_pReqPATH[0])
               bErr |= 0x02;
           zi++ ;
       }
       if (!bErr)
       {
           if (zi != "HTTP/")
               bErr |= 0x04;
           else
           {
               zi += 5;
               if      (zi == "1.0\r\n")   { zi += 5; m_nVersion = 0; }
               else if (zi == "1.1\r\n")   { zi += 5; m_nVersion = 1; }
               else if (zi == "2.0\r\n")   { zi += 5; m_nVersion = 2; }
               else
                   bErr |= 0x08;
           }
       }
       /*
       **  ** Now grab the other headers of interest. Note headers not of interest are ignored. The main objective is to reject HTTP requests that are malformed. The process assumes
       **    ** each header is in it's own line and is of the form "header_name: value\r\n".
       **           */
       for (nLine = 2; !zi.eof() && !bErr ; nLine++)
       {
           if (zi == "\r\n")
               break ;
           for (mkA = mkB = mkC = zi ; !zi.eof() ; zi++)
           {
               if (*zi == CHAR_COLON && zi[1]== CHAR_SPACE)
               {
                   zi += 2;
                   for (len = 0,mkB = zi ; !zi.eof() ; len++, zi++)
                   {
                       if (*zi == CHAR_CR && zi[1]== CHAR_NL)
                           { mkC = zi ; zi += 2; break ; }
                   }
                   if (!len)
                       bErr |= 0x10;
                   break ;
               }
           }
           switch  (toupper(*mkA))
           {
           case ''A'':
               if (mkA.Equiv("Accept"))            { for (m_pAccept = ph,          xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Accept-Charset"))    { for (m_pAcceptCharset = ph,   xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Accept-Language"))   { for (m_pAcceptLang = ph,      xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Accept-Encoding"))   { for (m_pAcceptCode = ph,      xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Authorization: basic"))
               {
                   for (j = ph, xi = mkB ; xi != mkC ; j++, xi++)
                       *j = *xi ;
                   *j++ = 0;
                   Base64Decode(deco, ph) ;
                   m_Auth = deco ;
               }
               break ;
           case ''C'':
               if (mkA.Equiv("Cache-Control"))     { for (m_pCacheControl = ph,    xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Content-Type"))      { for (m_pContentType = ph,     xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Client-ip"))         { for (m_pCliIP = ph,           xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("Content-Length"))    { for (j = ph, xi = mkB ; xi != mkC ; j++, xi++) *j = *xi ; *j++ = 0; m_nContentLen = *ph ? atoi(ph) : 0; break ; }
               if (mkA.Equiv("Connection"))        { m_nConnection = mkB.Equiv("keep-alive") ? 0: 15;break ; }
               if (mkA.Equiv("Cookie"))
               {
                   for (xi = mkB ; *xi ; xi++)
                   {
                       if (xi == "_hz_")
                       {
                           xi += 5;
                           for (j = ph, n = 0; *xi && n < 32&&*xi > CHAR_SPACE && *xi != CHAR_SCOLON ; j++, xi++, n++)
                               *j = *xi ;
                           *j++ = 0;
                           IsHexnum(cookie, ph) ;
                           m_CookieSub = cookie ;
                           break ;
                       }
                   }
               }
               break ;
           case ''F'': if (mkA.Equiv("From"))  { for (m_pFrom = ph, xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; }    break ;
           case ''H'': if (mkA.Equiv("Host"))
                       {
                           for (m_pHost = ph, xi = mkB ; *xi != CHAR_COLON && xi != mkC ; ph++, xi++)
                               *ph = *xi ;
                           *ph++ = 0;
                       }
                       if (xi == CHAR_COLON)
                           for (; xi != mkC ; xi++) ;
                       break ;
           case ''I'': if (mkA.Equiv("If-Modified-Since")) { for (j = ph, xi = mkB ; xi != mkC ; j++, xi++) *j = *xi ; *j++ = 0; m_LastMod = ph ; break ; }
                       if (mkA.Equiv("If-None-Match"))     { for (m_pETag = ph, xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; }
                       break ;
           case ''K'': if (mkA.Equiv("Keep-Alive"))
                           m_nConnection = 15;
                       break ;
           case ''M'': if (mkA.Equiv("Max-Forwards"))  { for (j = ph, xi = mkB ; xi != mkC ; j++, xi++) *j = *xi ; *j++ = 0; m_nMaxForwards = *ph ? atoi(ph) : 0; }    break ;
           case ''P'': if (mkA.Equiv("Pragma"))        { for (m_pPragma = ph,  xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; } break ;
           case ''R'': if (mkA.Equiv("Referer"))       { for (m_pReferer = ph, xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; m_Referer = m_pReferer ; }    break ;
           case ''U'': if (mkA.Equiv("User-Agent"))    { for (m_pUserAgent = ph, xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
                       if (mkA.Equiv("UA-CPU"))        { for (m_pProcessor = ph, xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; }
                       break ;
           case ''V'': if (mkA.Equiv("Via"))
                           { for (m_pVia = ph, xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; }
                       break ;
           case ''x'':
           case ''X'':
               if (mkA.Equiv("X-Forwarded-For"))       { for (m_pFwrdIP = ph,  xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("X-ProxyUser-IP"))        { for (m_pProxIP = ph,  xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("X-Forwarded-Host"))      { for (m_pXost = ph,    xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; break ; }
               if (mkA.Equiv("X-Forwarded-Server"))    { for (m_pServer = ph,  xi = mkB ; xi != mkC ; ph++, xi++) *ph = *xi ; *ph++ = 0; }
               break ;
           default:
               break ;
           }
       }
       if (m_ClientIP == IPADDR_BAD || m_ClientIP == IPADDR_NULL || m_ClientIP == IPADDR_LOCAL)
       {
           if (m_pCliIP)
               m_ClientIP = m_pCliIP ;
       }
       if (m_ClientIP == IPADDR_BAD || m_ClientIP == IPADDR_NULL || m_ClientIP == IPADDR_LOCAL)
       {
           if (m_pFwrdIP)
               m_ClientIP = m_pFwrdIP ;
       }
       if (m_ClientIP == IPADDR_BAD || m_ClientIP == IPADDR_NULL || m_ClientIP == IPADDR_LOCAL)
       {
           if (m_pProxIP)
               m_ClientIP = m_pProxIP ;
       }
       if (m_ClientIP == IPADDR_BAD || m_ClientIP == IPADDR_NULL || m_ClientIP == IPADDR_LOCAL)
       {
       }
       if (!m_pHost)
           bErr |= 0x40;
       if (bErr)
       {
           m_bMsgComplete = true ;
           m_Report.Printf("%s Sock %d/%d REQUEST [\n", *m_Occur, m_pCx->CliSocket(), m_pCx->CliPort()) ;
           m_Report << ZI ;
           m_Report << "]\n" ;
           if (bErr & 0x01)m_Report.Printf("Line 1: Failed to find HTTP Method\n") ;
           if (bErr & 0x02)m_Report.Printf("Line 1: Malformed HTTP resource request\n") ;
           if (bErr & 0x04)m_Report.Printf("Line 1: Invalid HTTP Version\n") ;
           if (bErr & 0x08)m_Report.Printf("Line %d: No space after colon\n", nLine) ;
           if (bErr & 0x10)m_Report.Printf("Line %d: Could not evaluate line\n", nLine) ;
           if (bErr & 0x20)m_Report.Printf("Could not detect client IP\n") ;
           if (bErr & 0x40)m_Report.Printf("No Host header supplied\n") ;
           if (m_eMethod == HTTP_CONNECT && (!m_pHost || m_pHost != _hzGlobal_Hostname))
           {
               if (!(bErr & 0x20))
               {
                   SetStatusIP(m_ClientIP, HZ_IPSTATUS_BLACK_PROT, 9000);
                   return E_FORMAT ;
               }
           }
           if (m_pBuf)             m_Report.Printf("m_pBuf           = %s\n", m_pBuf) ;
           if (m_pAccept)          m_Report.Printf("m_pAccept        = %s\n", m_pAccept) ;
           if (m_pAcceptCharset)   m_Report.Printf("m_pAcceptCharset = %s\n", m_pAcceptCharset) ;
           if (m_pAcceptLang)      m_Report.Printf("m_pAcceptLang    = %s\n", m_pAcceptLang) ;
           if (m_pAcceptCode)      m_Report.Printf("m_pAcceptCode    = %s\n", m_pAcceptCode) ;
           if (m_pCacheControl)    m_Report.Printf("m_pCacheControl  = %s\n", m_pCacheControl) ;
           if (m_pConnection)      m_Report.Printf("m_pConnection    = %s\n", m_pConnection) ;
           if (m_pContentType)     m_Report.Printf("m_pContentType   = %s\n", m_pContentType) ;
           if (m_pETag)            m_Report.Printf("m_pETag          = %s\n", m_pETag) ;
           if (m_pPragma)          m_Report.Printf("m_pPragma        = %s\n", m_pPragma) ;
           if (m_pUserAgent)       m_Report.Printf("m_pUserAgent     = %s\n", m_pUserAgent) ;
           if (m_pProcessor)       m_Report.Printf("m_pProcessor     = %s\n", m_pProcessor) ;
           if (m_pVia)             m_Report.Printf("m_pVia           = %s\n", m_pVia) ;
           if (m_pCliIP)           m_Report.Printf("m_pCliIP         = %s\n", m_pCliIP) ;
           if (m_pHost)            m_Report.Printf("m_pHost          = %s\n", m_pHost) ;
           if (m_pXost)            m_Report.Printf("m_pXost          = %s\n", m_pXost) ;
           if (m_pFwrdIP)          m_Report.Printf("m_pFwrdIP        = %s\n", m_pFwrdIP) ;
           if (m_pProxIP)          m_Report.Printf("m_pProxIP        = %s\n", m_pProxIP) ;
           if (m_pServer)          m_Report.Printf("m_pServer        = %s\n", m_pServer) ;
           if (m_pFrom)            m_Report.Printf("m_pFrom          = %s\n", m_pFrom) ;
           if (m_pReferer)         m_Report.Printf("m_pReferer       = %s\n", m_pReferer) ;
           if (m_pReqPATH)         m_Report.Printf("m_pReqPATH       = %s\n", m_pReqPATH) ;
           if (m_pReqFRAG)         m_Report.Printf("m_pReqFRAG       = %s\n", m_pReqFRAG) ;
           SendError(HTTPMSG_NOTFOUND, "SORRY! INTERNAL ERROR\n") ;
           return E_FORMAT ;
       }
       if (_hzGlobal_Debug & HZ_DEBUG_SERVER)
       {
           m_Report.Printf("%s Sock %d/%d REQUEST [\n", *m_Occur, m_pCx->CliSocket(), m_pCx->CliPort()) ;
           m_Report << ZI ;
           m_Report << "]\n" ;
       }
   }
   m_bHdrComplete = true ;
stage_two:
   if (ZI.Size() < (m_nHeaderLen + m_nContentLen))
   {
       m_Report.Printf("Not recv in full. Hdr %d, cont %d, actual %d\n", m_nHeaderLen, m_nContentLen, ZI.Size()) ;
       return E_OK ;
   }
   if (ZI.Size() > (m_nHeaderLen + m_nContentLen))
       m_Report.Printf("Msg over: Hdr %d, cont %d, actual %d\n", m_nHeaderLen, m_nContentLen, ZI.Size()) ;
   m_bMsgComplete = true ;
   zi = ZI ;
   zi += m_nHeaderLen ;
   if (m_eMethod == HTTP_POST)
   {
       if (m_pContentType)
       {
           for (n = 0,i = m_pContentType ; *i ; i++)
           {
               if (*i == CHAR_SCOLON)
                   { n = 1; continue ; }
               if (n)
               {
                   if (!memcmp(i, "boundary=", 9))
                       { i += 9; boundary = i ; break ; }
               }
           }
       }
       if (!boundary)
           _setnvpairs(zi) ;
       else
       {
           for (; !zi.eof() ;)
           {
               if (zi != boundary)
                   { zi++ ; continue ; }
               /*
               **  ** In the general case, data occurs in the form:-
               **      **  boundary\nContent-Disposition: form-data; name="fldname"
               **      **  data
               **      **  blank line.
               **      ** Note that in the empty field case, there are two blank lines (3 \r\n sequences)
               **      **
               **      ** In the file upload case in the form:-
               **      **  boundary\nContent-Disposition: form-data; name="fldname"; filename="filename"
               **      **  Content-Type: ...
               **      **  blank line
               **      **  filedata
               **      ** Note that the filedata is terminated by the appearence of the boundary on a line by itself and that the whole submission is
               **      ** terminated by the boundary followed directly by two minus signs.
               **                     */
               zi += boundary.Length() ;
               if (zi == "--")
                   break ;
               zi.Skipwhite() ;
               if (zi != "Content-Disposition: form-data; name=")
               {
                   m_Report.Printf("Malformed multipart form submission (case 1)\n") ;
                   for (; !zi.eof() && *zi != CHAR_NL ; zi++) ;
                   break ;
               }
               for (zi += 38;!zi.eof() && *zi != CHAR_DQUOTE ; zi++)
                   Word.AddByte(*zi) ;
               zi++ ;
               Pair.name = Word ;
               Word.Clear() ;
               if (*zi == CHAR_SCOLON)
               {
                   if (zi != "; filename=")
                   {
                       m_Report.Printf("Malformed multipart form submission (case 2)\n") ;
                       for (; !zi.eof() && *zi != CHAR_NL ; zi++) ;
                       break ;
                   }
                   for (zi += 12;!zi.eof() && *zi != CHAR_DQUOTE ; zi++)
                       Word.AddByte(*zi) ;
                   zi++ ;
                   Pair.value = Word ;
                   Word.Clear() ;
                   upload.m_fldname = Pair.name ;
                   upload.m_filename = Pair.value ;
                   zi.Skipwhite() ;
                   if (zi != "Content-Type: ")
                   {
                       m_Report.Printf("Expected Content-Type for submitted file\n") ;
                       break ;
                   }
                   for (zi += 14;!zi.eof() && *zi != CHAR_NL ; zi++)
                   {
                       if (*zi == CHAR_CR)
                           continue ;
                       if (*zi == CHAR_NL)
                           break ;
                       Word.AddByte(*zi) ;
                   }
                   S = Word ;
                   Word.Clear() ;
                   upload.m_mime = Str2Mimetype(S) ;
                   if (_hzGlobal_Debug & HZ_DEBUG_SERVER)
                       m_Report.Printf("MIME type of %s is %d (%s)\n", *Pair.value, upload.m_mime, *S) ;
                   zi++ ;
                   if (zi == "\r\n")
                       zi += 2;
                   for (; !zi.eof() ; zi++)
                   {
                       if (zi == "\r\n--")
                       {
                           zi += 4;
                           if (zi == boundary)
                               break ;
                           upload.m_file << "\r\n--" ;
                           continue ;
                       }
                       upload.m_file.AddByte(*zi) ;
                   }
                   m_Inputs.Add(Pair) ;
                   m_mapStrings.Insert(Pair.name, Pair.value) ;
                   m_Report.Printf("Field name/value %s=%s\n", *Pair.name, *Pair.value) ;
                   m_Uploads.Insert(upload.m_fldname, upload) ;
                   m_Report.Printf("Got file of %d bytes\n", upload.m_file.Size()) ;
               }
               else
               {
                   if (*zi != CHAR_CR)
                       m_Report.Printf("Warning fld not at CR, char=%c instead\n", *zi) ;
                   zi.Skipwhite() ;
                   for (; !zi.eof() ; zi++)
                   {
                       if (zi == "\r\n")
                       {
                           zi += 2;
                           if (zi == "--")
                           {
                               zi += 2;
                               if (zi == boundary)
                                   break ;
                           }
                           Word.AddByte(CHAR_NL) ;
                           continue ;
                       }
                       Word.AddByte(*zi) ;
                   }
                   Pair.value = Word ;
                   Word.Clear() ;
                   m_Inputs.Add(Pair) ;
                   m_mapStrings.Insert(Pair.name, Pair.value) ;
                   m_Report.Printf("Field name/value %s=%s\n", *Pair.name, *Pair.value) ;
               }
           }
       }
   }
   return E_OK ;
}