Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Commit

Permalink
Added ARC support
Browse files Browse the repository at this point in the history
  • Loading branch information
swisspol committed Jan 9, 2014
1 parent 2e58791 commit 78480e0
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 133 deletions.
57 changes: 33 additions & 24 deletions CGDWebServer/GCDWebServer.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
if (extension.length) {
mimeType = [_overrides objectForKey:extension];
if (mimeType == nil) {
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, NULL);
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (ARC_BRIDGE CFStringRef)extension, NULL);
if (uti) {
mimeType = [(id)UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType) autorelease];
mimeType = ARC_BRIDGE_RELEASE(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
CFRelease(uti);
}
}
Expand All @@ -61,8 +61,8 @@
}

NSString* GCDWebServerUnescapeURLString(NSString* string) {
return [(id)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""),
kCFStringEncodingUTF8) autorelease];
return ARC_BRIDGE_RELEASE(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""),
kCFStringEncodingUTF8));
}

NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
Expand Down Expand Up @@ -90,7 +90,7 @@
}
[scanner setScanLocation:([scanner scanLocation] + 1)];
}
[scanner release];
ARC_RELEASE(scanner);
return parameters;
}

Expand All @@ -105,17 +105,17 @@ @implementation GCDWebServerHandler

- (id)initWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock {
if ((self = [super init])) {
_matchBlock = Block_copy(matchBlock);
_processBlock = Block_copy(processBlock);
_matchBlock = [matchBlock copy];
_processBlock = [processBlock copy];
}
return self;
}

- (void)dealloc {
Block_release(_matchBlock);
Block_release(_processBlock);
ARC_RELEASE(_matchBlock);
ARC_RELEASE(_processBlock);

[super dealloc];
ARC_DEALLOC(super);
}

@end
Expand All @@ -140,16 +140,16 @@ - (void)dealloc {
[self stop];
}

[_handlers release];
ARC_RELEASE(_handlers);

[super dealloc];
ARC_DEALLOC(super);
}

- (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)handlerBlock {
DCHECK(_source == NULL);
GCDWebServerHandler* handler = [[GCDWebServerHandler alloc] initWithMatchBlock:matchBlock processBlock:handlerBlock];
[_handlers insertObject:handler atIndex:0];
[handler release];
ARC_RELEASE(handler);
}

