Very rough first start, not even everything added

This commit is contained in:
Darren VanBuren 2017-03-07 14:51:44 -08:00
commit af3619d4fa
88 changed files with 24251 additions and 0 deletions

View file

@ -0,0 +1,313 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include "HTTPProtocol.h"
StrPtrLen HTTPProtocol::sMethods[] =
{
StrPtrLen("GET"),
StrPtrLen("HEAD"),
StrPtrLen("POST"),
StrPtrLen("OPTIONS"),
StrPtrLen("PUT"),
StrPtrLen("DELETE"),
StrPtrLen("TRACE"),
StrPtrLen("CONNECT"),
};
HTTPMethod HTTPProtocol::GetMethod(const StrPtrLen* inMethodStr)
{
HTTPMethod theMethod = httpIllegalMethod;
if (inMethodStr->Len == 0)
return httpIllegalMethod;
switch((inMethodStr->Ptr)[0])
{
case 'G': theMethod = httpGetMethod; break;
case 'H': theMethod = httpHeadMethod; break;
case 'P': theMethod = httpPostMethod; break; // Most likely POST and not PUT
case 'O': theMethod = httpOptionsMethod; break;
case 'D': theMethod = httpDeleteMethod; break;
case 'T': theMethod = httpTraceMethod; break;
case 'C': theMethod = httpConnectMethod; break;
}
if ( (theMethod != httpIllegalMethod) && (inMethodStr->Equal(sMethods[theMethod])) )
return theMethod;
// Check for remaining methods (Only PUT method is left)
if ( inMethodStr->Equal(sMethods[httpPutMethod]) )
return httpPutMethod;
return httpIllegalMethod;
}
StrPtrLen HTTPProtocol::sHeaders[] =
{
StrPtrLen("Connection"),
StrPtrLen("Date"),
StrPtrLen("Authorization"),
StrPtrLen("If-Modified-Since"),
StrPtrLen("Server"),
StrPtrLen("WWW-Authenticate"),
StrPtrLen("Expires"),
StrPtrLen("Last-Modified"),
StrPtrLen("Cache-Control"),
StrPtrLen("Pragma"),
StrPtrLen("Trailer"),
StrPtrLen("Transfer-Encoding"),
StrPtrLen("Upgrade"),
StrPtrLen("Via"),
StrPtrLen("Warning"),
StrPtrLen("Accept"),
StrPtrLen("Accept-Charset"),
StrPtrLen("Accept-Encoding"),
StrPtrLen("Accept-Language"),
StrPtrLen("Expect"),
StrPtrLen("From"),
StrPtrLen("Host"),
StrPtrLen("If-Match"),
StrPtrLen("If-None-Match"),
StrPtrLen("If-Range"),
StrPtrLen("If-Unmodified-Since"),
StrPtrLen("Max-Forwards"),
StrPtrLen("Proxy-Authorization"),
StrPtrLen("Range"),
StrPtrLen("Referer"),
StrPtrLen("TE"),
StrPtrLen("User-Agent"),
StrPtrLen("Accept-Ranges"),
StrPtrLen("Age"),
StrPtrLen("ETag"),
StrPtrLen("Location"),
StrPtrLen("Proxy-Authenticate"),
StrPtrLen("Retry-After"),
StrPtrLen("Vary"),
StrPtrLen("Allow"),
StrPtrLen("Content-Encoding"),
StrPtrLen("Content-Language"),
StrPtrLen("Content-Length"),
StrPtrLen("Content-Location"),
StrPtrLen("Content-MD5"),
StrPtrLen("Content-Range"),
StrPtrLen("Content-Type"),
StrPtrLen("X-SessionCookie"),
StrPtrLen("X-Server-IP-Address"),
StrPtrLen(" ,")
};
HTTPHeader HTTPProtocol::GetHeader(const StrPtrLen* inHeaderStr)
{
if (inHeaderStr->Len == 0)
return httpIllegalHeader;
HTTPHeader theHeader = httpIllegalHeader;
//chances are this is one of our selected "VIP" headers. so check for this.
switch((inHeaderStr->Ptr)[0])
{
case 'C': case 'c': theHeader = httpConnectionHeader; break;
case 'S': case 's': theHeader = httpServerHeader; break;
case 'D': case 'd': theHeader = httpDateHeader; break;
case 'A': case 'a': theHeader = httpAuthorizationHeader; break;
case 'W': case 'w': theHeader = httpWWWAuthenticateHeader; break;
case 'I': case 'i': theHeader = httpIfModifiedSinceHeader; break;
case 'E': case 'e': theHeader = httpExpiresHeader; break;
case 'L': case 'l': theHeader = httpLastModifiedHeader; break;
// Added this to optimize for HTTP tunnelling in the server (Not really a VIP header)
case 'X': case 'x': theHeader = httpSessionCookieHeader; break;
}
if ((theHeader != httpIllegalHeader) &&
(inHeaderStr->EqualIgnoreCase(sHeaders[theHeader].Ptr, sHeaders[theHeader].Len)))
return theHeader;
//If this isn't one of our VIP headers, go through the remaining request headers, trying
//to find the right one.
for (SInt32 x = httpNumVIPHeaders; x < httpNumHeaders; x++)
if (inHeaderStr->EqualIgnoreCase(sHeaders[x].Ptr, sHeaders[x].Len))
return x;
return httpIllegalHeader;
}
StrPtrLen HTTPProtocol::sStatusCodeStrings[] =
{
StrPtrLen("Continue"), //kContinue
StrPtrLen("Switching Protocols"), //kSwitchingProtocols
StrPtrLen("OK"), //kOK
StrPtrLen("Created"), //kCreated
StrPtrLen("Accepted"), //kAccepted
StrPtrLen("Non Authoritative Information"), //kNonAuthoritativeInformation
StrPtrLen("No Content"), //kNoContent
StrPtrLen("Reset Content"), //kResetContent
StrPtrLen("Partial Content"), //kPartialContent
StrPtrLen("Multiple Choices"), //kMultipleChoices
StrPtrLen("Moved Permanently"), //kMovedPermanently
StrPtrLen("Found"), //kFound
StrPtrLen("See Other"), //kSeeOther
StrPtrLen("Not Modified"), //kNotModified
StrPtrLen("Use Proxy"), //kUseProxy
StrPtrLen("Temporary Redirect"), //kTemporaryRedirect
StrPtrLen("Bad Request"), //kBadRequest
StrPtrLen("Unauthorized"), //kUnAuthorized
StrPtrLen("Payment Required"), //kPaymentRequired
StrPtrLen("Forbidden"), //kForbidden
StrPtrLen("Not Found"), //kNotFound
StrPtrLen("Method Not Allowed"), //kMethodNotAllowed
StrPtrLen("Not Acceptable"), //kNotAcceptable
StrPtrLen("Proxy Authentication Required"), //kProxyAuthenticationRequired
StrPtrLen("Request Time-out"), //kRequestTimeout
StrPtrLen("Conflict"), //kConflict
StrPtrLen("Gone"), //kGone
StrPtrLen("Length Required"), //kLengthRequired
StrPtrLen("Precondition Failed"), //kPreconditionFailed
StrPtrLen("Request Entity Too Large"), //kRequestEntityTooLarge
StrPtrLen("Request-URI Too Large"), //kRequestURITooLarge
StrPtrLen("Unsupported Media Type"), //kUnsupportedMediaType
StrPtrLen("Request Range Not Satisfiable"), //kRequestRangeNotSatisfiable
StrPtrLen("Expectation Failed"), //kExpectationFailed
StrPtrLen("Internal Server Error"), //kInternalServerError
StrPtrLen("Not Implemented"), //kNotImplemented
StrPtrLen("Bad Gateway"), //kBadGateway
StrPtrLen("Service Unavailable"), //kServiceUnavailable
StrPtrLen("Gateway Timeout"), //kGatewayTimeout
StrPtrLen("HTTP Version not supported") //kHTTPVersionNotSupported
};
SInt32 HTTPProtocol::sStatusCodes[] =
{
100, //kContinue
101, //kSwitchingProtocols
200, //kOK
201, //kCreated
202, //kAccepted
203, //kNonAuthoritativeInformation
204, //kNoContent
205, //kResetContent
206, //kPartialContent
300, //kMultipleChoices
301, //kMovedPermanently
302, //kFound
303, //kSeeOther
304, //kNotModified
305, //kUseProxy
307, //kTemporaryRedirect
400, //kBadRequest
401, //kUnAuthorized
402, //kPaymentRequired
403, //kForbidden
404, //kNotFound
405, //kMethodNotAllowed
406, //kNotAcceptable
407, //kProxyAuthenticationRequired
408, //kRequestTimeout
409, //kConflict
410, //kGone
411, //kLengthRequired
412, //kPreconditionFailed
413, //kRequestEntityTooLarge
414, //kRequestURITooLarge
415, //kUnsupportedMediaType
416, //kRequestRangeNotSatisfiable
417, //kExpectationFailed
500, //kInternalServerError
501, //kNotImplemented
502, //kBadGateway
503, //kServiceUnavailable
504, //kGatewayTimeout
505 //kHTTPVersionNotSupported
};
StrPtrLen HTTPProtocol::sStatusCodeAsStrings[] =
{
StrPtrLen("100"), //kContinue
StrPtrLen("101"), //kSwitchingProtocols
StrPtrLen("200"), //kOK
StrPtrLen("201"), //kCreated
StrPtrLen("202"), //kAccepted
StrPtrLen("203"), //kNonAuthoritativeInformation
StrPtrLen("204"), //kNoContent
StrPtrLen("205"), //kResetContent
StrPtrLen("206"), //kPartialContent
StrPtrLen("300"), //kMultipleChoices
StrPtrLen("301"), //kMovedPermanently
StrPtrLen("302"), //kFound
StrPtrLen("303"), //kSeeOther
StrPtrLen("304"), //kNotModified
StrPtrLen("305"), //kUseProxy
StrPtrLen("307"), //kTemporaryRedirect
StrPtrLen("400"), //kBadRequest
StrPtrLen("401"), //kUnAuthorized
StrPtrLen("402"), //kPaymentRequired
StrPtrLen("403"), //kForbidden
StrPtrLen("404"), //kNotFound
StrPtrLen("405"), //kMethodNotAllowed
StrPtrLen("406"), //kNotAcceptable
StrPtrLen("407"), //kProxyAuthenticationRequired
StrPtrLen("408"), //kRequestTimeout
StrPtrLen("409"), //kConflict
StrPtrLen("410"), //kGone
StrPtrLen("411"), //kLengthRequired
StrPtrLen("412"), //kPreconditionFailed
StrPtrLen("413"), //kRequestEntityTooLarge
StrPtrLen("414"), //kRequestURITooLarge
StrPtrLen("415"), //kUnsupportedMediaType
StrPtrLen("416"), //kRequestRangeNotSatisfiable
StrPtrLen("417"), //kExpectationFailed
StrPtrLen("500"), //kInternalServerError
StrPtrLen("501"), //kNotImplemented
StrPtrLen("502"), //kBadGateway
StrPtrLen("503"), //kServiceUnavailable
StrPtrLen("504"), //kGatewayTimeout
StrPtrLen("505") //kHTTPVersionNotSupported
};
StrPtrLen HTTPProtocol::sVersionStrings[] =
{
StrPtrLen("HTTP/0.9"),
StrPtrLen("HTTP/1.0"),
StrPtrLen("HTTP/1.1")
};
HTTPVersion HTTPProtocol::GetVersion(StrPtrLen* versionStr)
{
if (versionStr->Len != 8)
return httpIllegalVersion;
SInt32 limit = httpNumVersions;
for (SInt32 x = 0; x < limit; x++)
{
if (versionStr->EqualIgnoreCase(sVersionStrings[x].Ptr, sVersionStrings[x].Len))
return x;
}
return httpIllegalVersion;
}

