21 Commits
3.1 ... 3.2.2

Author SHA1 Message Date
Pierre-Olivier Latour
1a6786488a Bumped version 2015-01-15 09:34:49 -08:00
Pierre-Olivier Latour
472c7855a7 Only wipe GCDWebUploader.bundle on Debug to avoid issues on Xcode bot 2015-01-05 23:54:23 -08:00
Pierre-Olivier Latour
2fdeb9581c Added Xcode bot scheme 2015-01-05 23:47:58 -08:00
Pierre-Olivier Latour
c4310fcdf4 Addressed static analyzer warnings 2015-01-05 23:47:49 -08:00
Pierre-Olivier Latour
33645d3c6b Fixed incorrect documentation for GCDWebServerAsyncStreamBlock 2015-01-02 18:55:30 -08:00
Pierre-Olivier Latour
3618dcac7e Added asyncResponse2 mode 2015-01-02 09:41:45 -08:00
Pierre-Olivier Latour
432e3826c9 Update README.md 2014-12-08 07:49:07 -08:00
Pierre-Olivier Latour
4e31508195 Removed invalid check 2014-12-02 08:39:29 -08:00
Pierre-Olivier Latour
628f6673b0 Bumped version 2014-12-02 06:52:31 -08:00
Pierre-Olivier Latour
1944cd8a6e Fixed tests 2014-11-28 16:40:55 +09:00
Pierre-Olivier Latour
d2001e38ca Fixes 2014-11-28 16:21:01 +09:00
Pierre-Olivier Latour
18889793b7 Fixed behavior of GCDWebServerOption_BonjourName option 2014-11-19 09:01:57 +09:00
Pierre-Olivier Latour
14d538b0fb Added GCDWebServerOption_BindToLocalhost option 2014-11-19 08:56:43 +09:00
Pierre-Olivier Latour
3b7198b4cc Merge pull request #105 from nickgravelyn/fix-crash-in-ios-unit-test
Prevent GWS_DNOT_REACHED when there is no application
2014-11-19 08:31:56 +09:00
Nick Gravelyn
abb891334a Adding check to _endBackgroundTask to verify the application exists before calling GWS_DNOT_REACHED.
This enables what is admittedly a rare scenario which is running these servers inside application-less unit tests where there is no UIApplication.
2014-11-18 14:13:00 -08:00
Pierre-Olivier Latour
059f5c8d01 Update README.md 2014-11-17 23:05:18 +09:00
Pierre-Olivier Latour
9d9546bb6d Bumped version 2014-11-07 11:44:11 +09:00
Pierre-Olivier Latour
2ff05b1aa0 Bumped version 2014-11-07 11:43:10 +09:00
Pierre-Olivier Latour
bf2c9a170d Workaround Firefox and IE not showing file selection dialog 2014-11-07 11:42:36 +09:00
Pierre-Olivier Latour
15caa9cd20 Fix 2014-10-18 12:42:38 -07:00
Pierre-Olivier Latour
32ba49ae34 Removed MRC support entirely 2014-10-18 09:32:24 -07:00
32 changed files with 421 additions and 494 deletions

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebDAVServer requires ARC
#endif
// WebDAV specifications: http://webdav.org/specs/rfc4918.html
// Requires "HEADER_SEARCH_PATHS = $(SDKROOT)/usr/include/libxml2" in Xcode build settings
@@ -418,9 +422,6 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
}
if (!success) {
NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding];
#if !__has_feature(objc_arc)
[string autorelease];
#endif
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
}
} else {
@@ -519,9 +520,6 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
}
if (!success) {
NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding];
#if !__has_feature(objc_arc)
[string autorelease];
#endif
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
}
@@ -607,11 +605,7 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
- (instancetype)initWithUploadDirectory:(NSString*)path {
if ((self = [super init])) {
_uploadDirectory = [[path stringByStandardizingPath] copy];
#if __has_feature(objc_arc)
GCDWebDAVServer* __unsafe_unretained server = self;
#else
__block GCDWebDAVServer* server = self;
#endif
// 9.1 PROPFIND method
[self addDefaultHandlerForMethod:@"PROPFIND" requestClass:[GCDWebServerDataRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
@@ -667,17 +661,6 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
return self;
}
#if !__has_feature(objc_arc)
- (void)dealloc {
[_uploadDirectory release];
[_allowedExtensions release];
[super dealloc];
}
#endif
@end
@implementation GCDWebDAVServer (Subclassing)

View File

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

View File

@@ -422,8 +422,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "cd \"$BUILT_PRODUCTS_DIR\"\nrm -rf \"GCDWebUploader.bundle\"\n";
showEnvVarsInLog = 0;
shellScript = "if [ \"$CONFIGURATION\" == \"Debug\" ]; then\n cd \"$BUILT_PRODUCTS_DIR\"\n rm -rf \"GCDWebUploader.bundle\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0610"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "NO"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DD76FA90486AB0100D96B5E"
BuildableName = "GCDWebServer"
BlueprintName = "GCDWebServer (Mac)"
ReferencedContainer = "container:GCDWebServer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DD76FA90486AB0100D96B5E"
BuildableName = "GCDWebServer"
BlueprintName = "GCDWebServer (Mac)"
ReferencedContainer = "container:GCDWebServer.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DD76FA90486AB0100D96B5E"
BuildableName = "GCDWebServer"
BlueprintName = "GCDWebServer (Mac)"
ReferencedContainer = "container:GCDWebServer.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8DD76FA90486AB0100D96B5E"
BuildableName = "GCDWebServer"
BlueprintName = "GCDWebServer (Mac)"
ReferencedContainer = "container:GCDWebServer.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Release">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -79,7 +79,7 @@ extern NSString* const GCDWebServerOption_Port;
* 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.
* The default value is nil.
*/
extern NSString* const GCDWebServerOption_BonjourName;
@@ -90,6 +90,17 @@ extern NSString* const GCDWebServerOption_BonjourName;
*/
extern NSString* const GCDWebServerOption_BonjourType;
/**
* Only accept HTTP requests coming from localhost i.e. not from the outside
* network (NSNumber / BOOL).
*
* The default value is NO.
*
* @warning Bonjour should be disabled if using this option since the server
* will not be reachable from the outside network anyway.
*/
extern NSString* const GCDWebServerOption_BindToLocalhost;
/**
* The maximum number of incoming HTTP requests that can be queued waiting to
* be handled before new ones are dropped (NSNumber / NSUInteger).
@@ -512,6 +523,14 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
*
* @warning The interpretation of the "level" argument depends on the logging
* facility used at compile time.
*
* If using the built-in logging facility, the log levels are as follow:
* DEBUG = 0
* VERBOSE = 1
* INFO = 2
* WARNING = 3
* ERROR = 4
* EXCEPTION = 5
*/
+ (void)setLogLevel:(int)level;

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <TargetConditionals.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
@@ -46,6 +50,7 @@
NSString* const GCDWebServerOption_Port = @"Port";
NSString* const GCDWebServerOption_BonjourName = @"BonjourName";
NSString* const GCDWebServerOption_BonjourType = @"BonjourType";
NSString* const GCDWebServerOption_BindToLocalhost = @"BindToLocalhost";
NSString* const GCDWebServerOption_MaxPendingConnections = @"MaxPendingConnections";
NSString* const GCDWebServerOption_ServerName = @"ServerName";
NSString* const GCDWebServerOption_AuthenticationMethod = @"AuthenticationMethod";
@@ -93,7 +98,6 @@ void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* format, ..
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
va_end(arguments);
fprintf(stderr, "[%s] %s\n", levelNames[level], [message UTF8String]);
ARC_RELEASE(message);
}
}
@@ -142,13 +146,6 @@ static void _ExecuteMainThreadRunLoopSources() {
return self;
}
- (void)dealloc {
ARC_RELEASE(_matchBlock);
ARC_RELEASE(_asyncProcessBlock);
ARC_DEALLOC(super);
}
@end
@interface GCDWebServer () {
@@ -212,11 +209,10 @@ static void _ExecuteMainThreadRunLoopSources() {
GWS_DCHECK(_options == nil); // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
GWS_DCHECK(_disconnectTimer == NULL); // The server can never be dealloc'ed while the disconnect timer is pending because of the retain-cycle
ARC_RELEASE(_handlers);
ARC_DISPATCH_RELEASE(_sourceGroup);
ARC_DISPATCH_RELEASE(_syncQueue);
ARC_DEALLOC(super);
#if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
dispatch_release(_sourceGroup);
dispatch_release(_syncQueue);
#endif
}
#if TARGET_OS_IPHONE
@@ -288,8 +284,6 @@ static void _ExecuteMainThreadRunLoopSources() {
[[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid;
GWS_LOG_DEBUG(@"Did end background task");
} else {
GWS_DNOT_REACHED();
}
}
@@ -339,12 +333,12 @@ static void _ExecuteMainThreadRunLoopSources() {
- (NSString*)bonjourName {
CFStringRef name = _resolutionService ? CFNetServiceGetName(_resolutionService) : NULL;
return name && CFStringGetLength(name) ? ARC_BRIDGE_RELEASE(CFStringCreateCopy(kCFAllocatorDefault, name)) : nil;
return name && CFStringGetLength(name) ? CFBridgingRelease(CFStringCreateCopy(kCFAllocatorDefault, name)) : nil;
}
- (NSString*)bonjourType {
CFStringRef type = _resolutionService ? CFNetServiceGetType(_resolutionService) : NULL;
return type && CFStringGetLength(type) ? ARC_BRIDGE_RELEASE(CFStringCreateCopy(kCFAllocatorDefault, type)) : nil;
return type && CFStringGetLength(type) ? CFBridgingRelease(CFStringCreateCopy(kCFAllocatorDefault, type)) : nil;
}
- (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock {
@@ -357,7 +351,6 @@ static void _ExecuteMainThreadRunLoopSources() {
GWS_DCHECK(_options == nil);
GCDWebServerHandler* handler = [[GCDWebServerHandler alloc] initWithMatchBlock:matchBlock asyncProcessBlock:processBlock];
[_handlers insertObject:handler atIndex:0];
ARC_RELEASE(handler);
}
- (void)removeAllHandlers {
@@ -371,7 +364,7 @@ static void _NetServiceRegisterCallBack(CFNetServiceRef service, CFStreamError*
if (error->error) {
GWS_LOG_ERROR(@"Bonjour registration error %i (domain %i)", (int)error->error, (int)error->domain);
} else {
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
GCDWebServer* server = (__bridge GCDWebServer*)info;
GWS_LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]);
CFNetServiceResolveWithTimeout(server->_resolutionService, 1.0, NULL);
}
@@ -386,7 +379,7 @@ static void _NetServiceResolveCallBack(CFNetServiceRef service, CFStreamError* e
GWS_LOG_ERROR(@"Bonjour resolution error %i (domain %i)", (int)error->error, (int)error->domain);
}
} else {
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
GCDWebServer* server = (__bridge GCDWebServer*)info;
GWS_LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL);
if ([server.delegate respondsToSelector:@selector(webServerDidCompleteBonjourRegistration:)]) {
[server.delegate webServerDidCompleteBonjourRegistration:server];
@@ -407,7 +400,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
return [data base64Encoding];
}
#endif
return ARC_AUTORELEASE([[NSString alloc] initWithData:[data base64EncodedDataWithOptions:0] encoding:NSASCIIStringEncoding]);
return [[NSString alloc] initWithData:[data base64EncodedDataWithOptions:0] encoding:NSASCIIStringEncoding];
}
- (int)_createListeningSocket:(BOOL)useIPv6
@@ -487,11 +480,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &noSigPipe, sizeof(noSigPipe)); // Make sure this socket cannot generate SIG_PIPE
GCDWebServerConnection* connection = [[_connectionClass alloc] initWithServer:self localAddress:localAddress remoteAddress:remoteAddress 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 {
GWS_LOG_ERROR(@"Failed accepting %s socket: %s (%i)", isIPv6 ? "IPv6" : "IPv4", strerror(errno), errno);
}
@@ -505,6 +494,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
GWS_DCHECK(_source4 == NULL);
NSUInteger port = [_GetOption(_options, GCDWebServerOption_Port, @0) unsignedIntegerValue];
BOOL bindToLocalhost = [_GetOption(_options, GCDWebServerOption_BindToLocalhost, @NO) boolValue];
NSUInteger maxPendingConnections = [_GetOption(_options, GCDWebServerOption_MaxPendingConnections, @16) unsignedIntegerValue];
struct sockaddr_in addr4;
@@ -512,7 +502,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = htons(port);
addr4.sin_addr.s_addr = htonl(INADDR_ANY);
addr4.sin_addr.s_addr = bindToLocalhost ? htonl(INADDR_LOOPBACK) : htonl(INADDR_ANY);
int listeningSocket4 = [self _createListeningSocket:NO localAddress:&addr4 length:sizeof(addr4) maxPendingConnections:maxPendingConnections error:error];
if (listeningSocket4 <= 0) {
return NO;
@@ -533,7 +523,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
addr6.sin6_len = sizeof(addr6);
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
addr6.sin6_addr = in6addr_any;
addr6.sin6_addr = bindToLocalhost ? in6addr_loopback : in6addr_any;
int listeningSocket6 = [self _createListeningSocket:YES localAddress:&addr6 length:sizeof(addr6) maxPendingConnections:maxPendingConnections error:error];
if (listeningSocket6 <= 0) {
close(listeningSocket4);
@@ -565,12 +555,12 @@ static inline NSString* _EncodeBase64(NSString* string) {
_source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES];
_port = port;
NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, @"");
NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, nil);
NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp");
if (bonjourName) {
_registrationService = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), (ARC_BRIDGE CFStringRef)bonjourType, (ARC_BRIDGE CFStringRef)(bonjourName.length ? bonjourName : _serverName), (SInt32)_port);
_registrationService = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), (__bridge CFStringRef)bonjourType, (__bridge CFStringRef)(bonjourName.length ? bonjourName : _serverName), (SInt32)_port);
if (_registrationService) {
CFNetServiceClientContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
CFNetServiceClientContext context = {0, (__bridge void*)self, NULL, NULL, NULL};
CFNetServiceSetClient(_registrationService, _NetServiceRegisterCallBack, &context);
CFNetServiceScheduleWithRunLoop(_registrationService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
@@ -620,19 +610,19 @@ static inline NSString* _EncodeBase64(NSString* string) {
dispatch_source_cancel(_source6);
dispatch_source_cancel(_source4);
dispatch_group_wait(_sourceGroup, DISPATCH_TIME_FOREVER); // Wait until the cancellation handlers have been called which guarantees the listening sockets are closed
ARC_DISPATCH_RELEASE(_source6);
#if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
dispatch_release(_source6);
#endif
_source6 = NULL;
ARC_DISPATCH_RELEASE(_source4);
#if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
dispatch_release(_source4);
#endif
_source4 = NULL;
_port = 0;
ARC_RELEASE(_serverName);
_serverName = nil;
ARC_RELEASE(_authenticationRealm);
_authenticationRealm = nil;
ARC_RELEASE(_authenticationBasicAccounts);
_authenticationBasicAccounts = nil;
ARC_RELEASE(_authenticationDigestAccounts);
_authenticationDigestAccounts = nil;
dispatch_async(dispatch_get_main_queue(), ^{
@@ -682,7 +672,6 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![self _start:error])
#endif
{
ARC_RELEASE(_options);
_options = nil;
return NO;
}
@@ -714,7 +703,6 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (_source4) {
[self _stop];
}
ARC_RELEASE(_options);
_options = nil;
} else {
GWS_DNOT_REACHED();
@@ -741,7 +729,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (NSURL*)bonjourServerURL {
if (_source4 && _resolutionService) {
NSString* name = (ARC_BRIDGE NSString*)CFNetServiceGetTargetHost(_resolutionService);
NSString* name = (__bridge NSString*)CFNetServiceGetTargetHost(_resolutionService);
if (name.length) {
name = [name substringToIndex:(name.length - 1)]; // Strip trailing period at end of domain
if (_port != 80) {
@@ -813,7 +801,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![requestMethod isEqualToString:method]) {
return nil;
}
return ARC_AUTORELEASE([[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);
return [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
} asyncProcessBlock:block];
}
@@ -834,7 +822,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
if ([urlPath caseInsensitiveCompare:path] != NSOrderedSame) {
return nil;
}
return ARC_AUTORELEASE([[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);
return [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
} asyncProcessBlock:block];
} else {
@@ -872,7 +860,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
GCDWebServerRequest* request = [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
[request setAttribute:captures forKey:GCDWebServerRequestAttribute_RegexCaptures];
return ARC_AUTORELEASE(request);
return request;
} asyncProcessBlock:block];
} else {
@@ -939,11 +927,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (void)addGETHandlerForBasePath:(NSString*)basePath directoryPath:(NSString*)directoryPath indexFilename:(NSString*)indexFilename cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests {
if ([basePath hasPrefix:@"/"] && [basePath hasSuffix:@"/"]) {
#if __has_feature(objc_arc)
GCDWebServer* __unsafe_unretained server = self;
#else
__block GCDWebServer* server = self;
#endif
[self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) {
if (![requestMethod isEqualToString:@"GET"]) {
@@ -952,7 +936,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![urlPath hasPrefix:basePath]) {
return nil;
}
return ARC_AUTORELEASE([[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]);
return [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
} processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
@@ -1000,7 +984,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
[XLSharedFacility setMinLogLevel:level];
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
GCDWebServerLogLevel = level;
#else
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__)
GCDWebServerLogLevel = level;
#endif
}
@@ -1008,28 +992,28 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (void)logVerbose:(NSString*)format, ... {
va_list arguments;
va_start(arguments, format);
GWS_LOG_VERBOSE(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
GWS_LOG_VERBOSE(@"%@", [[NSString alloc] initWithFormat:format arguments:arguments]);
va_end(arguments);
}
- (void)logInfo:(NSString*)format, ... {
va_list arguments;
va_start(arguments, format);
GWS_LOG_INFO(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
GWS_LOG_INFO(@"%@", [[NSString alloc] initWithFormat:format arguments:arguments]);
va_end(arguments);
}
- (void)logWarning:(NSString*)format, ... {
va_list arguments;
va_start(arguments, format);
GWS_LOG_WARNING(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
GWS_LOG_WARNING(@"%@", [[NSString alloc] initWithFormat:format arguments:arguments]);
va_end(arguments);
}
- (void)logError:(NSString*)format, ... {
va_list arguments;
va_start(arguments, format);
GWS_LOG_ERROR(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
GWS_LOG_ERROR(@"%@", [[NSString alloc] initWithFormat:format arguments:arguments]);
va_end(arguments);
}
@@ -1093,7 +1077,6 @@ static CFHTTPMessageRef _CreateHTTPMessageFromPerformingRequest(NSData* inData,
} else {
GWS_DNOT_REACHED();
}
ARC_RELEASE(outData);
}
}
close(httpSocket);
@@ -1107,7 +1090,6 @@ static void _LogResult(NSString* format, ...) {
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
va_end(arguments);
fprintf(stdout, "%s\n", [message UTF8String]);
ARC_RELEASE(message);
}
- (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path {
@@ -1130,8 +1112,8 @@ static void _LogResult(NSString* format, ...) {
if (requestData) {
CFHTTPMessageRef request = _CreateHTTPMessageFromData(requestData, YES);
if (request) {
NSString* requestMethod = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(request));
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(request));
NSString* requestMethod = CFBridgingRelease(CFHTTPMessageCopyRequestMethod(request));
NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(request));
_LogResult(@"[%i] %@ %@", (int)[index integerValue], requestMethod, requestURL.path);
NSString* prefix = [index stringByAppendingString:@"-"];
for (NSString* responseFile in files) {
@@ -1151,8 +1133,8 @@ static void _LogResult(NSString* format, ...) {
success = NO;
}
NSDictionary* expectedHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(expectedResponse));
NSDictionary* actualHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(actualResponse));
NSDictionary* expectedHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(expectedResponse));
NSDictionary* actualHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(actualResponse));
for (NSString* expectedHeader in expectedHeaders) {
if ([ignoredHeaders containsObject:expectedHeader]) {
continue;
@@ -1171,10 +1153,10 @@ static void _LogResult(NSString* format, ...) {
}
}
NSString* expectedContentLength = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(expectedResponse, CFSTR("Content-Length")));
NSData* expectedBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(expectedResponse));
NSString* actualContentLength = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(actualResponse, CFSTR("Content-Length")));
NSData* actualBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(actualResponse));
NSString* expectedContentLength = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(expectedResponse, CFSTR("Content-Length")));
NSData* expectedBody = CFBridgingRelease(CFHTTPMessageCopyBody(expectedResponse));
NSString* actualContentLength = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(actualResponse, CFSTR("Content-Length")));
NSData* actualBody = CFBridgingRelease(CFHTTPMessageCopyBody(actualResponse));
if ([actualContentLength isEqualToString:expectedContentLength] && (actualBody.length > expectedBody.length)) { // Handle web browser closing connection before retrieving entire body (e.g. when playing a video file)
actualBody = [actualBody subdataWithRange:NSMakeRange(0, expectedBody.length)];
}
@@ -1191,7 +1173,6 @@ static void _LogResult(NSString* format, ...) {
[task setLaunchPath:@"/usr/bin/opendiff"];
[task setArguments:@[expectedPath, actualPath]];
[task launch];
ARC_RELEASE(task);
}
}
#endif

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <TargetConditionals.h>
#import <netdb.h>
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
@@ -172,7 +176,6 @@ static int32_t _connectionCounter = 0;
}
}];
ARC_RELEASE(bodyData);
}
static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
@@ -244,15 +247,8 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
@implementation GCDWebServerConnection (Write)
- (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, kGCDWebServerGCDQueue, ^{
#if __has_feature(objc_arc)
[data self]; // Keeps ARC from releasing data too early
#else
[data release];
#endif
});
dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t remainingData, int error) {
@@ -268,13 +264,15 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
});
ARC_DISPATCH_RELEASE(buffer);
#if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
dispatch_release(buffer);
#endif
}
- (void)_writeHeadersWithCompletionBlock:(WriteHeadersCompletionBlock)block {
GWS_DCHECK(_responseMessage);
CFDataRef data = CFHTTPMessageCopySerializedMessage(_responseMessage);
[self _writeData:(ARC_BRIDGE NSData*)data withCompletionBlock:block];
[self _writeData:(__bridge NSData*)data withCompletionBlock:block];
CFRelease(data);
}
@@ -349,11 +347,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
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);
GWS_DCHECK(_continueData);
}
@@ -362,7 +356,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
if (_digestAuthenticationNonce == nil) {
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
_digestAuthenticationNonce = ARC_RETAIN(GCDWebServerComputeMD5Digest(@"%@", ARC_BRIDGE_RELEASE(CFUUIDCreateString(kCFAllocatorDefault, uuid))));
_digestAuthenticationNonce = GCDWebServerComputeMD5Digest(@"%@", CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)));
CFRelease(uuid);
}
}
@@ -376,8 +370,8 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
_statusCode = statusCode;
_responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)_server.serverName);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822([NSDate date]));
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (__bridge CFStringRef)_server.serverName);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (__bridge CFStringRef)GCDWebServerFormatRFC822([NSDate date]));
}
- (void)_startProcessingRequest {
@@ -410,36 +404,36 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
if (hasBody && ![response performOpen:&error]) {
GWS_LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
} else {
_response = ARC_RETAIN(response);
_response = response;
}
}
if (_response) {
[self _initializeResponseHeadersWithStatusCode:_response.statusCode];
if (_response.lastModifiedDate) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822(_response.lastModifiedDate));
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (__bridge CFStringRef)GCDWebServerFormatRFC822(_response.lastModifiedDate));
}
if (_response.eTag) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (ARC_BRIDGE CFStringRef)_response.eTag);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (__bridge CFStringRef)_response.eTag);
}
if ((_response.statusCode >= 200) && (_response.statusCode < 300)) {
if (_response.cacheControlMaxAge > 0) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), (ARC_BRIDGE CFStringRef)[NSString stringWithFormat:@"max-age=%i, public", (int)_response.cacheControlMaxAge]);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), (__bridge CFStringRef)[NSString stringWithFormat:@"max-age=%i, public", (int)_response.cacheControlMaxAge]);
} else {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), CFSTR("no-cache"));
}
}
if (_response.contentType != nil) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Type"), (ARC_BRIDGE CFStringRef)GCDWebServerNormalizeHeaderValue(_response.contentType));
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Type"), (__bridge CFStringRef)GCDWebServerNormalizeHeaderValue(_response.contentType));
}
if (_response.contentLength != NSUIntegerMax) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Length"), (ARC_BRIDGE CFStringRef)[NSString stringWithFormat:@"%lu", (unsigned long)_response.contentLength]);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Length"), (__bridge CFStringRef)[NSString stringWithFormat:@"%lu", (unsigned long)_response.contentLength]);
}
if (_response.usesChunkedTransferEncoding) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Transfer-Encoding"), CFSTR("chunked"));
}
[_response.additionalHeaders enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, (ARC_BRIDGE CFStringRef)key, (ARC_BRIDGE CFStringRef)obj);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
}];
[self _writeHeadersWithCompletionBlock:^(BOOL success) {
@@ -524,7 +518,6 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
}];
ARC_RELEASE(chunkData);
}
- (void)_readRequestHeaders {
@@ -533,23 +526,23 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
[self _readHeaders:headersData withCompletionBlock:^(NSData* extraData) {
if (extraData) {
NSString* requestMethod = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(_requestMessage)); // Method verbs are case-sensitive and uppercase
NSString* requestMethod = CFBridgingRelease(CFHTTPMessageCopyRequestMethod(_requestMessage)); // Method verbs are case-sensitive and uppercase
if (_server.shouldAutomaticallyMapHEADToGET && [requestMethod isEqualToString:@"HEAD"]) {
requestMethod = @"GET";
_virtualHEAD = YES;
}
NSDictionary* requestHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(_requestMessage));
NSDictionary* requestHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones
NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(_requestMessage));
if (requestURL) {
requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders];
GWS_DCHECK(requestURL);
}
NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(ARC_BRIDGE_RELEASE(CFURLCopyPath((CFURLRef)requestURL))) : nil; // Don't use -[NSURL path] which strips the ending slash
NSString* queryString = requestURL ? ARC_BRIDGE_RELEASE(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil; // Don't use -[NSURL query] to make sure query is not unescaped;
NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(CFBridgingRelease(CFURLCopyPath((CFURLRef)requestURL))) : nil; // Don't use -[NSURL path] which strips the ending slash
NSString* queryString = requestURL ? CFBridgingRelease(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil; // Don't use -[NSURL query] to make sure query is not unescaped;
NSDictionary* requestQuery = queryString ? GCDWebServerParseURLEncodedForm(queryString) : @{};
if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) {
for (_handler in _server.handlers) {
_request = ARC_RETAIN(_handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery));
_request = _handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery);
if (_request) {
break;
}
@@ -604,14 +597,13 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
}];
ARC_RELEASE(headersData);
}
- (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket {
if ((self = [super init])) {
_server = ARC_RETAIN(server);
_localAddress = ARC_RETAIN(localAddress);
_remoteAddress = ARC_RETAIN(remoteAddress);
_server = server;
_localAddress = localAddress;
_remoteAddress = remoteAddress;
_socket = socket;
GWS_LOG_DEBUG(@"Did open connection on socket %i", _socket);
@@ -619,7 +611,6 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
if (![self open]) {
close(_socket);
ARC_RELEASE(self);
return nil;
}
_opened = YES;
@@ -650,26 +641,14 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
[_server didEndConnection:self];
ARC_RELEASE(_server);
ARC_RELEASE(_localAddress);
ARC_RELEASE(_remoteAddress);
if (_requestMessage) {
CFRelease(_requestMessage);
}
ARC_RELEASE(_request);
if (_responseMessage) {
CFRelease(_responseMessage);
}
ARC_RELEASE(_response);
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
ARC_RELEASE(_requestPath);
ARC_RELEASE(_responsePath);
#endif
ARC_DEALLOC(super);
}
@end
@@ -681,11 +660,11 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
if (_server.recordingEnabled) {
_connectionIndex = OSAtomicIncrement32(&_connectionCounter);
_requestPath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
_requestPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
_requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
GWS_DCHECK(_requestFD > 0);
_responsePath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
_responsePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
_responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
GWS_DCHECK(_responseFD > 0);
}

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <TargetConditionals.h>
#if TARGET_OS_IPHONE
#import <MobileCoreServices/MobileCoreServices.h>
@@ -50,14 +54,14 @@ void GCDWebServerInitializeFunctions() {
_dateFormatterRFC822 = [[NSDateFormatter alloc] init];
_dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
_dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
_dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
_dateFormatterRFC822.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
GWS_DCHECK(_dateFormatterRFC822);
}
if (_dateFormatterISO8601 == nil) {
_dateFormatterISO8601 = [[NSDateFormatter alloc] init];
_dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
_dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'";
_dateFormatterISO8601.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
_dateFormatterISO8601.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
GWS_DCHECK(_dateFormatterISO8601);
}
if (_dateFormatterQueue == NULL) {
@@ -96,7 +100,6 @@ NSString* GCDWebServerExtractHeaderValueParameter(NSString* value, NSString* nam
[scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:&parameter];
}
}
ARC_RELEASE(scanner);
return parameter;
}
@@ -150,7 +153,7 @@ NSString* GCDWebServerDescribeData(NSData* data, NSString* type) {
NSString* charset = GCDWebServerExtractHeaderValueParameter(type, @"charset");
NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
if (string) {
return ARC_AUTORELEASE(string);
return string;
}
}
return [NSString stringWithFormat:@"<%lu bytes>", (unsigned long)data.length];
@@ -168,9 +171,9 @@ NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
if (extension.length) {
mimeType = [_overrides objectForKey:extension];
if (mimeType == nil) {
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (ARC_BRIDGE CFStringRef)extension, NULL);
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
if (uti) {
mimeType = ARC_BRIDGE_RELEASE(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
mimeType = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
CFRelease(uti);
}
}
@@ -179,11 +182,11 @@ NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
}
NSString* GCDWebServerEscapeURLString(NSString* string) {
return ARC_BRIDGE_RELEASE(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
}
NSString* GCDWebServerUnescapeURLString(NSString* string) {
return ARC_BRIDGE_RELEASE(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
return CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
}
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
@@ -219,7 +222,6 @@ NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
}
[scanner setScanLocation:([scanner scanLocation] + 1)];
}
ARC_RELEASE(scanner);
return parameters;
}
@@ -247,7 +249,7 @@ NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6) {
if (store) {
CFPropertyListRef info = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4")); // There is no equivalent for IPv6 but the primary interface should be the same
if (info) {
primaryInterface = [[NSString stringWithString:[(ARC_BRIDGE NSDictionary*)info objectForKey:@"PrimaryInterface"]] UTF8String];
primaryInterface = [[NSString stringWithString:[(__bridge NSDictionary*)info objectForKey:@"PrimaryInterface"]] UTF8String];
CFRelease(info);
}
CFRelease(store);
@@ -280,7 +282,7 @@ NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6) {
NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) {
va_list arguments;
va_start(arguments, format);
const char* string = [ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]) UTF8String];
const char* string = [[[NSString alloc] initWithFormat:format arguments:arguments] UTF8String];
va_end(arguments);
unsigned char md5[CC_MD5_DIGEST_LENGTH];
CC_MD5(string, (CC_LONG)strlen(string), md5);

