[611] | 1 | /*
|
---|
| 2 | Copyright (C) 1996
|
---|
| 3 |
|
---|
| 4 | This program is free software; you can redistribute it and/or modify
|
---|
| 5 | it under the terms of the GNU General Public License as published by
|
---|
| 6 | the Free Software Foundation; either version 2 of the License, or
|
---|
| 7 | (at your option) any later version.
|
---|
| 8 |
|
---|
| 9 | This program is distributed in the hope that it will be useful,
|
---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 12 | GNU General Public License for more details.
|
---|
| 13 |
|
---|
| 14 | You should have received a copy of the GNU General Public License
|
---|
| 15 | along with this program; if not, write to the Free Software
|
---|
| 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
| 17 |
|
---|
| 18 | The author can be contacted via Email at [email protected]
|
---|
| 19 | */
|
---|
[1279] | 20 | #include "text_t.h"
|
---|
[611] | 21 | #include <windows.h>
|
---|
| 22 | #include <stdlib.h>
|
---|
| 23 | #include <stdio.h>
|
---|
| 24 | #include <string.h>
|
---|
| 25 | #include <memory.h>
|
---|
| 26 | #pragma hdrstop
|
---|
| 27 | #include "parse.h"
|
---|
| 28 | #include "netio.h"
|
---|
| 29 | #include "settings.h"
|
---|
| 30 | #include "httpreq.h" //Had to put myself here because of the global types...
|
---|
| 31 | #include "httpsrv.h"
|
---|
| 32 | #include "httpsend.h"
|
---|
| 33 | #include "cgiwrapper.h"
|
---|
| 34 |
|
---|
| 35 | /*
|
---|
| 36 | Implementation Notes:
|
---|
| 37 |
|
---|
| 38 | HTTP field names, method and version strings are converted to upper case
|
---|
| 39 | right after being read from the client in order to allow case insensitive
|
---|
| 40 | string comparisons to be done on them. Since these fields are worked with a
|
---|
| 41 | lot, this should help performance.
|
---|
| 42 | */
|
---|
| 43 |
|
---|
| 44 | //Private Data and declarations
|
---|
| 45 | #define IO_BUFFER_SIZE 16384 //16K IO Buffer
|
---|
| 46 | #define MAX_HTTP_LINE_LEN 1024 //Max length of line in a header of 1024
|
---|
| 47 | #define MAX_HTTP_FIELD_NAME_LEN 128 //Max length of name field in line
|
---|
| 48 | #define MAX_HTTP_FIELD_LEN 1024 //Max length of data in line
|
---|
| 49 |
|
---|
| 50 | //Private Function Declarations with Return Contstants
|
---|
| 51 |
|
---|
| 52 | /*
|
---|
| 53 | Function Name: DispatchRequest
|
---|
| 54 | Purpose: Manages having the request parsed, then sent to the right function
|
---|
| 55 | to send a response or handle an error.
|
---|
| 56 | Parameters:
|
---|
| 57 | ClientSocket - Socket the client is on
|
---|
| 58 | ClientSockAddr - Address of client
|
---|
| 59 | AddrLen - Length of address of client
|
---|
| 60 | IOBuffer - Pointer to buffer allocated for IO operations
|
---|
| 61 | ThreadNum - Number of thread that called this function for debugging purposes
|
---|
| 62 | Notes: I'm still playing with the keep alive support. I commented out
|
---|
| 63 | the stuff for giving a client a timeout because I was unable to detect
|
---|
| 64 | disconnects.
|
---|
| 65 | More Notes: Not sure if this organization will allow me to easily add support
|
---|
| 66 | for ISAPI filter DLLs.
|
---|
| 67 | */
|
---|
| 68 | void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen, BYTE *IOBuffer);
|
---|
| 69 |
|
---|
| 70 | /*
|
---|
| 71 | Function Name: Get HTTP Headers
|
---|
| 72 | Purpose: Manages having the request parsed, then sent to the right function
|
---|
| 73 | to send a response or handle an error.
|
---|
| 74 | Parameters:
|
---|
| 75 | RequestInfo - Request information structure (see httpreq.h)
|
---|
| 76 | RequestFields - HTTP request fields structure (see httpreq.h)
|
---|
| 77 | Returns: GH_ERROR on error (diconnect, bad data, Windows in a bad mood, etc.)
|
---|
| 78 | GH_UNKNOWN_VERSION if the version number is not HTTP/0.9 or HTTP/1.x
|
---|
| 79 | GH_SIMPLE_REQUEST on a properly formated HTTP/0.9 request
|
---|
| 80 | GH_10_REQUEST on a properly formated HTTP/1.x request
|
---|
| 81 | */
|
---|
| 82 | int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
|
---|
| 83 | #define GH_ERROR -1
|
---|
| 84 | #define GH_UNKNOWN_VERSION 0
|
---|
| 85 | #define GH_SIMPLE_REQUEST 1
|
---|
| 86 | #define GH_10_REQUEST 2
|
---|
| 87 |
|
---|
| 88 | /*
|
---|
| 89 | Function Name: Clean Up HTTP Headers
|
---|
| 90 | Purpose: Cleans up memory dynamicly allocated for headers
|
---|
| 91 | Parameters:
|
---|
| 92 | RequestInfo - Request information structure (see httpreq.h)
|
---|
| 93 | RequestFields - HTTP request fields structure (see httpreq.h)
|
---|
| 94 | Returns: Nothing
|
---|
| 95 | */
|
---|
| 96 | void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
|
---|
| 97 |
|
---|
| 98 | /*
|
---|
| 99 | Function Name: Split Query
|
---|
| 100 | Purpose: Splits the file and query part of a URI. In other words, it
|
---|
| 101 | puts the parts before and after the "?" in differnet strings.
|
---|
| 102 | Parameters:
|
---|
| 103 | URIStr - The requested URI
|
---|
| 104 | FileStr - String to contain the name of the path + file part of the URI
|
---|
| 105 | QueryStr - String to contain the query part of the URI
|
---|
| 106 | Returns: TRUE if there is a query, else FALSE
|
---|
| 107 | */
|
---|
| 108 | BOOL SplitQuery(char *URIStr, char *FileStr, char *QueryStr, int ThreadNum);
|
---|
| 109 |
|
---|
| 110 | /*
|
---|
| 111 | Function Name: Get File
|
---|
| 112 | Purpose: Attempts to find a given file, including looking for index.html.
|
---|
| 113 | Updates the given URI string so it points to the true document location
|
---|
| 114 | Parameters:
|
---|
| 115 | FilePath - Path of file, may be modified to best reflect the retrived file
|
---|
| 116 | or directory
|
---|
| 117 | URIStr - URI string, minus the query
|
---|
| 118 | Returns: GF_ERROR on error
|
---|
| 119 | GF_FILE_FOUND on success
|
---|
| 120 | GF_INDEX_FOUND if file is a directory with an index.html file in it
|
---|
| 121 | GF_DIRECTORY if file is a directory
|
---|
| 122 | GF_FILE_NOT_FOUND if file was found
|
---|
| 123 | */
|
---|
| 124 |
|
---|
| 125 | /*
|
---|
| 126 | Function Name: Process Simple Request
|
---|
| 127 | Purpose: Sends a reply to a HTTP 0.9 "simple" request
|
---|
| 128 | Parameters:
|
---|
| 129 | ClientSocket - Socket the client is on
|
---|
| 130 | RequestInfo - Structure storing the parsed headers
|
---|
| 131 | IOBuffer - Pointer to buffer allocated for IO operations
|
---|
| 132 | TheadNum - Number of calling thread for debugging
|
---|
| 133 | Notes: I should really test this and see if it works...
|
---|
| 134 | */
|
---|
| 135 | void ProcessSimpleRequest(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
|
---|
| 136 |
|
---|
| 137 | //Public Functions
|
---|
| 138 | /******************************************************************************/
|
---|
| 139 | void RequestThread(RequestThreadMessageT *Parameters) {
|
---|
| 140 | SOCKADDR_IN ClientSockAddr;
|
---|
| 141 | SOCKET ClientSocket;
|
---|
| 142 | int AddrLen;
|
---|
| 143 | //Allocate an IO buffer for this thread
|
---|
| 144 | BYTE *IOBuffer = new BYTE[IO_BUFFER_SIZE];
|
---|
| 145 |
|
---|
| 146 | //Get the parameters for the request
|
---|
| 147 | ClientSocket = Parameters->ClientSocket;
|
---|
| 148 | ClientSockAddr = Parameters->ClientSockAddr;
|
---|
| 149 | AddrLen = Parameters->AddrLen;
|
---|
| 150 | DispatchRequest(ClientSocket, ClientSockAddr, AddrLen, IOBuffer);
|
---|
| 151 | }
|
---|
| 152 | /******************************************************************************/
|
---|
| 153 |
|
---|
| 154 | //Private Functions
|
---|
| 155 |
|
---|
| 156 | /******************************************************************************/
|
---|
| 157 | void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen, BYTE *IOBuffer) {
|
---|
| 158 | RequestInfoT RequestInfo;
|
---|
| 159 | RequestFieldsT RequestFields;
|
---|
| 160 |
|
---|
| 161 | // TrayAddConnection();
|
---|
| 162 |
|
---|
| 163 | //Setup the RequestInfo structure
|
---|
| 164 | memset(&RequestInfo, 0, sizeof(RequestInfoT));
|
---|
| 165 | RequestInfo.ThreadNum = 0;
|
---|
| 166 | RequestInfo.IOBuffer = IOBuffer;
|
---|
| 167 | RequestInfo.IOBufferSize = IO_BUFFER_SIZE;
|
---|
| 168 | RequestInfo.ClientSocket = ClientSocket;
|
---|
| 169 | RequestInfo.ClientSockAddr = ClientSockAddr;
|
---|
| 170 | RequestInfo.AddrLen = AddrLen;
|
---|
| 171 | RequestInfo.KeepAlive = FALSE;
|
---|
| 172 |
|
---|
| 173 | int GetHeadersResult;
|
---|
| 174 | do {
|
---|
| 175 | //Get Headers
|
---|
| 176 | GetHeadersResult = GetHTTPHeaders(RequestInfo, RequestFields);
|
---|
| 177 | //Figure out what version we're dealing with and deal with it
|
---|
| 178 | switch (GetHeadersResult) {
|
---|
| 179 | case GH_SIMPLE_REQUEST :
|
---|
| 180 | SendHTTPError(400, "HTTP Request not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
|
---|
| 181 | // TrayIncNumServed();
|
---|
| 182 | break;
|
---|
| 183 | case GH_10_REQUEST :
|
---|
| 184 | ExamineURIStr(RequestFields.URIStr,&RequestInfo,&RequestFields);
|
---|
| 185 | // TrayIncNumServed();
|
---|
| 186 | break;
|
---|
| 187 | case GH_UNKNOWN_VERSION :
|
---|
| 188 | SendHTTPError(400, "HTTP Version not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
|
---|
| 189 | // TrayIncNumServed();
|
---|
| 190 | break;
|
---|
| 191 | case GH_ERROR:
|
---|
| 192 | //Disconnect
|
---|
| 193 | RequestInfo.KeepAlive = FALSE;
|
---|
| 194 | break;
|
---|
| 195 | }
|
---|
| 196 | CleanUpHTTPHeaders(RequestInfo, RequestFields);
|
---|
| 197 | } while (0/*RequestInfo.KeepAlive == TRUE*/);
|
---|
| 198 | //Close connection
|
---|
| 199 | CloseSocket(RequestInfo.ClientSocket);
|
---|
| 200 | // TrayRemoveConnection();
|
---|
| 201 | }
|
---|
| 202 |
|
---|
| 203 | /******************************************************************************/
|
---|
| 204 | int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
|
---|
| 205 | //Parsing and IO buffers
|
---|
| 206 | char CurLine[NETIO_MAX_LINE];
|
---|
| 207 | char NextLine[NETIO_MAX_LINE];
|
---|
| 208 | char FieldNameStr[MAX_HTTP_FIELD_NAME_LEN];
|
---|
| 209 | char FieldValStr[MAX_HTTP_FIELD_LEN];
|
---|
| 210 |
|
---|
| 211 | //Parsing and IO working vars
|
---|
| 212 | int ReadBufferIndex;
|
---|
| 213 | int DataInBuffer;
|
---|
| 214 | int Start;
|
---|
| 215 | int End;
|
---|
| 216 | int Len;
|
---|
| 217 |
|
---|
| 218 | //Clear all the fields
|
---|
| 219 | memset(&RequestFields, 0, sizeof(RequestFieldsT));
|
---|
| 220 |
|
---|
| 221 | ReadBufferIndex = 0;
|
---|
| 222 | DataInBuffer = 0;
|
---|
| 223 |
|
---|
| 224 | //Get First Line
|
---|
| 225 | if (GetLine(CurLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
|
---|
| 226 | RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
|
---|
| 227 | RequestInfo.ThreadNum) != 0) return GH_ERROR;
|
---|
| 228 | do {//Get Next Line, append it if the first charactor is space
|
---|
| 229 | if(GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
|
---|
| 230 | RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
|
---|
| 231 | RequestInfo.ThreadNum) != 0) return GH_ERROR;
|
---|
| 232 | if ((NextLine[0] == ' ') || (NextLine[0] == '\t'))
|
---|
| 233 | strcat(CurLine, NextLine);
|
---|
| 234 | } while ((NextLine[0] == ' ') || (NextLine[0] == '\t'));
|
---|
| 235 | //Method String (first word)
|
---|
| 236 | Start = 0;
|
---|
| 237 | GetWord(RequestFields.MethodStr, CurLine, Start, End);
|
---|
| 238 | CharUpper(RequestFields.MethodStr);
|
---|
| 239 |
|
---|
| 240 | //Version String (last word)
|
---|
| 241 | GetLastWord(RequestFields.VersionStr, CurLine, Start);
|
---|
| 242 | CharUpper(RequestFields.VersionStr);
|
---|
| 243 |
|
---|
| 244 | if (strncmp(RequestFields.VersionStr, "HTTP/", 5) != 0) {
|
---|
| 245 | //No version, assume simple request
|
---|
| 246 | //part after method is URI
|
---|
| 247 | memcpy(RequestFields.URIStr, CurLine + End, strlen(CurLine) + 1 - End);
|
---|
| 248 | return GH_SIMPLE_REQUEST;
|
---|
| 249 | }
|
---|
| 250 |
|
---|
| 251 | //URI String (in between End of first and Start of last)
|
---|
| 252 | //<Method> <WhiteSpace> <URI> <WhiteSpace> <Version> <CRLF>
|
---|
| 253 | // End^ Start^
|
---|
| 254 | int URIStrLen = Start - End;;
|
---|
| 255 | if (URIStrLen > ReqURIStrLen-1) URIStrLen = ReqURIStrLen - 1;
|
---|
| 256 | memcpy(RequestFields.URIStr, CurLine + End, URIStrLen);
|
---|
| 257 | RequestFields.URIStr[URIStrLen] = 0;
|
---|
| 258 | TrimRight(RequestFields.URIStr); //Remove trailing space
|
---|
| 259 |
|
---|
| 260 | //Only accept requests from HTTP/0.9 or HTTP/1.X clients, we'll
|
---|
| 261 | //assume that anything else will require an upgrade or patch
|
---|
| 262 | if (strncmp(RequestFields.VersionStr, "HTTP/1.", 7) != 0)
|
---|
| 263 | return GH_UNKNOWN_VERSION;
|
---|
| 264 |
|
---|
| 265 | //Get the rest of the lines
|
---|
| 266 |
|
---|
| 267 | strcpy(CurLine, NextLine);
|
---|
| 268 |
|
---|
| 269 | while (CurLine[0] != 0) {//Blank Line, we're done
|
---|
| 270 | do {//Get Next Line, append it if the first charactor is space
|
---|
| 271 | if (GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
|
---|
| 272 | RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
|
---|
| 273 | RequestInfo.ThreadNum) != 0)
|
---|
| 274 | return GH_ERROR;
|
---|
| 275 | if ((NextLine[0] == ' ') || (NextLine[0] == '\t'))
|
---|
| 276 | strcat(CurLine, NextLine);
|
---|
| 277 | } while ((NextLine[0] == ' ') || (NextLine[0] == '\t'));
|
---|
| 278 |
|
---|
| 279 | Start = 0;
|
---|
| 280 | GetWord(FieldNameStr, CurLine, Start, End);
|
---|
| 281 | CharUpper(FieldNameStr);
|
---|
| 282 |
|
---|
| 283 | Len = strlen(CurLine) - End;
|
---|
| 284 | memcpy(FieldValStr, CurLine + End, Len);
|
---|
| 285 | FieldValStr[Len] = 0;
|
---|
| 286 |
|
---|
| 287 | //Process it
|
---|
| 288 | //In order of expected commonality
|
---|
| 289 | //All constants are in canonized, thus in upper case and case sensitive
|
---|
| 290 | //comparisons are used
|
---|
| 291 | //--Just About Always--
|
---|
| 292 | if (strcmp("ACCEPT:", FieldNameStr) == 0) {
|
---|
| 293 | if (RequestFields.AcceptStr[0] == '\0') {
|
---|
| 294 | strncpy(RequestFields.AcceptStr, FieldValStr, ReqAcceptStrLen - 1);
|
---|
| 295 | // if (Len >= ReqAcceptStrLen)
|
---|
| 296 | // if (log_debug) log_message("Accept field truncated");
|
---|
| 297 | }
|
---|
| 298 | else {
|
---|
| 299 | //Append it with a comma
|
---|
| 300 | int AcceptStrLen = strlen(RequestFields.AcceptStr);
|
---|
| 301 | if ((ReqAcceptStrLen - AcceptStrLen) >= 10) {
|
---|
| 302 | strncat(RequestFields.AcceptStr, ", ", ReqAcceptStrLen - AcceptStrLen - 1);
|
---|
| 303 | strncat(RequestFields.AcceptStr, FieldValStr, ReqAcceptStrLen - AcceptStrLen - 3);
|
---|
| 304 | }
|
---|
| 305 | }
|
---|
| 306 | }
|
---|
| 307 | else if (strcmp("DATE:", FieldNameStr) == 0) {
|
---|
| 308 | strncpy(RequestFields.DateStr, FieldValStr, ReqDateStrLen - 1);
|
---|
| 309 | // if (Len >= ReqDateStrLen) LogError("Date field truncated");
|
---|
| 310 | }
|
---|
| 311 | else if (strcmp("USER-AGENT:", FieldNameStr) == 0) {
|
---|
| 312 | strncpy(RequestFields.UserAgentStr, FieldValStr, ReqUserAgentStrLen - 1);
|
---|
| 313 | // if (Len >= ReqUserAgentStrLen) {
|
---|
| 314 | // LogError("User Agent field truncated, value follows");
|
---|
| 315 | // LogError(RequestFields.UserAgentStr);
|
---|
| 316 | // }
|
---|
| 317 | }
|
---|
| 318 | else if (strcmp("CONNECTION:", FieldNameStr) == 0) {
|
---|
| 319 | strncpy(RequestFields.ConnectionStr, FieldValStr, ReqConnectionStrLen - 1);
|
---|
| 320 | // if (Len >= ReqConnectionStrLen) LogError("Connection field truncated");
|
---|
| 321 | }
|
---|
| 322 | //--Sometimes--
|
---|
| 323 | else if (strcmp("ACCEPT-LANGUAGE:", FieldNameStr) == 0) {
|
---|
| 324 | strncpy(RequestFields.AcceptLangStr, FieldValStr, ReqAcceptLangStrLen - 1);
|
---|
| 325 | // if (Len >= ReqAcceptLangStrLen) LogError("Accept-Language field truncated");
|
---|
| 326 | }
|
---|
| 327 | else if (strcmp("REFERER:", FieldNameStr) == 0) {
|
---|
| 328 | strncpy(RequestFields.RefererStr, FieldValStr, ReqRefererStrLen - 1);
|
---|
| 329 | // if (Len >= ReqRefererStrLen) LogError("Referer field truncated");
|
---|
| 330 | }
|
---|
| 331 | else if (strcmp("IF-MODIFIED-SINCE:", FieldNameStr) == 0) {
|
---|
| 332 | strncpy(RequestFields.IfModSinceStr, FieldValStr, ReqIfModSinceStrLen - 1);
|
---|
| 333 | // if (Len >= ReqIfModSinceStrLen) LogError("If Modified Since field truncated");
|
---|
| 334 | }
|
---|
| 335 | //--Uncommon--
|
---|
| 336 | else if (strcmp("FROM:", FieldNameStr) == 0) {
|
---|
| 337 | strncpy(RequestFields.FromStr, FieldValStr, ReqFromStrLen - 1);
|
---|
| 338 | // if (Len >= ReqFromStrLen) LogError("From field truncated");
|
---|
| 339 | }
|
---|
| 340 | else if (strcmp("MIME-VERSION:", FieldNameStr) == 0) {
|
---|
| 341 | strncpy(RequestFields.MIMEVerStr, FieldValStr, ReqMIMEVerStrLen - 1);
|
---|
| 342 | // if (Len >= ReqMIMEVerStrLen) LogError("MIME Version field truncated");
|
---|
| 343 | }
|
---|
| 344 | else if (strcmp("PRAGMA:", FieldNameStr) == 0) {
|
---|
| 345 | strncpy(RequestFields.PragmaStr, FieldValStr, ReqPragmaStrLen - 1);
|
---|
| 346 | // if (Len >= ReqPragmaStrLen) LogError("Pragma field truncated");
|
---|
| 347 | }
|
---|
| 348 | //--Special case--
|
---|
| 349 | else if (strcmp("AUTHORIZATION:", FieldNameStr) == 0) {
|
---|
| 350 | strncpy(RequestFields.AuthorizationStr, FieldValStr, ReqAuthorizationStrLen - 1);
|
---|
| 351 | // if (Len >= ReqAuthorizationStrLen) LogError("Authorization field truncated");
|
---|
| 352 | }
|
---|
| 353 | else if (strcmp("CONTENT-LENGTH:", FieldNameStr) == 0) {
|
---|
| 354 | strncpy(RequestFields.ContentLengthStr, FieldValStr, ReqContentLengthStrLen - 1);
|
---|
| 355 | // if (Len >= ReqContentLengthStrLen) LogError("Content Length field truncated");
|
---|
| 356 | }
|
---|
| 357 | else if (strcmp("CONTENT-TYPE:", FieldNameStr) == 0) {
|
---|
| 358 | strncpy(RequestFields.ContentTypeStr, FieldValStr, ReqContentTypeStrLen - 1);
|
---|
| 359 | // if (Len >= ReqContentTypeStrLen) LogError("Content Type field truncated");
|
---|
| 360 | }
|
---|
| 361 | else if (strcmp("CONTENT-ENCODING:", FieldNameStr) == 0) {
|
---|
| 362 | strncpy(RequestFields.ContentEncodingStr, FieldValStr, ReqContentEncodingStrLen - 1);
|
---|
| 363 | // if (Len >= ReqContentEncodingStrLen) LogError("Content Encoding field truncated");
|
---|
| 364 | }
|
---|
| 365 | else {
|
---|
| 366 | //Add it to the other headers
|
---|
| 367 | int VarLen = strlen(FieldNameStr);
|
---|
| 368 | if (FieldNameStr[VarLen - 1] == ':') {
|
---|
| 369 | //Remove the colon
|
---|
| 370 | FieldNameStr[VarLen - 1] = '\0';
|
---|
| 371 | VarLen--;
|
---|
| 372 | }
|
---|
| 373 | RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var = new char[VarLen + 1];
|
---|
| 374 | RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val = new char[Len + 1];
|
---|
| 375 | strcpy(RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var, FieldNameStr);
|
---|
| 376 | strcpy(RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val, FieldValStr);
|
---|
| 377 | RequestFields.NumOtherHeaders++;
|
---|
| 378 | }
|
---|
| 379 | strcpy(CurLine, NextLine);
|
---|
| 380 | }
|
---|
| 381 |
|
---|
| 382 |
|
---|
| 383 | if (RequestFields.ContentLengthStr[0] != 0) { //Do we have attached data?
|
---|
| 384 | unsigned int NumRecv;
|
---|
| 385 |
|
---|
| 386 | RequestFields.ContentLength = atol(RequestFields.ContentLengthStr);
|
---|
| 387 | if (RequestFields.ContentLength > 0) {
|
---|
| 388 | // ThreadDebugMessage(RequestInfo.ThreadNum, "Getting content");
|
---|
| 389 |
|
---|
| 390 | //Allocate memory
|
---|
| 391 | RequestFields.Content = new BYTE[RequestFields.ContentLength];
|
---|
| 392 |
|
---|
| 393 | //Get rest of data from get lines
|
---|
| 394 | NumRecv = DataInBuffer - ReadBufferIndex;
|
---|
| 395 |
|
---|
| 396 | if (NumRecv >RequestFields.ContentLength) {
|
---|
| 397 | //Overflow, only read what they said they'd send
|
---|
| 398 | NumRecv = RequestFields.ContentLength;
|
---|
| 399 | }
|
---|
| 400 | memcpy(RequestFields.Content, RequestInfo.IOBuffer + ReadBufferIndex,
|
---|
| 401 | NumRecv);
|
---|
| 402 |
|
---|
| 403 | while (NumRecv < RequestFields.ContentLength) {
|
---|
| 404 | NumRecv = GetData(RequestInfo.ClientSocket,
|
---|
| 405 | RequestFields.Content + NumRecv,
|
---|
| 406 | RequestFields.ContentLength - NumRecv,
|
---|
| 407 | RequestInfo.ThreadNum);
|
---|
| 408 | if (NumRecv < 0) return GH_ERROR;
|
---|
| 409 | }
|
---|
| 410 | }
|
---|
| 411 | else {
|
---|
| 412 | RequestFields.Content = NULL;
|
---|
| 413 | RequestFields.ContentLength = 0;
|
---|
| 414 | }
|
---|
| 415 | }
|
---|
| 416 | else {
|
---|
| 417 | RequestFields.Content = NULL;
|
---|
| 418 | RequestFields.ContentLength = 0;
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | return GH_10_REQUEST;
|
---|
| 422 | }
|
---|
| 423 |
|
---|
| 424 | /******************************************************************************/
|
---|
| 425 | void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
|
---|
| 426 | //Clean up memory allocated for the Content
|
---|
| 427 | if (RequestFields.Content != NULL)
|
---|
| 428 | delete[] RequestFields.Content;
|
---|
| 429 | while (RequestFields.NumOtherHeaders > 0) {
|
---|
| 430 | RequestFields.NumOtherHeaders--;
|
---|
| 431 | delete[] RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var;
|
---|
| 432 | delete[] RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val;
|
---|
| 433 | }
|
---|
| 434 |
|
---|
| 435 | // clean up memory allocated for the IOBuffer
|
---|
| 436 | if (RequestInfo.IOBuffer != NULL) {
|
---|
| 437 | delete[] RequestInfo.IOBuffer;
|
---|
| 438 | RequestInfo.IOBuffer = NULL;
|
---|
| 439 | }
|
---|
| 440 | }
|
---|