소스 검색

Factored out HTTP date parsing and formatting

Pierre-Olivier Latour 11 년 전
부모
커밋
7339a7a2a6
3개의 변경된 파일33개의 추가작업 그리고 19개의 파일을 삭제
  1. 30 1
      CGDWebServer/GCDWebServer.m
  2. 1 18
      CGDWebServer/GCDWebServerConnection.m
  3. 2 0
      CGDWebServer/GCDWebServerPrivate.h

+ 30 - 1
CGDWebServer/GCDWebServer.m

@@ -63,6 +63,8 @@
 }
 }
 @end
 @end
 
 
+static NSDateFormatter* _dateFormatterRFC822 = nil;
+static dispatch_queue_t _dateFormatterQueue = NULL;
 #if !TARGET_OS_IPHONE
 #if !TARGET_OS_IPHONE
 static BOOL _run;
 static BOOL _run;
 #endif
 #endif
@@ -115,6 +117,22 @@ NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) {
   return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding);
   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) {
 NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
   static NSDictionary* _overrides = nil;
   static NSDictionary* _overrides = nil;
   if (_overrides == nil) {
   if (_overrides == nil) {
@@ -258,7 +276,18 @@ static void _SignalHandler(int signal) {
 @synthesize handlers=_handlers, port=_port;
 @synthesize handlers=_handlers, port=_port;
 
 
 + (void)initialize {
 + (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 {
 - (instancetype)init {

+ 1 - 18
CGDWebServer/GCDWebServerConnection.m

@@ -45,8 +45,6 @@ static NSData* _CRLFData = nil;
 static NSData* _CRLFCRLFData = nil;
 static NSData* _CRLFCRLFData = nil;
 static NSData* _continueData = nil;
 static NSData* _continueData = nil;
 static NSData* _lastChunkData = nil;
 static NSData* _lastChunkData = nil;
-static NSDateFormatter* _dateFormatter = nil;
-static dispatch_queue_t _formatterQueue = NULL;
 
 
 @interface GCDWebServerConnection () {
 @interface GCDWebServerConnection () {
 @private
 @private
@@ -384,18 +382,6 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
   if (_lastChunkData == nil) {
   if (_lastChunkData == nil) {
     _lastChunkData = [[NSData alloc] initWithBytes:"0\r\n\r\n" length:5];
     _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 {
 - (void)_initializeResponseHeadersWithStatusCode:(NSInteger)statusCode {
@@ -403,10 +389,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
   _responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
   _responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
   CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
   CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
   CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)[[_server class] serverName]);
   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
 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

+ 2 - 0
CGDWebServer/GCDWebServerPrivate.h

@@ -110,6 +110,8 @@ static inline BOOL GCDWebServerIsValidByteRange(NSRange range) {
 
 
 extern NSString* GCDWebServerExtractHeaderParameter(NSString* header, NSString* attribute);
 extern NSString* GCDWebServerExtractHeaderParameter(NSString* header, NSString* attribute);
 extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset);
 extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset);
+extern NSString* GCDWebServerFormatHTTPDate(NSDate* date);
+extern NSDate* GCDWebServerParseHTTPDate(NSString* string);
 
 
 @interface GCDWebServerConnection ()
 @interface GCDWebServerConnection ()
 - (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket;
 - (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket;