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