View file

@ -0,0 +1,204 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#ifndef __HTTPPROTOCOL_H__
#define __HTTPPROTOCOL_H__
#include "OSHeaders.h"
#include "StrPtrLen.h"
// Versions
enum
{
http09version = 0,
http10Version = 1,
http11Version = 2,
httpNumVersions = 3,
httpIllegalVersion = 3
};
typedef UInt32 HTTPVersion;
// Methods
enum
{
httpGetMethod = 0,
httpHeadMethod = 1,
httpPostMethod = 2,
httpOptionsMethod = 3,
httpPutMethod = 4,
httpDeleteMethod = 5,
httpTraceMethod = 6,
httpConnectMethod = 7,
httpNumMethods = 8,
httpIllegalMethod = 8
};
typedef UInt32 HTTPMethod;
// Headers
enum
{
// VIP headers
httpConnectionHeader = 0, // general header
httpDateHeader = 1, // general header
httpAuthorizationHeader = 2, // request header
httpIfModifiedSinceHeader = 3, // request header
httpServerHeader = 4, // response header
httpWWWAuthenticateHeader = 5, // response header
httpExpiresHeader = 6, // entity header
httpLastModifiedHeader = 7, // entity header
httpNumVIPHeaders = 8,
//Other general http headers
httpCacheControlHeader = 8,
httpPragmaHeader = 9,
httpTrailerHeader = 10,
httpTransferEncodingHeader = 11,
httpUpgradeHeader = 12,
httpViaHeader = 13,
httpWarningHeader = 14,
// Other request headers
httpAcceptHeader = 15,
httpAcceptCharsetHeader = 16,
httpAcceptEncodingHeader = 17,
httpAcceptLanguageHeader = 18,
httpExpectHeader = 19,
httpFromHeader = 20,
httpHostHeader = 21,
httpIfMatchHeader = 22,
httpIfNoneMatchHeader = 23,
httpIfRangeHeader = 24,
httpIfUnmodifiedSinceHeader = 25,
httpMaxForwardsHeader = 26,
httpProxyAuthorizationHeader = 27,
httpRangeHeader = 28,
httpRefererHeader = 29,
httpTEHeader = 30,
httpUserAgentHeader = 31,
// Other response headers
httpAcceptRangesHeader = 32,
httpAgeHeader = 33,
httpETagHeader = 34,
httpLocationHeader = 35,
httpProxyAuthenticateHeader = 36,
httpRetryAfterHeader = 37,
httpVaryHeader = 38,
// Other entity headers
httpAllowHeader = 39,
httpContentEncodingHeader = 40,
httpContentLanguageHeader = 41,
httpContentLengthHeader = 42,
httpContentLocationHeader = 43,
httpContentMD5Header = 44,
httpContentRangeHeader = 45,
httpContentTypeHeader = 46,
// QTSS Specific headers
// Add headers that are not part of the HTTP spec here
// Make sure and up the number of headers and httpIllegalHeader number
httpSessionCookieHeader = 47, // Used for HTTP tunnelling
httpServerIPAddressHeader = 48,
httpNumHeaders = 49,
httpIllegalHeader = 49
};
typedef UInt32 HTTPHeader;
// Status codes
enum
{
httpContinue = 0, //100
httpSwitchingProtocols = 1, //101
httpOK = 2, //200
httpCreated = 3, //201
httpAccepted = 4, //202
httpNonAuthoritativeInformation = 5, //203
httpNoContent = 6, //204
httpResetContent = 7, //205
httpPartialContent = 8, //206
httpMultipleChoices = 9, //300
httpMovedPermanently = 10, //301
httpFound = 11, //302
httpSeeOther = 12, //303
httpNotModified = 13, //304
httpUseProxy = 14, //305
httpTemporaryRedirect = 15, //307
httpBadRequest = 16, //400
httpUnAuthorized = 17, //401
httpPaymentRequired = 18, //402
httpForbidden = 19, //403
httpNotFound = 20, //404
httpMethodNotAllowed = 21, //405
httpNotAcceptable = 22, //406
httpProxyAuthenticationRequired = 23, //407
httpRequestTimeout = 24, //408
httpConflict = 25, //409
httpGone = 26, //410
httpLengthRequired = 27, //411
httpPreconditionFailed = 28, //412
httpRequestEntityTooLarge = 29, //413
httpRequestURITooLarge = 30, //414
httpUnsupportedMediaType = 31, //415
httpRequestRangeNotSatisfiable = 32, //416
httpExpectationFailed = 33, //417
httpInternalServerError = 34, //500
httpNotImplemented = 35, //501
httpBadGateway = 36, //502
httpServiceUnavailable = 37, //503
httpGatewayTimeout = 38, //504
httpHTTPVersionNotSupported = 39, //505
httpNumStatusCodes = 40
};
typedef UInt32 HTTPStatusCode;
class HTTPProtocol
{
public:
// Methods
static HTTPMethod GetMethod(const StrPtrLen* inMethodStr);
static StrPtrLen* GetMethodString(HTTPMethod inMethod) { return &sMethods[inMethod]; }
// Headers
static HTTPHeader GetHeader(const StrPtrLen* inHeaderStr);
static StrPtrLen* GetHeaderString(HTTPHeader inHeader) { return &sHeaders[inHeader]; }
// Status codes
static StrPtrLen* GetStatusCodeString(HTTPStatusCode inStat) { return &sStatusCodeStrings[inStat]; }
static SInt32 GetStatusCode(HTTPStatusCode inStat) { return sStatusCodes[inStat]; }
static StrPtrLen* GetStatusCodeAsString(HTTPStatusCode inStat) { return &sStatusCodeAsStrings[inStat]; }
// Versions
static HTTPVersion GetVersion(StrPtrLen* versionStr);
static StrPtrLen* GetVersionString(HTTPVersion version) { return &sVersionStrings[version]; }
private:
static StrPtrLen sMethods[];
static StrPtrLen sHeaders[];
static StrPtrLen sStatusCodeStrings[];
static StrPtrLen sStatusCodeAsStrings[];
static SInt32 sStatusCodes[];
static StrPtrLen sVersionStrings[];
};
#endif // __HTTPPROTOCOL_H__