- (void)removeAllHandlers {
Expand Down Expand Up @@ -212,8 +212,12 @@ - (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name {

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
GCDWebServerConnection* connection = [[connectionClass alloc] initWithServer:self address:data socket:socket]; // Connection will automatically retain itself while opened
#if __has_feature(objc_arc)
[connection self]; // Prevent compiler from complaining about unused variable / useless statement
#else
[connection release];
#endif
} else {
LOG_ERROR(@"Failed accepting socket (%i): %s", errno, strerror(errno));
}
Expand All @@ -235,9 +239,9 @@ - (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name {
}

if (name) {
_service = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), CFSTR("_http._tcp"), (CFStringRef)name, _port);
_service = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), CFSTR("_http._tcp"), (ARC_BRIDGE CFStringRef)name, _port);
if (_service) {
CFNetServiceClientContext context = {0, self, NULL, NULL, NULL};
CFNetServiceClientContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
CFNetServiceSetClient(_service, _NetServiceClientCallBack, &context);
CFNetServiceScheduleWithRunLoop(_service, CFRunLoopGetMain(), kCFRunLoopCommonModes);
CFStreamError error = {0};
Expand Down Expand Up @@ -326,7 +330,7 @@ @implementation GCDWebServer (Handlers)
- (void)addDefaultHandlerForMethod:(NSString*)method requestClass:(Class)class processBlock:(GCDWebServerProcessBlock)block {
[self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) {

return [[[class alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery] autorelease];
return ARC_AUTORELEASE([[class alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);

} processBlock:block];
}
Expand Down Expand Up @@ -363,6 +367,11 @@ - (GCDWebServerResponse*)_responseWithContentsOfDirectory:(NSString*)path {

- (void)addHandlerForBasePath:(NSString*)basePath localPath:(NSString*)localPath indexFilename:(NSString*)indexFilename cacheAge:(NSUInteger)cacheAge {
if ([basePath hasPrefix:@"/"] && [basePath hasSuffix:@"/"]) {
#if __has_feature(objc_arc)
__unsafe_unretained GCDWebServer* server = self;
#else
GCDWebServer* server = self;
#endif
[self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) {

if (![requestMethod isEqualToString:@"GET"]) {
Expand All @@ -371,7 +380,7 @@ - (void)addHandlerForBasePath:(NSString*)basePath localPath:(NSString*)localPath
if (![urlPath hasPrefix:basePath]) {
return nil;
}
return [[[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery] autorelease];
return ARC_AUTORELEASE([[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);

} processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

Expand All @@ -383,12 +392,12 @@ - (void)addHandlerForBasePath:(NSString*)basePath localPath:(NSString*)localPath
if (indexFilename) {
NSString* indexPath = [filePath stringByAppendingPathComponent:indexFilename];
if ([[NSFileManager defaultManager] fileExistsAtPath:indexPath isDirectory:&isDirectory] && !isDirectory) {
return [self _responseWithContentsOfFile:indexPath];
return [server _responseWithContentsOfFile:indexPath];
}
}
response = [self _responseWithContentsOfDirectory:filePath];
response = [server _responseWithContentsOfDirectory:filePath];
} else {
response = [self _responseWithContentsOfFile:filePath];
response = [server _responseWithContentsOfFile:filePath];
}
}
if (response) {
Expand All @@ -414,7 +423,7 @@ - (void)addHandlerForMethod:(NSString*)method path:(NSString*)path requestClass:
if ([urlPath caseInsensitiveCompare:path] != NSOrderedSame) {
return nil;
}
return [[[class alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery] autorelease];
return ARC_AUTORELEASE([[class alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);

} processBlock:block];
} else {
Expand All @@ -433,7 +442,7 @@ - (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex request
if ([expression firstMatchInString:urlPath options:0 range:NSMakeRange(0, urlPath.length)] == nil) {
return nil;
}
return [[[class alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery] autorelease];
return ARC_AUTORELEASE([[class alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);

} processBlock:block];
} else {
Expand Down
58 changes: 34 additions & 24 deletions CGDWebServer/GCDWebServerConnection.m
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ - (void)_readDataWithCompletionBlock:(ReadDataCompletionBlock)block {
return true;
});
block(data);
[data release];
ARC_RELEASE(data);
} else {
block(nil);
}
Expand Down Expand Up @@ -190,9 +190,15 @@ - (void)_writeBuffer:(dispatch_data_t)buffer withCompletionBlock:(WriteBufferCom
}

- (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)block {
#if !__has_feature(objc_arc)
[data retain];
#endif
dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, dispatch_get_current_queue(), ^{
#if __has_feature(objc_arc)
[data self]; // Keeps ARC from releasing data too early
#else
[data release];
#endif
});
[self _writeBuffer:buffer withCompletionBlock:block];
dispatch_release(buffer);
Expand All @@ -201,7 +207,7 @@ - (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)b
- (void)_writeHeadersWithCompletionBlock:(WriteHeadersCompletionBlock)block {
DCHECK(_responseMessage);
CFDataRef message = CFHTTPMessageCopySerializedMessage(_responseMessage);
[self _writeData:(NSData*)message withCompletionBlock:block];
[self _writeData:(ARC_BRIDGE NSData*)message withCompletionBlock:block];
CFRelease(message);
}

Expand Down Expand Up @@ -245,15 +251,19 @@ + (void)initialize {
}
if (_continueData == nil) {
CFHTTPMessageRef message = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 100, NULL, kCFHTTPVersion1_1);
#if __has_feature(objc_arc)
_continueData = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(message));
#else
_continueData = (NSData*)CFHTTPMessageCopySerializedMessage(message);
#endif
CFRelease(message);
DCHECK(_continueData);
}
if (_dateFormatter == nil) {
_dateFormatter = [[NSDateFormatter alloc] init];
_dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
_dateFormatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
_dateFormatter.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] autorelease];
_dateFormatter.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
DCHECK(_dateFormatter);
}
if (_formatterQueue == NULL) {
Expand All @@ -265,10 +275,10 @@ + (void)initialize {
- (void)_initializeResponseHeadersWithStatusCode:(NSInteger)statusCode {
_responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (CFStringRef)[[_server class] serverName]);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)[[_server class] serverName]);
dispatch_sync(_formatterQueue, ^{
NSString* date = [_dateFormatter stringFromDate:[NSDate date]];
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (CFStringRef)date);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)date);
});
}

Expand All @@ -288,23 +298,23 @@ - (void)_processRequest {

GCDWebServerResponse* response = [self processRequest:_request withBlock:_handler.processBlock];
if (![response hasBody] || [response open]) {
_response = [response retain];
_response = ARC_RETAIN(response);
}

if (_response) {
[self _initializeResponseHeadersWithStatusCode:_response.statusCode];
NSUInteger maxAge = _response.cacheControlMaxAge;
if (maxAge > 0) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), (CFStringRef)[NSString stringWithFormat:@"max-age=%i, public", (int)maxAge]);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), (ARC_BRIDGE CFStringRef)[NSString stringWithFormat:@"max-age=%i, public", (int)maxAge]);
} else {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), CFSTR("no-cache"));
}
[_response.additionalHeaders enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, (CFStringRef)key, (CFStringRef)obj);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, (ARC_BRIDGE CFStringRef)key, (ARC_BRIDGE CFStringRef)obj);
}];
if ([_response hasBody]) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Type"), (CFStringRef)_response.contentType);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Length"), (CFStringRef)[NSString stringWithFormat:@"%i", (int)_response.contentLength]);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Type"), (ARC_BRIDGE CFStringRef)_response.contentType);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Length"), (ARC_BRIDGE CFStringRef)[NSString stringWithFormat:@"%i", (int)_response.contentLength]);
}
[self _writeHeadersWithCompletionBlock:^(BOOL success) {

Expand Down Expand Up @@ -373,30 +383,30 @@ - (void)_readRequestHeaders {
[self _readHeadersWithCompletionBlock:^(NSData* extraData) {

if (extraData) {
NSString* requestMethod = [[(id)CFHTTPMessageCopyRequestMethod(_requestMessage) autorelease] uppercaseString];
NSString* requestMethod = [ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(_requestMessage)) uppercaseString];
DCHECK(requestMethod);
NSURL* requestURL = [(id)CFHTTPMessageCopyRequestURL(_requestMessage) autorelease];
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(_requestMessage));
DCHECK(requestURL);
NSString* requestPath = GCDWebServerUnescapeURLString([(id)CFURLCopyPath((CFURLRef)requestURL) autorelease]); // Don't use -[NSURL path] which strips the ending slash
NSString* requestPath = GCDWebServerUnescapeURLString(ARC_BRIDGE_RELEASE(CFURLCopyPath((CFURLRef)requestURL))); // Don't use -[NSURL path] which strips the ending slash
DCHECK(requestPath);
NSDictionary* requestQuery = nil;
NSString* queryString = [(id)CFURLCopyQueryString((CFURLRef)requestURL, NULL) autorelease]; // Don't use -[NSURL query] to make sure query is not unescaped;
NSString* queryString = ARC_BRIDGE_RELEASE(CFURLCopyQueryString((CFURLRef)requestURL, NULL)); // Don't use -[NSURL query] to make sure query is not unescaped;
if (queryString.length) {
requestQuery = GCDWebServerParseURLEncodedForm(queryString);
DCHECK(requestQuery);
}
NSDictionary* requestHeaders = [(id)CFHTTPMessageCopyAllHeaderFields(_requestMessage) autorelease];
NSDictionary* requestHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(_requestMessage));
DCHECK(requestHeaders);
for (_handler in _server.handlers) {
_request = [_handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery) retain];
_request = ARC_RETAIN(_handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery));
if (_request) {
break;
}
}
if (_request) {
if (_request.hasBody) {
if (extraData.length <= _request.contentLength) {
NSString* expectHeader = [(id)CFHTTPMessageCopyHeaderFieldValue(_requestMessage, CFSTR("Expect")) autorelease];
NSString* expectHeader = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(_requestMessage, CFSTR("Expect")));
if (expectHeader) {
if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) {
[self _writeData:_continueData withCompletionBlock:^(BOOL success) {
Expand Down Expand Up @@ -432,8 +442,8 @@ - (void)_readRequestHeaders {

- (id)initWithServer:(GCDWebServer*)server address:(NSData*)address socket:(CFSocketNativeHandle)socket {
if ((self = [super init])) {
_server = [server retain];
_address = [address retain];
_server = ARC_RETAIN(server);
_address = ARC_RETAIN(address);
_socket = socket;

[self open];
Expand All @@ -444,20 +454,20 @@ - (id)initWithServer:(GCDWebServer*)server address:(NSData*)address socket:(CFSo
- (void)dealloc {
[self close];

[_server release];
[_address release];
ARC_RELEASE(_server);
ARC_RELEASE(_address);

if (_requestMessage) {
CFRelease(_requestMessage);
}
[_request release];
ARC_RELEASE(_request);

if (_responseMessage) {
CFRelease(_responseMessage);
}
[_response release];
ARC_RELEASE(_response);

[super dealloc];
ARC_DEALLOC(super);
}

@end
Expand Down
18 changes: 17 additions & 1 deletion CGDWebServer/GCDWebServerPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#if __has_feature(objc_arc)
#define ARC_BRIDGE __bridge
#define ARC_BRIDGE_RELEASE(__OBJECT__) CFBridgingRelease(__OBJECT__)
#define ARC_RETAIN(__OBJECT__) __OBJECT__
#define ARC_RELEASE(__OBJECT__)
#define ARC_AUTORELEASE(__OBJECT__) __OBJECT__
#define ARC_DEALLOC(__OBJECT__)
#else
#define ARC_BRIDGE
#define ARC_BRIDGE_RELEASE(__OBJECT__) [(id)__OBJECT__ autorelease]
#define ARC_RETAIN(__OBJECT__) [__OBJECT__ retain]
#define ARC_RELEASE(__OBJECT__) [__OBJECT__ release]
#define ARC_AUTORELEASE(__OBJECT__) [__OBJECT__ autorelease]
#define ARC_DEALLOC(__OBJECT__) [__OBJECT__ dealloc]
#endif

#import "GCDWebServerConnection.h"

#ifdef __GCDWEBSERVER_LOGGING_HEADER__
Expand All @@ -47,7 +63,7 @@ static inline void __LogMessage(long level, NSString* format, ...) {
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
va_end(arguments);
printf("[%s] %s\n", levelNames[level], [message UTF8String]);
[message release];
ARC_RELEASE(message);
}
}

Expand Down
Loading

0 comments on commit 78480e0

Please sign in to comment.