5 Commits
2.5.2 ... 2.5.3

Author SHA1 Message Date
Pierre-Olivier Latour
d1e2a1a12f Bumped version 2014-10-07 13:27:04 -07:00
Pierre-Olivier Latour
54d5abd3a8 Fixed rare race-condition with disconnection timer 2014-10-07 13:26:55 -07:00
Pierre-Olivier Latour
a9fee8d7e2 Fixed rare exception in GCDWebServerParseURLEncodedForm() 2014-10-07 12:16:14 -07:00
Pierre-Olivier Latour
6b15bdaa4e Merge pull request #89 from nickgravelyn/capture-regex-parameters-in-request
Added attributes to GCDWebServerRequest with support to retrieve regex captured variables
2014-09-30 10:52:31 -07:00
Nick Gravelyn
3771cf4e92 Adding an attribute collection to GCDWebServerRequest and adding regular expression captures as an attribute. 2014-09-30 10:45:45 -07:00
6 changed files with 71 additions and 28 deletions

View File

@@ -7,7 +7,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'GCDWebServer' s.name = 'GCDWebServer'
s.version = '2.5.2' s.version = '2.5.3'
s.author = { 'Pierre-Olivier Latour' => 'info@pol-online.net' } s.author = { 'Pierre-Olivier Latour' => 'info@pol-online.net' }
s.license = { :type => 'BSD', :file => 'LICENSE' } s.license = { :type => 'BSD', :file => 'LICENSE' }
s.homepage = 'https://github.com/swisspol/GCDWebServer' s.homepage = 'https://github.com/swisspol/GCDWebServer'

View File

