Эх сурвалжийг харах

Automatically handle ETag and Last-Modified-Date caching

Pierre-Olivier Latour 11 жил өмнө
parent
commit
bda3d917ca

+ 28 - 4
CGDWebServer/GCDWebServerConnection.m

@@ -392,17 +392,41 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
   CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate([NSDate date]));
   CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate([NSDate date]));
 }
 }
 
 
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
+static inline BOOL _CompareResources(NSString* responseETag, NSString* requestETag, NSDate* responseLastModified, NSDate* requestLastModified) {
+  if ([requestETag isEqualToString:@"*"] && (!responseLastModified || !requestLastModified || ([responseLastModified compare:requestLastModified] != NSOrderedDescending))) {
+    return YES;
+  } else {
+    if ([responseETag isEqualToString:requestETag]) {
+      return YES;
+    }
+    if (responseLastModified && requestLastModified && ([responseLastModified compare:requestLastModified] != NSOrderedDescending)) {
+      return YES;
+    }
+  }
+  return NO;
+}
+
 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
 - (void)_processRequest {
 - (void)_processRequest {
   DCHECK(_responseMessage == NULL);
   DCHECK(_responseMessage == NULL);
   
   
   GCDWebServerResponse* response = [self processRequest:_request withBlock:_handler.processBlock];
   GCDWebServerResponse* response = [self processRequest:_request withBlock:_handler.processBlock];
   if (response) {
   if (response) {
-    NSError* error = nil;
-    if ([response hasBody] && ![response performOpen:&error]) {
-      LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
+    if ((response.statusCode >= 200) && (response.statusCode < 300) && _CompareResources(response.eTag, _request.ifNoneMatch, response.lastModifiedDate, _request.ifModifiedSince)) {
+      NSInteger code = [_request.method isEqualToString:@"HEAD"] || [_request.method isEqualToString:@"GET"] ? kGCDWebServerHTTPStatusCode_NotModified : kGCDWebServerHTTPStatusCode_PreconditionFailed;
+      _response = [[GCDWebServerResponse alloc] initWithStatusCode:code];
+      _response.cacheControlMaxAge = response.cacheControlMaxAge;
+      _response.lastModifiedDate = response.lastModifiedDate;
+      _response.eTag = response.eTag;
+      DCHECK(_response);
     } else {
     } else {
-      _response = ARC_RETAIN(response);
+      NSError* error = nil;
+      if ([response hasBody] && ![response performOpen:&error]) {
+        LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
+      } else {
+        _response = ARC_RETAIN(response);
+      }
     }
     }
   }
   }