diff --git a/CGDWebServer/GCDWebServer.h b/CGDWebServer/GCDWebServer.h
index 657c06a..372e54d 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 4e53eaf..c156c77 100644
--- a/CGDWebServer/GCDWebServer.m
+++ b/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);
diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m
index d12603c..2cc6e4b 100644
--- a/CGDWebServer/GCDWebServerConnection.m
+++ b/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);
diff --git a/CGDWebServer/GCDWebServerPrivate.h b/CGDWebServer/GCDWebServerPrivate.h
index b2238ef..88efee6 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 9f454b7..ac2d988 100644
--- a/CGDWebServer/GCDWebServerRequest.m
+++ b/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"]);
diff --git a/GCDWebDAVServer/GCDWebDAVServer.m b/GCDWebDAVServer/GCDWebDAVServer.m
index 241c7ea..a9af8ad 100644
--- a/GCDWebDAVServer/GCDWebDAVServer.m
+++ b/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:@"%@", [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 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
[xmlString appendString:@"\n"];
}
CFRelease(escapedPath);
+ } else {
+ [self logError:@"Failed escaping path: %@", itemPath];
}
}