浏览代码

Added support for "ETag" and "If-None-Match" headers

Pierre-Olivier Latour 11 年之前
父节点
当前提交
6210564bfc

+ 3 - 0
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 {

+ 1 - 0
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;
 }

+ 2 - 1
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;

+ 8 - 5
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);

+ 1 - 0
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;

+ 3 - 1
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);