Use internal functions for date formatting in WebDAV

This commit is contained in:
Pierre-Olivier Latour
2014-04-11 21:45:39 -07:00
parent bb32a721b6
commit c062d9d6d3
6 changed files with 43 additions and 20 deletions
+4
View File
@@ -51,6 +51,10 @@ NSString* GCDWebServerEscapeURLString(NSString* string);
NSString* GCDWebServerUnescapeURLString(NSString* string); NSString* GCDWebServerUnescapeURLString(NSString* string);
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form); 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* 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 #ifdef __cplusplus
} }
+31 -4
View File
@@ -75,6 +75,7 @@ GCDWebServerLogLevel GCDLogLevel = kGCDWebServerLogLevel_Debug;
#endif #endif
static NSDateFormatter* _dateFormatterRFC822 = nil; static NSDateFormatter* _dateFormatterRFC822 = nil;
static NSDateFormatter* _dateFormatterISO8601 = nil;
static dispatch_queue_t _dateFormatterQueue = NULL; static dispatch_queue_t _dateFormatterQueue = NULL;
#if !TARGET_OS_IPHONE #if !TARGET_OS_IPHONE
static BOOL _run; static BOOL _run;
@@ -139,18 +140,34 @@ NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) {
return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding); return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding);
} }
NSString* GCDWebServerFormatHTTPDate(NSDate* date) { NSString* GCDWebServerFormatRFC822(NSDate* date) {
__block NSString* string; __block NSString* string;
dispatch_sync(_dateFormatterQueue, ^{ dispatch_sync(_dateFormatterQueue, ^{
string = [_dateFormatterRFC822 stringFromDate:date]; // HTTP/1.1 server must use RFC822 string = [_dateFormatterRFC822 stringFromDate:date];
}); });
return string; return string;
} }
NSDate* GCDWebServerParseHTTPDate(NSString* string) { NSDate* GCDWebServerParseRFC822(NSString* string) {
__block NSDate* date; __block NSDate* date;
dispatch_sync(_dateFormatterQueue, ^{ 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; return date;
} }
@@ -324,6 +341,8 @@ static void _SignalHandler(int signal) {
#endif #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 { + (void)initialize {
if (_dateFormatterRFC822 == nil) { if (_dateFormatterRFC822 == nil) {
DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread 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"]); _dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
DCHECK(_dateFormatterRFC822); 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) { if (_dateFormatterQueue == NULL) {
_dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); _dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
DCHECK(_dateFormatterQueue); DCHECK(_dateFormatterQueue);
+2 -2
View File
@@ -435,7 +435,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]);
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 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
@@ -463,7 +463,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
if (_response) { if (_response) {
[self _initializeResponseHeadersWithStatusCode:_response.statusCode]; [self _initializeResponseHeadersWithStatusCode:_response.statusCode];
if (_response.lastModifiedDate) { 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) { if (_response.eTag) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (ARC_BRIDGE CFStringRef)_response.eTag); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (ARC_BRIDGE CFStringRef)_response.eTag);
-2
View File
@@ -116,8 +116,6 @@ extern NSString* GCDWebServerNormalizeHeaderValue(NSString* value);
extern NSString* GCDWebServerTruncateHeaderValue(NSString* value); extern NSString* GCDWebServerTruncateHeaderValue(NSString* value);
extern NSString* GCDWebServerExtractHeaderValueParameter(NSString* header, NSString* attribute); extern NSString* GCDWebServerExtractHeaderValueParameter(NSString* header, NSString* attribute);
extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset); extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset);
extern NSString* GCDWebServerFormatHTTPDate(NSDate* date);
extern NSDate* GCDWebServerParseHTTPDate(NSString* string);
extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType); extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType);
@interface GCDWebServerConnection () @interface GCDWebServerConnection ()
+1 -1
View File
@@ -199,7 +199,7 @@
NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"]; NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"];
if (modifiedHeader) { if (modifiedHeader) {
_modifiedSince = [GCDWebServerParseHTTPDate(modifiedHeader) copy]; _modifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy];
} }
_noneMatch = ARC_RETAIN([_headers objectForKey:@"If-None-Match"]); _noneMatch = ARC_RETAIN([_headers objectForKey:@"If-None-Match"]);
+5 -11
View File
@@ -335,19 +335,11 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
} }
if ((properties & kDAVProperty_CreationDate) && [attributes objectForKey:NSFileCreationDate]) { if ((properties & kDAVProperty_CreationDate) && [attributes objectForKey:NSFileCreationDate]) {
NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; [xmlString appendFormat:@"<D:creationdate>%@</D:creationdate>", GCDWebServerFormatISO8601([attributes fileCreationDate])];
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]]];
} }
if ((properties & kDAVProperty_LastModified) && [attributes objectForKey:NSFileModificationDate]) { 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
NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; [xmlString appendFormat:@"<D:getlastmodified>%@</D:getlastmodified>", GCDWebServerFormatRFC822([attributes fileModificationDate])];
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_ContentLength) && !isDirectory && [attributes objectForKey:NSFileSize]) { 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"]; [xmlString appendString:@"</D:response>\n"];
} }
CFRelease(escapedPath); CFRelease(escapedPath);
} else {
[self logError:@"Failed escaping path: %@", itemPath];
} }
} }