diff --git a/GCDWebServer/Core/GCDWebServerConnection.h b/GCDWebServer/Core/GCDWebServerConnection.h index 43242af..8f73494 100644 --- a/GCDWebServer/Core/GCDWebServerConnection.h +++ b/GCDWebServer/Core/GCDWebServerConnection.h @@ -44,8 +44,9 @@ - (BOOL)open; // Return NO to reject connection e.g. after validating local or remote addresses - (void)didReadBytes:(const void*)bytes length:(NSUInteger)length; // Called after data has been read from the connection - (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length; // Called after data has been written to the connection +- (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request; // Called before request is processed to return an override response bypassing processing or nil to continue - Default implementation checks authentication if applicable - (GCDWebServerResponse*)processRequest:(GCDWebServerRequest*)request withBlock:(GCDWebServerProcessBlock)block; // Only called if the request can be processed -- (GCDWebServerResponse*)replaceResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request; // Default implementation replaces any response matching the "ETag" or "Last-Modified-Date" header of the request by a barebone "Not-Modified" (304) one +- (GCDWebServerResponse*)overrideResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request; // Default implementation replaces any response matching the "ETag" or "Last-Modified-Date" header of the request by a barebone "Not-Modified" (304) one - (void)abortRequest:(GCDWebServerRequest*)request withStatusCode:(NSInteger)statusCode; // If request headers were malformed, "request" will be nil - (void)close; @end diff --git a/GCDWebServer/Core/GCDWebServerConnection.m b/GCDWebServer/Core/GCDWebServerConnection.m index f1210a4..434bfed 100644 --- a/GCDWebServer/Core/GCDWebServerConnection.m +++ b/GCDWebServer/Core/GCDWebServerConnection.m @@ -372,20 +372,23 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) { DCHECK(_responseMessage == NULL); BOOL hasBody = NO; - GCDWebServerResponse* response = [self processRequest:_request withBlock:_handler.processBlock]; + GCDWebServerResponse* response = [self preflightRequest:_request]; + if (!response) { + response = [self processRequest:_request withBlock:_handler.processBlock]; + } if (response) { - response = [self replaceResponse:response forRequest:_request]; - if (response) { - if ([response hasBody]) { - [response prepareForReading]; - hasBody = !_virtualHEAD; - } - NSError* error = nil; - if (hasBody && ![response performOpen:&error]) { - LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error); - } else { - _response = ARC_RETAIN(response); - } + response = [self overrideResponse:response forRequest:_request]; + } + if (response) { + if ([response hasBody]) { + [response prepareForReading]; + hasBody = !_virtualHEAD; + } + NSError* error = nil; + if (hasBody && ![response performOpen:&error]) { + LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error); + } else { + _response = ARC_RETAIN(response); } } @@ -704,27 +707,27 @@ static NSString* _StringFromAddressData(NSData* data) { #endif } -- (GCDWebServerResponse*)processRequest:(GCDWebServerRequest*)request withBlock:(GCDWebServerProcessBlock)block { - LOG_DEBUG(@"Connection on socket %i processing request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead); +- (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request { + LOG_DEBUG(@"Connection on socket %i preflighting request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead); GCDWebServerResponse* response = nil; - BOOL authorized = YES; if (_server.authenticationBasicAccount) { NSString* authorizationHeader = [request.headers objectForKey:@"Authorization"]; if (![authorizationHeader hasPrefix:@"Basic "] || ![[authorizationHeader substringFromIndex:6] isEqualToString:_server.authenticationBasicAccount]) { - authorized = NO; + response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_Unauthorized]; + [response setValue:[NSString stringWithFormat:@"Basic realm=\"%@\"", _server.authenticationRealm] forAdditionalHeader:@"WWW-Authenticate"]; } } - if (authorized) { - @try { - response = block(request); - } - @catch (NSException* exception) { - LOG_EXCEPTION(exception); - } - } else { - response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_Unauthorized]; - [response setValue:[NSString stringWithFormat:@"Basic realm=\"%@\"", _server.authenticationRealm] forAdditionalHeader:@"WWW-Authenticate"]; - return response; + return response; +} + +- (GCDWebServerResponse*)processRequest:(GCDWebServerRequest*)request withBlock:(GCDWebServerProcessBlock)block { + LOG_DEBUG(@"Connection on socket %i processing request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead); + GCDWebServerResponse* response = nil; + @try { + response = block(request); + } + @catch (NSException* exception) { + LOG_EXCEPTION(exception); } return response; } @@ -744,7 +747,7 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET return NO; } -- (GCDWebServerResponse*)replaceResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request { +- (GCDWebServerResponse*)overrideResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request { if ((response.statusCode >= 200) && (response.statusCode < 300) && _CompareResources(response.eTag, request.ifNoneMatch, response.lastModifiedDate, request.ifModifiedSince)) { NSInteger code = [request.method isEqualToString:@"HEAD"] || [request.method isEqualToString:@"GET"] ? kGCDWebServerHTTPStatusCode_NotModified : kGCDWebServerHTTPStatusCode_PreconditionFailed; GCDWebServerResponse* newResponse = [GCDWebServerResponse responseWithStatusCode:code];