From c062d9d6d39908e41bc0592d90d0699fe7fefc94 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Latour Date: Fri, 11 Apr 2014 21:45:39 -0700 Subject: [PATCH] Use internal functions for date formatting in WebDAV --- CGDWebServer/GCDWebServer.h | 4 +++ CGDWebServer/GCDWebServer.m | 35 ++++++++++++++++++++++++--- CGDWebServer/GCDWebServerConnection.m | 4 +-- CGDWebServer/GCDWebServerPrivate.h | 2 -- CGDWebServer/GCDWebServerRequest.m | 2 +- GCDWebDAVServer/GCDWebDAVServer.m | 16 ++++-------- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/CGDWebServer/GCDWebServer.h b/CGDWebServer/GCDWebServer.h index 657c06a0..372e54d8 100644 --- a/CGDWebServer/GCDWebServer.h +++ b/CGDWebServer/GCDWebServer.h @@ -51,6 +51,10 @@ NSString* GCDWebServerEscapeURLString(NSString* string); NSString* GCDWebServerUnescapeURLString(NSString* string); NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form); NSString* GCDWebServerGetPrimaryIPv4Address(); // Returns IPv4 address of primary connected service on OS X or of WiFi interface on iOS if connected +NSString* GCDWebServerFormatRFC822(NSDate* date); +NSDate* GCDWebServerParseRFC822(NSString* string); +NSString* GCDWebServerFormatISO8601(NSDate* date); +NSDate* GCDWebServerParseISO8601(NSString* string); #ifdef __cplusplus } diff --git a/CGDWebServer/GCDWebServer.m b/CGDWebServer/GCDWebServer.m index 4e53eaf1..c156c777 100644 --- a/CGDWebServer/GCDWebServer.m +++ b/CGDWebServer/GCDWebServer.m @@ -75,6 +75,7 @@ @interface GCDWebServerHandler () { #endif static NSDateFormatter* _dateFormatterRFC822 = nil; +static NSDateFormatter* _dateFormatterISO8601 = nil; static dispatch_queue_t _dateFormatterQueue = NULL; #if !TARGET_OS_IPHONE static BOOL _run; @@ -139,18 +140,34 @@ NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) { return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding); } -NSString* GCDWebServerFormatHTTPDate(NSDate* date) { +NSString* GCDWebServerFormatRFC822(NSDate* date) { __block NSString* string; dispatch_sync(_dateFormatterQueue, ^{ - string = [_dateFormatterRFC822 stringFromDate:date]; // HTTP/1.1 server must use RFC822 + string = [_dateFormatterRFC822 stringFromDate:date]; }); return string; } -NSDate* GCDWebServerParseHTTPDate(NSString* string) { +NSDate* GCDWebServerParseRFC822(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) + date = [_dateFormatterRFC822 dateFromString:string]; + }); + return date; +} + +NSString* GCDWebServerFormatISO8601(NSDate* date) { + __block NSString* string; + dispatch_sync(_dateFormatterQueue, ^{ + string = [_dateFormatterISO8601 stringFromDate:date]; + }); + return string; +} + +NSDate* GCDWebServerParseISO8601(NSString* string) { + __block NSDate* date; + dispatch_sync(_dateFormatterQueue, ^{ + date = [_dateFormatterISO8601 dateFromString:string]; }); return date; } @@ -324,6 +341,8 @@ + (void)load { #endif +// HTTP/1.1 server must use RFC822 +// TODO: Handle RFC 850 and ANSI C's asctime() format (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3) + (void)initialize { if (_dateFormatterRFC822 == nil) { DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread @@ -333,6 +352,14 @@ + (void)initialize { _dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); DCHECK(_dateFormatterRFC822); } + if (_dateFormatterISO8601 == nil) { + DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread + _dateFormatterISO8601 = [[NSDateFormatter alloc] init]; + _dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + _dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'"; + _dateFormatterISO8601.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); + DCHECK(_dateFormatterISO8601); + } if (_dateFormatterQueue == NULL) { _dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); DCHECK(_dateFormatterQueue); diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index d12603ca..2cc6e4be 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -435,7 +435,7 @@ - (void)_initializeResponseHeadersWithStatusCode:(NSInteger)statusCode { _responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close")); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)[[_server class] serverName]); - CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate([NSDate date])); + CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822([NSDate date])); } // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html @@ -463,7 +463,7 @@ - (void)_processRequest { if (_response) { [self _initializeResponseHeadersWithStatusCode:_response.statusCode]; if (_response.lastModifiedDate) { - CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate(_response.lastModifiedDate)); + CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822(_response.lastModifiedDate)); } if (_response.eTag) { CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (ARC_BRIDGE CFStringRef)_response.eTag); diff --git a/CGDWebServer/GCDWebServerPrivate.h b/CGDWebServer/GCDWebServerPrivate.h index b2238eff..88efee6a 100644 --- a/CGDWebServer/GCDWebServerPrivate.h +++ b/CGDWebServer/GCDWebServerPrivate.h @@ -116,8 +116,6 @@ extern NSString* GCDWebServerNormalizeHeaderValue(NSString* value); extern NSString* GCDWebServerTruncateHeaderValue(NSString* value); extern NSString* GCDWebServerExtractHeaderValueParameter(NSString* header, NSString* attribute); extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset); -extern NSString* GCDWebServerFormatHTTPDate(NSDate* date); -extern NSDate* GCDWebServerParseHTTPDate(NSString* string); extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType); @interface GCDWebServerConnection () diff --git a/CGDWebServer/GCDWebServerRequest.m b/CGDWebServer/GCDWebServerRequest.m index 9f454b7f..ac2d988e 100644 --- a/CGDWebServer/GCDWebServerRequest.m +++ b/CGDWebServer/GCDWebServerRequest.m @@ -199,7 +199,7 @@ - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDict NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"]; if (modifiedHeader) { - _modifiedSince = [GCDWebServerParseHTTPDate(modifiedHeader) copy]; + _modifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy]; } _noneMatch = ARC_RETAIN([_headers objectForKey:@"If-None-Match"]); diff --git a/GCDWebDAVServer/GCDWebDAVServer.m b/GCDWebDAVServer/GCDWebDAVServer.m index 241c7ea9..a9af8ad4 100644 --- a/GCDWebDAVServer/GCDWebDAVServer.m +++ b/GCDWebDAVServer/GCDWebDAVServer.m @@ -335,19 +335,11 @@ - (void)_addPropertyResponseForItem:(NSString*)itemPath resource:(NSString*)reso } if ((properties & kDAVProperty_CreationDate) && [attributes objectForKey:NSFileCreationDate]) { - NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; - formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; - formatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; - formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'"; - [xmlString appendFormat:@"%@", [formatter stringFromDate:[attributes fileCreationDate]]]; + [xmlString appendFormat:@"%@", GCDWebServerFormatISO8601([attributes fileCreationDate])]; } - if ((properties & kDAVProperty_LastModified) && [attributes objectForKey:NSFileModificationDate]) { - NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; - formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; - formatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; - formatter.dateFormat = @"EEE', 'd' 'MMM' 'yyyy' 'HH:mm:ss' GMT'"; - [xmlString appendFormat:@"%@", [formatter stringFromDate:[attributes fileModificationDate]]]; + if ((properties & kDAVProperty_LastModified) && isFile && [attributes objectForKey:NSFileModificationDate]) { // Last modification date is not useful for directories as it changes implicitely and 'Last-Modified' header is not provided for directories anyway + [xmlString appendFormat:@"%@", GCDWebServerFormatRFC822([attributes fileModificationDate])]; } if ((properties & kDAVProperty_ContentLength) && !isDirectory && [attributes objectForKey:NSFileSize]) { @@ -360,6 +352,8 @@ - (void)_addPropertyResponseForItem:(NSString*)itemPath resource:(NSString*)reso [xmlString appendString:@"\n"]; } CFRelease(escapedPath); + } else { + [self logError:@"Failed escaping path: %@", itemPath]; } }