@@ -147,7 +147,6 @@ static void _ExecuteMainThreadRunLoopSources() {
NSMutableArray* _handlers; NSMutableArray* _handlers;
NSInteger _activeConnections; // Accessed through _syncQueue only NSInteger _activeConnections; // Accessed through _syncQueue only
BOOL _connected; // Accessed on main thread only BOOL _connected; // Accessed on main thread only
BOOL _disconnecting; // Accessed on main thread only
CFRunLoopTimerRef _disconnectTimer; // Accessed on main thread only CFRunLoopTimerRef _disconnectTimer; // Accessed on main thread only
NSDictionary* _options; NSDictionary* _options;
@@ -193,23 +192,11 @@ static void _ExecuteMainThreadRunLoopSources() {
GCDWebServerInitializeFunctions(); GCDWebServerInitializeFunctions();
} }
static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
DCHECK([NSThread isMainThread]);
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
@autoreleasepool {
[server _didDisconnect];
}
server->_disconnecting = NO;
}
- (instancetype)init { - (instancetype)init {
if ((self = [super init])) { if ((self = [super init])) {
_syncQueue = dispatch_queue_create([NSStringFromClass([self class]) UTF8String], DISPATCH_QUEUE_SERIAL); _syncQueue = dispatch_queue_create([NSStringFromClass([self class]) UTF8String], DISPATCH_QUEUE_SERIAL);
_sourceSemaphore = dispatch_semaphore_create(0); _sourceSemaphore = dispatch_semaphore_create(0);
_handlers = [[NSMutableArray alloc] init]; _handlers = [[NSMutableArray alloc] init];
CFRunLoopTimerContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
_disconnectTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VAL, HUGE_VAL, 0, 0, _DisconnectTimerCallBack, &context);
CFRunLoopAddTimer(CFRunLoopGetMain(), _disconnectTimer, kCFRunLoopCommonModes);
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
_backgroundTask = UIBackgroundTaskInvalid; _backgroundTask = UIBackgroundTaskInvalid;
#endif #endif
@@ -221,9 +208,8 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
DCHECK(_connected == NO); DCHECK(_connected == NO);
DCHECK(_activeConnections == 0); DCHECK(_activeConnections == 0);
DCHECK(_options == nil); // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source DCHECK(_options == nil); // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
DCHECK(_disconnectTimer == NULL); // The server can never be dealloc'ed while the disconnect timer is pending because of the retain-cycle
CFRunLoopTimerInvalidate(_disconnectTimer);
CFRelease(_disconnectTimer);
ARC_RELEASE(_handlers); ARC_RELEASE(_handlers);
ARC_DISPATCH_RELEASE(_sourceSemaphore); ARC_DISPATCH_RELEASE(_sourceSemaphore);
ARC_DISPATCH_RELEASE(_syncQueue); ARC_DISPATCH_RELEASE(_syncQueue);
@@ -273,9 +259,10 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
DCHECK(_activeConnections >= 0); DCHECK(_activeConnections >= 0);
if (_activeConnections == 0) { if (_activeConnections == 0) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (_disconnecting) { if (_disconnectTimer) {
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL); CFRunLoopTimerInvalidate(_disconnectTimer);
_disconnecting = NO; CFRelease(_disconnectTimer);
_disconnectTimer = NULL;
} }
if (_connected == NO) { if (_connected == NO) {
[self _didConnect]; [self _didConnect];
@@ -329,8 +316,17 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
if (_activeConnections == 0) { if (_activeConnections == 0) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if ((_disconnectDelay > 0.0) && (_source != NULL)) { if ((_disconnectDelay > 0.0) && (_source != NULL)) {
CFRunLoopTimerSetNextFireDate(_disconnectTimer, CFAbsoluteTimeGetCurrent() + _disconnectDelay); if (_disconnectTimer) {
_disconnecting = YES; CFRunLoopTimerInvalidate(_disconnectTimer);
CFRelease(_disconnectTimer);
}
_disconnectTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + _disconnectDelay, 0.0, 0, 0, ^(CFRunLoopTimerRef timer) {
DCHECK([NSThread isMainThread]);
[self _didDisconnect];
CFRelease(_disconnectTimer);
_disconnectTimer = NULL;
});
CFRunLoopAddTimer(CFRunLoopGetMain(), _disconnectTimer, kCFRunLoopCommonModes);
} else { } else {
[self _didDisconnect]; [self _didDisconnect];
} }
@@ -592,9 +588,10 @@ static inline NSString* _EncodeBase64(NSString* string) {
_authenticationDigestAccounts = nil; _authenticationDigestAccounts = nil;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (_disconnecting) { if (_disconnectTimer) {
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL); CFRunLoopTimerInvalidate(_disconnectTimer);
_disconnecting = NO; CFRelease(_disconnectTimer);
_disconnectTimer = NULL;
[self _didDisconnect]; [self _didDisconnect];
} }
}); });
@@ -793,10 +790,23 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![requestMethod isEqualToString:method]) { if (![requestMethod isEqualToString:method]) {
return nil; return nil;
} }
if ([expression firstMatchInString:urlPath options:0 range:NSMakeRange(0, urlPath.length)] == nil) {
NSArray* matches = [expression matchesInString:urlPath options:0 range:NSMakeRange(0, urlPath.length)];
if (matches.count == 0) {
return nil; return nil;
} }
return ARC_AUTORELEASE([[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);
NSMutableArray* captures = [NSMutableArray array];
for (NSTextCheckingResult* result in matches) {
// Start at 1; index 0 is the whole string
for (NSUInteger i = 1; i < result.numberOfRanges; i++) {
[captures addObject:[urlPath substringWithRange:[result rangeAtIndex:i]]];
}
}
GCDWebServerRequest* request = [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
[request setAttribute:captures forKey:GCDWebServerRequestAttribute_RegexCaptures];
return ARC_AUTORELEASE(request);
} processBlock:block]; } processBlock:block];
} else { } else {

View File

@@ -204,10 +204,13 @@ NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
} }
key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "]; key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "];
NSString* unescapedKey = key ? GCDWebServerUnescapeURLString(key) : nil;
value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "]; value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
if (key && value) { NSString* unescapedValue = value ? GCDWebServerUnescapeURLString(value) : nil;
[parameters setObject:GCDWebServerUnescapeURLString(value) forKey:GCDWebServerUnescapeURLString(key)]; if (unescapedKey && unescapedValue) {
[parameters setObject:unescapedValue forKey:unescapedKey];
} else { } else {
LOG_WARNING(@"Failed parsing URL encoded form for key \"%@\" and value \"%@\"", key, value);
DNOT_REACHED(); DNOT_REACHED();
} }

