From bcd9654330ab5ca98ddccc06827deb57e94665a1 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Latour Date: Thu, 28 Mar 2013 13:09:24 -0700 Subject: [PATCH 1/6] Fixed headers not being parsed properly when not received all at once --- CGDWebServer/GCDWebServerConnection.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index 50759ed8..c88b3f98 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -95,17 +95,22 @@ - (void)_readDataWithCompletionBlock:(ReadDataCompletionBlock)block { - (void)_readHeadersWithCompletionBlock:(ReadHeadersCompletionBlock)block { DCHECK(_requestMessage); - NSMutableData* data = [NSMutableData dataWithCapacity:kHeadersReadBuffer]; [self _readBufferWithLength:SIZE_T_MAX completionBlock:^(dispatch_data_t buffer) { if (buffer) { + NSMutableData* data = [NSMutableData dataWithCapacity:kHeadersReadBuffer]; dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* buffer, size_t size) { [data appendBytes:buffer length:size]; return true; }); NSRange range = [data rangeOfData:_separatorData options:0 range:NSMakeRange(0, data.length)]; if (range.location == NSNotFound) { - [self _readHeadersWithCompletionBlock:block]; + if (CFHTTPMessageAppendBytes(_requestMessage, data.bytes, data.length)) { + [self _readHeadersWithCompletionBlock:block]; + } else { + LOG_ERROR(@"Failed appending request headers data from socket %i", _socket); + block(nil); + } } else { NSUInteger length = range.location + range.length; if (CFHTTPMessageAppendBytes(_requestMessage, data.bytes, length)) { From 20507e9e8591db20b7609cadf7df1efb6470c63c Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Latour Date: Mon, 1 Apr 2013 14:21:58 -0700 Subject: [PATCH 2/6] Small fixes --- CGDWebServer/GCDWebServer.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CGDWebServer/GCDWebServer.m b/CGDWebServer/GCDWebServer.m index 0f81565e..0d734cab 100644 --- a/CGDWebServer/GCDWebServer.m +++ b/CGDWebServer/GCDWebServer.m @@ -202,16 +202,15 @@ - (BOOL)startWithRunloop:(NSRunLoop*)runloop port:(NSUInteger)port bonjourName:( if (CFSocketSetAddress(_socket, (CFDataRef)[NSData dataWithBytes:&addr4 length:sizeof(addr4)]) == kCFSocketSuccess) { CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0); CFRunLoopAddSource([runloop getCFRunLoop], source, kCFRunLoopCommonModes); - if (port == 0) { - // determine the actual port we are listening on + if (port == 0) { // Determine the actual port we are listening on CFDataRef addressData = CFSocketCopyAddress(_socket); struct sockaddr_in* sockaddr = (struct sockaddr_in*)CFDataGetBytePtr(addressData); + DCHECK(sockaddr); _port = ntohs(sockaddr->sin_port); CFRelease(addressData); } else { _port = port; } - CFRelease(source); if (name) { From a557080a07c70499b4d1a539345229b878934b3f Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Latour Date: Mon, 1 Apr 2013 15:42:16 -0700 Subject: [PATCH 3/6] Removed dependency on CFSocket to be 100% GCD based --- CGDWebServer/GCDWebServer.h | 7 +- CGDWebServer/GCDWebServer.m | 160 +++++++++++++++----------- CGDWebServer/GCDWebServerConnection.m | 10 +- CGDWebServer/GCDWebServerPrivate.h | 1 + README.md | 2 +- 5 files changed, 103 insertions(+), 77 deletions(-) diff --git a/CGDWebServer/GCDWebServer.h b/CGDWebServer/GCDWebServer.h index 3f9f0755..8f4b94f3 100644 --- a/CGDWebServer/GCDWebServer.h +++ b/CGDWebServer/GCDWebServer.h @@ -36,8 +36,7 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r NSMutableArray* _handlers; NSUInteger _port; - NSRunLoop* _runLoop; - CFSocketRef _socket; + dispatch_source_t _source; CFNetServiceRef _service; } @property(nonatomic, readonly, getter=isRunning) BOOL running; @@ -45,8 +44,8 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r - (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock; - (void)removeAllHandlers; -- (BOOL)start; // Default is main runloop, 8080 port and computer name -- (BOOL)startWithRunloop:(NSRunLoop*)runloop port:(NSUInteger)port bonjourName:(NSString*)name; // Pass nil name to disable Bonjour or empty string to use computer name +- (BOOL)start; // Default is 8080 port and computer name +- (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name; // Pass nil name to disable Bonjour or empty string to use computer name - (void)stop; @end diff --git a/CGDWebServer/GCDWebServer.m b/CGDWebServer/GCDWebServer.m index 0d734cab..66890e94 100644 --- a/CGDWebServer/GCDWebServer.m +++ b/CGDWebServer/GCDWebServer.m @@ -34,6 +34,8 @@ #import "GCDWebServerPrivate.h" +#define kMaxPendingConnections 16 + static BOOL _run; NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) { @@ -134,7 +136,7 @@ - (id)init { } - (void)dealloc { - if (_runLoop) { + if (_source) { [self stop]; } @@ -144,19 +146,19 @@ - (void)dealloc { } - (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)handlerBlock { - DCHECK(_runLoop == nil); + DCHECK(_source == NULL); GCDWebServerHandler* handler = [[GCDWebServerHandler alloc] initWithMatchBlock:matchBlock processBlock:handlerBlock]; [_handlers insertObject:handler atIndex:0]; [handler release]; } - (void)removeAllHandlers { - DCHECK(_runLoop == nil); + DCHECK(_source == NULL); [_handlers removeAllObjects]; } - (BOOL)start { - return [self startWithRunloop:[NSRunLoop mainRunLoop] port:8080 bonjourName:@""]; + return [self startWithPort:8080 bonjourName:@""]; } static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* error, void* info) { @@ -169,29 +171,13 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er } } -static void _SocketCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void* data, void* info) { - if (type == kCFSocketAcceptCallBack) { - CFSocketNativeHandle handle = *(CFSocketNativeHandle*)data; - int set = 1; - setsockopt(handle, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); // Make sure this socket cannot generate SIG_PIPE - @autoreleasepool { - Class class = [[(GCDWebServer*)info class] connectionClass]; - GCDWebServerConnection* connection = [[class alloc] initWithServer:(GCDWebServer*)info address:(NSData*)address socket:handle]; - [connection release]; // Connection will automatically retain itself while opened - } - } else { - DNOT_REACHED(); - } -} - -- (BOOL)startWithRunloop:(NSRunLoop*)runloop port:(NSUInteger)port bonjourName:(NSString*)name { - DCHECK(runloop); - DCHECK(_runLoop == nil); - CFSocketContext context = {0, self, NULL, NULL, NULL}; - _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, _SocketCallBack, &context); - if (_socket) { +- (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name { + DCHECK(_source == NULL); + int listeningSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listeningSocket > 0) { int yes = 1; - setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(listeningSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(listeningSocket, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)); struct sockaddr_in addr4; bzero(&addr4, sizeof(addr4)); @@ -199,66 +185,104 @@ - (BOOL)startWithRunloop:(NSRunLoop*)runloop port:(NSUInteger)port bonjourName:( addr4.sin_family = AF_INET; addr4.sin_port = htons(port); addr4.sin_addr.s_addr = htonl(INADDR_ANY); - if (CFSocketSetAddress(_socket, (CFDataRef)[NSData dataWithBytes:&addr4 length:sizeof(addr4)]) == kCFSocketSuccess) { - CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0); - CFRunLoopAddSource([runloop getCFRunLoop], source, kCFRunLoopCommonModes); - if (port == 0) { // Determine the actual port we are listening on - CFDataRef addressData = CFSocketCopyAddress(_socket); - struct sockaddr_in* sockaddr = (struct sockaddr_in*)CFDataGetBytePtr(addressData); - DCHECK(sockaddr); - _port = ntohs(sockaddr->sin_port); - CFRelease(addressData); - } else { - _port = port; - } - CFRelease(source); - - if (name) { - _service = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), CFSTR("_http._tcp"), (CFStringRef)name, _port); - if (_service) { - CFNetServiceClientContext context = {0, self, NULL, NULL, NULL}; - CFNetServiceSetClient(_service, _NetServiceClientCallBack, &context); - CFNetServiceScheduleWithRunLoop(_service, [runloop getCFRunLoop], kCFRunLoopCommonModes); - CFStreamError error = {0}; - CFNetServiceRegisterWithOptions(_service, 0, &error); + if (bind(listeningSocket, (void*)&addr4, sizeof(addr4)) == 0) { + if (listen(listeningSocket, kMaxPendingConnections) == 0) { + _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, listeningSocket, 0, kGCDWebServerGCDQueue); + dispatch_source_set_cancel_handler(_source, ^{ + + @autoreleasepool { + int result = close(listeningSocket); + if (result != 0) { + LOG_ERROR(@"Failed closing socket (%i): %s", errno, strerror(errno)); + } else { + LOG_DEBUG(@"Closed listening socket"); + } + } + + }); + dispatch_source_set_event_handler(_source, ^{ + + @autoreleasepool { + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + int socket = accept(listeningSocket, &addr, &addrlen); + if (socket > 0) { + int yes = 1; + setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(yes)); // Make sure this socket cannot generate SIG_PIPE + + NSData* data = [NSData dataWithBytes:&addr length:addrlen]; + Class connectionClass = [[self class] connectionClass]; + GCDWebServerConnection* connection = [[connectionClass alloc] initWithServer:self address:data socket:socket]; + [connection release]; // Connection will automatically retain itself while opened + } else { + LOG_ERROR(@"Failed accepting socket (%i): %s", errno, strerror(errno)); + } + } + + }); + + if (port == 0) { // Determine the actual port we are listening on + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + if (getsockname(listeningSocket, &addr, &addrlen) == 0) { + struct sockaddr_in* sockaddr = (struct sockaddr_in*)&addr; + _port = ntohs(sockaddr->sin_port); + } else { + LOG_ERROR(@"Failed retrieving socket address (%i): %s", errno, strerror(errno)); + } } else { - LOG_ERROR(@"Failed creating CFNetService"); + _port = port; } + + if (name) { + _service = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), CFSTR("_http._tcp"), (CFStringRef)name, _port); + if (_service) { + CFNetServiceClientContext context = {0, self, NULL, NULL, NULL}; + CFNetServiceSetClient(_service, _NetServiceClientCallBack, &context); + CFNetServiceScheduleWithRunLoop(_service, CFRunLoopGetMain(), kCFRunLoopCommonModes); + CFStreamError error = {0}; + CFNetServiceRegisterWithOptions(_service, 0, &error); + } else { + LOG_ERROR(@"Failed creating CFNetService"); + } + } + + dispatch_resume(_source); + LOG_VERBOSE(@"%@ started on port %i", [self class], (int)_port); + } else { + LOG_ERROR(@"Failed listening on socket (%i): %s", errno, strerror(errno)); + close(listeningSocket); } - - _runLoop = [runloop retain]; - LOG_VERBOSE(@"%@ started on port %i", [self class], (int)_port); } else { - LOG_ERROR(@"Failed binding socket"); - CFRelease(_socket); - _socket = NULL; + LOG_ERROR(@"Failed binding socket (%i): %s", errno, strerror(errno)); + close(listeningSocket); } } else { - LOG_ERROR(@"Failed creating CFSocket"); + LOG_ERROR(@"Failed creating socket (%i): %s", errno, strerror(errno)); } - return (_runLoop != nil ? YES : NO); + return (_source ? YES : NO); } - (BOOL)isRunning { - return (_runLoop != nil ? YES : NO); + return (_source ? YES : NO); } - (void)stop { - DCHECK(_runLoop != nil); - if (_socket) { + DCHECK(_source != NULL); + if (_source) { if (_service) { - CFNetServiceUnscheduleFromRunLoop(_service, [_runLoop getCFRunLoop], kCFRunLoopCommonModes); + CFNetServiceUnscheduleFromRunLoop(_service, CFRunLoopGetMain(), kCFRunLoopCommonModes); CFNetServiceSetClient(_service, NULL, NULL); CFRelease(_service); + _service = NULL; } - CFSocketInvalidate(_socket); - CFRelease(_socket); - _socket = NULL; + dispatch_source_cancel(_source); // This will close the socket + dispatch_release(_source); + _source = NULL; + LOG_VERBOSE(@"%@ stopped", [self class]); } - [_runLoop release]; - _runLoop = nil; _port = 0; } @@ -283,9 +307,9 @@ - (BOOL)runWithPort:(NSUInteger)port { _run = YES; void* handler = signal(SIGINT, _SignalHandler); if (handler != SIG_ERR) { - if ([self startWithRunloop:[NSRunLoop currentRunLoop] port:port bonjourName:@""]) { + if ([self startWithPort:port bonjourName:@""]) { while (_run) { - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, true); } [self stop]; success = YES; diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index c88b3f98..e119a058 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -27,7 +27,6 @@ #import "GCDWebServerPrivate.h" -#define kReadWriteQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) #define kHeadersReadBuffer 1024 #define kBodyWriteBufferSize (32 * 1024) @@ -49,7 +48,7 @@ @implementation GCDWebServerConnection (Read) - (void)_readBufferWithLength:(NSUInteger)length completionBlock:(ReadBufferCompletionBlock)block { - dispatch_read(_socket, length, kReadWriteQueue, ^(dispatch_data_t buffer, int error) { + dispatch_read(_socket, length, kGCDWebServerGCDQueue, ^(dispatch_data_t buffer, int error) { @autoreleasepool { if (error == 0) { @@ -173,7 +172,7 @@ @implementation GCDWebServerConnection (Write) - (void)_writeBuffer:(dispatch_data_t)buffer withCompletionBlock:(WriteBufferCompletionBlock)block { size_t size = dispatch_data_get_size(buffer); - dispatch_write(_socket, buffer, kReadWriteQueue, ^(dispatch_data_t data, int error) { + dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t data, int error) { @autoreleasepool { if (error == 0) { @@ -483,7 +482,10 @@ - (GCDWebServerResponse*)processRequest:(GCDWebServerRequest*)request withBlock: } - (void)close { - close(_socket); + int result = close(_socket); + if (result != 0) { + LOG_ERROR(@"Failed closing socket %i for connection (%i): %s", _socket, errno, strerror(errno)); + } LOG_DEBUG(@"Did close connection on socket %i", _socket); } diff --git a/CGDWebServer/GCDWebServerPrivate.h b/CGDWebServer/GCDWebServerPrivate.h index f53ac8b2..fc734039 100644 --- a/CGDWebServer/GCDWebServerPrivate.h +++ b/CGDWebServer/GCDWebServerPrivate.h @@ -79,6 +79,7 @@ static inline void __LogMessage(long level, NSString* format, ...) { #endif #define kGCDWebServerDefaultMimeType @"application/octet-stream" +#define kGCDWebServerGCDQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) #ifdef __cplusplus extern "C" { diff --git a/README.md b/README.md index e7038716..64058009 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ You start by creating an instance of the 'GCDWebServer' class. Note that you can Then you add one or more "handlers" to the server: each handler gets a chance to handle an incoming web request and provide a response. Handlers are called in a LIFO queue, so the latest added handler overrides any previously added ones. -Finally you start the server on a given port. Note that even if built on GCD, GCDWebServer still requires a runloop to be around (by default the main thread runloop is used). This is because there is no CGD API at this point to handle listening sockets, so it must be done using CFSocket which requires a runloop. However, the runloop is only used to accept the connection: immediately afterwards, the connection handling is dispatched to GCD queues. +Finally you start the server on a given port. Understanding GCDWebServer Architecture ======================================= From cbcf661dc20033f27e2234a2b19a4501c045d7e0 Mon Sep 17 00:00:00 2001 From: Thomas Mellenthin Date: Mon, 22 Apr 2013 17:04:41 +0200 Subject: [PATCH 4/6] Shadowing warnings --- CGDWebServer/GCDWebServer.m | 4 ++-- CGDWebServer/GCDWebServerConnection.m | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CGDWebServer/GCDWebServer.m b/CGDWebServer/GCDWebServer.m index 4fa6df83..a249febb 100644 --- a/CGDWebServer/GCDWebServer.m +++ b/CGDWebServer/GCDWebServer.m @@ -195,8 +195,8 @@ - (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name { socklen_t addrlen = sizeof(addr); int socket = accept(listeningSocket, &addr, &addrlen); if (socket > 0) { - int yes = 1; - setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(yes)); // Make sure this socket cannot generate SIG_PIPE + int localYes = 1; + setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &localYes, sizeof(localYes)); // Make sure this socket cannot generate SIG_PIPE NSData* data = [NSData dataWithBytes:&addr length:addrlen]; Class connectionClass = [[self class] connectionClass]; diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index d98fa605..4ac1f92b 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -75,11 +75,11 @@ - (void)_readBufferWithLength:(NSUInteger)length completionBlock:(ReadBufferComp } - (void)_readDataWithCompletionBlock:(ReadDataCompletionBlock)block { - [self _readBufferWithLength:SIZE_T_MAX completionBlock:^(dispatch_data_t buffer) { + [self _readBufferWithLength:SIZE_T_MAX completionBlock:^(dispatch_data_t blockBuffer) { - if (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* buffer, size_t size) { + if (blockBuffer) { + NSMutableData* data = [[NSMutableData alloc] initWithCapacity:dispatch_data_get_size(blockBuffer)]; + dispatch_data_apply(blockBuffer, ^bool(dispatch_data_t region, size_t offset, const void* buffer, size_t size) { [data appendBytes:buffer length:size]; return true; }); @@ -97,8 +97,8 @@ - (void)_readHeadersWithCompletionBlock:(ReadHeadersCompletionBlock)block { if (buffer) { NSMutableData* data = [NSMutableData dataWithCapacity:kHeadersReadBuffer]; - dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* buffer, size_t size) { - [data appendBytes:buffer length:size]; + dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* blockBuffer, size_t size) { + [data appendBytes:blockBuffer length:size]; return true; }); NSRange range = [data rangeOfData:_separatorData options:0 range:NSMakeRange(0, data.length)]; @@ -137,8 +137,8 @@ - (void)_readBodyWithRemainingLength:(NSUInteger)length completionBlock:(ReadBod if (buffer) { NSInteger remainingLength = length - dispatch_data_get_size(buffer); if (remainingLength >= 0) { - bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* buffer, size_t size) { - NSInteger result = [_request write:buffer maxLength:size]; + bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* blockBuffer, size_t size) { + NSInteger result = [_request write:blockBuffer maxLength:size]; if (result != size) { LOG_ERROR(@"Failed writing request body on socket %i (error %i)", _socket, (int)result); return false; From cb326b88979ea4e49ec9ff22f58a92c65d3bd227 Mon Sep 17 00:00:00 2001 From: Thomas Mellenthin Date: Tue, 23 Apr 2013 14:07:29 +0200 Subject: [PATCH 5/6] Plugged memory leaks. --- CGDWebServer/GCDWebServerConnection.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index 4ac1f92b..230d0a79 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -208,7 +208,7 @@ - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block { if (result > 0) { dispatch_data_t wrapper = dispatch_data_create(buffer, result, NULL, DISPATCH_DATA_DESTRUCTOR_FREE); [self _writeBuffer:wrapper withCompletionBlock:^(BOOL success) { - + if (success) { [self _writeBodyWithCompletionBlock:block]; } else { @@ -216,6 +216,7 @@ - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block { } }]; + dispatch_release(wrapper); } else if (result < 0) { LOG_ERROR(@"Failed reading response body on socket %i (error %i)", _socket, (int)result); block(NO); @@ -391,7 +392,7 @@ - (void)_readRequestHeaders { if (_request) { if (_request.hasBody) { if (extraData.length <= _request.contentLength) { - NSString* expectHeader = (__bridge id)CFHTTPMessageCopyHeaderFieldValue(_requestMessage, CFSTR("Expect")); + NSString* expectHeader = (__bridge_transfer NSString*)CFHTTPMessageCopyHeaderFieldValue(_requestMessage, CFSTR("Expect")); if (expectHeader) { if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) { [self _writeData:_continueData withCompletionBlock:^(BOOL success) { From 12350809f0520a785f8cc4fa02012e880c36f1a3 Mon Sep 17 00:00:00 2001 From: Thomas Mellenthin Date: Tue, 30 Apr 2013 15:46:02 +0200 Subject: [PATCH 6/6] Fixed early release of data (ARC). This caused scrambled headers received by the client, because the memory was released and reused, befor the buffer was sent. --- CGDWebServer/GCDWebServerConnection.m | 1 + 1 file changed, 1 insertion(+) diff --git a/CGDWebServer/GCDWebServerConnection.m b/CGDWebServer/GCDWebServerConnection.m index 230d0a79..11ef02fa 100644 --- a/CGDWebServer/GCDWebServerConnection.m +++ b/CGDWebServer/GCDWebServerConnection.m @@ -190,6 +190,7 @@ - (void)_writeBuffer:(dispatch_data_t)buffer withCompletionBlock:(WriteBufferCom - (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)block { dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, dispatch_get_current_queue(), ^{ + [data self]; // keeps ARC from releasing data too early. }); [self _writeBuffer:buffer withCompletionBlock:block]; }