View File

@@ -28,35 +28,6 @@
#import <os/object.h>
#import <sys/socket.h>
/**
* ARC <-> MRC compatibility macros.
*/
#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__)
#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
#define ARC_DISPATCH_RETAIN(__OBJECT__)
#define ARC_DISPATCH_RELEASE(__OBJECT__)
#else
#define ARC_DISPATCH_RETAIN(__OBJECT__) dispatch_retain(__OBJECT__)
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
#endif
#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]
#define ARC_DISPATCH_RETAIN(__OBJECT__) dispatch_retain(__OBJECT__)
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
#endif
/**
* All GCDWebServer headers.
*/
@@ -77,15 +48,28 @@
#import "GCDWebServerFileResponse.h"
#import "GCDWebServerStreamedResponse.h"
/**
* Check if a custom logging facility should be used instead.
*/
#if defined(__GCDWEBSERVER_LOGGING_HEADER__)
#define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
#import __GCDWEBSERVER_LOGGING_HEADER__
/**
* Automatically detect if XLFacility is available and if so use it as a
* logging facility.
*/
#if defined(__has_include) && __has_include("XLFacilityMacros.h")
#elif defined(__has_include) && __has_include("XLFacilityMacros.h")
#define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__
#undef XLOG_TAG
#define XLOG_TAG @"gcdwebserver.internal"
#import "XLFacilityMacros.h"
#define GWS_LOG_DEBUG(...) XLOG_DEBUG(__VA_ARGS__)
@@ -120,16 +104,6 @@ extern int GCDWebServerLogLevel;
#define GWS_LOG_ERROR(...) DDLogError(__VA_ARGS__)
#define GWS_LOG_EXCEPTION(__EXCEPTION__) DDLogError(@"%@", __EXCEPTION__)
/**
* Check if a custom logging facility should be used instead.
*/
#elif defined(__GCDWEBSERVER_LOGGING_HEADER__)
#define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
#import __GCDWEBSERVER_LOGGING_HEADER__
/**
* If all of the above fail, then use GCDWebServer built-in
* logging facility.
@@ -145,7 +119,7 @@ typedef NS_ENUM(int, GCDWebServerLoggingLevel) {
kGCDWebServerLoggingLevel_Info,
kGCDWebServerLoggingLevel_Warning,
kGCDWebServerLoggingLevel_Error,
kGCDWebServerLoggingLevel_Exception,
kGCDWebServerLoggingLevel_Exception
};
extern GCDWebServerLoggingLevel GCDWebServerLogLevel;

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <zlib.h>
#import "GCDWebServerPrivate.h"
@@ -84,7 +88,9 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
- (BOOL)open:(NSError**)error {
int result = inflateInit2(&_stream, 15 + 16);
if (result != Z_OK) {
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
if (error) {
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
}
return NO;
}
if (![super open:error]) {
@@ -110,8 +116,9 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
_stream.avail_out = (uInt)maxLength;
int result = inflate(&_stream, Z_NO_FLUSH);
if ((result != Z_OK) && (result != Z_STREAM_END)) {
ARC_RELEASE(decodedData);
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
if (error) {
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
}
return NO;
}
length += maxLength - _stream.avail_out;
@@ -125,7 +132,6 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
}
decodedData.length = length;
BOOL success = length ? [super writeData:decodedData error:error] : YES; // No need to call writer if we have no data yet
ARC_RELEASE(decodedData);
return success;
}
@@ -167,19 +173,18 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
if ((self = [super init])) {
_method = [method copy];
_url = ARC_RETAIN(url);
_headers = ARC_RETAIN(headers);
_url = url;
_headers = headers;
_path = [path copy];
_query = ARC_RETAIN(query);
_query = query;
_type = ARC_RETAIN(GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Content-Type"]));
_type = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Content-Type"]);
_chunked = [GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Transfer-Encoding"]) isEqualToString:@"chunked"];
NSString* lengthHeader = [_headers objectForKey:@"Content-Length"];
if (lengthHeader) {
NSInteger length = [lengthHeader integerValue];
if (_chunked || (length < 0)) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
_length = length;
@@ -194,7 +199,6 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
} else {
if (_type) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
_length = NSUIntegerMax;
@@ -204,7 +208,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
if (modifiedHeader) {
_modifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy];
}
_noneMatch = ARC_RETAIN([_headers objectForKey:@"If-None-Match"]);
_noneMatch = [_headers objectForKey:@"If-None-Match"];
_range = NSMakeRange(NSUIntegerMax, 0);
NSString* rangeHeader = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Range"]);
@@ -246,21 +250,6 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
return self;
}
- (void)dealloc {
ARC_RELEASE(_method);
ARC_RELEASE(_url);
ARC_RELEASE(_headers);
ARC_RELEASE(_path);
ARC_RELEASE(_query);
ARC_RELEASE(_type);
ARC_RELEASE(_modifiedSince);
ARC_RELEASE(_noneMatch);
ARC_RELEASE(_decoders);
ARC_RELEASE(_attributes);
ARC_DEALLOC(super);
}
- (BOOL)hasBody {
return _type ? YES : NO;
}
@@ -290,7 +279,6 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
if ([GCDWebServerNormalizeHeaderValue([self.headers objectForKey:@"Content-Encoding"]) isEqualToString:@"gzip"]) {
GCDWebServerGZipDecoder* decoder = [[GCDWebServerGZipDecoder alloc] initWithRequest:self writer:_writer];
[_decoders addObject:decoder];
ARC_RELEASE(decoder);
_writer = decoder;
}
}

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <zlib.h>
#import "GCDWebServerPrivate.h"
@@ -90,7 +94,9 @@
- (BOOL)open:(NSError**)error {
int result = deflateInit2(&_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
if (result != Z_OK) {
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
if (error) {
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
}
return NO;
}
if (![super open:error]) {
@@ -126,8 +132,9 @@
if (result == Z_STREAM_END) {
_finished = YES;
} else if (result != Z_OK) {
ARC_RELEASE(encodedData);
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
if (error) {
*error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
}
return nil;
}
length += maxLength - _stream.avail_out;
@@ -140,7 +147,7 @@
} while (length == 0); // Make sure we don't return an empty NSData if not in finished state
encodedData.length = length;
}
return ARC_AUTORELEASE(encodedData);
return encodedData;
}
- (void)close {
@@ -174,7 +181,7 @@
gzipContentEncodingEnabled=_gzipped, additionalHeaders=_headers;
+ (instancetype)response {
return ARC_AUTORELEASE([[[self class] alloc] init]);
return [[[self class] alloc] init];
}
- (instancetype)init {
@@ -189,16 +196,6 @@
return self;
}
- (void)dealloc {
ARC_RELEASE(_type);
ARC_RELEASE(_lastModified);
ARC_RELEASE(_eTag);
ARC_RELEASE(_headers);
ARC_RELEASE(_encoders);
ARC_DEALLOC(super);
}
- (void)setValue:(NSString*)value forAdditionalHeader:(NSString*)header {
[_headers setValue:value forKey:header];
}
@@ -228,7 +225,6 @@
if (_gzipped) {
GCDWebServerGZipEncoder* encoder = [[GCDWebServerGZipEncoder alloc] initWithResponse:self reader:_reader];
[_encoders addObject:encoder];
ARC_RELEASE(encoder);
_reader = encoder;
}
}
@@ -288,11 +284,11 @@
@implementation GCDWebServerResponse (Extensions)
+ (instancetype)responseWithStatusCode:(NSInteger)statusCode {
return ARC_AUTORELEASE([[self alloc] initWithStatusCode:statusCode]);
return [[self alloc] initWithStatusCode:statusCode];
}
+ (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent {
return ARC_AUTORELEASE([[self alloc] initWithRedirect:location permanent:permanent]);
return [[self alloc] initWithRedirect:location permanent:permanent];
}
- (instancetype)initWithStatusCode:(NSInteger)statusCode {

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
@interface GCDWebServerDataRequest () {
@@ -40,14 +44,6 @@
@synthesize data=_data;
- (void)dealloc {
ARC_RELEASE(_data);
ARC_RELEASE(_text);
ARC_RELEASE(_jsonObject);
ARC_DEALLOC(super);
}
- (BOOL)open:(NSError**)error {
if (self.contentLength != NSUIntegerMax) {
_data = [[NSMutableData alloc] initWithCapacity:self.contentLength];
@@ -55,7 +51,9 @@
_data = [[NSMutableData alloc] init];
}
if (_data == nil) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}];
if (error) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}];
}
return NO;
}
return YES;
@@ -99,7 +97,7 @@
if (_jsonObject == nil) {
NSString* mimeType = GCDWebServerTruncateHeaderValue(self.contentType);
if ([mimeType isEqualToString:@"application/json"] || [mimeType isEqualToString:@"text/json"] || [mimeType isEqualToString:@"text/javascript"]) {
_jsonObject = ARC_RETAIN([NSJSONSerialization JSONObjectWithData:_data options:0 error:NULL]);
_jsonObject = [NSJSONSerialization JSONObjectWithData:_data options:0 error:NULL];
} else {
GWS_DNOT_REACHED();
}

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
@interface GCDWebServerFileRequest () {
@@ -40,22 +44,21 @@
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
_temporaryPath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
_temporaryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
}
return self;
}
- (void)dealloc {
unlink([_temporaryPath fileSystemRepresentation]);
ARC_RELEASE(_temporaryPath);
ARC_DEALLOC(super);
}
- (BOOL)open:(NSError**)error {
_file = open([_temporaryPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (_file <= 0) {
*error = GCDWebServerMakePosixError(errno);
if (error) {
*error = GCDWebServerMakePosixError(errno);
}
return NO;
}
return YES;
@@ -63,7 +66,9 @@
- (BOOL)writeData:(NSData*)data error:(NSError**)error {
if (write(_file, data.bytes, data.length) != (ssize_t)data.length) {
*error = GCDWebServerMakePosixError(errno);
if (error) {
*error = GCDWebServerMakePosixError(errno);
}
return NO;
}
return YES;
@@ -71,7 +76,9 @@
- (BOOL)close:(NSError**)error {
if (close(_file) < 0) {
*error = GCDWebServerMakePosixError(errno);
if (error) {
*error = GCDWebServerMakePosixError(errno);
}
return NO;
}
#ifdef __GCDWEBSERVER_ENABLE_TESTING__

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
#define kMultiPartBufferSize (256 * 1024)
@@ -63,19 +67,11 @@ static NSData* _dashNewlineData = nil;
if ((self = [super init])) {
_controlName = [name copy];
_contentType = [type copy];
_mimeType = ARC_RETAIN(GCDWebServerTruncateHeaderValue(_contentType));
_mimeType = GCDWebServerTruncateHeaderValue(_contentType);
}
return self;
}
- (void)dealloc {
ARC_RELEASE(_controlName);
ARC_RELEASE(_contentType);
ARC_RELEASE(_mimeType);
ARC_DEALLOC(super);
}
@end
@interface GCDWebServerMultiPartArgument () {
@@ -91,7 +87,7 @@ static NSData* _dashNewlineData = nil;
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type data:(NSData*)data {
if ((self = [super initWithControlName:name contentType:type])) {
_data = ARC_RETAIN(data);
_data = data;
if ([self.contentType hasPrefix:@"text/"]) {
NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
@@ -101,13 +97,6 @@ static NSData* _dashNewlineData = nil;
return self;
}
- (void)dealloc {
ARC_RELEASE(_data);
ARC_RELEASE(_string);
ARC_DEALLOC(super);
}
- (NSString*)description {
return [NSString stringWithFormat:@"<%@ | '%@' | %lu bytes>", [self class], self.mimeType, (unsigned long)_data.length];
}
@@ -135,11 +124,6 @@ static NSData* _dashNewlineData = nil;
- (void)dealloc {
unlink([_temporaryPath fileSystemRepresentation]);
ARC_RELEASE(_fileName);
ARC_RELEASE(_temporaryPath);
ARC_DEALLOC(super);
}
- (NSString*)description {
@@ -187,14 +171,13 @@ static NSData* _dashNewlineData = nil;
NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
if (data == nil) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
if ((self = [super init])) {
_boundary = ARC_RETAIN(data);
_defaultcontrolName = ARC_RETAIN(name);
_arguments = ARC_RETAIN(arguments);
_files = ARC_RETAIN(files);
_boundary = data;
_defaultcontrolName = name;
_arguments = arguments;
_files = files;
_data = [[NSMutableData alloc] initWithCapacity:kMultiPartBufferSize];
_state = kParserState_Start;
}
@@ -202,23 +185,10 @@ static NSData* _dashNewlineData = nil;
}
- (void)dealloc {
ARC_RELEASE(_boundary);
ARC_RELEASE(_defaultcontrolName);
ARC_RELEASE(_data);
ARC_RELEASE(_arguments);
ARC_RELEASE(_files);
ARC_RELEASE(_controlName);
ARC_RELEASE(_fileName);
ARC_RELEASE(_contentType);
if (_tmpFile > 0) {
close(_tmpFile);
unlink([_tmpPath fileSystemRepresentation]);
}
ARC_RELEASE(_tmpPath);
ARC_RELEASE(_subParser);
ARC_DEALLOC(super);
}
// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
@@ -229,15 +199,10 @@ static NSData* _dashNewlineData = nil;
NSRange range = [_data rangeOfData:_newlinesData options:0 range:NSMakeRange(0, _data.length)];
if (range.location != NSNotFound) {
ARC_RELEASE(_controlName);
_controlName = nil;
ARC_RELEASE(_fileName);
_fileName = nil;
ARC_RELEASE(_contentType);
_contentType = nil;
ARC_RELEASE(_tmpPath);
_tmpPath = nil;
ARC_RELEASE(_subParser);
_subParser = nil;
NSString* headers = [[NSString alloc] initWithData:[_data subdataWithRange:NSMakeRange(0, range.location)] encoding:NSUTF8StringEncoding];
if (headers) {
@@ -247,15 +212,15 @@ static NSData* _dashNewlineData = nil;
NSString* name = [header substringToIndex:subRange.location];
NSString* value = [[header substringFromIndex:(subRange.location + subRange.length)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([name caseInsensitiveCompare:@"Content-Type"] == NSOrderedSame) {
_contentType = ARC_RETAIN(GCDWebServerNormalizeHeaderValue(value));
_contentType = GCDWebServerNormalizeHeaderValue(value);
} else if ([name caseInsensitiveCompare:@"Content-Disposition"] == NSOrderedSame) {
NSString* contentDisposition = GCDWebServerNormalizeHeaderValue(value);
if ([GCDWebServerTruncateHeaderValue(contentDisposition) isEqualToString:@"form-data"]) {
_controlName = ARC_RETAIN(GCDWebServerExtractHeaderValueParameter(contentDisposition, @"name"));
_fileName = ARC_RETAIN(GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename"));
_controlName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"name");
_fileName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename");
} else if ([GCDWebServerTruncateHeaderValue(contentDisposition) isEqualToString:@"file"]) {
_controlName = ARC_RETAIN(_defaultcontrolName);
_fileName = ARC_RETAIN(GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename"));
_controlName = _defaultcontrolName;
_fileName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename");
}
}
} else {
@@ -265,7 +230,6 @@ static NSData* _dashNewlineData = nil;
if (_contentType == nil) {
_contentType = @"text/plain";
}
ARC_RELEASE(headers);
} else {
GWS_LOG_ERROR(@"Failed decoding headers in part of 'multipart/form-data'");
GWS_DNOT_REACHED();
@@ -314,7 +278,6 @@ static NSData* _dashNewlineData = nil;
GWS_DNOT_REACHED();
success = NO;
}
ARC_RELEASE(_subParser);
_subParser = nil;
} else if (_tmpPath) {
ssize_t result = write(_tmpFile, dataBytes, dataLength);
@@ -323,7 +286,6 @@ static NSData* _dashNewlineData = nil;
_tmpFile = 0;
GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithControlName:_controlName contentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
[_files addObject:file];
ARC_RELEASE(file);
} else {
GWS_DNOT_REACHED();
success = NO;
@@ -332,14 +294,11 @@ static NSData* _dashNewlineData = nil;
GWS_DNOT_REACHED();
success = NO;
}
ARC_RELEASE(_tmpPath);
_tmpPath = nil;
} else {
NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength];
GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithControlName:_controlName contentType:_contentType data:data];
[_arguments addObject:argument];
ARC_RELEASE(argument);
ARC_RELEASE(data);
}
}
@@ -413,18 +372,13 @@ static NSData* _dashNewlineData = nil;
return self;
}
- (void)dealloc {
ARC_RELEASE(_arguments);
ARC_RELEASE(_files);
ARC_DEALLOC(super);
}
- (BOOL)open:(NSError**)error {
NSString* boundary = GCDWebServerExtractHeaderValueParameter(self.contentType, @"boundary");
_parser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:nil arguments:_arguments files:_files];
if (_parser == nil) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}];
if (error) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}];
}
return NO;
}
return YES;
@@ -432,7 +386,9 @@ static NSData* _dashNewlineData = nil;
- (BOOL)writeData:(NSData*)data error:(NSError**)error {
if (![_parser appendBytes:data.bytes length:data.length]) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}];
if (error) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}];
}
return NO;
}
return YES;
@@ -440,10 +396,11 @@ static NSData* _dashNewlineData = nil;
- (BOOL)close:(NSError**)error {
BOOL atEnd = [_parser isAtEnd];
ARC_RELEASE(_parser);
_parser = nil;
if (!atEnd) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}];
if (error) {
*error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}];
}
return NO;
}
return YES;

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
@interface GCDWebServerURLEncodedFormRequest () {
@@ -41,12 +45,6 @@
return @"application/x-www-form-urlencoded";
}
- (void)dealloc {
ARC_RELEASE(_arguments);
ARC_DEALLOC(super);
}
- (BOOL)close:(NSError**)error {
if (![super close:error]) {
return NO;
@@ -54,9 +52,8 @@
NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
NSString* string = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
_arguments = ARC_RETAIN(GCDWebServerParseURLEncodedForm(string));
_arguments = GCDWebServerParseURLEncodedForm(string);
GWS_DCHECK(_arguments);
ARC_RELEASE(string);
return YES;
}

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
@interface GCDWebServerDataResponse () {
@@ -37,18 +41,17 @@
@implementation GCDWebServerDataResponse
+ (instancetype)responseWithData:(NSData*)data contentType:(NSString*)type {
return ARC_AUTORELEASE([[[self class] alloc] initWithData:data contentType:type]);
return [[[self class] alloc] initWithData:data contentType:type];
}
- (instancetype)initWithData:(NSData*)data contentType:(NSString*)type {
if (data == nil) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
if ((self = [super init])) {
_data = ARC_RETAIN(data);
_data = data;
self.contentType = type;
self.contentLength = data.length;
@@ -56,12 +59,6 @@
return self;
}
- (void)dealloc {
ARC_RELEASE(_data);
ARC_DEALLOC(super);
}
- (NSData*)readData:(NSError**)error {
NSData* data;
if (_done) {
@@ -85,30 +82,29 @@
@implementation GCDWebServerDataResponse (Extensions)
+ (instancetype)responseWithText:(NSString*)text {
return ARC_AUTORELEASE([[self alloc] initWithText:text]);
return [[self alloc] initWithText:text];
}
+ (instancetype)responseWithHTML:(NSString*)html {
return ARC_AUTORELEASE([[self alloc] initWithHTML:html]);
return [[self alloc] initWithHTML:html];
}
+ (instancetype)responseWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
return ARC_AUTORELEASE([[self alloc] initWithHTMLTemplate:path variables:variables]);
return [[self alloc] initWithHTMLTemplate:path variables:variables];
}
+ (instancetype)responseWithJSONObject:(id)object {
return ARC_AUTORELEASE([[self alloc] initWithJSONObject:object]);
return [[self alloc] initWithJSONObject:object];
}
+ (instancetype)responseWithJSONObject:(id)object contentType:(NSString*)type {
return ARC_AUTORELEASE([[self alloc] initWithJSONObject:object contentType:type]);
return [[self alloc] initWithJSONObject:object contentType:type];
}
- (instancetype)initWithText:(NSString*)text {
NSData* data = [text dataUsingEncoding:NSUTF8StringEncoding];
if (data == nil) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
return [self initWithData:data contentType:@"text/plain; charset=utf-8"];
@@ -118,7 +114,6 @@
NSData* data = [html dataUsingEncoding:NSUTF8StringEncoding];
if (data == nil) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
return [self initWithData:data contentType:@"text/html; charset=utf-8"];
@@ -130,7 +125,6 @@
[html replaceOccurrencesOfString:[NSString stringWithFormat:@"%%%@%%", key] withString:value options:0 range:NSMakeRange(0, html.length)];
}];
id response = [self initWithHTML:html];
ARC_RELEASE(html);
return response;
}
@@ -141,7 +135,6 @@
- (instancetype)initWithJSONObject:(id)object contentType:(NSString*)type {
NSData* data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL];
if (data == nil) {
ARC_RELEASE(self);
return nil;
}
return [self initWithData:data contentType:type];

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
@interface GCDWebServerErrorResponse ()
@@ -37,7 +41,7 @@
GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
va_list arguments;
va_start(arguments, format);
GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments]);
GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
va_end(arguments);
return response;
}
@@ -46,7 +50,7 @@
GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
va_list arguments;
va_start(arguments, format);
GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments]);
GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
va_end(arguments);
return response;
}
@@ -55,7 +59,7 @@
GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
va_list arguments;
va_start(arguments, format);
GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments]);
GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
va_end(arguments);
return response;
}
@@ -64,7 +68,7 @@
GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
va_list arguments;
va_start(arguments, format);
GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments]);
GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
va_end(arguments);
return response;
}
@@ -82,7 +86,6 @@ static inline NSString* _EscapeHTMLString(NSString* string) {
if ((self = [self initWithHTML:html])) {
self.statusCode = statusCode;
}
ARC_RELEASE(message);
return self;
}

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <sys/stat.h>
#import "GCDWebServerPrivate.h"
@@ -43,19 +47,19 @@
@implementation GCDWebServerFileResponse
+ (instancetype)responseWithFile:(NSString*)path {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path]);
return [[[self class] alloc] initWithFile:path];
}
+ (instancetype)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path isAttachment:attachment]);
return [[[self class] alloc] initWithFile:path isAttachment:attachment];
}
+ (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path byteRange:range]);
return [[[self class] alloc] initWithFile:path byteRange:range];
}
+ (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
return ARC_AUTORELEASE([[[self class] alloc] initWithFile:path byteRange:range isAttachment:attachment]);
return [[[self class] alloc] initWithFile:path byteRange:range isAttachment:attachment];
}
- (instancetype)initWithFile:(NSString*)path {
@@ -78,13 +82,11 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
struct stat info;
if (lstat([path fileSystemRepresentation], &info) || !(info.st_mode & S_IFREG)) {
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
#ifndef __LP64__
if (info.st_size >= (off_t)4294967295) { // In 32 bit mode, we can't handle files greater than 4 GiBs (don't use "NSUIntegerMax" here to avoid potential unsigned to signed conversion issues)
GWS_DNOT_REACHED();
ARC_RELEASE(self);
return nil;
}
#endif
@@ -100,7 +102,6 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
range.location = fileSize - range.length;
}
if (range.length == 0) {
ARC_RELEASE(self);
return nil; // TODO: Return 416 status code and "Content-Range: bytes */{file length}" header
}
} else {
@@ -125,7 +126,6 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
if (lossyFileName) {
NSString* value = [NSString stringWithFormat:@"attachment; filename=\"%@\"; filename*=UTF-8''%@", lossyFileName, GCDWebServerEscapeURLString(fileName)];
[self setValue:value forAdditionalHeader:@"Content-Disposition"];
ARC_RELEASE(lossyFileName);
} else {
GWS_DNOT_REACHED();
}
@@ -139,20 +139,18 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
return self;
}
- (void)dealloc {
ARC_RELEASE(_path);
ARC_DEALLOC(super);
}
- (BOOL)open:(NSError**)error {
_file = open([_path fileSystemRepresentation], O_NOFOLLOW | O_RDONLY);
if (_file <= 0) {
*error = GCDWebServerMakePosixError(errno);
if (error) {
*error = GCDWebServerMakePosixError(errno);
}
return NO;
}
if (lseek(_file, _offset, SEEK_SET) != (off_t)_offset) {
*error = GCDWebServerMakePosixError(errno);
if (error) {
*error = GCDWebServerMakePosixError(errno);
}
close(_file);
return NO;
}
@@ -164,14 +162,16 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
NSMutableData* data = [[NSMutableData alloc] initWithLength:length];
ssize_t result = read(_file, data.mutableBytes, length);
if (result < 0) {
*error = GCDWebServerMakePosixError(errno);
if (error) {
*error = GCDWebServerMakePosixError(errno);
}
return nil;
}
if (result > 0) {
[data setLength:result];
_size -= result;
}
return ARC_AUTORELEASE(data);
return data;
}
- (void)close {

View File

@@ -29,8 +29,8 @@
/**
* The GCDWebServerStreamBlock is called to stream the data for the HTTP body.
* The block must return empty NSData when done or nil on error and set the
* "error" argument which is guaranteed to be non-NULL.
* The block must return either a chunk of data, an empty NSData when done, or
* nil on error and set the "error" argument which is guaranteed to be non-NULL.
*/
typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
@@ -39,13 +39,10 @@ typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
* except the streamed data can be returned at a later time allowing for
* truly asynchronous generation of the data.
*
* The block must return empty NSData when done or nil on error and set the
* "error" argument which is guaranteed to be non-NULL.
* The block must call "completionBlock" passing the new chunk of data when ready,
* an empty NSData when done, or nil on error and pass a NSError.
*
* The block must regularly call "completionBlock" passing new streamed data.
* Eventually it must call "completionBlock" passing an empty NSData indicating
* the end of the stream has been reached, or pass nil and an NSError in case of
* error.
* The block cannot call "completionBlock" more than once per invocation.
*/
typedef void (^GCDWebServerAsyncStreamBlock)(GCDWebServerBodyReaderCompletionBlock completionBlock);

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import "GCDWebServerPrivate.h"
@interface GCDWebServerStreamedResponse () {
@@ -36,11 +40,11 @@
@implementation GCDWebServerStreamedResponse
+ (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type streamBlock:block]);
return [[[self class] alloc] initWithContentType:type streamBlock:block];
}
+ (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type asyncStreamBlock:block]);
return [[[self class] alloc] initWithContentType:type asyncStreamBlock:block];
}
- (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
@@ -62,12 +66,6 @@
return self;
}
- (void)dealloc {
ARC_RELEASE(_block);
ARC_DEALLOC(super);
}
- (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
_block(block);
}