View File

@@ -153,6 +153,7 @@ extern NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) NS_FORMAT_F
- (BOOL)performOpen:(NSError**)error; - (BOOL)performOpen:(NSError**)error;
- (BOOL)performWriteData:(NSData*)data error:(NSError**)error; - (BOOL)performWriteData:(NSData*)data error:(NSError**)error;
- (BOOL)performClose:(NSError**)error; - (BOOL)performClose:(NSError**)error;
- (void)setAttribute:(id)attribute forKey:(NSString*)key;
@end @end
@interface GCDWebServerResponse () @interface GCDWebServerResponse ()

View File

@@ -27,6 +27,15 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
/**
* Attribute key to retrieve an NSArray containing NSStrings from a GCDWebServerRequest
* with the contents of any regular expression captures done on the request path.
*
* @warning This attribute will only be set on the request if adding a handler using
* -addHandlerForMethod:pathRegex:requestClass:processBlock:.
*/
extern NSString* const GCDWebServerRequestAttribute_RegexCaptures;
/** /**
* This protocol is used by the GCDWebServerConnection to communicate with * This protocol is used by the GCDWebServerConnection to communicate with
* the GCDWebServerRequest and write the received HTTP body data. * the GCDWebServerRequest and write the received HTTP body data.
@@ -163,4 +172,11 @@
*/ */
- (BOOL)hasByteRange; - (BOOL)hasByteRange;
/**
* Retrieves an attribute associated with this request using the given key.
*
* @return The attribute value for the key.
*/
- (id)attributeForKey:(NSString*)key;
@end @end

View File

@@ -29,6 +29,8 @@
#import "GCDWebServerPrivate.h" #import "GCDWebServerPrivate.h"
NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerRequestAttribute_RegexCaptures";
#define kZlibErrorDomain @"ZlibErrorDomain" #define kZlibErrorDomain @"ZlibErrorDomain"
#define kGZipInitialBufferSize (256 * 1024) #define kGZipInitialBufferSize (256 * 1024)
@@ -152,6 +154,7 @@
BOOL _opened; BOOL _opened;
NSMutableArray* _decoders; NSMutableArray* _decoders;
NSMutableDictionary* _attributes;
id<GCDWebServerBodyWriter> __unsafe_unretained _writer; id<GCDWebServerBodyWriter> __unsafe_unretained _writer;
} }
@end @end
@@ -238,6 +241,7 @@
} }
_decoders = [[NSMutableArray alloc] init]; _decoders = [[NSMutableArray alloc] init];
_attributes = [[NSMutableDictionary alloc] init];
} }
return self; return self;
} }
@@ -252,6 +256,7 @@
ARC_RELEASE(_modifiedSince); ARC_RELEASE(_modifiedSince);
ARC_RELEASE(_noneMatch); ARC_RELEASE(_noneMatch);
ARC_RELEASE(_decoders); ARC_RELEASE(_decoders);
ARC_RELEASE(_attributes);
ARC_DEALLOC(super); ARC_DEALLOC(super);
} }
@@ -264,6 +269,10 @@
return GCDWebServerIsValidByteRange(_range); return GCDWebServerIsValidByteRange(_range);
} }
- (id)attributeForKey:(NSString*)key {
return [_attributes objectForKey:key];
}
- (BOOL)open:(NSError**)error { - (BOOL)open:(NSError**)error {
return YES; return YES;
} }
@@ -307,6 +316,10 @@
return [_writer close:error]; return [_writer close:error];
} }
- (void)setAttribute:(id)attribute forKey:(NSString*)key {
[_attributes setValue:attribute forKey:key];
}
- (NSString*)description { - (NSString*)description {
NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path]; NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path];
for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) { for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) {