Return Type | Function name | Arguments |
---|---|---|
hzEcode | hzHttpEvent::ProcessEvent | (hzChain&,) |
Declared in file: hzHttpServer.h
Defined in file : hzHttpServer.cpp
Function Logic:
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 ; }