| 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 ;
}