View file

@ -0,0 +1,419 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include "HTTPRequest.h"
#include "HTTPProtocol.h"
#include "OSMemory.h"
#include "StringParser.h"
#include "StringTranslator.h"
#include "ResizeableStringFormatter.h"
#include "DateTranslator.h"
StrPtrLen HTTPRequest::sColonSpace(": ", 2);
static Bool16 sFalse = false;
static Bool16 sTrue = true;
static StrPtrLen sCloseString("close", 5);
static StrPtrLen sKeepAliveString("keep-alive", 10);
static StrPtrLen sDefaultRealm("Streaming Server", 19);
UInt8 HTTPRequest::sURLStopConditions[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 //'\t' is a stop condition
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, //10-19 //'\r' & '\n' are stop conditions
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //30-39 //' '
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40-49
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-59
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //60-69
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150-159
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240-249
0, 0, 0, 0, 0, 0 //250-255
};
// Constructor
HTTPRequest::HTTPRequest(StrPtrLen* serverHeader, StrPtrLen* requestPtr)
{
// Store the pointer to the server header field
fSvrHeader = *serverHeader;
// Set initial state
fRequestHeader = *requestPtr;
fResponseHeader = NULL;
fResponseFormatter = NULL;
fMethod = httpIllegalMethod;
fVersion = httpIllegalVersion;
fAbsoluteURI = NULL;
fRelativeURI = NULL;
fAbsoluteURIScheme = NULL;
fHostHeader = NULL;
fRequestPath = NULL;
fStatusCode = httpOK;
fRequestKeepAlive = false; // Default value when there is no version string
}
// Constructor for creating a response only
HTTPRequest::HTTPRequest(StrPtrLen* serverHeader)
{
// Store the pointer to the server header field
fSvrHeader = *serverHeader;
// We do not require any of these:
fRequestHeader = NULL;
fMethod = httpIllegalMethod;
fVersion = httpIllegalVersion;
fRequestLine = NULL;
fAbsoluteURI = NULL;
fRelativeURI = NULL;
fAbsoluteURIScheme = NULL;
fHostHeader = NULL;
fRequestPath = NULL;
fStatusCode = 0;
fRequestKeepAlive = false;
// We require the response but we allocate memory only when we call
// CreateResponseHeader
fResponseHeader = NULL;
fResponseFormatter = NULL;
}
// Destructor
HTTPRequest::~HTTPRequest()
{
if (fResponseHeader != NULL)
{
if (fResponseHeader->Ptr != NULL)
delete fResponseHeader->Ptr;
delete fResponseHeader;
}
if (fResponseFormatter != NULL)
delete fResponseFormatter;
if (fRequestPath != NULL)
delete [] fRequestPath;
}
//Parses the request
QTSS_Error HTTPRequest::Parse()
{
Assert(fRequestHeader.Ptr != NULL);
StringParser parser(&fRequestHeader);
// Store the request line (used for logging)
// (ex: GET /index.html HTTP/1.0)
StringParser requestLineParser(&fRequestHeader);
requestLineParser.ConsumeUntil(&fRequestLine, StringParser::sEOLMask);
// Parse request line returns an error if there is an error in the
// request URI or the formatting of the request line.
// If the method or version are not found, they are set
// to httpIllegalMethod or httpIllegalVersion respectively,
// and QTSS_NoErr is returned.
QTSS_Error err = ParseRequestLine(&parser);
if (err != QTSS_NoErr)
return err;
// Parse headers and set values of headers into fFieldValues array
err = ParseHeaders(&parser);
if (err != QTSS_NoErr)
return err;
return QTSS_NoErr;
}
QTSS_Error HTTPRequest::ParseRequestLine(StringParser* parser)
{
// Get the method - If the method is not one of the defined methods
// then it doesn't return an error but sets fMethod to httpIllegalMethod
StrPtrLen theParsedData;
parser->ConsumeWord(&theParsedData);
fMethod = HTTPProtocol::GetMethod(&theParsedData);
// Consume whitespace
parser->ConsumeWhitespace();
// Parse the URI - If it fails returns an error after setting
// the fStatusCode to the appropriate error code
QTSS_Error err = ParseURI(parser);
if (err != QTSS_NoErr)
return err;
// Consume whitespace
parser->ConsumeWhitespace();
// If there is a version, consume the version string
StrPtrLen versionStr;
parser->ConsumeUntil(&versionStr, StringParser::sEOLMask);
// Check the version
if (versionStr.Len > 0)
fVersion = HTTPProtocol::GetVersion(&versionStr);
// Go past the end of line
if (!parser->ExpectEOL())
{
fStatusCode = httpBadRequest;
return QTSS_BadArgument; // Request line is not properly formatted!
}
return QTSS_NoErr;
}
QTSS_Error HTTPRequest::ParseURI(StringParser* parser)
{
// read in the complete URL into fRequestAbsURI
parser->ConsumeUntil(&fAbsoluteURI, sURLStopConditions);
StringParser urlParser(&fAbsoluteURI);
// we always should have a slash before the URI
// If not, that indicates this is a full URI
if (fAbsoluteURI.Ptr[0] != '/')
{
//if it is a full URL, store the scheme and host name
urlParser.ConsumeLength(&fAbsoluteURIScheme, 7); //consume "http://"
urlParser.ConsumeUntil(&fHostHeader, '/');
}
// whatever is in this position is the relative URI
StrPtrLen relativeURI(urlParser.GetCurrentPosition(), urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen());
// read this URI into fRequestRelURI
fRelativeURI = relativeURI;
// Allocate memory for fRequestPath
UInt32 len = fRelativeURI.Len;
len++;
char* relativeURIDecoded = NEW char[len];
SInt32 theBytesWritten = StringTranslator::DecodeURL(fRelativeURI.Ptr, fRelativeURI.Len,
relativeURIDecoded, len);
//if negative, an error occurred, reported as an QTSS_Error
//we also need to leave room for a terminator.
if ((theBytesWritten < 0) || ((UInt32)theBytesWritten == len))
{
fStatusCode = httpBadRequest;
return QTSS_BadArgument;
}
fRequestPath = NEW char[theBytesWritten + 1];
::memcpy(fRequestPath, relativeURIDecoded + 1, theBytesWritten);
delete relativeURIDecoded;
fRequestPath[theBytesWritten] = '\0';
return QTSS_NoErr;
}
// Parses the Connection header and makes sure that request is properly terminated
QTSS_Error HTTPRequest::ParseHeaders(StringParser* parser)
{
StrPtrLen theKeyWord;
Bool16 isStreamOK;
//Repeat until we get a \r\n\r\n, which signals the end of the headers
while ((parser->PeekFast() != '\r') && (parser->PeekFast() != '\n'))
{
//First get the header identifier
isStreamOK = parser->GetThru(&theKeyWord, ':');
if (!isStreamOK)
{ // No colon after header!
fStatusCode = httpBadRequest;
return QTSS_BadArgument;
}
if (parser->PeekFast() == ' ')
{ // handle space, if any
isStreamOK = parser->Expect(' ');
Assert(isStreamOK);
}
//Look up the proper header enumeration based on the header string.
HTTPHeader theHeader = HTTPProtocol::GetHeader(&theKeyWord);
StrPtrLen theHeaderVal;
isStreamOK = parser->GetThruEOL(&theHeaderVal);
if (!isStreamOK)
{ // No EOL after header!
fStatusCode = httpBadRequest;
return QTSS_BadArgument;
}
// If this is the connection header
if ( theHeader == httpConnectionHeader )
{ // Set the keep alive boolean based on the connection header value
SetKeepAlive(&theHeaderVal);
}
// Have the header field and the value; Add value to the array
// If the field is invalid (or unrecognized) just skip over gracefully
if ( theHeader != httpIllegalHeader )
fFieldValues[theHeader] = theHeaderVal;
}
isStreamOK = parser->ExpectEOL();
Assert(isStreamOK);
return QTSS_NoErr;
}
void HTTPRequest::SetKeepAlive(StrPtrLen *keepAliveValue)
{
if ( sCloseString.EqualIgnoreCase(keepAliveValue->Ptr, keepAliveValue->Len) )
fRequestKeepAlive = sFalse;
else
{
Assert( sKeepAliveString.EqualIgnoreCase(keepAliveValue->Ptr, keepAliveValue->Len) );
fRequestKeepAlive = sTrue;
}
}
void HTTPRequest::PutStatusLine(StringFormatter* putStream, HTTPStatusCode status,
HTTPVersion version)
{
putStream->Put(*(HTTPProtocol::GetVersionString(version)));
putStream->PutSpace();
putStream->Put(*(HTTPProtocol::GetStatusCodeAsString(status)));
putStream->PutSpace();
putStream->Put(*(HTTPProtocol::GetStatusCodeString(status)));
putStream->PutEOL();
}
StrPtrLen* HTTPRequest::GetHeaderValue(HTTPHeader inHeader)
{
if ( inHeader != httpIllegalHeader )
return &fFieldValues[inHeader];
return NULL;
}
void HTTPRequest:: CreateResponseHeader(HTTPVersion version, HTTPStatusCode statusCode)
{
// If we are creating a second response for the same request, make sure and
// deallocate memory for old response and allocate fresh memory
if (fResponseFormatter != NULL)
{
if(fResponseHeader->Ptr != NULL)
delete fResponseHeader->Ptr;
delete fResponseHeader;
delete fResponseFormatter;
}
// Allocate memory for the response when you first create it
char* responseString = NEW char[kMinHeaderSizeInBytes];
fResponseHeader = NEW StrPtrLen(responseString, kMinHeaderSizeInBytes);
fResponseFormatter = NEW ResizeableStringFormatter(fResponseHeader->Ptr, fResponseHeader->Len);
//make a partial header for the given version and status code
PutStatusLine(fResponseFormatter, statusCode, version);
Assert(fSvrHeader.Ptr != NULL);
fResponseFormatter->Put(fSvrHeader);
fResponseFormatter->PutEOL();
fResponseHeader->Len = fResponseFormatter->GetCurrentOffset();
}
StrPtrLen* HTTPRequest::GetCompleteResponseHeader()
{
fResponseFormatter->PutEOL();
fResponseHeader->Len = fResponseFormatter->GetCurrentOffset();
return fResponseHeader;
}
void HTTPRequest::AppendResponseHeader(HTTPHeader inHeader, StrPtrLen* inValue)
{
fResponseFormatter->Put(*(HTTPProtocol::GetHeaderString(inHeader)));
fResponseFormatter->Put(sColonSpace);
fResponseFormatter->Put(*inValue);
fResponseFormatter->PutEOL();
fResponseHeader->Len = fResponseFormatter->GetCurrentOffset();
}
void HTTPRequest::AppendContentLengthHeader(UInt64 length_64bit)
{
char* contentLength = NEW char[256];
qtss_sprintf(contentLength, "%"_64BITARG_"d", length_64bit);
StrPtrLen contentLengthPtr(contentLength);
AppendResponseHeader(httpContentLengthHeader, &contentLengthPtr);
}
void HTTPRequest::AppendContentLengthHeader(UInt32 length_32bit)
{
char* contentLength = NEW char[256];
qtss_sprintf(contentLength, "%"_U32BITARG_"", length_32bit);
StrPtrLen contentLengthPtr(contentLength);
AppendResponseHeader(httpContentLengthHeader, &contentLengthPtr);
}
void HTTPRequest::AppendConnectionCloseHeader()
{
AppendResponseHeader(httpConnectionHeader, &sCloseString);
}
void HTTPRequest::AppendConnectionKeepAliveHeader()
{
AppendResponseHeader(httpConnectionHeader, &sKeepAliveString);
}
void HTTPRequest::AppendDateAndExpiresFields()
{
Assert(OSThread::GetCurrent() != NULL);
DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
// Append dates, and have this response expire immediately
this->AppendResponseHeader(httpDateHeader, &theDate);
this->AppendResponseHeader(httpExpiresHeader, &theDate);
}
void HTTPRequest::AppendDateField()
{
Assert(OSThread::GetCurrent() != NULL);
DateBuffer* theDateBuffer = OSThread::GetCurrent()->GetDateBuffer();
theDateBuffer->InexactUpdate(); // Update the date buffer to the current date & time
StrPtrLen theDate(theDateBuffer->GetDateBuffer(), DateBuffer::kDateBufferLen);
// Append date
this->AppendResponseHeader(httpDateHeader, &theDate);
}
time_t HTTPRequest::ParseIfModSinceHeader()
{
time_t theIfModSinceDate = (time_t) DateTranslator::ParseDate(&fFieldValues[httpIfModifiedSinceHeader]);
return theIfModSinceDate;
}