View File

@@ -65,7 +65,7 @@
<div id="alerts"></div>
<div class="btn-toolbar">
<button type="button" class="btn btn-primary fileinput-button">
<button type="button" class="btn btn-primary fileinput-button" id="upload-file">
<span class="glyphicon glyphicon-upload"></span> Upload Files&hellip;
<input id="fileupload" type="file" name="files[]" multiple>
</button>

View File

@@ -178,6 +178,17 @@ function _reload(path) {
$(document).ready(function() {
// Workaround Firefox and IE not showing file selection dialog when clicking on "upload-file" <button>
// Making it a <div> instead also works but then it the button doesn't work anymore with tab selection or accessibility
$("#upload-file").click(function(event) {
$("#fileupload").click();
});
// Prevent event bubbling when using workaround above
$("#fileupload").click(function(event) {
event.stopPropagation();
});
$("#fileupload").fileupload({
dropZone: $(document),
pasteZone: null,

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !__has_feature(objc_arc)
#error GCDWebUploader requires ARC
#endif
#import <TargetConditionals.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
@@ -292,17 +296,10 @@
if ((self = [super init])) {
NSBundle* siteBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"GCDWebUploader" ofType:@"bundle"]];
if (siteBundle == nil) {
#if !__has_feature(objc_arc)
[self release];
#endif
return nil;
}
_uploadDirectory = [[path stringByStandardizingPath] copy];
#if __has_feature(objc_arc)
GCDWebUploader* __unsafe_unretained server = self;
#else
__block GCDWebUploader* server = self;
#endif
// Resource files
[self addGETHandlerForBasePath:@"/" directoryPath:[siteBundle resourcePath] indexFilename:nil cacheAge:3600 allowRangeRequests:NO];
@@ -313,11 +310,7 @@
#if TARGET_OS_IPHONE
NSString* device = [[UIDevice currentDevice] name];
#else
#if __has_feature(objc_arc)
NSString* device = CFBridgingRelease(SCDynamicStoreCopyComputerName(NULL, NULL));
#else
NSString* device = [(id)SCDynamicStoreCopyComputerName(NULL, NULL) autorelease];
#endif
#endif
NSString* title = server.title;
if (title == nil) {
@@ -401,22 +394,6 @@
return self;
}
#if !__has_feature(objc_arc)
- (void)dealloc {
[_uploadDirectory release];
[_allowedExtensions release];
[_title release];
[_header release];
[_prologue release];
[_epilogue release];
[_footer release];
[super dealloc];
}
#endif
@end
@implementation GCDWebUploader (Subclassing)

View File

@@ -141,9 +141,10 @@ int main(int argc, const char* argv[]) {
NSString* authenticationRealm = nil;
NSString* authenticationUser = nil;
NSString* authenticationPassword = nil;
BOOL bindToLocalhost = NO;
if (argc == 1) {
fprintf(stdout, "Usage: %s [-mode webServer | htmlPage | htmlForm | htmlFileUpload | webDAV | webUploader | streamingResponse | asyncResponse] [-record] [-root directory] [-tests directory] [-authenticationMethod Basic | Digest] [-authenticationRealm realm] [-authenticationUser user] [-authenticationPassword password]\n\n", basename((char*)argv[0]));
fprintf(stdout, "Usage: %s [-mode webServer | htmlPage | htmlForm | htmlFileUpload | webDAV | webUploader | streamingResponse | asyncResponse] [-record] [-root directory] [-tests directory] [-authenticationMethod Basic | Digest] [-authenticationRealm realm] [-authenticationUser user] [-authenticationPassword password] [--localhost]\n\n", basename((char*)argv[0]));
} else {
for (int i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
@@ -188,6 +189,8 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[i], "-authenticationPassword") && (i + 1 < argc)) {
++i;
authenticationPassword = [NSString stringWithUTF8String:argv[i]];
} else if (!strcmp(argv[i], "--localhost")) {
bindToLocalhost = YES;
}
}
}
@@ -354,7 +357,7 @@ int main(int argc, const char* argv[]) {
fprintf(stdout, "Running in Async Response mode");
webServer = [[GCDWebServer alloc] init];
[webServer addHandlerForMethod:@"GET"
path:@"/"
path:@"/async"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
@@ -363,16 +366,34 @@ int main(int argc, const char* argv[]) {
completionBlock(response);
});
}];
[webServer addHandlerForMethod:@"GET"
path:@"/async2"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock handlerCompletionBlock) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__block int countDown = 10;
GCDWebServerStreamedResponse* response = [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock readerCompletionBlock) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSData* data = countDown ? [[NSString stringWithFormat:@"%i\n", countDown--] dataUsingEncoding:NSUTF8StringEncoding] : [NSData data];
readerCompletionBlock(data, nil);
});
}];
handlerCompletionBlock(response);
});
}];
break;
}
}
#if __has_feature(objc_arc)
fprintf(stdout, " (ARC is ON)\n");
#else
fprintf(stdout, " (ARC is OFF)\n");
#endif
if (webServer) {
Delegate* delegate = [[Delegate alloc] init];
@@ -391,6 +412,7 @@ int main(int argc, const char* argv[]) {
fprintf(stdout, "\n");
NSMutableDictionary* options = [NSMutableDictionary dictionary];
[options setObject:@8080 forKey:GCDWebServerOption_Port];
[options setObject:@(bindToLocalhost) forKey:GCDWebServerOption_BindToLocalhost];
[options setObject:@"" forKey:GCDWebServerOption_BonjourName];
if (authenticationUser && authenticationPassword) {
[options setValue:authenticationRealm forKey:GCDWebServerOption_AuthenticationRealm];
@@ -406,10 +428,6 @@ int main(int argc, const char* argv[]) {
}
}
webServer.delegate = nil;
#if !__has_feature(objc_arc)
[delegate release];
[webServer release];
#endif
}
}
return result;

