diff --git a/CGDWebServer/GCDWebServer.m b/CGDWebServer/GCDWebServer.m index 7c555d7..cc8bb3e 100644 --- a/CGDWebServer/GCDWebServer.m +++ b/CGDWebServer/GCDWebServer.m @@ -63,6 +63,8 @@ } @end +static NSDateFormatter* _dateFormatterRFC822 = nil; +static dispatch_queue_t _dateFormatterQueue = NULL; #if !TARGET_OS_IPHONE static BOOL _run; #endif @@ -115,6 +117,22 @@ NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) { return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding); } +NSString* GCDWebServerFormatHTTPDate(NSDate* date) { + __block NSString* string; + dispatch_sync(_dateFormatterQueue, ^{ + string = [_dateFormatterRFC822 stringFromDate:date]; // HTTP/1.1 server must use RFC822 + }); + return string; +} + +NSDate* GCDWebServerParseHTTPDate(NSString* string) { + __block NSDate* date; + dispatch_sync(_dateFormatterQueue, ^{ + date = [_dateFormatterRFC822 dateFromString:string]; // TODO: Handle RFC 850 and ANSI C's asctime() format (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3) + }); + return date; +} + NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) { static NSDictionary* _overrides = nil; if (_overrides == nil) { @@ -258,7 +276,18 @@ static void _SignalHandler(int signal) { @synthesize handlers=_handlers, port=_port; + (void)initialize { - [GCDWebServerConnection class]; // Initialize class immediately to make sure it happens on the main thread + if (_dateFormatterRFC822 == nil) { + DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread + _dateFormatterRFC822 = [[NSDateFormatter alloc] init]; + _dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + _dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; + _dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); + DCHECK(_dateFormatterRFC822); + } + if (_dateFormatterQueue == NULL) { + _dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + DCHECK(_dateFormatterQueue); + } } - (instancetype)init { diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index c4e5441..54c0e8e 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -45,8 +45,6 @@ static NSData* _CRLFData = nil; static NSData* _CRLFCRLFData = nil; static NSData* _continueData = nil; static NSData* _lastChunkData = nil; -static NSDateFormatter* _dateFormatter = nil; -static dispatch_queue_t _formatterQueue = NULL; @interface GCDWebServerConnection () { @private @@ -384,18 +382,6 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) { if (_lastChunkData == nil) { _lastChunkData = [[NSData alloc] initWithBytes:"0\r\n\r\n" length:5]; } - if (_dateFormatter == nil) { - DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread - _dateFormatter = [[NSDateFormatter alloc] init]; - _dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; - _dateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; - _dateFormatter.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); - DCHECK(_dateFormatter); - } - if (_formatterQueue == NULL) { - _formatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - DCHECK(_formatterQueue); - } } - (void)_initializeResponseHeadersWithStatusCode:(NSInteger)statusCode { @@ -403,10 +389,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) { _responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close")); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)[[_server class] serverName]); - dispatch_sync(_formatterQueue, ^{ - NSString* date = [_dateFormatter stringFromDate:[NSDate date]]; - CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)date); - }); + CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate([NSDate date])); } // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html diff --git a/CGDWebServer/GCDWebServerPrivate.h b/CGDWebServer/GCDWebServerPrivate.h index 08662c2..5941487 100644 --- a/CGDWebServer/GCDWebServerPrivate.h +++ b/CGDWebServer/GCDWebServerPrivate.h @@ -110,6 +110,8 @@ static inline BOOL GCDWebServerIsValidByteRange(NSRange range) { extern NSString* GCDWebServerExtractHeaderParameter(NSString* header, NSString* attribute); extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset); +extern NSString* GCDWebServerFormatHTTPDate(NSDate* date); +extern NSDate* GCDWebServerParseHTTPDate(NSString* string); @interface GCDWebServerConnection () - (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket;