diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index 54c0e8e..ad7e436 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -408,6 +408,9 @@ 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)); + } 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 190b71b..a23f2e4 100644 --- a/CGDWebServer/GCDWebServerFileResponse.m +++ b/CGDWebServer/GCDWebServerFileResponse.m @@ -74,6 +74,10 @@ static inline NSError* _MakePosixError(int code) { return [self initWithFile:path byteRange:range isAttachment:NO]; } +static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) { + return [NSDate dateWithTimeIntervalSince1970:((NSTimeInterval)t->tv_sec + (NSTimeInterval)t->tv_nsec / 1000000000.0)]; +} + - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment { struct stat info; if (lstat([path fileSystemRepresentation], &info) || !(info.st_mode & S_IFREG)) { @@ -121,6 +125,7 @@ static inline NSError* _MakePosixError(int code) { self.contentType = GCDWebServerGetMimeTypeForExtension([path pathExtension]); self.contentLength = (range.location != NSNotFound ? range.length : (NSUInteger)info.st_size); + self.lastModifiedDate = _NSDateFromTimeSpec(&info.st_mtimespec); } return self; } diff --git a/CGDWebServer/GCDWebServerResponse.h b/CGDWebServer/GCDWebServerResponse.h index 1e22ee1..16a20b3 100644 --- a/CGDWebServer/GCDWebServerResponse.h +++ b/CGDWebServer/GCDWebServerResponse.h @@ -37,7 +37,8 @@ @property(nonatomic, copy) NSString* contentType; // Default is nil i.e. no body (must be set if a body is present) @property(nonatomic) NSUInteger contentLength; // Default is NSNotFound i.e. undefined (if a body is present but length is undefined, chunked transfer encoding will be enabled) @property(nonatomic) NSInteger statusCode; // Default is 200 -@property(nonatomic) NSUInteger cacheControlMaxAge; // Default is 0 seconds i.e. "no-cache" +@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, getter=isGZipContentEncodingEnabled) BOOL gzipContentEncodingEnabled; // Default is disabled + (instancetype)response; - (instancetype)init; diff --git a/CGDWebServer/GCDWebServerResponse.m b/CGDWebServer/GCDWebServerResponse.m index 193dce0..30f819c 100644 --- a/CGDWebServer/GCDWebServerResponse.m +++ b/CGDWebServer/GCDWebServerResponse.m @@ -156,6 +156,7 @@ NSUInteger _length; NSInteger _status; NSUInteger _maxAge; + NSDate* _lastModified; NSMutableDictionary* _headers; BOOL _chunked; BOOL _gzipped; @@ -168,7 +169,7 @@ @implementation GCDWebServerResponse -@synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, +@synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, lastModifiedDate=_lastModified, gzipContentEncodingEnabled=_gzipped, additionalHeaders=_headers; + (instancetype)response { @@ -189,6 +190,7 @@ - (void)dealloc { ARC_RELEASE(_type); + ARC_RELEASE(_lastModified); ARC_RELEASE(_headers); ARC_RELEASE(_encoders);