View File

@@ -6,8 +6,6 @@ Overview
[![Platform](http://cocoapod-badges.herokuapp.com/p/GCDWebServer/badge.png)](https://github.com/swisspol/GCDWebServer)
[![License](http://img.shields.io/cocoapods/l/GCDWebServer.svg)](LICENSE)
*ANNOUNCEMENT: If you like GCDWebServer, check out [XLFacility](https://github.com/swisspol/XLFacility), an elegant and powerful logging facility for OS X & iOS by the same author and also open-source. XLFacility can be used seemlessly to handle logging from GCDWebServer (see "Logging in GCDWebServer" below).*
GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in OS X & iOS apps. It was written from scratch with the following goals in mind:
* Elegant and easy to use architecture with only 4 core classes: server, connection, request and response (see "Understanding GCDWebServer's Architecture" below)
* Well designed API with fully documented headers for easy integration and customization
@@ -38,6 +36,7 @@ What's not supported (but not really required from an embedded HTTP server):
Requirements:
* OS X 10.7 or later (x86_64)
* iOS 5.0 or later (armv7, armv7s or arm64)
* ARC memory management only (if you need MRC support use GCDWebServer 3.1 and earlier)
Getting Started
===============
@@ -187,24 +186,25 @@ New in GCDWebServer 3.0 is the ability to process HTTP requests aysnchronously i
```objectivec
[webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
NSMutableArray* contents = [NSMutableArray arrayWithObjects:@"<html><body><p>\n", @"Hello World!\n", @"</p></body></html>\n", nil]; // Fake data source we are reading from
GCDWebServerStreamedResponse* response = [GCDWebServerStreamedResponse responseWithContentType:@"text/html" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
// Simulate a delay reading from the fake data source
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
completionBlock([@"<html><body><p>Hello" dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 1st part of the stream data
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
completionBlock([@"World</p></body></html>" dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 2nd part of the stream data
NSString* string = contents.firstObject;
if (string) {
[contents removeObjectAtIndex:0];
completionBlock([string dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 2nd part of the stream data
} else {
completionBlock([NSData data], nil); // Must pass an empty NSData to signal the end of the stream
});
}
});
}];
return response;
}];
```

View File

@@ -11,13 +11,11 @@ OSX_TARGET="GCDWebServer (Mac)"
IOS_TARGET="GCDWebServer (iOS)"
CONFIGURATION="Release"
MRC_BUILD_DIR="/tmp/GCDWebServer-MRC"
MRC_PRODUCT="$MRC_BUILD_DIR/$CONFIGURATION/GCDWebServer"
ARC_BUILD_DIR="/tmp/GCDWebServer-ARC"
ARC_PRODUCT="$ARC_BUILD_DIR/$CONFIGURATION/GCDWebServer"
BUILD_DIR="/tmp/GCDWebServer-Build"
PRODUCT="$BUILD_DIR/$CONFIGURATION/GCDWebServer"
PAYLOAD_ZIP="Tests/Payload.zip"
PAYLOAD_DIR="/tmp/GCDWebServer"
PAYLOAD_DIR="/tmp/GCDWebServer-Payload"
function runTests {
rm -rf "$PAYLOAD_DIR"
@@ -26,61 +24,37 @@ function runTests {
if [ "$4" != "" ]; then
cp -f "$4" "$PAYLOAD_DIR/Payload"
pushd "$PAYLOAD_DIR/Payload"
SetFile -d "1/1/2014 00:00:00" -m "1/1/2014 00:00:00" `basename "$4"`
TZ=GMT SetFile -d "1/1/2014 00:00:00" -m "1/1/2014 00:00:00" `basename "$4"`
popd
fi
logLevel=2 $1 -mode "$2" -root "$PAYLOAD_DIR/Payload" -tests "$3"
}
# 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 for oldest deployment target (TODO: run tests on iOS)
rm -rf "$BUILD_DIR"
xcodebuild -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$BUILD_DIR" "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 for default deployment target (TODO: run tests on iOS)
rm -rf "$BUILD_DIR"
xcodebuild -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$BUILD_DIR" > /dev/null
# 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 OS X for oldest deployment target
rm -rf "$BUILD_DIR"
xcodebuild -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$BUILD_DIR" "MACOSX_DEPLOYMENT_TARGET=10.7" > /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 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 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
# Build for OS X for default deployment target
rm -rf "$BUILD_DIR"
xcodebuild -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$BUILD_DIR" > /dev/null
# Run tests
runTests $MRC_PRODUCT "htmlForm" "Tests/HTMLForm"
runTests $ARC_PRODUCT "htmlForm" "Tests/HTMLForm"
runTests $MRC_PRODUCT "htmlFileUpload" "Tests/HTMLFileUpload"
runTests $ARC_PRODUCT "htmlFileUpload" "Tests/HTMLFileUpload"
runTests $MRC_PRODUCT "webServer" "Tests/WebServer"
runTests $ARC_PRODUCT "webServer" "Tests/WebServer"
runTests $MRC_PRODUCT "webDAV" "Tests/WebDAV-Transmit"
runTests $ARC_PRODUCT "webDAV" "Tests/WebDAV-Transmit"
runTests $MRC_PRODUCT "webDAV" "Tests/WebDAV-Cyberduck"
runTests $ARC_PRODUCT "webDAV" "Tests/WebDAV-Cyberduck"
runTests $MRC_PRODUCT "webDAV" "Tests/WebDAV-Finder"
runTests $ARC_PRODUCT "webDAV" "Tests/WebDAV-Finder"
runTests $MRC_PRODUCT "webUploader" "Tests/WebUploader"
runTests $ARC_PRODUCT "webUploader" "Tests/WebUploader"
runTests $MRC_PRODUCT "webServer" "Tests/WebServer-Sample-Movie" "Tests/Sample-Movie.mp4"
runTests $ARC_PRODUCT "webServer" "Tests/WebServer-Sample-Movie" "Tests/Sample-Movie.mp4"
runTests $PRODUCT "htmlForm" "Tests/HTMLForm"
runTests $PRODUCT "htmlFileUpload" "Tests/HTMLFileUpload"
runTests $PRODUCT "webServer" "Tests/WebServer"
runTests $PRODUCT "webDAV" "Tests/WebDAV-Transmit"
runTests $PRODUCT "webDAV" "Tests/WebDAV-Cyberduck"
runTests $PRODUCT "webDAV" "Tests/WebDAV-Finder"
runTests $PRODUCT "webUploader" "Tests/WebUploader"
runTests $PRODUCT "webServer" "Tests/WebServer-Sample-Movie" "Tests/Sample-Movie.mp4"
# Done
echo "\nAll tests completed successfully!"

View File

@@ -36,16 +36,6 @@
@implementation AppDelegate
#if !__has_feature(objc_arc)
- (void)dealloc {
[_window release];
[super dealloc];
}
#endif
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
CGRect bounds = ([UIScreen instancesRespondToSelector:@selector(nativeBounds)] ? [[UIScreen mainScreen] nativeBounds] : [[UIScreen mainScreen] bounds]);
_window = [[UIWindow alloc] initWithFrame:bounds];