Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS HTTP Daemon * FILE: http.cpp * PURPOSE: HTTP 1.1 parser engine * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) * REVISIONS: * CSH 01/09/2000 Created * TODO: - Implement message-body * - Implement more generel-header entries * - Implement more request-header entries * - Implement more entity-header entries */#include <debug.h>#include <iostream>#include <string.h>#include <http.h>
CHAR MethodTable[NUMMETHODS][8] = {"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE"};
CHAR GenerelTable[NUMGENERELS][18] = {"Cache-Control", "Connection", "Date", "Pragma", "Transfer-Encoding", "Upgrade", "Via"};
CHAR RequestTable[NUMREQUESTS][20] = {"Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "From", "Host", "If-Modified-Since", "If-Match", "If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards", "Proxy-Authorization", "Range", "Referer", "User-Agent"};
CHAR EntityTable[NUMENTITIES][17] = {"Allow", "Content-Base", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "ETag", "Expires", "Last-Modified"};
// *************************** CHttpParser ***************************
// Default constructorCHttpParser::CHttpParser(){ nHead = 0; nTail = 0;}
// Default destructorCHttpParser::~CHttpParser(){}
// Returns TRUE if a complete HTTP message is in bufferBOOL CHttpParser::Complete(){ UINT nTmp;
/*DPRINT("--1:-%d---\n", sBuffer[nHead-2]); DPRINT("--2:-%d---\n", sBuffer[nHead-1]);
sBuffer[nHead] = '!'; sBuffer[nHead+1] = 0; DPRINT("Examining buffer: (Head: %d, Tail: %d)\n", nHead, nTail); DPRINT("%s\n", (LPSTR)&sBuffer[nTail]);*/
nTmp = nTail; if (!Parse()) { if (!bUnknownMethod) nTail = nTmp; return FALSE; } else return TRUE;}
// Read a character from bufferBOOL CHttpParser::ReadChar(LPSTR lpsStr){ if (nTail <= nHead) { if (nTail != nHead) { lpsStr[0] = sBuffer[nTail]; nTail++; return TRUE; } else { lpsStr[0] = 0; return FALSE; } } else { if (nTail == sizeof(sBuffer)) nTail = 0; if (nTail != nHead) { lpsStr[0] = sBuffer[nTail]; nTail++; return TRUE; } else { lpsStr[0] = 0; return FALSE; } }}
// Peek at a character in the bufferBOOL CHttpParser::PeekChar(LPSTR lpsStr){ UINT nFakeTail;
if (nTail == sizeof(sBuffer)) nFakeTail = 0; else nFakeTail = nTail; if (nFakeTail != nHead) { lpsStr[0] = sBuffer[nFakeTail]; return TRUE; } else { lpsStr[0] = 0; return FALSE; }}
// Read a string from buffer. Only A-Z, a-z, 0-9 and '-' are valid charactersBOOL CHttpParser::ReadString(LPSTR lpsStr, UINT nLength){ UINT i = 0; CHAR sTmp;
while (PeekChar(&sTmp)) { if (((sTmp >= 'A') && (sTmp <= 'Z')) || ((sTmp >= 'a') && (sTmp <= 'z')) || ((sTmp >= '0') && (sTmp <= '9')) || (sTmp == '-')) { if (i >= (nLength - 1)) { lpsStr[0] = 0; return FALSE; } ReadChar(&sTmp); lpsStr[i] = sTmp; i++; } else { lpsStr[i] = 0; return TRUE; } } lpsStr[0] = 0; return FALSE;}
// Read a string from buffer. Stop if SP or CR is found or when there are no more// charactersBOOL CHttpParser::ReadSpecial(LPSTR lpsStr, UINT nLength){ UINT i = 0; CHAR sTmp;
while (PeekChar(&sTmp) && (sTmp != ' ') && (sTmp != 13)) { if (i >= (nLength - 1)) { lpsStr[nLength - 1] = 0; return FALSE; } ReadChar(&sTmp); lpsStr[i] = sTmp; i++; } lpsStr[i] = 0; return TRUE;}
// Skip until "sCh" is foundVOID CHttpParser::Skip(CHAR sCh){ CHAR sTmp;
while (PeekChar(&sTmp) && (sTmp != sCh)) ReadChar(&sTmp);}
// Return TRUE if sCh is the next characterBOOL CHttpParser::Expect(CHAR sCh){ CHAR sTmp;
if (PeekChar(&sTmp)) { if (sTmp == sCh) { ReadChar(&sTmp); return TRUE; } } return FALSE;}
// Return TRUE if CRLF are the next charactersBOOL CHttpParser::ExpectCRLF(){ return (Expect(13) && Expect(10));}
// Request = RequestLine | *( GenerelHeader | RequestHeader | EntityHeader )// CRLF [ MessageBody ]BOOL CHttpParser::Parse(){ BOOL bStatus;
if (RequestLine()) { do { if (!ReadString(sHeader, sizeof(sHeader))) break; bStatus = (GenerelHeader()); bStatus = (RequestHeader() || bStatus); bStatus = (EntityHeader() || bStatus); } while (bStatus); // CRLF if (!ExpectCRLF()) return FALSE; MessageBody(); return TRUE; } return FALSE;}
// RequestLine = Method SP RequestURI SP HTTP-Version CRLFBOOL CHttpParser::RequestLine(){ CHAR sCh; UINT i;
bUnknownMethod = FALSE;
// RFC 2068 states that servers SHOULD ignore any empty nine(s) received where a // Request-Line is expected while (PeekChar(&sCh) && ((sCh == 13) || (sCh == 10)));
if (!ReadString(sMethod, sizeof(sMethod))) return FALSE;
for (i = 0; i < NUMMETHODS; i++) { if (strcmp(MethodTable[i], sMethod) == 0) { nMethodNo = i; if (!Expect(' ')) return FALSE; // URI (ie. host/directory/resource) if (!ReadSpecial(sUri, sizeof(sUri))) return FALSE; if (!Expect(' ')) return FALSE; // HTTP version (eg. HTTP/1.1) if (!ReadSpecial(sVersion, sizeof(sVersion))) return FALSE; // CRLF if (!ExpectCRLF()) return FALSE;
return TRUE; } } bUnknownMethod = TRUE; return FALSE;}
// GenerelHeader = Cache-Control | Connection | Date | Pragma | Transfer-Encoding |// Upgrade | ViaBOOL CHttpParser::GenerelHeader(){ INT i;
for (i = 0; i < NUMGENERELS; i++) { if (strcmp(GenerelTable[i], sHeader) == 0) { switch (i) { case 1: { //Connection Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); break; } default: { Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); } } return TRUE; } } return FALSE;}
// RequestHeader = Accept | Accept-Charset | Accept-Encoding | Accept-Language |// Authorization | From | Host | If-Modified-Since | If-Match |// If-None-Match | If-Range | If-Unmodified-Since | Max-Forwards |// Proxy-Authorization | Range | Referer | User-AgentBOOL CHttpParser::RequestHeader(){ INT i;
for (i = 0; i < NUMREQUESTS; i++) { if (strcmp(RequestTable[i], sHeader) == 0) { switch (i) { case 0: { //Accept Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); break; } case 2: { //Accept-Encoding Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); break; } case 3: { //Accept-Language Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); break; } case 6: { //Host Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); break; } case 16: { //User-Agent Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); break; } default: { Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); return TRUE; } } return TRUE; } } return FALSE;}
// EntityHeader = Allow | Content-Base | Content-Encoding | Content-Language |// Content-Length | Content-Location | Content-MD5 |// Content-Range | Content-Type | ETag | Expires |// Last-Modified | extension-headerBOOL CHttpParser::EntityHeader(){ INT i;
for (i = 0; i < NUMENTITIES; i++) { if (strcmp(EntityTable[i], sHeader) == 0) { switch (i) { case 0: default: { //cout << "<Entity-Header>: #" << i << endl; Expect(':'); Expect(' '); Skip(13); ExpectCRLF(); return TRUE; } } return FALSE; } } return FALSE;}
// MessageBody = *OCTETBOOL CHttpParser::MessageBody(){ return FALSE;}