View file

@ -0,0 +1,137 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#ifndef __HTTPREQUEST_H__
#define __HTTPREQUEST_H__
#include "HTTPProtocol.h"
#include "StrPtrLen.h"
#include "StringParser.h"
#include "ResizeableStringFormatter.h"
#include "OSHeaders.h"
#include "QTSS.h"
class HTTPRequest
{
public:
// Constructor
HTTPRequest(StrPtrLen* serverHeader, StrPtrLen* requestPtr);
// This cosntructor is used when the request has been parsed and thrown away
// and the response has to be created
HTTPRequest(StrPtrLen* serverHeader);
// Destructor
virtual ~HTTPRequest();
// Should be called before accessing anything in the request header
// Calls ParseRequestLine and ParseHeaders
QTSS_Error Parse();
// Basic access methods for the HTTP method, the absolute request URI,
// the host name from URI, the relative request URI, the request file path,
// the HTTP version, the Status code, the keep-alive tag.
HTTPMethod GetMethod(){ return fMethod; }
StrPtrLen* GetRequestLine(){ return &fRequestLine; }
StrPtrLen* GetRequestAbsoluteURI(){ return &fAbsoluteURI; }
StrPtrLen* GetSchemefromAbsoluteURI(){ return &fAbsoluteURIScheme; }
StrPtrLen* GetHostfromAbsoluteURI(){ return &fHostHeader; }
StrPtrLen* GetRequestRelativeURI(){ return &fRelativeURI; }
char* GetRequestPath(){ return fRequestPath; }
HTTPVersion GetVersion(){ return fVersion; }
HTTPStatusCode GetStatusCode(){ return fStatusCode; }
Bool16 IsRequestKeepAlive(){ return fRequestKeepAlive; }
// If header field exists in the request, it will be found in the dictionary
// and the value returned. Otherwise, NULL is returned.
StrPtrLen* GetHeaderValue(HTTPHeader inHeader);
// Creates a header with the corresponding version and status code
void CreateResponseHeader(HTTPVersion version, HTTPStatusCode statusCode);
// To append response header fields as appropriate
void AppendResponseHeader(HTTPHeader inHeader, StrPtrLen* inValue);
void AppendDateAndExpiresFields();
void AppendDateField();
void AppendConnectionCloseHeader();
void AppendConnectionKeepAliveHeader();
void AppendContentLengthHeader(UInt64 length_64bit);
void AppendContentLengthHeader(UInt32 length_32bit);
// Returns the completed response header by appending CRLF to the end of the header
// fields buffer
StrPtrLen* GetCompleteResponseHeader();
// Parse if-modified-since header
time_t ParseIfModSinceHeader();
private:
enum { kMinHeaderSizeInBytes = 512 };
// Gets the method, version and calls ParseURI
QTSS_Error ParseRequestLine(StringParser* parser);
// Parses the URI to get absolute and relative URIs, the host name and the file path
QTSS_Error ParseURI(StringParser* parser);
// Parses the headers and adds them into a dictionary
// Also calls SetKeepAlive with the Connection header field's value if it exists
QTSS_Error ParseHeaders(StringParser* parser);
// Sets fRequestKeepAlive
void SetKeepAlive(StrPtrLen* keepAliveValue);
// Used in initialize and CreateResponseHeader
void PutStatusLine(StringFormatter* putStream, HTTPStatusCode status, HTTPVersion version);
//For writing into the premade headers
StrPtrLen* GetServerHeader(){ return &fSvrHeader; }
// Complete request and response headers
StrPtrLen fRequestHeader;
ResizeableStringFormatter* fResponseFormatter;
StrPtrLen* fResponseHeader;
// Private members
HTTPMethod fMethod;
HTTPVersion fVersion;
StrPtrLen fRequestLine;
// For the URI (fAbsoluteURI and fRelativeURI are the same if the URI is of the form "/path")
StrPtrLen fAbsoluteURI; // If it is of the form "http://foo.bar.com/path"
StrPtrLen fRelativeURI; // If it is of the form "/path"
// If it is an absolute URI, these fields will be filled in
// "http://foo.bar.com/path" => fAbsoluteURIScheme = "http", fHostHeader = "foo.bar.com",
// fRequestPath = "path"
StrPtrLen fAbsoluteURIScheme;
StrPtrLen fHostHeader; // If the full url is given in the request line
char* fRequestPath; // Also contains the query string
HTTPStatusCode fStatusCode;
Bool16 fRequestKeepAlive; // Keep-alive information in the client request
StrPtrLen fFieldValues[httpNumHeaders]; // Array of header field values parsed from the request
StrPtrLen fSvrHeader; // Server header set up at initialization
static StrPtrLen sColonSpace;
static UInt8 sURLStopConditions[];
};
#endif // __HTTPREQUEST_H__