mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-04-24 00:00:04 +08:00
#35 First pass at unit tests
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
xcuserdata
|
xcuserdata
|
||||||
project.xcworkspace
|
project.xcworkspace
|
||||||
|
|
||||||
|
Tests/Payload
|
||||||
|
|||||||
@@ -79,7 +79,9 @@ NSString* GCDWebServerGetPrimaryIPv4Address(); // Returns IPv4 address of prima
|
|||||||
@property(nonatomic, readonly) NSURL* serverURL; // Only non-nil if server is running
|
@property(nonatomic, readonly) NSURL* serverURL; // Only non-nil if server is running
|
||||||
@property(nonatomic, readonly) NSURL* bonjourServerURL; // Only non-nil if server is running and Bonjour registration is active
|
@property(nonatomic, readonly) NSURL* bonjourServerURL; // Only non-nil if server is running and Bonjour registration is active
|
||||||
#if !TARGET_OS_IPHONE
|
#if !TARGET_OS_IPHONE
|
||||||
|
@property(nonatomic, getter=isRecordingEnabled) BOOL recordingEnabled; // Creates files in the current directory containing the raw data for all requests and responses (directory most NOT contain prior recordings)
|
||||||
- (BOOL)runWithPort:(NSUInteger)port; // Starts then automatically stops on SIGINT i.e. Ctrl-C (use on main thread only)
|
- (BOOL)runWithPort:(NSUInteger)port; // Starts then automatically stops on SIGINT i.e. Ctrl-C (use on main thread only)
|
||||||
|
- (NSInteger)runTestsInDirectory:(NSString*)path withPort:(NSUInteger)port; // Returns number of failed tests or -1 if server failed to start
|
||||||
#endif
|
#endif
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
+166
-3
@@ -53,6 +53,9 @@
|
|||||||
NSUInteger _port;
|
NSUInteger _port;
|
||||||
dispatch_source_t _source;
|
dispatch_source_t _source;
|
||||||
CFNetServiceRef _service;
|
CFNetServiceRef _service;
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
BOOL _recording;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -152,9 +155,13 @@ NSDate* GCDWebServerParseHTTPDate(NSString* string) {
|
|||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType) {
|
static inline BOOL _IsTextContentType(NSString* type) {
|
||||||
if ([contentType hasPrefix:@"text/"] || [contentType isEqualToString:@"application/json"] || [contentType isEqualToString:@"application/xml"]) {
|
return ([type hasPrefix:@"text/"] || [type hasPrefix:@"application/json"] || [type hasPrefix:@"application/xml"]);
|
||||||
NSString* charset = GCDWebServerExtractHeaderValueParameter(contentType, @"charset");
|
}
|
||||||
|
|
||||||
|
NSString* GCDWebServerDescribeData(NSData* data, NSString* type) {
|
||||||
|
if (_IsTextContentType(type)) {
|
||||||
|
NSString* charset = GCDWebServerExtractHeaderValueParameter(type, @"charset");
|
||||||
NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
|
NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
|
||||||
if (string) {
|
if (string) {
|
||||||
return ARC_AUTORELEASE(string);
|
return ARC_AUTORELEASE(string);
|
||||||
@@ -529,6 +536,18 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er
|
|||||||
|
|
||||||
@implementation GCDWebServer (Extensions)
|
@implementation GCDWebServer (Extensions)
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
|
||||||
|
- (void)setRecordingEnabled:(BOOL)flag {
|
||||||
|
_recording = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isRecordingEnabled {
|
||||||
|
return _recording;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
- (NSURL*)serverURL {
|
- (NSURL*)serverURL {
|
||||||
if (_source) {
|
if (_source) {
|
||||||
NSString* ipAddress = GCDWebServerGetPrimaryIPv4Address();
|
NSString* ipAddress = GCDWebServerGetPrimaryIPv4Address();
|
||||||
@@ -576,6 +595,150 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CFHTTPMessageRef _CreateHTTPMessageFromFileDump(NSString* path, BOOL isRequest) {
|
||||||
|
NSData* data = [NSData dataWithContentsOfFile:path];
|
||||||
|
if (data) {
|
||||||
|
CFHTTPMessageRef message = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, isRequest);
|
||||||
|
if (CFHTTPMessageAppendBytes(message, data.bytes, data.length)) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
CFRelease(message);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CFHTTPMessageRef _CreateHTTPMessageFromHTTPRequestResponse(CFHTTPMessageRef request) {
|
||||||
|
CFHTTPMessageRef response = NULL;
|
||||||
|
CFReadStreamRef stream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
|
||||||
|
if (CFReadStreamOpen(stream)) {
|
||||||
|
CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||||
|
CFDataSetLength(data, 256 * 1024);
|
||||||
|
CFIndex length = 0;
|
||||||
|
while (1) {
|
||||||
|
CFIndex result = CFReadStreamRead(stream, CFDataGetMutableBytePtr(data) + length, CFDataGetLength(data) - length);
|
||||||
|
if (result <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length += result;
|
||||||
|
if (length >= CFDataGetLength(data)) {
|
||||||
|
CFDataSetLength(data, 2 * CFDataGetLength(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CFReadStreamGetStatus(stream) == kCFStreamStatusAtEnd) {
|
||||||
|
response = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
|
||||||
|
if (response) {
|
||||||
|
CFDataSetLength(data, length);
|
||||||
|
CFHTTPMessageSetBody(response, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(data);
|
||||||
|
CFReadStreamClose(stream);
|
||||||
|
CFRelease(stream);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _LogResult(NSString* format, ...) {
|
||||||
|
va_list arguments;
|
||||||
|
va_start(arguments, format);
|
||||||
|
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
|
||||||
|
va_end(arguments);
|
||||||
|
fprintf(stdout, "%s\n", [message UTF8String]);
|
||||||
|
ARC_RELEASE(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)runTestsInDirectory:(NSString*)path withPort:(NSUInteger)port {
|
||||||
|
NSInteger result = -1;
|
||||||
|
if ([self startWithPort:port bonjourName:nil]) {
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
|
||||||
|
for (NSString* requestFile in files) {
|
||||||
|
if (![requestFile hasSuffix:@".request"]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
@autoreleasepool {
|
||||||
|
NSString* index = [[requestFile componentsSeparatedByString:@"-"] firstObject];
|
||||||
|
BOOL success = NO;
|
||||||
|
CFHTTPMessageRef request = _CreateHTTPMessageFromFileDump([path stringByAppendingPathComponent:requestFile], YES);
|
||||||
|
if (request) {
|
||||||
|
_LogResult(@"[%i] %@ %@", (int)[index integerValue], ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(request)), [ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(request)) path]);
|
||||||
|
NSString* prefix = [index stringByAppendingString:@"-"];
|
||||||
|
for (NSString* responseFile in files) {
|
||||||
|
if ([responseFile hasPrefix:prefix] && [responseFile hasSuffix:@".response"]) {
|
||||||
|
CFHTTPMessageRef expectedResponse = _CreateHTTPMessageFromFileDump([path stringByAppendingPathComponent:responseFile], NO);
|
||||||
|
if (expectedResponse) {
|
||||||
|
CFHTTPMessageRef actualResponse = _CreateHTTPMessageFromHTTPRequestResponse(request);
|
||||||
|
if (actualResponse) {
|
||||||
|
success = YES;
|
||||||
|
|
||||||
|
CFIndex expectedStatusCode = CFHTTPMessageGetResponseStatusCode(expectedResponse);
|
||||||
|
CFIndex actualStatusCode = CFHTTPMessageGetResponseStatusCode(actualResponse);
|
||||||
|
if (actualStatusCode != expectedStatusCode) {
|
||||||
|
_LogResult(@" Status code not matching:\n Expected: %i\n Actual: %i", (int)expectedStatusCode, (int)actualStatusCode);
|
||||||
|
success = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary* expectedHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(expectedResponse));
|
||||||
|
NSDictionary* actualHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(actualResponse));
|
||||||
|
for (NSString* expectedHeader in expectedHeaders) {
|
||||||
|
if ([expectedHeader isEqualToString:@"Date"]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSString* expectedValue = [expectedHeaders objectForKey:expectedHeader];
|
||||||
|
NSString* actualValue = [actualHeaders objectForKey:expectedHeader];
|
||||||
|
if (![actualValue isEqualToString:expectedValue]) {
|
||||||
|
_LogResult(@" Header '%@' not matching:\n Expected: \"%@\"\n Actual: \"%@\"", expectedHeader, expectedValue, actualValue);
|
||||||
|
success = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (NSString* actualHeader in actualHeaders) {
|
||||||
|
if (![expectedHeaders objectForKey:actualHeader]) {
|
||||||
|
_LogResult(@" Header '%@' not matching:\n Expected: \"%@\"\n Actual: \"%@\"", actualHeader, nil, [actualHeaders objectForKey:actualHeader]);
|
||||||
|
success = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData* expectedBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(expectedResponse));
|
||||||
|
NSData* actualBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(actualResponse));
|
||||||
|
if (![actualBody isEqualToData:expectedBody]) {
|
||||||
|
_LogResult(@" Bodies not matching:\n Expected: %lu bytes\n Actual: %lu bytes", (unsigned long)expectedBody.length, (unsigned long)actualBody.length);
|
||||||
|
success = NO;
|
||||||
|
|
||||||
|
if (_IsTextContentType([expectedHeaders objectForKey:@"Content-Type"])) {
|
||||||
|
NSString* expectedPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingPathExtension:@"txt"]];
|
||||||
|
NSString* actualPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingPathExtension:@"txt"]];
|
||||||
|
if ([expectedBody writeToFile:expectedPath atomically:YES] && [actualBody writeToFile:actualPath atomically:YES]) {
|
||||||
|
NSTask* task = [[NSTask alloc] init];
|
||||||
|
[task setLaunchPath:@"/usr/bin/opendiff"];
|
||||||
|
[task setArguments:@[expectedPath, actualPath]];
|
||||||
|
[task launch];
|
||||||
|
ARC_RELEASE(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(actualResponse);
|
||||||
|
}
|
||||||
|
CFRelease(expectedResponse);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(request);
|
||||||
|
}
|
||||||
|
_LogResult(@"");
|
||||||
|
if (!success) {
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self stop];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -25,7 +25,11 @@
|
|||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#import <TargetConditionals.h>
|
||||||
#import <netdb.h>
|
#import <netdb.h>
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
#import <libkern/OSAtomic.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#import "GCDWebServerPrivate.h"
|
#import "GCDWebServerPrivate.h"
|
||||||
|
|
||||||
@@ -45,6 +49,9 @@ static NSData* _CRLFData = nil;
|
|||||||
static NSData* _CRLFCRLFData = nil;
|
static NSData* _CRLFCRLFData = nil;
|
||||||
static NSData* _continueData = nil;
|
static NSData* _continueData = nil;
|
||||||
static NSData* _lastChunkData = nil;
|
static NSData* _lastChunkData = nil;
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
static int32_t _connectionCounter = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
@interface GCDWebServerConnection () {
|
@interface GCDWebServerConnection () {
|
||||||
@private
|
@private
|
||||||
@@ -62,6 +69,14 @@ static NSData* _lastChunkData = nil;
|
|||||||
CFHTTPMessageRef _responseMessage;
|
CFHTTPMessageRef _responseMessage;
|
||||||
GCDWebServerResponse* _response;
|
GCDWebServerResponse* _response;
|
||||||
NSInteger _statusCode;
|
NSInteger _statusCode;
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
NSUInteger _connectionIndex;
|
||||||
|
NSString* _requestPath;
|
||||||
|
int _requestFD;
|
||||||
|
NSString* _responsePath;
|
||||||
|
int _responseFD;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -77,6 +92,18 @@ static NSData* _lastChunkData = nil;
|
|||||||
LOG_DEBUG(@"Connection received %zu bytes on socket %i", size, _socket);
|
LOG_DEBUG(@"Connection received %zu bytes on socket %i", size, _socket);
|
||||||
_bytesRead += size;
|
_bytesRead += size;
|
||||||
[self didUpdateBytesRead];
|
[self didUpdateBytesRead];
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
if (_requestFD > 0) {
|
||||||
|
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||||
|
return (write(_requestFD, chunkBytes, chunkSize) == (ssize_t)chunkSize);
|
||||||
|
});
|
||||||
|
if (!success) {
|
||||||
|
LOG_ERROR(@"Failed recording request data: %s (%i)", strerror(errno), errno);
|
||||||
|
close(_requestFD);
|
||||||
|
_requestFD = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
block(buffer);
|
block(buffer);
|
||||||
} else {
|
} else {
|
||||||
if (_bytesRead > 0) {
|
if (_bytesRead > 0) {
|
||||||
@@ -100,8 +127,8 @@ static NSData* _lastChunkData = nil;
|
|||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
NSMutableData* data = [[NSMutableData alloc] initWithCapacity:dispatch_data_get_size(buffer)];
|
NSMutableData* data = [[NSMutableData alloc] initWithCapacity:dispatch_data_get_size(buffer)];
|
||||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* bufferChunk, size_t size) {
|
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||||
[data appendBytes:bufferChunk length:size];
|
[data appendBytes:chunkBytes length:chunkSize];
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
block(data);
|
block(data);
|
||||||
@@ -119,8 +146,8 @@ static NSData* _lastChunkData = nil;
|
|||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
NSMutableData* data = [NSMutableData dataWithCapacity:kHeadersReadBuffer];
|
NSMutableData* data = [NSMutableData dataWithCapacity:kHeadersReadBuffer];
|
||||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* bufferChunk, size_t size) {
|
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||||
[data appendBytes:bufferChunk length:size];
|
[data appendBytes:chunkBytes length:chunkSize];
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
NSRange range = [data rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(0, data.length)];
|
NSRange range = [data rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(0, data.length)];
|
||||||
@@ -158,7 +185,7 @@ static NSData* _lastChunkData = nil;
|
|||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
if (dispatch_data_get_size(buffer) <= length) {
|
if (dispatch_data_get_size(buffer) <= length) {
|
||||||
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* chunkBytes, size_t chunkSize) {
|
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||||
NSData* data = [NSData dataWithBytesNoCopy:(void*)chunkBytes length:chunkSize freeWhenDone:NO];
|
NSData* data = [NSData dataWithBytesNoCopy:(void*)chunkBytes length:chunkSize freeWhenDone:NO];
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
if (![_request performWriteData:data error:&error]) {
|
if (![_request performWriteData:data error:&error]) {
|
||||||
@@ -245,7 +272,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
[self _readBufferWithLength:SIZE_T_MAX completionBlock:^(dispatch_data_t buffer) {
|
[self _readBufferWithLength:SIZE_T_MAX completionBlock:^(dispatch_data_t buffer) {
|
||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* chunkBytes, size_t chunkSize) {
|
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||||
[chunkData appendBytes:chunkBytes length:chunkSize];
|
[chunkData appendBytes:chunkBytes length:chunkSize];
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -263,6 +290,9 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
|
|
||||||
- (void)_writeBuffer:(dispatch_data_t)buffer withCompletionBlock:(WriteBufferCompletionBlock)block {
|
- (void)_writeBuffer:(dispatch_data_t)buffer withCompletionBlock:(WriteBufferCompletionBlock)block {
|
||||||
size_t size = dispatch_data_get_size(buffer);
|
size_t size = dispatch_data_get_size(buffer);
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
ARC_DISPATCH_RETAIN(buffer);
|
||||||
|
#endif
|
||||||
dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t data, int error) {
|
dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t data, int error) {
|
||||||
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
@@ -271,12 +301,27 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
LOG_DEBUG(@"Connection sent %zu bytes on socket %i", size, _socket);
|
LOG_DEBUG(@"Connection sent %zu bytes on socket %i", size, _socket);
|
||||||
_bytesWritten += size;
|
_bytesWritten += size;
|
||||||
[self didUpdateBytesWritten];
|
[self didUpdateBytesWritten];
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
if (_responseFD > 0) {
|
||||||
|
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||||
|
return (write(_responseFD, chunkBytes, chunkSize) == (ssize_t)chunkSize);
|
||||||
|
});
|
||||||
|
if (!success) {
|
||||||
|
LOG_ERROR(@"Failed recording response data: %s (%i)", strerror(errno), errno);
|
||||||
|
close(_responseFD);
|
||||||
|
_responseFD = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
block(YES);
|
block(YES);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(@"Error while writing to socket %i: %s (%i)", _socket, strerror(error), error);
|
LOG_ERROR(@"Error while writing to socket %i: %s (%i)", _socket, strerror(error), error);
|
||||||
block(NO);
|
block(NO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
ARC_DISPATCH_RELEASE(buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -285,7 +330,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
#if !__has_feature(objc_arc)
|
#if !__has_feature(objc_arc)
|
||||||
[data retain];
|
[data retain];
|
||||||
#endif
|
#endif
|
||||||
dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, dispatch_get_main_queue(), ^{
|
dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, kGCDWebServerGCDQueue, ^{
|
||||||
#if __has_feature(objc_arc)
|
#if __has_feature(objc_arc)
|
||||||
[data self]; // Keeps ARC from releasing data too early
|
[data self]; // Keeps ARC from releasing data too early
|
||||||
#else
|
#else
|
||||||
@@ -655,6 +700,11 @@ static NSString* _StringFromAddressData(NSData* data) {
|
|||||||
}
|
}
|
||||||
ARC_RELEASE(_response);
|
ARC_RELEASE(_response);
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
ARC_RELEASE(_requestPath);
|
||||||
|
ARC_RELEASE(_responsePath);
|
||||||
|
#endif
|
||||||
|
|
||||||
ARC_DEALLOC(super);
|
ARC_DEALLOC(super);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,6 +714,21 @@ static NSString* _StringFromAddressData(NSData* data) {
|
|||||||
|
|
||||||
- (void)open {
|
- (void)open {
|
||||||
LOG_DEBUG(@"Did open connection on socket %i", _socket);
|
LOG_DEBUG(@"Did open connection on socket %i", _socket);
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
if (_server.recordingEnabled) {
|
||||||
|
_connectionIndex = OSAtomicIncrement32(&_connectionCounter);
|
||||||
|
|
||||||
|
_requestPath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
|
||||||
|
_requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY);
|
||||||
|
DCHECK(_requestFD > 0);
|
||||||
|
|
||||||
|
_responsePath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
|
||||||
|
_responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY);
|
||||||
|
DCHECK(_responseFD > 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[self _readRequestHeaders];
|
[self _readRequestHeaders];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,6 +797,38 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET
|
|||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(@"Did close connection on socket %i", _socket);
|
LOG_DEBUG(@"Did close connection on socket %i", _socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !TARGET_OS_IPHONE
|
||||||
|
if (_requestPath) {
|
||||||
|
BOOL success = NO;
|
||||||
|
NSError* error = nil;
|
||||||
|
if (_requestFD > 0) {
|
||||||
|
close(_requestFD);
|
||||||
|
NSString* name = [NSString stringWithFormat:@"%03lu-%@.request", (unsigned long)_connectionIndex, _virtualHEAD ? @"HEAD" : _request.method];
|
||||||
|
success = [[NSFileManager defaultManager] moveItemAtPath:_requestPath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
LOG_ERROR(@"Failed saving recorded request: %@", error);
|
||||||
|
DNOT_REACHED();
|
||||||
|
}
|
||||||
|
unlink([_requestPath fileSystemRepresentation]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_responsePath) {
|
||||||
|
BOOL success = NO;
|
||||||
|
NSError* error = nil;
|
||||||
|
if (_responseFD > 0) {
|
||||||
|
close(_responseFD);
|
||||||
|
NSString* name = [NSString stringWithFormat:@"%03lu-%i.response", (unsigned long)_connectionIndex, (int)_statusCode];
|
||||||
|
success = [[NSFileManager defaultManager] moveItemAtPath:_responsePath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
|
||||||
|
}
|
||||||
|
if (!success) {
|
||||||
|
LOG_ERROR(@"Failed saving recorded response: %@", error);
|
||||||
|
DNOT_REACHED();
|
||||||
|
}
|
||||||
|
unlink([_responsePath fileSystemRepresentation]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (_request) {
|
if (_request) {
|
||||||
LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
|
LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -36,8 +36,10 @@
|
|||||||
#define ARC_AUTORELEASE(__OBJECT__) __OBJECT__
|
#define ARC_AUTORELEASE(__OBJECT__) __OBJECT__
|
||||||
#define ARC_DEALLOC(__OBJECT__)
|
#define ARC_DEALLOC(__OBJECT__)
|
||||||
#if (TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_6_0)) || (!TARGET_OS_IPHONE && (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_8))
|
#if (TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_6_0)) || (!TARGET_OS_IPHONE && (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_8))
|
||||||
|
#define ARC_DISPATCH_RETAIN(__OBJECT__)
|
||||||
#define ARC_DISPATCH_RELEASE(__OBJECT__)
|
#define ARC_DISPATCH_RELEASE(__OBJECT__)
|
||||||
#else
|
#else
|
||||||
|
#define ARC_DISPATCH_RETAIN(__OBJECT__) dispatch_retain(__OBJECT__)
|
||||||
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
|
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
@@ -47,6 +49,7 @@
|
|||||||
#define ARC_RELEASE(__OBJECT__) [__OBJECT__ release]
|
#define ARC_RELEASE(__OBJECT__) [__OBJECT__ release]
|
||||||
#define ARC_AUTORELEASE(__OBJECT__) [__OBJECT__ autorelease]
|
#define ARC_AUTORELEASE(__OBJECT__) [__OBJECT__ autorelease]
|
||||||
#define ARC_DEALLOC(__OBJECT__) [__OBJECT__ dealloc]
|
#define ARC_DEALLOC(__OBJECT__) [__OBJECT__ dealloc]
|
||||||
|
#define ARC_DISPATCH_RETAIN(__OBJECT__) dispatch_retain(__OBJECT__)
|
||||||
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
|
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+91
-13
@@ -25,6 +25,8 @@
|
|||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#import <libgen.h>
|
||||||
|
|
||||||
#import "GCDWebServer.h"
|
#import "GCDWebServer.h"
|
||||||
|
|
||||||
#import "GCDWebServerDataRequest.h"
|
#import "GCDWebServerDataRequest.h"
|
||||||
@@ -37,22 +39,71 @@
|
|||||||
|
|
||||||
#import "GCDWebUploader.h"
|
#import "GCDWebUploader.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kMode_WebServer = 0,
|
||||||
|
kMode_HTMLPage,
|
||||||
|
kMode_HTMLForm,
|
||||||
|
kMode_WebDAV,
|
||||||
|
kMode_WebUploader,
|
||||||
|
kMode_StreamingResponse
|
||||||
|
} Mode;
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
BOOL success = NO;
|
int result = -1;
|
||||||
int mode = (argc == 2 ? MIN(MAX(atoi(argv[1]), 0), 5) : 0);
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
Mode mode = kMode_WebServer;
|
||||||
|
BOOL recording = NO;
|
||||||
|
NSString* rootDirectory = NSHomeDirectory();
|
||||||
|
NSString* testDirectory = nil;
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
fprintf(stdout, "Usage: %s [-mode webServer | htmlPage | htmlForm | webDAV | webUploader | streamingResponse] [-record] [-root directory] [-tests directory]\n\n", basename((char*)argv[0]));
|
||||||
|
} else {
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (argv[i][0] != '-') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(argv[i], "-mode") && (i + 1 < argc)) {
|
||||||
|
++i;
|
||||||
|
if (!strcmp(argv[i], "webServer")) {
|
||||||
|
mode = kMode_WebServer;
|
||||||
|
} else if (!strcmp(argv[i], "htmlPage")) {
|
||||||
|
mode = kMode_HTMLPage;
|
||||||
|
} else if (!strcmp(argv[i], "htmlForm")) {
|
||||||
|
mode = kMode_HTMLForm;
|
||||||
|
} else if (!strcmp(argv[i], "webDAV")) {
|
||||||
|
mode = kMode_WebDAV;
|
||||||
|
} else if (!strcmp(argv[i], "webUploader")) {
|
||||||
|
mode = kMode_WebUploader;
|
||||||
|
} else if (!strcmp(argv[i], "streamingResponse")) {
|
||||||
|
mode = kMode_StreamingResponse;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(argv[i], "-record")) {
|
||||||
|
recording = YES;
|
||||||
|
} else if (!strcmp(argv[i], "-root") && (i + 1 < argc)) {
|
||||||
|
++i;
|
||||||
|
rootDirectory = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:argv[i] length:strlen(argv[i])] stringByStandardizingPath];
|
||||||
|
} else if (!strcmp(argv[i], "-tests") && (i + 1 < argc)) {
|
||||||
|
++i;
|
||||||
|
testDirectory = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:argv[i] length:strlen(argv[i])] stringByStandardizingPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GCDWebServer* webServer = nil;
|
GCDWebServer* webServer = nil;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
|
||||||
// Simply serve contents of home directory
|
// Simply serve contents of home directory
|
||||||
case 0: {
|
case kMode_WebServer: {
|
||||||
|
fprintf(stdout, "Running in Web Server mode from \"%s\"", [rootDirectory UTF8String]);
|
||||||
webServer = [[GCDWebServer alloc] init];
|
webServer = [[GCDWebServer alloc] init];
|
||||||
[webServer addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:0 allowRangeRequests:YES];
|
[webServer addGETHandlerForBasePath:@"/" directoryPath:rootDirectory indexFilename:nil cacheAge:0 allowRangeRequests:YES];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders a HTML page
|
// Renders a HTML page
|
||||||
case 1: {
|
case kMode_HTMLPage: {
|
||||||
|
fprintf(stdout, "Running in HTML Page mode");
|
||||||
webServer = [[GCDWebServer alloc] init];
|
webServer = [[GCDWebServer alloc] init];
|
||||||
[webServer addDefaultHandlerForMethod:@"GET"
|
[webServer addDefaultHandlerForMethod:@"GET"
|
||||||
requestClass:[GCDWebServerRequest class]
|
requestClass:[GCDWebServerRequest class]
|
||||||
@@ -65,7 +116,8 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implements an HTML form
|
// Implements an HTML form
|
||||||
case 2: {
|
case kMode_HTMLForm: {
|
||||||
|
fprintf(stdout, "Running in HTML Form mode");
|
||||||
webServer = [[GCDWebServer alloc] init];
|
webServer = [[GCDWebServer alloc] init];
|
||||||
[webServer addHandlerForMethod:@"GET"
|
[webServer addHandlerForMethod:@"GET"
|
||||||
path:@"/"
|
path:@"/"
|
||||||
@@ -96,17 +148,23 @@ int main(int argc, const char* argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3: {
|
// Serve home directory through WebDAV
|
||||||
webServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:[[NSFileManager defaultManager] currentDirectoryPath]];
|
case kMode_WebDAV: {
|
||||||
|
fprintf(stdout, "Running in WebDAV mode from \"%s\"", [rootDirectory UTF8String]);
|
||||||
|
webServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:rootDirectory];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 4: {
|
// Serve home directory through web uploader
|
||||||
webServer = [[GCDWebUploader alloc] initWithUploadDirectory:[[NSFileManager defaultManager] currentDirectoryPath]];
|
case kMode_WebUploader: {
|
||||||
|
fprintf(stdout, "Running in Web Uploader mode from \"%s\"", [rootDirectory UTF8String]);
|
||||||
|
webServer = [[GCDWebUploader alloc] initWithUploadDirectory:rootDirectory];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5: {
|
// Test streaming responses
|
||||||
|
case kMode_StreamingResponse: {
|
||||||
|
fprintf(stdout, "Running in Streaming Response mode");
|
||||||
webServer = [[GCDWebServer alloc] init];
|
webServer = [[GCDWebServer alloc] init];
|
||||||
[webServer addHandlerForMethod:@"GET"
|
[webServer addHandlerForMethod:@"GET"
|
||||||
path:@"/"
|
path:@"/"
|
||||||
@@ -130,10 +188,30 @@ int main(int argc, const char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
success = [webServer runWithPort:8080];
|
#if __has_feature(objc_arc)
|
||||||
|
fprintf(stdout, " (ARC is ON)\n");
|
||||||
|
#else
|
||||||
|
fprintf(stdout, " (ARC is OFF)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (webServer) {
|
||||||
|
if (testDirectory) {
|
||||||
|
fprintf(stdout, "<RUNNING TESTS FROM \"%s\">\n\n", [testDirectory UTF8String]);
|
||||||
|
result = (int)[webServer runTestsInDirectory:testDirectory withPort:8080];
|
||||||
|
} else {
|
||||||
|
if (recording) {
|
||||||
|
fprintf(stdout, "<RECORDING ENABLED>\n");
|
||||||
|
webServer.recordingEnabled = YES;
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
if ([webServer runWithPort:8080]) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
#if !__has_feature(objc_arc)
|
#if !__has_feature(objc_arc)
|
||||||
[webServer release];
|
[webServer release];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return success ? 0 : -1;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh -ex
|
||||||
|
|
||||||
|
TARGET="GCDWebServer (Mac)"
|
||||||
|
CONFIGURATION="Release"
|
||||||
|
PAYLOAD_ZIP="Tests/Payload.zip"
|
||||||
|
PAYLOAD_DIR="/tmp/payload"
|
||||||
|
|
||||||
|
MRC_BUILD_DIR="/tmp/GCDWebServer-MRC"
|
||||||
|
MRC_PRODUCT="$MRC_BUILD_DIR/$CONFIGURATION/GCDWebServer"
|
||||||
|
ARC_BUILD_DIR="/tmp/GCDWebServer-ARC"
|
||||||
|
ARC_PRODUCT="$ARC_BUILD_DIR/$CONFIGURATION/GCDWebServer"
|
||||||
|
|
||||||
|
function runTests {
|
||||||
|
rm -rf "$PAYLOAD_DIR"
|
||||||
|
ditto -x -k "$PAYLOAD_ZIP" "$PAYLOAD_DIR"
|
||||||
|
logLevel=2 $1 -root "$PAYLOAD_DIR" -tests "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build in manual memory management mode
|
||||||
|
rm -rf "MRC_BUILD_DIR"
|
||||||
|
xcodebuild -target "$TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$MRC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=NO" > /dev/null
|
||||||
|
|
||||||
|
# Build in ARC mode
|
||||||
|
rm -rf "ARC_BUILD_DIR"
|
||||||
|
xcodebuild -target "$TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$ARC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=YES" > /dev/null
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
runTests $MRC_PRODUCT "WebServer"
|
||||||
|
runTests $ARC_PRODUCT "WebServer"
|
||||||
|
|
||||||
|
# Done
|
||||||
|
echo "\nAll tests completed successfully!"
|
||||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
|||||||
|
HTTP/1.1 200 OK
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Content-Length: 221
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:22 GMT
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html><head><meta charset="utf-8"></head><body>
|
||||||
|
<ul>
|
||||||
|
<li><a href="Copy.txt">Copy.txt</a></li>
|
||||||
|
<li><a href="images/">images/</a></li>
|
||||||
|
<li><a href="PDF%20Reports/">PDF Reports/</a></li>
|
||||||
|
</ul>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
GET / HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
HTTP/1.1 200 OK
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Content-Type: text/plain
|
||||||
|
Last-Modified: Thu, 10 Apr 2014 11:10:14 GMT
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:24 GMT
|
||||||
|
Accept-Ranges: bytes
|
||||||
|
Content-Length: 271
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Etag: 73212403/1397128214/0
|
||||||
|
|
||||||
|
For the colorful.
|
||||||
|
|
||||||
|
Color is more than just a hue. It expresses a feeling. Makes a statement. Declares an allegiance. Color reveals your personality. iPhone 5c, in five anything-but-shy colors, does just that. It’s not just for lovers of color. It’s for the colorful.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
GET /Copy.txt HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
HTTP/1.1 200 OK
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Content-Length: 218
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:27 GMT
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html><head><meta charset="utf-8"></head><body>
|
||||||
|
<ul>
|
||||||
|
<li><a href="capable_green_ipad_l.png">capable_green_ipad_l.png</a></li>
|
||||||
|
<li><a href="hero_mba_11.jpg">hero_mba_11.jpg</a></li>
|
||||||
|
</ul>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
GET /images/ HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
|||||||
|
GET /images/capable_green_ipad_l.png HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/images/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
|||||||
|
GET /images/hero_mba_11.jpg HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/images/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
HTTP/1.1 304 Not Modified
|
||||||
|
Last-Modified: Thu, 10 Apr 2014 21:46:56 GMT
|
||||||
|
Etag: 73209474/1397166416/0
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:34 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
GET /images/capable_green_ipad_l.png HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/images/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
If-None-Match: 73209474/1397166416/0
|
||||||
|
If-Modified-Since: Thu, 10 Apr 2014 21:46:56 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
HTTP/1.1 304 Not Modified
|
||||||
|
Last-Modified: Thu, 10 Apr 2014 21:51:14 GMT
|
||||||
|
Etag: 73212154/1397166674/0
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:37 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
GET /images/hero_mba_11.jpg HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/images/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
If-None-Match: 73212154/1397166674/0
|
||||||
|
If-Modified-Since: Thu, 10 Apr 2014 21:51:14 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
HTTP/1.1 200 OK
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Content-Length: 199
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:40 GMT
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html><head><meta charset="utf-8"></head><body>
|
||||||
|
<ul>
|
||||||
|
<li><a href="Apple%20Economic%20Impact%20on%20Cupertino.pdf">Apple Economic Impact on Cupertino.pdf</a></li>
|
||||||
|
</ul>
|
||||||
|
</body></html>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
GET /PDF%20Reports/ HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
|||||||
|
GET /PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/PDF%20Reports/
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
HTTP/1.1 304 Not Modified
|
||||||
|
Last-Modified: Wed, 01 May 2013 12:01:13 GMT
|
||||||
|
Etag: 73212107/1367409673/0
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:42 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
GET /PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
Accept: */*
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
Range: bytes=0-32767
|
||||||
|
If-None-Match: 73212107/1367409673/0
|
||||||
|
If-Modified-Since: Wed, 01 May 2013 12:01:13 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
HTTP/1.1 304 Not Modified
|
||||||
|
Last-Modified: Wed, 01 May 2013 12:01:13 GMT
|
||||||
|
Etag: 73212107/1367409673/0
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:42:42 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
GET /PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf HTTP/1.1
|
||||||
|
Host: localhost:8080
|
||||||
|
Connection: keep-alive
|
||||||
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36
|
||||||
|
Accept: */*
|
||||||
|
DNT: 1
|
||||||
|
Referer: http://localhost:8080/PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf
|
||||||
|
Accept-Encoding: gzip,deflate,sdch
|
||||||
|
Accept-Language: en-US,en;q=0.8,fr;q=0.6
|
||||||
|
Range: bytes=32768-181951
|
||||||
|
If-None-Match: 73212107/1367409673/0
|
||||||
|
If-Modified-Since: Wed, 01 May 2013 12:01:13 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
HTTP/1.1 200 OK
|
||||||
|
Cache-Control: no-cache
|
||||||
|
Content-Length: 221
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Connection: Close
|
||||||
|
Server: GCDWebServer
|
||||||
|
Date: Fri, 11 Apr 2014 02:43:00 GMT
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
HEAD / HTTP/1.1
|
||||||
|
User-Agent: curl/7.30.0
|
||||||
|
Host: localhost:8080
|
||||||
|
Accept: */*
|
||||||
|
|
||||||
Reference in New Issue
Block a user