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

View File

@@ -147,7 +147,6 @@ static void _ExecuteMainThreadRunLoopSources() {
NSMutableArray* _handlers;
NSInteger _activeConnections; // Accessed through _syncQueue only
BOOL _connected; // Accessed on main thread only
BOOL _disconnecting; // Accessed on main thread only
CFRunLoopTimerRef _disconnectTimer; // Accessed on main thread only
NSDictionary* _options;
@@ -193,23 +192,11 @@ static void _ExecuteMainThreadRunLoopSources() {
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 {
if ((self = [super init])) {
_syncQueue = dispatch_queue_create([NSStringFromClass([self class]) UTF8String], DISPATCH_QUEUE_SERIAL);
_sourceSemaphore = dispatch_semaphore_create(0);
_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
_backgroundTask = UIBackgroundTaskInvalid;
#endif
@@ -221,9 +208,8 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
DCHECK(_connected == NO);
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(_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_DISPATCH_RELEASE(_sourceSemaphore);
ARC_DISPATCH_RELEASE(_syncQueue);
@@ -273,9 +259,10 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
DCHECK(_activeConnections >= 0);
if (_activeConnections == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
if (_disconnecting) {
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL);
_disconnecting = NO;
if (_disconnectTimer) {
CFRunLoopTimerInvalidate(_disconnectTimer);
CFRelease(_disconnectTimer);
_disconnectTimer = NULL;
}
if (_connected == NO) {
[self _didConnect];
@@ -329,8 +316,17 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
if (_activeConnections == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
if ((_disconnectDelay > 0.0) && (_source != NULL)) {
CFRunLoopTimerSetNextFireDate(_disconnectTimer, CFAbsoluteTimeGetCurrent() + _disconnectDelay);
_disconnecting = YES;
if (_disconnectTimer) {
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 {
[self _didDisconnect];
}
@@ -592,9 +588,10 @@ static inline NSString* _EncodeBase64(NSString* string) {
_authenticationDigestAccounts = nil;
dispatch_async(dispatch_get_main_queue(), ^{
if (_disconnecting) {
CFRunLoopTimerSetNextFireDate(_disconnectTimer, HUGE_VAL);
_disconnecting = NO;
if (_disconnectTimer) {
CFRunLoopTimerInvalidate(_disconnectTimer);
CFRelease(_disconnectTimer);
_disconnectTimer = NULL;
[self _didDisconnect];
}
});
@@ -793,10 +790,23 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![requestMethod isEqualToString:method]) {
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 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];
} else {

View File

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

View File

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

View File

@@ -27,6 +27,15 @@
#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
* the GCDWebServerRequest and write the received HTTP body data.
@@ -163,4 +172,11 @@
*/
- (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

View File

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