[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 |
|
---|
| 28 | #include <windows.h>
|
---|
| 29 | #include <stdlib.h>
|
---|
| 30 | #include <stdio.h>
|
---|
| 31 | #include <string.h>
|
---|
| 32 | #include <memory.h>
|
---|
[3810] | 33 | #include "httpreq.h"
|
---|
[611] | 34 | #include "parse.h"
|
---|
| 35 | #include "netio.h"
|
---|
| 36 | #include "settings.h"
|
---|
| 37 | #include "httpsrv.h"
|
---|
| 38 | #include "httpsend.h"
|
---|
| 39 | #include "cgiwrapper.h"
|
---|
[2353] | 40 | #include "d_winsock.h"
|
---|
[611] | 41 |
|
---|
| 42 | /*
|
---|
| 43 | Implementation Notes:
|
---|
| 44 |
|
---|
| 45 | HTTP field names, method and version strings are converted to upper case
|
---|
| 46 | right after being read from the client in order to allow case insensitive
|
---|
| 47 | string comparisons to be done on them. Since these fields are worked with a
|
---|
| 48 | lot, this should help performance.
|
---|
| 49 | */
|
---|
| 50 |
|
---|
| 51 | //Private Data and declarations
|
---|
| 52 | #define IO_BUFFER_SIZE 16384 //16K IO Buffer
|
---|
| 53 | #define MAX_HTTP_LINE_LEN 1024 //Max length of line in a header of 1024
|
---|
| 54 |
|
---|
| 55 | //Private Function Declarations with Return Contstants
|
---|
| 56 |
|
---|
| 57 | /*
|
---|
| 58 | Function Name: DispatchRequest
|
---|
| 59 | Purpose: Manages having the request parsed, then sent to the right function
|
---|
| 60 | to send a response or handle an error.
|
---|
| 61 | Parameters:
|
---|
| 62 | ClientSocket - Socket the client is on
|
---|
| 63 | ClientSockAddr - Address of client
|
---|
| 64 | AddrLen - Length of address of client
|
---|
| 65 | IOBuffer - Pointer to buffer allocated for IO operations
|
---|
| 66 | ThreadNum - Number of thread that called this function for debugging purposes
|
---|
| 67 | Notes: I'm still playing with the keep alive support. I commented out
|
---|
| 68 | the stuff for giving a client a timeout because I was unable to detect
|
---|
| 69 | disconnects.
|
---|
| 70 | More Notes: Not sure if this organization will allow me to easily add support
|
---|
| 71 | for ISAPI filter DLLs.
|
---|
| 72 | */
|
---|
| 73 | void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen, BYTE *IOBuffer);
|
---|
| 74 |
|
---|
| 75 | /*
|
---|
| 76 | Function Name: Get HTTP Headers
|
---|
| 77 | Purpose: Manages having the request parsed, then sent to the right function
|
---|
| 78 | to send a response or handle an error.
|
---|
| 79 | Parameters:
|
---|
| 80 | RequestInfo - Request information structure (see httpreq.h)
|
---|
| 81 | RequestFields - HTTP request fields structure (see httpreq.h)
|
---|
| 82 | Returns: GH_ERROR on error (diconnect, bad data, Windows in a bad mood, etc.)
|
---|
| 83 | GH_UNKNOWN_VERSION if the version number is not HTTP/0.9 or HTTP/1.x
|
---|
| 84 | GH_SIMPLE_REQUEST on a properly formated HTTP/0.9 request
|
---|
| 85 | GH_10_REQUEST on a properly formated HTTP/1.x request
|
---|
| 86 | */
|
---|
| 87 | int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
|
---|
[3017] | 88 | #define GH_BAD_METHOD -2
|
---|
[611] | 89 | #define GH_ERROR -1
|
---|
| 90 | #define GH_UNKNOWN_VERSION 0
|
---|
| 91 | #define GH_SIMPLE_REQUEST 1
|
---|
| 92 | #define GH_10_REQUEST 2
|
---|
| 93 |
|
---|
| 94 | /*
|
---|
| 95 | Function Name: Clean Up HTTP Headers
|
---|
| 96 | Purpose: Cleans up memory dynamicly allocated for headers
|
---|
| 97 | Parameters:
|
---|
| 98 | RequestInfo - Request information structure (see httpreq.h)
|
---|
| 99 | RequestFields - HTTP request fields structure (see httpreq.h)
|
---|
| 100 | Returns: Nothing
|
---|
| 101 | */
|
---|
| 102 | void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
|
---|
| 103 |
|
---|
| 104 | /*
|
---|
| 105 | Function Name: Split Query
|
---|
| 106 | Purpose: Splits the file and query part of a URI. In other words, it
|
---|
| 107 | puts the parts before and after the "?" in differnet strings.
|
---|
| 108 | Parameters:
|
---|
| 109 | URIStr - The requested URI
|
---|
| 110 | FileStr - String to contain the name of the path + file part of the URI
|
---|
| 111 | QueryStr - String to contain the query part of the URI
|
---|
| 112 | Returns: TRUE if there is a query, else FALSE
|
---|
| 113 | */
|
---|
| 114 | BOOL SplitQuery(char *URIStr, char *FileStr, char *QueryStr, int ThreadNum);
|
---|
| 115 |
|
---|
| 116 | /*
|
---|
| 117 | Function Name: Get File
|
---|
| 118 | Purpose: Attempts to find a given file, including looking for index.html.
|
---|
| 119 | Updates the given URI string so it points to the true document location
|
---|
| 120 | Parameters:
|
---|
| 121 | FilePath - Path of file, may be modified to best reflect the retrived file
|
---|
| 122 | or directory
|
---|
| 123 | URIStr - URI string, minus the query
|
---|
| 124 | Returns: GF_ERROR on error
|
---|
| 125 | GF_FILE_FOUND on success
|
---|
| 126 | GF_INDEX_FOUND if file is a directory with an index.html file in it
|
---|
| 127 | GF_DIRECTORY if file is a directory
|
---|
| 128 | GF_FILE_NOT_FOUND if file was found
|
---|
| 129 | */
|
---|
| 130 |
|
---|
| 131 | /*
|
---|
| 132 | Function Name: Process Simple Request
|
---|
| 133 | Purpose: Sends a reply to a HTTP 0.9 "simple" request
|
---|
| 134 | Parameters:
|
---|
| 135 | ClientSocket - Socket the client is on
|
---|
| 136 | RequestInfo - Structure storing the parsed headers
|
---|
| 137 | IOBuffer - Pointer to buffer allocated for IO operations
|
---|
| 138 | TheadNum - Number of calling thread for debugging
|
---|
| 139 | Notes: I should really test this and see if it works...
|
---|
| 140 | */
|
---|
| 141 | void ProcessSimpleRequest(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
|
---|
| 142 |
|
---|
| 143 | //Public Functions
|
---|
| 144 | /******************************************************************************/
|
---|
| 145 | void RequestThread(RequestThreadMessageT *Parameters) {
|
---|
| 146 | SOCKADDR_IN ClientSockAddr;
|
---|
| 147 | SOCKET ClientSocket;
|
---|
| 148 | int AddrLen;
|
---|
| 149 | //Allocate an IO buffer for this thread
|
---|
| 150 | BYTE *IOBuffer = new BYTE[IO_BUFFER_SIZE];
|
---|
| 151 |
|
---|
| 152 | //Get the parameters for the request
|
---|
| 153 | ClientSocket = Parameters->ClientSocket;
|
---|
| 154 | ClientSockAddr = Parameters->ClientSockAddr;
|
---|
| 155 | AddrLen = Parameters->AddrLen;
|
---|
| 156 | DispatchRequest(ClientSocket, ClientSockAddr, AddrLen, IOBuffer);
|
---|
| 157 | }
|
---|
| 158 | /******************************************************************************/
|
---|
| 159 |
|
---|
| 160 | //Private Functions
|
---|
| 161 |
|
---|
| 162 | /******************************************************************************/
|
---|
| 163 | void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen, BYTE *IOBuffer) {
|
---|
| 164 | RequestInfoT RequestInfo;
|
---|
| 165 | RequestFieldsT RequestFields;
|
---|
| 166 |
|
---|
| 167 | // TrayAddConnection();
|
---|
| 168 |
|
---|
| 169 | //Setup the RequestInfo structure
|
---|
| 170 | memset(&RequestInfo, 0, sizeof(RequestInfoT));
|
---|
| 171 | RequestInfo.ThreadNum = 0;
|
---|
| 172 | RequestInfo.IOBuffer = IOBuffer;
|
---|
| 173 | RequestInfo.IOBufferSize = IO_BUFFER_SIZE;
|
---|
| 174 | RequestInfo.ClientSocket = ClientSocket;
|
---|
| 175 | RequestInfo.ClientSockAddr = ClientSockAddr;
|
---|
| 176 | RequestInfo.AddrLen = AddrLen;
|
---|
| 177 | RequestInfo.KeepAlive = FALSE;
|
---|
| 178 |
|
---|
| 179 | int GetHeadersResult;
|
---|
| 180 | do {
|
---|
| 181 | //Get Headers
|
---|
| 182 | GetHeadersResult = GetHTTPHeaders(RequestInfo, RequestFields);
|
---|
[2353] | 183 |
|
---|
[611] | 184 | //Figure out what version we're dealing with and deal with it
|
---|
| 185 | switch (GetHeadersResult) {
|
---|
| 186 | case GH_SIMPLE_REQUEST :
|
---|
| 187 | SendHTTPError(400, "HTTP Request not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
|
---|
| 188 | // TrayIncNumServed();
|
---|
| 189 | break;
|
---|
| 190 | case GH_10_REQUEST :
|
---|
| 191 | ExamineURIStr(RequestFields.URIStr,&RequestInfo,&RequestFields);
|
---|
| 192 | // TrayIncNumServed();
|
---|
| 193 | break;
|
---|
| 194 | case GH_UNKNOWN_VERSION :
|
---|
| 195 | SendHTTPError(400, "HTTP Version not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
|
---|
| 196 | // TrayIncNumServed();
|
---|
| 197 | break;
|
---|
[3017] | 198 | /* added Feb 2002 to handle stupid MS behaviour */
|
---|
| 199 | case GH_BAD_METHOD :
|
---|
| 200 | SendHTTPError(501, "Not implemented", "Only GET and POST currently implemented", RequestInfo, RequestFields);
|
---|
| 201 | break;
|
---|
[611] | 202 | case GH_ERROR:
|
---|
| 203 | //Disconnect
|
---|
| 204 | RequestInfo.KeepAlive = FALSE;
|
---|
| 205 | break;
|
---|
| 206 | }
|
---|
| 207 | CleanUpHTTPHeaders(RequestInfo, RequestFields);
|
---|
| 208 | } while (0/*RequestInfo.KeepAlive == TRUE*/);
|
---|
| 209 | //Close connection
|
---|
| 210 | CloseSocket(RequestInfo.ClientSocket);
|
---|
| 211 | // TrayRemoveConnection();
|
---|
| 212 | }
|
---|
| 213 |
|
---|
[18313] | 214 | void resetRequestFieldsT(RequestFieldsT& RequestFields)
|
---|
| 215 | {
|
---|
| 216 | // Can't just 'memset' the text_t fields (as used to be done),
|
---|
| 217 | // as this could lead to inconsistent state in text_t fields
|
---|
| 218 | // ultimately resulting in a segmentation fault
|
---|
| 219 | // => need to go through an explicitly reset them
|
---|
| 220 |
|
---|
| 221 | //Simple request line info v0.9
|
---|
| 222 | RequestFields.MethodStr.clear();
|
---|
| 223 | RequestFields.URIStr.clear();
|
---|
| 224 | //added v1.0
|
---|
| 225 | RequestFields.VersionStr.clear();
|
---|
| 226 | //General Header
|
---|
| 227 | RequestFields.DateStr.clear();
|
---|
| 228 | RequestFields.MIMEVerStr.clear();
|
---|
| 229 | RequestFields.PragmaStr.clear();
|
---|
| 230 | //Request Header
|
---|
| 231 | RequestFields.AuthorizationStr.clear();
|
---|
| 232 | RequestFields.FromStr.clear();
|
---|
| 233 | RequestFields.IfModSinceStr.clear();
|
---|
| 234 | RequestFields.RefererStr.clear();
|
---|
| 235 | RequestFields.UserAgentStr.clear();
|
---|
| 236 | //Entity Header (Only CGI stuff)
|
---|
| 237 | RequestFields.ContentEncodingStr.clear();
|
---|
| 238 | RequestFields.ContentTypeStr.clear();
|
---|
| 239 | RequestFields.ContentLengthStr.clear();
|
---|
| 240 | //v1.0 Optional (the more common ones)
|
---|
| 241 | RequestFields.AcceptStr.clear();
|
---|
| 242 | RequestFields.AcceptLangStr.clear();
|
---|
| 243 | //v1.1 Exentions
|
---|
| 244 | RequestFields.ConnectionStr.clear();
|
---|
| 245 |
|
---|
| 246 | //Reset all the non text_t fields
|
---|
| 247 | RequestFields.ContentLength = 0;
|
---|
| 248 | RequestFields.Content = NULL;
|
---|
| 249 | RequestFields.NumOtherHeaders = 0;
|
---|
| 250 |
|
---|
| 251 | for (int i=0 ; i<MAX_OTHER_HEADERS; i++) {
|
---|
| 252 | RequestFields.OtherHeaders[i].Var.clear();
|
---|
| 253 | RequestFields.OtherHeaders[i].Val.clear();
|
---|
| 254 | }
|
---|
| 255 | }
|
---|
| 256 |
|
---|
[611] | 257 | /******************************************************************************/
|
---|
| 258 | int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
|
---|
| 259 | //Parsing and IO buffers
|
---|
[3810] | 260 | text_t CurLine;
|
---|
| 261 | text_t NextLine;
|
---|
| 262 | text_t FieldNameStr;
|
---|
| 263 | text_t FieldValStr;
|
---|
[611] | 264 |
|
---|
| 265 | //Parsing and IO working vars
|
---|
| 266 | int ReadBufferIndex;
|
---|
| 267 | int DataInBuffer;
|
---|
[3810] | 268 | text_t::const_iterator next;
|
---|
| 269 | text_t::const_iterator end;
|
---|
[611] | 270 |
|
---|
[18313] | 271 | resetRequestFieldsT(RequestFields);
|
---|
[611] | 272 |
|
---|
| 273 | ReadBufferIndex = 0;
|
---|
| 274 | DataInBuffer = 0;
|
---|
| 275 |
|
---|
| 276 | //Get First Line
|
---|
| 277 | if (GetLine(CurLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
|
---|
| 278 | RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
|
---|
| 279 | RequestInfo.ThreadNum) != 0) return GH_ERROR;
|
---|
| 280 | do {//Get Next Line, append it if the first charactor is space
|
---|
| 281 | if(GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
|
---|
| 282 | RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
|
---|
| 283 | RequestInfo.ThreadNum) != 0) return GH_ERROR;
|
---|
[3810] | 284 | if ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t')) {
|
---|
| 285 | CurLine += NextLine;
|
---|
| 286 | }
|
---|
| 287 | } while ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t'));
|
---|
[611] | 288 | //Method String (first word)
|
---|
[3810] | 289 | GetWord(RequestFields.MethodStr, CurLine.begin(), CurLine.end(), next);
|
---|
| 290 | uc(RequestFields.MethodStr);
|
---|
[3017] | 291 |
|
---|
| 292 | /* Added Feb 2002 - IE since about version 5 send stupid frontpage requests
|
---|
| 293 | for MS Document formats eg "GET /_vti_inf.html" */
|
---|
[3810] | 294 | if (RequestFields.MethodStr == "OPTIONS") {
|
---|
| 295 | return GH_BAD_METHOD;
|
---|
[3017] | 296 | }
|
---|
[611] | 297 | //Version String (last word)
|
---|
[3810] | 298 | GetLastWord(RequestFields.VersionStr, CurLine.begin(), CurLine.end(), end);
|
---|
| 299 | uc(RequestFields.VersionStr);
|
---|
| 300 | text_t::const_iterator versionbegin = RequestFields.VersionStr.begin();
|
---|
[611] | 301 |
|
---|
[3810] | 302 | if ((RequestFields.VersionStr.size() > 5) && (substr(versionbegin, versionbegin+5) != "HTTP/")) {
|
---|
[611] | 303 | //No version, assume simple request
|
---|
| 304 | //part after method is URI
|
---|
[3810] | 305 | RequestFields.URIStr = CurLine;
|
---|
[611] | 306 | return GH_SIMPLE_REQUEST;
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | //URI String (in between End of first and Start of last)
|
---|
| 310 | //<Method> <WhiteSpace> <URI> <WhiteSpace> <Version> <CRLF>
|
---|
[3810] | 311 | // next^ end^
|
---|
[2280] | 312 | text_t spacebuffer;
|
---|
[3810] | 313 | text_t::const_iterator here = next;
|
---|
| 314 | while (here != end) {
|
---|
[2280] | 315 | // do this to remove trailing space
|
---|
[3810] | 316 | if (*here == ' ' || *here == '\t') {
|
---|
| 317 | spacebuffer.push_back(*here);
|
---|
[2280] | 318 | } else {
|
---|
| 319 | if (!spacebuffer.empty()) {
|
---|
| 320 | RequestFields.URIStr += spacebuffer;
|
---|
| 321 | spacebuffer.clear();
|
---|
| 322 | }
|
---|
[3810] | 323 | RequestFields.URIStr.push_back(*here);
|
---|
[2280] | 324 | }
|
---|
[9598] | 325 | ++here;
|
---|
[2280] | 326 | }
|
---|
[2353] | 327 |
|
---|
[611] | 328 | //Only accept requests from HTTP/0.9 or HTTP/1.X clients, we'll
|
---|
| 329 | //assume that anything else will require an upgrade or patch
|
---|
[3810] | 330 | if ((RequestFields.VersionStr.size() > 7) && (substr(versionbegin, versionbegin+7) != "HTTP/1.")) {
|
---|
[611] | 331 | return GH_UNKNOWN_VERSION;
|
---|
[3810] | 332 | }
|
---|
[611] | 333 |
|
---|
| 334 | //Get the rest of the lines
|
---|
[3810] | 335 | CurLine = NextLine;
|
---|
[611] | 336 |
|
---|
[3810] | 337 | while (!CurLine.empty()) {//Blank Line, we're done
|
---|
[611] | 338 | do {//Get Next Line, append it if the first charactor is space
|
---|
| 339 | if (GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
|
---|
| 340 | RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
|
---|
| 341 | RequestInfo.ThreadNum) != 0)
|
---|
| 342 | return GH_ERROR;
|
---|
[11259] | 343 | if (NextLine.empty())
|
---|
| 344 | break;
|
---|
[3810] | 345 | if ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t')) {
|
---|
| 346 | CurLine += NextLine;
|
---|
| 347 | }
|
---|
| 348 | } while ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t'));
|
---|
[611] | 349 |
|
---|
[3810] | 350 | GetWord(FieldNameStr, CurLine.begin(), CurLine.end(), next);
|
---|
| 351 | uc(FieldNameStr);
|
---|
[611] | 352 |
|
---|
[3810] | 353 | FieldValStr = substr(next, CurLine.end());
|
---|
[611] | 354 |
|
---|
| 355 | //Process it
|
---|
| 356 | //In order of expected commonality
|
---|
| 357 | //All constants are in canonized, thus in upper case and case sensitive
|
---|
| 358 | //comparisons are used
|
---|
[3810] | 359 |
|
---|
[611] | 360 | //--Just About Always--
|
---|
[3810] | 361 | if (FieldNameStr == "ACCEPT:") {
|
---|
| 362 | if (!RequestFields.AcceptStr.empty()) {
|
---|
| 363 | RequestFields.AcceptStr += ", ";
|
---|
[611] | 364 | }
|
---|
[3810] | 365 | RequestFields.AcceptStr += FieldValStr;
|
---|
[611] | 366 | }
|
---|
[3810] | 367 | else if (FieldNameStr == "DATE:") {
|
---|
| 368 | RequestFields.DateStr = FieldValStr;
|
---|
[611] | 369 | }
|
---|
[3810] | 370 | else if (FieldNameStr == "USER-AGENT:") {
|
---|
| 371 | RequestFields.UserAgentStr = FieldValStr;
|
---|
[611] | 372 | }
|
---|
[3810] | 373 | else if (FieldNameStr == "CONNECTION:") {
|
---|
| 374 | RequestFields.ConnectionStr = FieldValStr;
|
---|
[611] | 375 | }
|
---|
| 376 | //--Sometimes--
|
---|
[3810] | 377 | else if (FieldNameStr == "ACCEPT-LANGUAGE:") {
|
---|
| 378 | RequestFields.AcceptLangStr = FieldValStr;
|
---|
[611] | 379 | }
|
---|
[3810] | 380 | else if (FieldNameStr == "REFERER:") {
|
---|
| 381 | RequestFields.RefererStr = FieldValStr;
|
---|
[611] | 382 | }
|
---|
[3810] | 383 | else if (FieldNameStr == "IF-MODIFIED-SINCE:") {
|
---|
| 384 | RequestFields.IfModSinceStr = FieldValStr;
|
---|
[611] | 385 | }
|
---|
| 386 | //--Uncommon--
|
---|
[3810] | 387 | else if (FieldNameStr == "FROM:") {
|
---|
| 388 | RequestFields.FromStr = FieldValStr;
|
---|
[611] | 389 | }
|
---|
[3810] | 390 | else if (FieldNameStr == "MIME-VERSION:") {
|
---|
| 391 | RequestFields.MIMEVerStr = FieldValStr;
|
---|
[611] | 392 | }
|
---|
[3810] | 393 | else if (FieldNameStr == "PRAGMA:") {
|
---|
| 394 | RequestFields.PragmaStr = FieldValStr;
|
---|
[611] | 395 | }
|
---|
| 396 | //--Special case--
|
---|
[3810] | 397 | else if (FieldNameStr == "AUTHORIZATION:") {
|
---|
| 398 | RequestFields.AuthorizationStr = FieldValStr;
|
---|
[611] | 399 | }
|
---|
[3810] | 400 | else if (FieldNameStr == "CONTENT-LENGTH:") {
|
---|
| 401 | RequestFields.ContentLengthStr = FieldValStr;
|
---|
[611] | 402 | }
|
---|
[3810] | 403 | else if (FieldNameStr == "CONTENT-TYPE:") {
|
---|
| 404 | RequestFields.ContentTypeStr = FieldValStr;
|
---|
[611] | 405 | }
|
---|
[3810] | 406 | else if (FieldNameStr == "CONTENT-ENCODING:") {
|
---|
| 407 | RequestFields.ContentEncodingStr = FieldValStr;
|
---|
[611] | 408 | }
|
---|
[3810] | 409 | else if (!FieldNameStr.empty()) {
|
---|
[611] | 410 | //Add it to the other headers
|
---|
[3810] | 411 |
|
---|
| 412 | //Remove the colon
|
---|
| 413 | if (*(FieldNameStr.end()-1) == ':') {
|
---|
| 414 | FieldNameStr.pop_back();
|
---|
[611] | 415 | }
|
---|
[3810] | 416 | RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var = FieldNameStr;
|
---|
| 417 | RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val = FieldValStr;
|
---|
[9598] | 418 | ++RequestFields.NumOtherHeaders;
|
---|
[611] | 419 | }
|
---|
[3810] | 420 | CurLine = NextLine;
|
---|
[611] | 421 | }
|
---|
| 422 |
|
---|
[3810] | 423 | if (!RequestFields.ContentLengthStr.empty()) { //Do we have attached data?
|
---|
[611] | 424 | unsigned int NumRecv;
|
---|
| 425 |
|
---|
[3810] | 426 | RequestFields.ContentLength = RequestFields.ContentLengthStr.getint();
|
---|
[611] | 427 | if (RequestFields.ContentLength > 0) {
|
---|
[2353] | 428 |
|
---|
[611] | 429 | //Allocate memory
|
---|
| 430 | RequestFields.Content = new BYTE[RequestFields.ContentLength];
|
---|
| 431 |
|
---|
| 432 | //Get rest of data from get lines
|
---|
| 433 | NumRecv = DataInBuffer - ReadBufferIndex;
|
---|
| 434 |
|
---|
| 435 | if (NumRecv >RequestFields.ContentLength) {
|
---|
| 436 | //Overflow, only read what they said they'd send
|
---|
| 437 | NumRecv = RequestFields.ContentLength;
|
---|
| 438 | }
|
---|
| 439 | memcpy(RequestFields.Content, RequestInfo.IOBuffer + ReadBufferIndex,
|
---|
| 440 | NumRecv);
|
---|
| 441 |
|
---|
| 442 | while (NumRecv < RequestFields.ContentLength) {
|
---|
[2353] | 443 | NumRecv += GetData(RequestInfo.ClientSocket,
|
---|
| 444 | RequestFields.Content + NumRecv,
|
---|
| 445 | RequestFields.ContentLength - NumRecv,
|
---|
| 446 | RequestInfo.ThreadNum);
|
---|
[611] | 447 | if (NumRecv < 0) return GH_ERROR;
|
---|
| 448 | }
|
---|
[2353] | 449 |
|
---|
| 450 | // It seems to be important on NT that all available data was read
|
---|
| 451 | // from the socket before the socket is closed (otherwise netscape
|
---|
| 452 | // throws a "connection reset by peer" error). Since netscape seems
|
---|
| 453 | // to send a few extra bytes in certain situations we'll make sure we
|
---|
| 454 | // slurp it all up here.
|
---|
[9636] | 455 | char *tmpbuffer = new char[100]; // this had new char(100)????
|
---|
[3056] | 456 | // unsigned long int nonblockmode=1;
|
---|
| 457 | // ioctlsocket(RequestInfo.ClientSocket, FIONBIO, &nonblockmode);
|
---|
[2353] | 458 | d_recv(RequestInfo.ClientSocket, tmpbuffer, 100, 0);
|
---|
[9636] | 459 | delete []tmpbuffer;
|
---|
[2353] | 460 |
|
---|
[611] | 461 | }
|
---|
| 462 | else {
|
---|
| 463 | RequestFields.Content = NULL;
|
---|
| 464 | RequestFields.ContentLength = 0;
|
---|
| 465 | }
|
---|
| 466 | }
|
---|
| 467 | else {
|
---|
| 468 | RequestFields.Content = NULL;
|
---|
| 469 | RequestFields.ContentLength = 0;
|
---|
| 470 | }
|
---|
| 471 |
|
---|
| 472 | return GH_10_REQUEST;
|
---|
| 473 | }
|
---|
| 474 |
|
---|
| 475 | /******************************************************************************/
|
---|
| 476 | void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
|
---|
| 477 | //Clean up memory allocated for the Content
|
---|
[3810] | 478 | if (RequestFields.Content != NULL) {
|
---|
[611] | 479 | delete[] RequestFields.Content;
|
---|
| 480 | }
|
---|
| 481 |
|
---|
| 482 | // clean up memory allocated for the IOBuffer
|
---|
| 483 | if (RequestInfo.IOBuffer != NULL) {
|
---|
| 484 | delete[] RequestInfo.IOBuffer;
|
---|
| 485 | RequestInfo.IOBuffer = NULL;
|
---|
| 486 | }
|
---|
| 487 | }
|
---|