2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS HTTP Daemon
5 * PURPOSE: HTTP 1.1 parser engine
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/09/2000 Created
9 * TODO: - Implement message-body
10 * - Implement more generel-header entries
11 * - Implement more request-header entries
12 * - Implement more entity-header entries
19 CHAR MethodTable[NUMMETHODS][8] = {"OPTIONS", "GET", "HEAD", "POST", "PUT",
22 CHAR GenerelTable[NUMGENERELS][18] = {"Cache-Control", "Connection", "Date", "Pragma",
23 "Transfer-Encoding", "Upgrade", "Via"};
25 CHAR RequestTable[NUMREQUESTS][20] = {"Accept", "Accept-Charset", "Accept-Encoding",
26 "Accept-Language", "Authorization", "From", "Host", "If-Modified-Since", "If-Match",
27 "If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards",
28 "Proxy-Authorization", "Range", "Referer", "User-Agent"};
30 CHAR EntityTable[NUMENTITIES][17] = {"Allow", "Content-Base", "Content-Encoding",
31 "Content-Language", "Content-Length", "Content-Location", "Content-MD5",
32 "Content-Range", "Content-Type", "ETag", "Expires", "Last-Modified"};
34 // *************************** CHttpParser ***************************
36 // Default constructor
37 CHttpParser::CHttpParser()
44 CHttpParser::~CHttpParser()
48 // Returns TRUE if a complete HTTP message is in buffer
49 BOOL CHttpParser::Complete()
53 /*DPRINT("--1:-%d---\n", sBuffer[nHead-2]);
54 DPRINT("--2:-%d---\n", sBuffer[nHead-1]);
58 DPRINT("Examining buffer: (Head: %d, Tail: %d)\n", nHead, nTail);
59 DPRINT("%s\n", (LPSTR)&sBuffer[nTail]);*/
71 // Read a character from buffer
72 BOOL CHttpParser::ReadChar(LPSTR lpsStr)
76 lpsStr[0] = sBuffer[nTail];
84 if (nTail == sizeof(sBuffer))
87 lpsStr[0] = sBuffer[nTail];
97 // Peek at a character in the buffer
98 BOOL CHttpParser::PeekChar(LPSTR lpsStr)
102 if (nTail == sizeof(sBuffer))
106 if (nFakeTail != nHead) {
107 lpsStr[0] = sBuffer[nFakeTail];
115 // Read a string from buffer. Only A-Z, a-z, 0-9 and '-' are valid characters
116 BOOL CHttpParser::ReadString(LPSTR lpsStr, UINT nLength)
121 while (PeekChar(&sTmp)) {
122 if (((sTmp >= 'A') && (sTmp <= 'Z')) || ((sTmp >= 'a') && (sTmp <= 'z')) ||
123 ((sTmp >= '0') && (sTmp <= '9')) || (sTmp == '-')) {
124 if (i >= (nLength - 1)) {
140 // Read a string from buffer. Stop if SP or CR is found or when there are no more
142 BOOL CHttpParser::ReadSpecial(LPSTR lpsStr, UINT nLength)
147 while (PeekChar(&sTmp) && (sTmp != ' ') && (sTmp != 13)) {
148 if (i >= (nLength - 1)) {
149 lpsStr[nLength - 1] = 0;
160 // Skip until "sCh" is found
161 VOID CHttpParser::Skip(CHAR sCh)
165 while (PeekChar(&sTmp) && (sTmp != sCh))
169 // Return TRUE if sCh is the next character
170 BOOL CHttpParser::Expect(CHAR sCh)
174 if (PeekChar(&sTmp)) {
183 // Return TRUE if CRLF are the next characters
184 BOOL CHttpParser::ExpectCRLF()
186 return (Expect(13) && Expect(10));
189 // Request = RequestLine | *( GenerelHeader | RequestHeader | EntityHeader )
190 // CRLF [ MessageBody ]
191 BOOL CHttpParser::Parse()
200 if (!ReadString(sHeader, sizeof(sHeader)))
202 bStatus = (GenerelHeader());
203 bStatus = (RequestHeader() || bStatus);
204 bStatus = (EntityHeader() || bStatus);
215 // RequestLine = Method SP RequestURI SP HTTP-Version CRLF
216 BOOL CHttpParser::RequestLine()
221 bUnknownMethod = FALSE;
223 // RFC 2068 states that servers SHOULD ignore any empty nine(s) received where a
224 // Request-Line is expected
225 while (PeekChar(&sCh) && ((sCh == 13) || (sCh == 10)));
227 if (!ReadString(sMethod, sizeof(sMethod)))
230 for (i = 0; i < NUMMETHODS; i++) {
231 if (strcmp(MethodTable[i], sMethod) == 0) {
235 // URI (ie. host/directory/resource)
236 if (!ReadSpecial(sUri, sizeof(sUri)))
240 // HTTP version (eg. HTTP/1.1)
241 if (!ReadSpecial(sVersion, sizeof(sVersion)))
250 bUnknownMethod = TRUE;
254 // GenerelHeader = Cache-Control | Connection | Date | Pragma | Transfer-Encoding |
256 BOOL CHttpParser::GenerelHeader()
260 for (i = 0; i < NUMGENERELS; i++) {
261 if (strcmp(GenerelTable[i], sHeader) == 0) {
284 // RequestHeader = Accept | Accept-Charset | Accept-Encoding | Accept-Language |
285 // Authorization | From | Host | If-Modified-Since | If-Match |
286 // If-None-Match | If-Range | If-Unmodified-Since | Max-Forwards |
287 // Proxy-Authorization | Range | Referer | User-Agent
288 BOOL CHttpParser::RequestHeader()
292 for (i = 0; i < NUMREQUESTS; i++) {
293 if (strcmp(RequestTable[i], sHeader) == 0) {
349 // EntityHeader = Allow | Content-Base | Content-Encoding | Content-Language |
350 // Content-Length | Content-Location | Content-MD5 |
351 // Content-Range | Content-Type | ETag | Expires |
352 // Last-Modified | extension-header
353 BOOL CHttpParser::EntityHeader()
357 for (i = 0; i < NUMENTITIES; i++) {
358 if (strcmp(EntityTable[i], sHeader) == 0) {
362 //cout << "<Entity-Header>: #" << i << endl;
376 // MessageBody = *OCTET
377 BOOL CHttpParser::MessageBody()