Răsfoiți Sursa

Use internal functions for date formatting in WebDAV

Pierre-Olivier Latour 11 ani în urmă
părinte
comite
c062d9d6d3

+ 4 - 0
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
 }

+ 31 - 4
CGDWebServer/GCDWebServer.m

@@ -75,6 +75,7 @@ GCDWebServerLogLevel GCDLogLevel = kGCDWebServerLogLevel_Debug;
 #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 @@ static void _SignalHandler(int signal) {
 
 #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 @@ static void _SignalHandler(int signal) {
     _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);

+ 2 - 2
CGDWebServer/GCDWebServerConnection.m

@@ -435,7 +435,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]);
-  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 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
   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);

+ 0 - 2
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 ()

+ 1 - 1
CGDWebServer/GCDWebServerRequest.m

@@ -199,7 +199,7 @@
     
     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"]);
     

+ 5 - 11
GCDWebDAVServer/GCDWebDAVServer.m

@@ -335,19 +335,11 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
       }
       
       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:@"<D:creationdate>%@</D:creationdate>", [formatter stringFromDate:[attributes fileCreationDate]]];
+        [xmlString appendFormat:@"<D:creationdate>%@</D:creationdate>", 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:@"<D:getlastmodified>%@</D:getlastmodified>", [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:@"<D:getlastmodified>%@</D:getlastmodified>", GCDWebServerFormatRFC822([attributes fileModificationDate])];
       }
       
       if ((properties & kDAVProperty_ContentLength) && !isDirectory && [attributes objectForKey:NSFileSize]) {
@@ -360,6 +352,8 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
       [xmlString appendString:@"</D:response>\n"];
     }
     CFRelease(escapedPath);
+  } else {
+    [self logError:@"Failed escaping path: %@", itemPath];
   }
 }