Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -33,10 +33,11 @@ #import "OFHTTPRequestFailedException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFInvalidServerReplyException.h" #import "OFNotConnectedException.h" +#import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" @@ -322,11 +323,11 @@ redirects: (size_t)redirects { void *pool = objc_autoreleasePoolPush(); OFURL *URL = [request URL]; OFString *scheme = [URL scheme]; - of_http_request_type_t requestType = [request requestType]; + of_http_request_method_t method = [request method]; OFMutableString *requestString; OFDictionary *headers = [request headers]; OFDataArray *POSTData = [request POSTData]; OFTCPSocket *socket; OFHTTPClientResponse *response; @@ -333,14 +334,19 @@ OFString *line, *path, *version, *redirect, *keepAlive; OFMutableDictionary *serverHeaders; OFEnumerator *keyEnumerator, *objectEnumerator; OFString *key, *object; int status; - const char *type = NULL; if (![scheme isEqual: @"http"] && ![scheme isEqual: @"https"]) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; + + if (method != OF_HTTP_REQUEST_METHOD_GET && + method != OF_HTTP_REQUEST_METHOD_HEAD && + method != OF_HTTP_REQUEST_METHOD_POST) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; /* Can we reuse the socket? */ if (_socket != nil && [[_lastURL scheme] isEqual: [URL scheme]] && [[_lastURL host] isEqual: [URL host]] && [_lastURL port] == [URL port]) { @@ -366,17 +372,10 @@ [_lastResponse release]; _lastResponse = nil; } else socket = [self OF_createSocketForRequest: request]; - if (requestType == OF_HTTP_REQUEST_TYPE_GET) - type = "GET"; - if (requestType == OF_HTTP_REQUEST_TYPE_HEAD) - type = "HEAD"; - if (requestType == OF_HTTP_REQUEST_TYPE_POST) - type = "POST"; - if ([(path = [URL path]) length] == 0) path = @"/"; /* * As a work around for a bug with split packets in lighttpd when using @@ -384,15 +383,17 @@ * send it all at once. */ if ([URL query] != nil) requestString = [OFMutableString stringWithFormat: @"%s %@?%@ HTTP/%@\r\n", - type, path, [URL query], [request protocolVersionString]]; + of_http_request_method_to_string(method), path, [URL query], + [request protocolVersionString]]; else requestString = [OFMutableString stringWithFormat: @"%s %@ HTTP/%@\r\n", - type, path, [request protocolVersionString]]; + of_http_request_method_to_string(method), path, + [request protocolVersionString]]; if ([URL port] == 80) [requestString appendFormat: @"Host: %@\r\n", [URL host]]; else [requestString appendFormat: @"Host: %@:%d\r\n", [URL host], @@ -408,11 +409,11 @@ while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) [requestString appendFormat: @"%@: %@\r\n", key, object]; - if (requestType == OF_HTTP_REQUEST_TYPE_POST) { + if (method == OF_HTTP_REQUEST_METHOD_POST) { OFString *contentType = [request MIMEType]; if (contentType == nil) contentType = @"application/x-www-form-urlencoded; " @"charset=UTF-8"; @@ -438,11 +439,11 @@ /* Reconnect in case a keep-alive connection timed out */ socket = [self OF_createSocketForRequest: request]; [socket writeString: requestString]; } - if (requestType == OF_HTTP_REQUEST_TYPE_POST) + if (method == OF_HTTP_REQUEST_METHOD_POST) [socket writeBuffer: [POSTData items] length: [POSTData count] * [POSTData itemSize]]; @try { line = [socket readLine]; @@ -457,11 +458,11 @@ */ if (line == nil) { socket = [self OF_createSocketForRequest: request]; [socket writeString: requestString]; - if (requestType == OF_HTTP_REQUEST_TYPE_POST) + if (method == OF_HTTP_REQUEST_METHOD_POST) [socket writeBuffer: [POSTData items] length: [POSTData count] * [POSTData itemSize]]; @try { @@ -575,18 +576,18 @@ if (follow) { OFHTTPRequest *newRequest; newRequest = [OFHTTPRequest requestWithURL: newURL]; - [newRequest setRequestType: requestType]; + [newRequest setMethod: method]; [newRequest setHeaders: headers]; [newRequest setPOSTData: POSTData]; [newRequest setMIMEType: [request MIMEType]]; if (status == 303) { [newRequest - setRequestType: OF_HTTP_REQUEST_TYPE_GET]; + setMethod: OF_HTTP_REQUEST_METHOD_GET]; [newRequest setPOSTData: nil]; [newRequest setMIMEType: nil]; } [newRequest retain]; Index: src/OFHTTPRequest.h ================================================================== --- src/OFHTTPRequest.h +++ src/OFHTTPRequest.h @@ -28,18 +28,28 @@ /*! @file */ /*! * @brief The type of an HTTP request. */ -typedef enum of_http_request_type_t { +typedef enum of_http_request_method_t { + /*! OPTIONS */ + OF_HTTP_REQUEST_METHOD_OPTIONS, /*! GET */ - OF_HTTP_REQUEST_TYPE_GET, - /*! POST */ - OF_HTTP_REQUEST_TYPE_POST, + OF_HTTP_REQUEST_METHOD_GET, /*! HEAD */ - OF_HTTP_REQUEST_TYPE_HEAD -} of_http_request_type_t; + OF_HTTP_REQUEST_METHOD_HEAD, + /*! POST */ + OF_HTTP_REQUEST_METHOD_POST, + /*! PUT */ + OF_HTTP_REQUEST_METHOD_PUT, + /*! DELETE */ + OF_HTTP_REQUEST_METHOD_DELETE, + /*! TRACE */ + OF_HTTP_REQUEST_METHOD_TRACE, + /*! CONNECT */ + OF_HTTP_REQUEST_METHOD_CONNECT +} of_http_request_method_t; /*! * @brief The HTTP version of the HTTP request. */ typedef struct of_http_request_protocol_version_t { @@ -53,21 +63,21 @@ * @brief A class for storing HTTP requests. */ @interface OFHTTPRequest: OFObject { OFURL *_URL; - of_http_request_type_t _requestType; + of_http_request_method_t _method; of_http_request_protocol_version_t _protocolVersion; OFDictionary *_headers; OFDataArray *_POSTData; OFString *_MIMEType; OFString *_remoteAddress; } #ifdef OF_HAVE_PROPERTIES @property (copy) OFURL *URL; -@property of_http_request_type_t requestType; +@property of_http_request_method_t method; @property of_http_request_protocol_version_t protocolVersion; @property (copy) OFDictionary *headers; @property (retain) OFDataArray *POSTData; @property (copy) OFString *MIMEType; @property (copy) OFString *remoteAddress; @@ -109,22 +119,22 @@ * @return The URL of the HTTP request */ - (OFURL*)URL; /*! - * @brief Sets the request type of the HTTP request. + * @brief Sets the request method of the HTTP request. * - * @param requestType The request type of the HTTP request + * @param method The request method of the HTTP request */ -- (void)setRequestType: (of_http_request_type_t)requestType; +- (void)setMethod: (of_http_request_method_t)method; /*! - * @brief Returns the request type of the HTTP request. + * @brief Returns the request method of the HTTP request. * - * @return The request type of the HTTP request + * @return The request method of the HTTP request */ -- (of_http_request_type_t)requestType; +- (of_http_request_method_t)method; /*! * @brief Sets the protocol version of the HTTP request. * * @param protocolVersion The protocol version of the HTTP request @@ -207,5 +217,29 @@ * * @return The remote address from which the request originates */ - (OFString*)remoteAddress; @end + +#ifdef __cplusplus +extern "C" { +#endif +/*! + * @brief Returns a C string describing the specified request method. + * + * @param method The request method which should be described as a C string + * @return A C string describing the specified request method + */ +extern const char* of_http_request_method_to_string( + of_http_request_method_t method); + +/*! + * @brief Returns the request method for the specified string. + * + * @param string The string for which the request method should be returned + * @return The request method for the specified string + */ +extern of_http_request_method_t of_http_request_method_from_string( + const char *string); +#ifdef __cplusplus +} +#endif Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -13,10 +13,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFHTTPRequest.h" #import "OFString.h" #import "OFURL.h" #import "OFDictionary.h" @@ -27,10 +29,58 @@ #import "macros.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "OFUnsupportedVersionException.h" + +const char* +of_http_request_method_to_string(of_http_request_method_t method) +{ + switch (method) { + case OF_HTTP_REQUEST_METHOD_OPTIONS: + return "OPTIONS"; + case OF_HTTP_REQUEST_METHOD_GET: + return "GET"; + case OF_HTTP_REQUEST_METHOD_HEAD: + return "HEAD"; + case OF_HTTP_REQUEST_METHOD_POST: + return "POST"; + case OF_HTTP_REQUEST_METHOD_PUT: + return "PUT"; + case OF_HTTP_REQUEST_METHOD_DELETE: + return "DELETE"; + case OF_HTTP_REQUEST_METHOD_TRACE: + return "TRACE"; + case OF_HTTP_REQUEST_METHOD_CONNECT: + return "CONNECT"; + } + + return NULL; +} + +of_http_request_method_t +of_http_request_method_from_string(const char *string) +{ + if (!strcmp(string, "OPTIONS")) + return OF_HTTP_REQUEST_METHOD_OPTIONS; + if (!strcmp(string, "GET")) + return OF_HTTP_REQUEST_METHOD_GET; + if (!strcmp(string, "HEAD")) + return OF_HTTP_REQUEST_METHOD_HEAD; + if (!strcmp(string, "POST")) + return OF_HTTP_REQUEST_METHOD_POST; + if (!strcmp(string, "PUT")) + return OF_HTTP_REQUEST_METHOD_PUT; + if (!strcmp(string, "DELETE")) + return OF_HTTP_REQUEST_METHOD_DELETE; + if (!strcmp(string, "TRACE")) + return OF_HTTP_REQUEST_METHOD_TRACE; + if (!strcmp(string, "CONNECT")) + return OF_HTTP_REQUEST_METHOD_CONNECT; + + @throw [OFInvalidFormatException exception]; +} @implementation OFHTTPRequest + (instancetype)request { return [[[self alloc] init] autorelease]; @@ -43,11 +93,11 @@ - init { self = [super init]; - _requestType = OF_HTTP_REQUEST_TYPE_GET; + _method = OF_HTTP_REQUEST_METHOD_GET; _protocolVersion.major = 1; _protocolVersion.minor = 1; return self; } @@ -80,11 +130,11 @@ - copy { OFHTTPRequest *copy = [[OFHTTPRequest alloc] init]; @try { - copy->_requestType = _requestType; + copy->_method = _method; copy->_protocolVersion = _protocolVersion; [copy setURL: _URL]; [copy setHeaders: _headers]; [copy setPOSTData: _POSTData]; [copy setMIMEType: _MIMEType]; @@ -104,11 +154,11 @@ if (![object isKindOfClass: [OFHTTPRequest class]]) return false; request = object; - if (request->_requestType != _requestType || + if (request->_method != _method || request->_protocolVersion.major != _protocolVersion.major || request->_protocolVersion.minor != _protocolVersion.minor || ![request->_URL isEqual: _URL] || ![request->_headers isEqual: _headers] || ![request->_POSTData isEqual: _POSTData] || @@ -123,11 +173,11 @@ { uint32_t hash; OF_HASH_INIT(hash); - OF_HASH_ADD(hash, _requestType); + OF_HASH_ADD(hash, _method); OF_HASH_ADD(hash, _protocolVersion.major); OF_HASH_ADD(hash, _protocolVersion.minor); OF_HASH_ADD_HASH(hash, [_URL hash]); OF_HASH_ADD_HASH(hash, [_headers hash]); OF_HASH_ADD_HASH(hash, [_POSTData hash]); @@ -147,18 +197,18 @@ - (OFURL*)URL { OF_GETTER(_URL, true) } -- (void)setRequestType: (of_http_request_type_t)requestType +- (void)setMethod: (of_http_request_method_t)method { - _requestType = requestType; + _method = method; } -- (of_http_request_type_t)requestType +- (of_http_request_method_t)method { - return _requestType; + return _method; } - (void)setProtocolVersion: (of_http_request_protocol_version_t)protocolVersion { if (protocolVersion.major != 1 || protocolVersion.minor > 1) @@ -246,43 +296,31 @@ } - (OFString*)description { void *pool = objc_autoreleasePoolPush(); - const char *requestTypeStr = NULL; + const char *method = of_http_request_method_to_string(_method); OFString *indentedHeaders, *indentedPOSTData, *ret; - switch (_requestType) { - case OF_HTTP_REQUEST_TYPE_GET: - requestTypeStr = "GET"; - break; - case OF_HTTP_REQUEST_TYPE_POST: - requestTypeStr = "POST"; - break; - case OF_HTTP_REQUEST_TYPE_HEAD: - requestTypeStr = "HEAD"; - break; - } - indentedHeaders = [[_headers description] stringByReplacingOccurrencesOfString: @"\n" withString: @"\n\t"]; indentedPOSTData = [[_POSTData description] stringByReplacingOccurrencesOfString: @"\n" withString: @"\n\t"]; ret = [[OFString alloc] initWithFormat: @"<%@:\n\tURL = %@\n" - @"\tRequest type = %s\n" + @"\tMethod = %s\n" @"\tHeaders = %@\n" @"\tPOST data = %@\n" @"\tPOST data MIME type = %@\n" @"\tRemote address = %@\n" @">", - [self class], _URL, requestTypeStr, indentedHeaders, - indentedPOSTData, _MIMEType, _remoteAddress]; + [self class], _URL, method, indentedHeaders, indentedPOSTData, + _MIMEType, _remoteAddress]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @end Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -289,11 +289,11 @@ AWAITING_PROLOG, PARSING_HEADERS, SEND_RESPONSE } _state; uint8_t _HTTPMinorVersion; - of_http_request_type_t _requestType; + of_http_request_method_t _method; OFString *_host, *_path; uint16_t _port; OFMutableDictionary *_headers; size_t _contentLength; OFDataArray *_POSTData; @@ -385,11 +385,11 @@ abort(); } - (bool)parseProlog: (OFString*)line { - OFString *type; + OFString *method; size_t pos; @try { OFString *version = [line substringWithRange: of_range([line length] - 9, 9)]; @@ -409,19 +409,21 @@ pos = [line rangeOfString: @" "].location; if (pos == OF_NOT_FOUND) return [self sendErrorAndClose: 400]; - type = [line substringWithRange: of_range(0, pos)]; - if ([type isEqual: @"GET"]) - _requestType = OF_HTTP_REQUEST_TYPE_GET; - else if ([type isEqual: @"POST"]) - _requestType = OF_HTTP_REQUEST_TYPE_POST; - else if ([type isEqual: @"HEAD"]) - _requestType = OF_HTTP_REQUEST_TYPE_HEAD; - else - return [self sendErrorAndClose: 501]; + method = [line substringWithRange: of_range(0, pos)]; + @try { + _method = of_http_request_method_from_string( + [method UTF8String]); + } @catch (OFInvalidFormatException *e) { + return [self sendErrorAndClose: 405]; + } + if (_method != OF_HTTP_REQUEST_METHOD_GET && + _method != OF_HTTP_REQUEST_METHOD_HEAD && + _method != OF_HTTP_REQUEST_METHOD_POST) + return [self sendErrorAndClose: 405]; @try { _path = [line substringWithRange: of_range(pos + 1, [line length] - pos - 10)]; } @catch (OFOutOfRangeException *e) { @@ -442,16 +444,12 @@ { OFString *key, *value; size_t pos; if ([line length] == 0) { - switch (_requestType) { - case OF_HTTP_REQUEST_TYPE_GET: - case OF_HTTP_REQUEST_TYPE_HEAD: - _state = SEND_RESPONSE; - break; - case OF_HTTP_REQUEST_TYPE_POST:; + switch (_method) { + case OF_HTTP_REQUEST_METHOD_POST:; OFString *tmp; char *buffer; tmp = [_headers objectForKey: @"Content-Length"]; if (tmp == nil) @@ -474,10 +472,13 @@ length:exception:)]; [_timer setFireDate: [OFDate dateWithTimeIntervalSinceNow: 5]]; return false; + default: + _state = SEND_RESPONSE; + break; } return true; } @@ -608,11 +609,11 @@ [URL setQuery: query]; } else [URL setPath: _path]; request = [OFHTTPRequest requestWithURL: URL]; - [request setRequestType: _requestType]; + [request setMethod: _method]; [request setProtocolVersion: (of_http_request_protocol_version_t){ 1, _HTTPMinorVersion }]; [request setHeaders: _headers]; [request setPOSTData: _POSTData]; [request setRemoteAddress: [_socket remoteAddress]]; Index: src/exceptions/OFHTTPRequestFailedException.h ================================================================== --- src/exceptions/OFHTTPRequestFailedException.h +++ src/exceptions/OFHTTPRequestFailedException.h @@ -22,11 +22,11 @@ @class OFHTTPRequest; @class OFHTTPResponse; /*! - * @brief An exception indicating that a HTTP request failed. + * @brief An exception indicating that an HTTP request failed. */ @interface OFHTTPRequestFailedException: OFException { OFHTTPRequest *_request; OFHTTPResponse *_response; Index: src/exceptions/OFHTTPRequestFailedException.m ================================================================== --- src/exceptions/OFHTTPRequestFailedException.m +++ src/exceptions/OFHTTPRequestFailedException.m @@ -64,26 +64,15 @@ [super dealloc]; } - (OFString*)description { - const char *type = "(unknown)"; - - switch ([_request requestType]) { - case OF_HTTP_REQUEST_TYPE_GET: - type = "GET"; - break; - case OF_HTTP_REQUEST_TYPE_HEAD: - type = "HEAD"; - break; - case OF_HTTP_REQUEST_TYPE_POST: - type = "POST"; - break; - } + const char *method = + of_http_request_method_to_string([_request method]); return [OFString stringWithFormat: - @"A HTTP %s request with URL %@ failed with code %d!", type, + @"An HTTP %s request with URL %@ failed with code %d!", method, [_request URL], [_response statusCode]]; } - (OFHTTPRequest*)request {