From 6210564bfc174aa809ddfe910e6d27e20cf876a1 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Latour Date: Tue, 8 Apr 2014 23:25:33 -0700 Subject: [PATCH] Added support for "ETag" and "If-None-Match" headers --- CGDWebServer/GCDWebServerConnection.m | 3 +++ CGDWebServer/GCDWebServerFileResponse.m | 1 + CGDWebServer/GCDWebServerRequest.h | 3 ++- CGDWebServer/GCDWebServerRequest.m | 13 ++++++++----- CGDWebServer/GCDWebServerResponse.h | 1 + CGDWebServer/GCDWebServerResponse.m | 4 +++- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index ad7e436..3cfa5bb 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -411,6 +411,9 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) { if (_response.lastModifiedDate) { CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate(_response.lastModifiedDate)); } + if (_response.eTag) { + CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (ARC_BRIDGE CFStringRef)_response.eTag); + } if (_response.cacheControlMaxAge > 0) { CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), (ARC_BRIDGE CFStringRef)[NSString stringWithFormat:@"max-age=%i, public", (int)_response.cacheControlMaxAge]); } else { diff --git a/CGDWebServer/GCDWebServerFileResponse.m b/CGDWebServer/GCDWebServerFileResponse.m index 01943c1..b390b8e 100644 --- a/CGDWebServer/GCDWebServerFileResponse.m +++ b/CGDWebServer/GCDWebServerFileResponse.m @@ -126,6 +126,7 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) { self.contentType = GCDWebServerGetMimeTypeForExtension([path pathExtension]); self.contentLength = (range.location != NSNotFound ? range.length : (NSUInteger)info.st_size); self.lastModifiedDate = _NSDateFromTimeSpec(&info.st_mtimespec); + self.eTag = [NSString stringWithFormat:@"%llu/%li/%li", info.st_ino, info.st_mtimespec.tv_sec, info.st_mtimespec.tv_nsec]; } return self; } diff --git a/CGDWebServer/GCDWebServerRequest.h b/CGDWebServer/GCDWebServerRequest.h index 3f97085..782ab44 100644 --- a/CGDWebServer/GCDWebServerRequest.h +++ b/CGDWebServer/GCDWebServerRequest.h @@ -41,7 +41,8 @@ @property(nonatomic, readonly) NSDictionary* query; // May be nil @property(nonatomic, readonly) NSString* contentType; // Automatically parsed from headers (nil if request has no body or set to "application/octet-stream" if a body is present without a "Content-Type" header) @property(nonatomic, readonly) NSUInteger contentLength; // Automatically parsed from headers (NSNotFound if request has no "Content-Length" header) -@property(nonatomic, readonly) NSDate* ifModifiedSinceDate; // Automatically parsed from headers (nil if request has no "If-Modified-Since" header or it is malformatted) +@property(nonatomic, readonly) NSDate* ifModifiedSince; // Automatically parsed from headers (nil if request has no "If-Modified-Since" header or it is malformatted) +@property(nonatomic, readonly) NSString* ifNoneMatch; // Automatically parsed from headers (nil if request has no "If-None-Match" header) @property(nonatomic, readonly) NSRange byteRange; // Automatically parsed from headers ([NSNotFound, 0] if request has no "Range" header, [offset, length] for byte range from beginning or [NSNotFound, -bytes] from end) @property(nonatomic, readonly) BOOL acceptsGzipContentEncoding; - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query; diff --git a/CGDWebServer/GCDWebServerRequest.m b/CGDWebServer/GCDWebServerRequest.m index e256052..a7477d9 100644 --- a/CGDWebServer/GCDWebServerRequest.m +++ b/CGDWebServer/GCDWebServerRequest.m @@ -145,7 +145,8 @@ NSString* _type; BOOL _chunked; NSUInteger _length; - NSDate* _modifiedSinceDate; + NSDate* _modifiedSince; + NSString* _noneMatch; NSRange _range; BOOL _gzipAccepted; @@ -157,7 +158,7 @@ @implementation GCDWebServerRequest : NSObject -@synthesize method=_method, URL=_url, headers=_headers, path=_path, query=_query, contentType=_type, contentLength=_length, ifModifiedSinceDate=_modifiedSinceDate, +@synthesize method=_method, URL=_url, headers=_headers, path=_path, query=_query, contentType=_type, contentLength=_length, ifModifiedSince=_modifiedSince, ifNoneMatch=_noneMatch, byteRange=_range, acceptsGzipContentEncoding=_gzipAccepted, usesChunkedTransferEncoding=_chunked; - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query { @@ -191,10 +192,11 @@ _length = NSNotFound; } - NSString* ifModifiedSinceHeader = [_headers objectForKey:@"If-Modified-Since"]; - if (ifModifiedSinceHeader) { - _modifiedSinceDate = [GCDWebServerParseHTTPDate(ifModifiedSinceHeader) copy]; + NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"]; + if (modifiedHeader) { + _modifiedSince = [GCDWebServerParseHTTPDate(modifiedHeader) copy]; } + _noneMatch = ARC_RETAIN([_headers objectForKey:@"If-None-Match"]); _range = NSMakeRange(NSNotFound, 0); NSString* rangeHeader = [[_headers objectForKey:@"Range"] lowercaseString]; @@ -243,6 +245,7 @@ ARC_RELEASE(_query); ARC_RELEASE(_type); ARC_RELEASE(_modifiedSinceDate); + ARC_RELEASE(_noneMatch); ARC_RELEASE(_decoders); ARC_DEALLOC(super); diff --git a/CGDWebServer/GCDWebServerResponse.h b/CGDWebServer/GCDWebServerResponse.h index 16a20b3..f0cf708 100644 --- a/CGDWebServer/GCDWebServerResponse.h +++ b/CGDWebServer/GCDWebServerResponse.h @@ -39,6 +39,7 @@ @property(nonatomic) NSInteger statusCode; // Default is 200 @property(nonatomic) NSUInteger cacheControlMaxAge; // Default is 0 seconds i.e. "Cache-Control: no-cache" @property(nonatomic, retain) NSDate* lastModifiedDate; // Default is nil i.e. no "Last-Modified" header +@property(nonatomic, copy) NSString* eTag; // Default is nil i.e. no "ETag" header @property(nonatomic, getter=isGZipContentEncodingEnabled) BOOL gzipContentEncodingEnabled; // Default is disabled + (instancetype)response; - (instancetype)init; diff --git a/CGDWebServer/GCDWebServerResponse.m b/CGDWebServer/GCDWebServerResponse.m index 63c5ee5..26bf207 100644 --- a/CGDWebServer/GCDWebServerResponse.m +++ b/CGDWebServer/GCDWebServerResponse.m @@ -157,6 +157,7 @@ NSInteger _status; NSUInteger _maxAge; NSDate* _lastModified; + NSString* _eTag; NSMutableDictionary* _headers; BOOL _chunked; BOOL _gzipped; @@ -169,7 +170,7 @@ @implementation GCDWebServerResponse -@synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, lastModifiedDate=_lastModified, +@synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, lastModifiedDate=_lastModified, eTag=_eTag, gzipContentEncodingEnabled=_gzipped, additionalHeaders=_headers; + (instancetype)response { @@ -191,6 +192,7 @@ - (void)dealloc { ARC_RELEASE(_type); ARC_RELEASE(_lastModified); + ARC_RELEASE(_eTag); ARC_RELEASE(_headers); ARC_RELEASE(_encoders);