mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-02-11 00:00:07 +08:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1e2a1a12f | ||
|
|
54d5abd3a8 | ||
|
|
a9fee8d7e2 | ||
|
|
6b15bdaa4e | ||
|
|
3771cf4e92 | ||
|
|
a5d83abdd0 | ||
|
|
f1e9f1a37c | ||
|
|
00b5ec87ba | ||
|
|
cf94e70a42 | ||
|
|
d47409c776 | ||
|
|
a9db13475b | ||
|
|
17fad0f1b9 | ||
|
|
5493d9e803 | ||
|
|
12b1edb958 | ||
|
|
7544a6dc4e |
@@ -1,19 +1,19 @@
|
||||
# http://guides.cocoapods.org/syntax/podspec.html
|
||||
# Verify Podspec with:
|
||||
# sudo gem update cocoapods
|
||||
# pod spec lint GCDWebServer.podspec --verbose
|
||||
# Add to source line:
|
||||
# :tag => s.version.to_s
|
||||
# http://guides.cocoapods.org/making/getting-setup-with-trunk.html
|
||||
# $ sudo gem update cocoapods
|
||||
# (optional) $ pod trunk register {email} {name} --description={computer}
|
||||
# $ pod trunk push
|
||||
# DELETE THIS SECTION BEFORE PROCEEDING!
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'GCDWebServer'
|
||||
s.version = '2.5'
|
||||
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'
|
||||
s.summary = 'Lightweight GCD based HTTP server for OS X & iOS (includes web based uploader & WebDAV server)'
|
||||
|
||||
s.source = { :git => 'https://github.com/swisspol/GCDWebServer.git' }
|
||||
s.source = { :git => 'https://github.com/swisspol/GCDWebServer.git', :tag => s.version.to_s }
|
||||
s.ios.deployment_target = '5.0'
|
||||
s.osx.deployment_target = '10.7'
|
||||
s.requires_arc = true
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0510;
|
||||
LastUpgradeCheck = 0600;
|
||||
};
|
||||
buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "GCDWebServer" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
@@ -491,7 +491,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD)";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
PRODUCT_NAME = GCDWebServer;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
@@ -501,7 +500,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD)";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
PRODUCT_NAME = GCDWebServer;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
@@ -553,7 +551,6 @@
|
||||
ARCHS = "$(ARCHS_STANDARD)";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
INFOPLIST_FILE = iOS/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
|
||||
PRODUCT_NAME = GCDWebServer;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -567,7 +564,6 @@
|
||||
ARCHS = "$(ARCHS_STANDARD)";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
INFOPLIST_FILE = iOS/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
|
||||
PRODUCT_NAME = GCDWebServer;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -77,16 +77,18 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r
|
||||
extern NSString* const GCDWebServerOption_Port;
|
||||
|
||||
/**
|
||||
* The Bonjour name used by the GCDWebServer (NSString).
|
||||
* The Bonjour name used by the GCDWebServer (NSString). If set to an empty string,
|
||||
* the name will automatically take the value of the GCDWebServerOption_ServerName
|
||||
* option. If this option is set to nil, Bonjour will be disabled.
|
||||
*
|
||||
* The default value is an empty string i.e. use the computer / device name.
|
||||
* The default value is an empty string.
|
||||
*/
|
||||
extern NSString* const GCDWebServerOption_BonjourName;
|
||||
|
||||
/**
|
||||
* The Bonjour service type used by the GCDWebServer (NSString).
|
||||
*
|
||||
* The default value is "_http._tcp", standard HTTP web server.
|
||||
* The default value is "_http._tcp", the service type for HTTP web servers.
|
||||
*/
|
||||
extern NSString* const GCDWebServerOption_BonjourType;
|
||||
|
||||
@@ -336,12 +338,14 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
|
||||
*
|
||||
* @warning This property is only valid if the server is running and Bonjour
|
||||
* registration has successfully completed, which can take up to a few seconds.
|
||||
* Also be aware this property will not automatically update if the Bonjour hostname
|
||||
* has been dynamically changed after the server started running (this should be rare).
|
||||
*/
|
||||
@property(nonatomic, readonly) NSURL* bonjourServerURL;
|
||||
|
||||
/**
|
||||
* Starts the server on port 8080 (OS X & iOS Simulator) or port 80 (iOS)
|
||||
* using the computer / device name for as the Bonjour name.
|
||||
* using the default Bonjour name.
|
||||
*
|
||||
* Returns NO if the server failed to start.
|
||||
*/
|
||||
@@ -350,7 +354,7 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
|
||||
/**
|
||||
* Starts the server on a given port and with a specific Bonjour name.
|
||||
* Pass a nil Bonjour name to disable Bonjour entirely or an empty string to
|
||||
* use the computer / device name.
|
||||
* use the default name.
|
||||
*
|
||||
* Returns NO if the server failed to start.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -160,7 +159,8 @@ static void _ExecuteMainThreadRunLoopSources() {
|
||||
CFTimeInterval _disconnectDelay;
|
||||
NSUInteger _port;
|
||||
dispatch_source_t _source;
|
||||
CFNetServiceRef _service;
|
||||
CFNetServiceRef _registrationService;
|
||||
CFNetServiceRef _resolutionService;
|
||||
#if TARGET_OS_IPHONE
|
||||
BOOL _suspendInBackground;
|
||||
UIBackgroundTaskIdentifier _backgroundTask;
|
||||
@@ -192,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
|
||||
@@ -220,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);
|
||||
@@ -272,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];
|
||||
@@ -328,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];
|
||||
}
|
||||
@@ -339,12 +336,12 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
}
|
||||
|
||||
- (NSString*)bonjourName {
|
||||
CFStringRef name = _service ? CFNetServiceGetName(_service) : NULL;
|
||||
CFStringRef name = _resolutionService ? CFNetServiceGetName(_resolutionService) : NULL;
|
||||
return name && CFStringGetLength(name) ? ARC_BRIDGE_RELEASE(CFStringCreateCopy(kCFAllocatorDefault, name)) : nil;
|
||||
}
|
||||
|
||||
- (NSString*)bonjourType {
|
||||
CFStringRef type = _service ? CFNetServiceGetType(_service) : NULL;
|
||||
CFStringRef type = _resolutionService ? CFNetServiceGetType(_resolutionService) : NULL;
|
||||
return type && CFStringGetLength(type) ? ARC_BRIDGE_RELEASE(CFStringCreateCopy(kCFAllocatorDefault, type)) : nil;
|
||||
}
|
||||
|
||||
@@ -360,11 +357,26 @@ static void _DisconnectTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
[_handlers removeAllObjects];
|
||||
}
|
||||
|
||||
static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* error, void* info) {
|
||||
static void _NetServiceRegisterCallBack(CFNetServiceRef service, CFStreamError* error, void* info) {
|
||||
DCHECK([NSThread isMainThread]);
|
||||
@autoreleasepool {
|
||||
if (error->error) {
|
||||
LOG_ERROR(@"Bonjour error %i (domain %i)", (int)error->error, (int)error->domain);
|
||||
LOG_ERROR(@"Bonjour registration error %i (domain %i)", (int)error->error, (int)error->domain);
|
||||
} else {
|
||||
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
|
||||
LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]);
|
||||
CFNetServiceResolveWithTimeout(server->_resolutionService, 1.0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _NetServiceResolveCallBack(CFNetServiceRef service, CFStreamError* error, void* info) {
|
||||
DCHECK([NSThread isMainThread]);
|
||||
@autoreleasepool {
|
||||
if (error->error) {
|
||||
if ((error->domain != kCFStreamErrorDomainNetServices) && (error->error != kCFNetServicesErrorTimeout)) {
|
||||
LOG_ERROR(@"Bonjour resolution error %i (domain %i)", (int)error->error, (int)error->domain);
|
||||
}
|
||||
} else {
|
||||
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
|
||||
LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL);
|
||||
@@ -392,8 +404,9 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
|
||||
- (BOOL)_start:(NSError**)error {
|
||||
DCHECK(_source == NULL);
|
||||
|
||||
NSUInteger port = [_GetOption(_options, GCDWebServerOption_Port, @0) unsignedIntegerValue];
|
||||
NSString* name = _GetOption(_options, GCDWebServerOption_BonjourName, @"");
|
||||
NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, @"");
|
||||
NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp");
|
||||
NSUInteger maxPendingConnections = [_GetOption(_options, GCDWebServerOption_MaxPendingConnections, @16) unsignedIntegerValue];
|
||||
int listeningSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
@@ -491,14 +504,21 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
_port = port;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
_service = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), (ARC_BRIDGE CFStringRef)bonjourType, (ARC_BRIDGE CFStringRef)name, (SInt32)_port);
|
||||
if (_service) {
|
||||
if (bonjourName) {
|
||||
_registrationService = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), (ARC_BRIDGE CFStringRef)bonjourType, (ARC_BRIDGE CFStringRef)(bonjourName.length ? bonjourName : _serverName), (SInt32)_port);
|
||||
if (_registrationService) {
|
||||
CFNetServiceClientContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
|
||||
CFNetServiceSetClient(_service, _NetServiceClientCallBack, &context);
|
||||
CFNetServiceScheduleWithRunLoop(_service, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
|
||||
CFNetServiceSetClient(_registrationService, _NetServiceRegisterCallBack, &context);
|
||||
CFNetServiceScheduleWithRunLoop(_registrationService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
CFStreamError streamError = {0};
|
||||
CFNetServiceRegisterWithOptions(_service, 0, &streamError);
|
||||
CFNetServiceRegisterWithOptions(_registrationService, 0, &streamError);
|
||||
|
||||
_resolutionService = CFNetServiceCreateCopy(kCFAllocatorDefault, _registrationService);
|
||||
if (_resolutionService) {
|
||||
CFNetServiceSetClient(_resolutionService, _NetServiceResolveCallBack, &context);
|
||||
CFNetServiceScheduleWithRunLoop(_resolutionService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(@"Failed creating CFNetService");
|
||||
}
|
||||
@@ -537,11 +557,19 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
- (void)_stop {
|
||||
DCHECK(_source != NULL);
|
||||
|
||||
if (_service) {
|
||||
CFNetServiceUnscheduleFromRunLoop(_service, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
CFNetServiceSetClient(_service, NULL, NULL);
|
||||
CFRelease(_service);
|
||||
_service = NULL;
|
||||
if (_registrationService) {
|
||||
if (_resolutionService) {
|
||||
CFNetServiceUnscheduleFromRunLoop(_resolutionService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
CFNetServiceSetClient(_resolutionService, NULL, NULL);
|
||||
CFNetServiceCancel(_resolutionService);
|
||||
CFRelease(_resolutionService);
|
||||
_resolutionService = NULL;
|
||||
}
|
||||
CFNetServiceUnscheduleFromRunLoop(_registrationService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
CFNetServiceSetClient(_registrationService, NULL, NULL);
|
||||
CFNetServiceCancel(_registrationService);
|
||||
CFRelease(_registrationService);
|
||||
_registrationService = NULL;
|
||||
}
|
||||
|
||||
dispatch_source_cancel(_source);
|
||||
@@ -560,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];
|
||||
}
|
||||
});
|
||||
@@ -623,7 +652,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
}
|
||||
|
||||
- (BOOL)isRunning {
|
||||
return (_source ? YES : NO);
|
||||
return (_options ? YES : NO);
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
@@ -663,13 +692,14 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
}
|
||||
|
||||
- (NSURL*)bonjourServerURL {
|
||||
if (_source && _service) {
|
||||
CFStringRef name = CFNetServiceGetName(_service);
|
||||
if (name && CFStringGetLength(name)) {
|
||||
if (_source && _resolutionService) {
|
||||
NSString* name = (ARC_BRIDGE NSString*)CFNetServiceGetTargetHost(_resolutionService);
|
||||
if (name.length) {
|
||||
name = [name substringToIndex:(name.length - 1)]; // Strip trailing period at end of domain
|
||||
if (_port != 80) {
|
||||
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@.local:%i/", name, (int)_port]];
|
||||
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%i/", name, (int)_port]];
|
||||
} else {
|
||||
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@.local/", name]];
|
||||
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/", name]];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -760,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 {
|
||||
@@ -849,17 +892,18 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
||||
|
||||
GCDWebServerResponse* response = nil;
|
||||
NSString* filePath = [directoryPath stringByAppendingPathComponent:[request.path substringFromIndex:basePath.length]];
|
||||
BOOL isDirectory;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory]) {
|
||||
if (isDirectory) {
|
||||
NSString* fileType = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] fileType];
|
||||
if (fileType) {
|
||||
if ([fileType isEqualToString:NSFileTypeDirectory]) {
|
||||
if (indexFilename) {
|
||||
NSString* indexPath = [filePath stringByAppendingPathComponent:indexFilename];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:indexPath isDirectory:&isDirectory] && !isDirectory) {
|
||||
NSString* indexType = [[[NSFileManager defaultManager] attributesOfItemAtPath:indexPath error:NULL] fileType];
|
||||
if ([indexType isEqualToString:NSFileTypeRegular]) {
|
||||
return [GCDWebServerFileResponse responseWithFile:indexPath];
|
||||
}
|
||||
}
|
||||
response = [server _responseWithContentsOfDirectory:filePath];
|
||||
} else {
|
||||
} else if ([fileType isEqualToString:NSFileTypeRegular]) {
|
||||
if (allowRangeRequests) {
|
||||
response = [GCDWebServerFileResponse responseWithFile:filePath byteRange:request.byteRange];
|
||||
[response setValue:@"bytes" forAdditionalHeader:@"Accept-Ranges"];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#import <AvailabilityMacros.h>
|
||||
#import <os/object.h>
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
#define ARC_BRIDGE __bridge
|
||||
@@ -35,7 +34,7 @@
|
||||
#define ARC_RELEASE(__OBJECT__)
|
||||
#define ARC_AUTORELEASE(__OBJECT__) __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 OS_OBJECT_USE_OBJC_RETAIN_RELEASE
|
||||
#define ARC_DISPATCH_RETAIN(__OBJECT__)
|
||||
#define ARC_DISPATCH_RELEASE(__OBJECT__)
|
||||
#else
|
||||
@@ -154,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 ()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:)]) {
|
||||
|
||||
@@ -322,6 +322,9 @@
|
||||
NSString* title = server.title;
|
||||
if (title == nil) {
|
||||
title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
||||
if (title == nil) {
|
||||
title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
|
||||
}
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (title == nil) {
|
||||
title = [[NSProcessInfo processInfo] processName];
|
||||
|
||||
24
Run-Tests.sh
24
Run-Tests.sh
@@ -32,19 +32,35 @@ function runTests {
|
||||
logLevel=2 $1 -mode "$2" -root "$PAYLOAD_DIR/Payload" -tests "$3"
|
||||
}
|
||||
|
||||
# Build for iOS in manual memory management mode (TODO: run tests on iOS)
|
||||
# Build for iOS in manual memory management mode and for oldest deployment target (TODO: run tests on iOS)
|
||||
rm -rf "$MRC_BUILD_DIR"
|
||||
xcodebuild -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$MRC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=NO" "IPHONEOS_DEPLOYMENT_TARGET=5.1.1" > /dev/null
|
||||
|
||||
# Build for iOS in manual memory management mode and for default deployment target (TODO: run tests on iOS)
|
||||
rm -rf "$MRC_BUILD_DIR"
|
||||
xcodebuild -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$MRC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=NO" > /dev/null
|
||||
|
||||
# Build for iOS in ARC mode (TODO: run tests on iOS)
|
||||
# Build for iOS in ARC mode and for oldest deployment target (TODO: run tests on iOS)
|
||||
rm -rf "$ARC_BUILD_DIR"
|
||||
xcodebuild -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$ARC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=YES" "IPHONEOS_DEPLOYMENT_TARGET=5.1.1" > /dev/null
|
||||
|
||||
# Build for iOS in ARC mode and for default deployment target (TODO: run tests on iOS)
|
||||
rm -rf "$ARC_BUILD_DIR"
|
||||
xcodebuild -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$ARC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=YES" > /dev/null
|
||||
|
||||
# Build for OS X in manual memory management mode
|
||||
# Build for OS X in manual memory management mode and for oldest deployment target
|
||||
rm -rf "$MRC_BUILD_DIR"
|
||||
xcodebuild -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$MRC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=NO" "MACOSX_DEPLOYMENT_TARGET=10.7" > /dev/null
|
||||
|
||||
# Build for OS X in manual memory management mode and for default deployment target
|
||||
rm -rf "$MRC_BUILD_DIR"
|
||||
xcodebuild -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$MRC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=NO" > /dev/null
|
||||
|
||||
# Build for OS X in ARC mode
|
||||
# Build for OS X in ARC mode and for oldest deployment target
|
||||
rm -rf "$ARC_BUILD_DIR"
|
||||
xcodebuild -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$ARC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=YES" "MACOSX_DEPLOYMENT_TARGET=10.7" > /dev/null
|
||||
|
||||
# Build for OS X in ARC mode and for default deployment target
|
||||
rm -rf "$ARC_BUILD_DIR"
|
||||
xcodebuild -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$ARC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=YES" > /dev/null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user