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. 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 // WebDAV specifications: http://webdav.org/specs/rfc4918.html
// Requires "HEADER_SEARCH_PATHS = $(SDKROOT)/usr/include/libxml2" in Xcode build settings // 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) { if (!success) {
NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding]; 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]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
} }
} else { } else {
@@ -519,9 +520,6 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
} }
if (!success) { if (!success) {
NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding]; 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]; 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 { - (instancetype)initWithUploadDirectory:(NSString*)path {
if ((self = [super init])) { if ((self = [super init])) {
_uploadDirectory = [[path stringByStandardizingPath] copy]; _uploadDirectory = [[path stringByStandardizingPath] copy];
#if __has_feature(objc_arc)
GCDWebDAVServer* __unsafe_unretained server = self; GCDWebDAVServer* __unsafe_unretained server = self;
#else
__block GCDWebDAVServer* server = self;
#endif
// 9.1 PROPFIND method // 9.1 PROPFIND method
[self addDefaultHandlerForMethod:@"PROPFIND" requestClass:[GCDWebServerDataRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { [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; return self;
} }
#if !__has_feature(objc_arc)
- (void)dealloc {
[_uploadDirectory release];
[_allowedExtensions release];
[super dealloc];
}
#endif
@end @end
@implementation GCDWebDAVServer (Subclassing) @implementation GCDWebDAVServer (Subclassing)

View File

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

View File

@@ -422,8 +422,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "cd \"$BUILT_PRODUCTS_DIR\"\nrm -rf \"GCDWebUploader.bundle\"\n"; shellScript = "if [ \"$CONFIGURATION\" == \"Debug\" ]; then\n cd \"$BUILT_PRODUCTS_DIR\"\n rm -rf \"GCDWebUploader.bundle\"\nfi\n";
showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* 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 * the name will automatically take the value of the GCDWebServerOption_ServerName
* option. If this option is set to nil, Bonjour will be disabled. * 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; extern NSString* const GCDWebServerOption_BonjourName;
@@ -90,6 +90,17 @@ extern NSString* const GCDWebServerOption_BonjourName;
*/ */
extern NSString* const GCDWebServerOption_BonjourType; 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 * The maximum number of incoming HTTP requests that can be queued waiting to
* be handled before new ones are dropped (NSNumber / NSUInteger). * 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 * @warning The interpretation of the "level" argument depends on the logging
* facility used at compile time. * 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; + (void)setLogLevel:(int)level;

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <TargetConditionals.h> #import <TargetConditionals.h>
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@@ -46,6 +50,7 @@
NSString* const GCDWebServerOption_Port = @"Port"; NSString* const GCDWebServerOption_Port = @"Port";
NSString* const GCDWebServerOption_BonjourName = @"BonjourName"; NSString* const GCDWebServerOption_BonjourName = @"BonjourName";
NSString* const GCDWebServerOption_BonjourType = @"BonjourType"; NSString* const GCDWebServerOption_BonjourType = @"BonjourType";
NSString* const GCDWebServerOption_BindToLocalhost = @"BindToLocalhost";
NSString* const GCDWebServerOption_MaxPendingConnections = @"MaxPendingConnections"; NSString* const GCDWebServerOption_MaxPendingConnections = @"MaxPendingConnections";
NSString* const GCDWebServerOption_ServerName = @"ServerName"; NSString* const GCDWebServerOption_ServerName = @"ServerName";
NSString* const GCDWebServerOption_AuthenticationMethod = @"AuthenticationMethod"; NSString* const GCDWebServerOption_AuthenticationMethod = @"AuthenticationMethod";
@@ -93,7 +98,6 @@ void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* format, ..
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments]; NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
va_end(arguments); va_end(arguments);
fprintf(stderr, "[%s] %s\n", levelNames[level], [message UTF8String]); fprintf(stderr, "[%s] %s\n", levelNames[level], [message UTF8String]);
ARC_RELEASE(message);
} }
} }
@@ -142,13 +146,6 @@ static void _ExecuteMainThreadRunLoopSources() {
return self; return self;
} }
- (void)dealloc {
ARC_RELEASE(_matchBlock);
ARC_RELEASE(_asyncProcessBlock);
ARC_DEALLOC(super);
}
@end @end
@interface GCDWebServer () { @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(_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 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); #if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
ARC_DISPATCH_RELEASE(_sourceGroup); dispatch_release(_sourceGroup);
ARC_DISPATCH_RELEASE(_syncQueue); dispatch_release(_syncQueue);
#endif
ARC_DEALLOC(super);
} }
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
@@ -288,8 +284,6 @@ static void _ExecuteMainThreadRunLoopSources() {
[[UIApplication sharedApplication] endBackgroundTask:_backgroundTask]; [[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid; _backgroundTask = UIBackgroundTaskInvalid;
GWS_LOG_DEBUG(@"Did end background task"); GWS_LOG_DEBUG(@"Did end background task");
} else {
GWS_DNOT_REACHED();
} }
} }
@@ -339,12 +333,12 @@ static void _ExecuteMainThreadRunLoopSources() {
- (NSString*)bonjourName { - (NSString*)bonjourName {
CFStringRef name = _resolutionService ? CFNetServiceGetName(_resolutionService) : NULL; 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 { - (NSString*)bonjourType {
CFStringRef type = _resolutionService ? CFNetServiceGetType(_resolutionService) : NULL; 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 { - (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock {
@@ -357,7 +351,6 @@ static void _ExecuteMainThreadRunLoopSources() {
GWS_DCHECK(_options == nil); GWS_DCHECK(_options == nil);
GCDWebServerHandler* handler = [[GCDWebServerHandler alloc] initWithMatchBlock:matchBlock asyncProcessBlock:processBlock]; GCDWebServerHandler* handler = [[GCDWebServerHandler alloc] initWithMatchBlock:matchBlock asyncProcessBlock:processBlock];
[_handlers insertObject:handler atIndex:0]; [_handlers insertObject:handler atIndex:0];
ARC_RELEASE(handler);
} }
- (void)removeAllHandlers { - (void)removeAllHandlers {
@@ -371,7 +364,7 @@ static void _NetServiceRegisterCallBack(CFNetServiceRef service, CFStreamError*
if (error->error) { if (error->error) {
GWS_LOG_ERROR(@"Bonjour registration error %i (domain %i)", (int)error->error, (int)error->domain); GWS_LOG_ERROR(@"Bonjour registration error %i (domain %i)", (int)error->error, (int)error->domain);
} else { } else {
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info; GCDWebServer* server = (__bridge GCDWebServer*)info;
GWS_LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]); GWS_LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]);
CFNetServiceResolveWithTimeout(server->_resolutionService, 1.0, NULL); 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); GWS_LOG_ERROR(@"Bonjour resolution error %i (domain %i)", (int)error->error, (int)error->domain);
} }
} else { } else {
GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info; GCDWebServer* server = (__bridge GCDWebServer*)info;
GWS_LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL); GWS_LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL);
if ([server.delegate respondsToSelector:@selector(webServerDidCompleteBonjourRegistration:)]) { if ([server.delegate respondsToSelector:@selector(webServerDidCompleteBonjourRegistration:)]) {
[server.delegate webServerDidCompleteBonjourRegistration:server]; [server.delegate webServerDidCompleteBonjourRegistration:server];
@@ -407,7 +400,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
return [data base64Encoding]; return [data base64Encoding];
} }
#endif #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 - (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 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 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 [connection self]; // Prevent compiler from complaining about unused variable / useless statement
#else
[connection release];
#endif
} else { } else {
GWS_LOG_ERROR(@"Failed accepting %s socket: %s (%i)", isIPv6 ? "IPv6" : "IPv4", strerror(errno), errno); 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); GWS_DCHECK(_source4 == NULL);
NSUInteger port = [_GetOption(_options, GCDWebServerOption_Port, @0) unsignedIntegerValue]; NSUInteger port = [_GetOption(_options, GCDWebServerOption_Port, @0) unsignedIntegerValue];
BOOL bindToLocalhost = [_GetOption(_options, GCDWebServerOption_BindToLocalhost, @NO) boolValue];
NSUInteger maxPendingConnections = [_GetOption(_options, GCDWebServerOption_MaxPendingConnections, @16) unsignedIntegerValue]; NSUInteger maxPendingConnections = [_GetOption(_options, GCDWebServerOption_MaxPendingConnections, @16) unsignedIntegerValue];
struct sockaddr_in addr4; struct sockaddr_in addr4;
@@ -512,7 +502,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
addr4.sin_len = sizeof(addr4); addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET; addr4.sin_family = AF_INET;
addr4.sin_port = htons(port); 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]; int listeningSocket4 = [self _createListeningSocket:NO localAddress:&addr4 length:sizeof(addr4) maxPendingConnections:maxPendingConnections error:error];
if (listeningSocket4 <= 0) { if (listeningSocket4 <= 0) {
return NO; return NO;
@@ -533,7 +523,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
addr6.sin6_len = sizeof(addr6); addr6.sin6_len = sizeof(addr6);
addr6.sin6_family = AF_INET6; addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port); 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]; int listeningSocket6 = [self _createListeningSocket:YES localAddress:&addr6 length:sizeof(addr6) maxPendingConnections:maxPendingConnections error:error];
if (listeningSocket6 <= 0) { if (listeningSocket6 <= 0) {
close(listeningSocket4); close(listeningSocket4);
@@ -565,12 +555,12 @@ static inline NSString* _EncodeBase64(NSString* string) {
_source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES]; _source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES];
_port = port; _port = port;
NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, @""); NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, nil);
NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp"); NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp");
if (bonjourName) { 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) { 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); CFNetServiceSetClient(_registrationService, _NetServiceRegisterCallBack, &context);
CFNetServiceScheduleWithRunLoop(_registrationService, CFRunLoopGetMain(), kCFRunLoopCommonModes); CFNetServiceScheduleWithRunLoop(_registrationService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
@@ -620,19 +610,19 @@ static inline NSString* _EncodeBase64(NSString* string) {
dispatch_source_cancel(_source6); dispatch_source_cancel(_source6);
dispatch_source_cancel(_source4); 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 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; _source6 = NULL;
ARC_DISPATCH_RELEASE(_source4); #if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
dispatch_release(_source4);
#endif
_source4 = NULL; _source4 = NULL;
_port = 0; _port = 0;
ARC_RELEASE(_serverName);
_serverName = nil; _serverName = nil;
ARC_RELEASE(_authenticationRealm);
_authenticationRealm = nil; _authenticationRealm = nil;
ARC_RELEASE(_authenticationBasicAccounts);
_authenticationBasicAccounts = nil; _authenticationBasicAccounts = nil;
ARC_RELEASE(_authenticationDigestAccounts);
_authenticationDigestAccounts = nil; _authenticationDigestAccounts = nil;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
@@ -682,7 +672,6 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![self _start:error]) if (![self _start:error])
#endif #endif
{ {
ARC_RELEASE(_options);
_options = nil; _options = nil;
return NO; return NO;
} }
@@ -714,7 +703,6 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (_source4) { if (_source4) {
[self _stop]; [self _stop];
} }
ARC_RELEASE(_options);
_options = nil; _options = nil;
} else { } else {
GWS_DNOT_REACHED(); GWS_DNOT_REACHED();
@@ -741,7 +729,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (NSURL*)bonjourServerURL { - (NSURL*)bonjourServerURL {
if (_source4 && _resolutionService) { if (_source4 && _resolutionService) {
NSString* name = (ARC_BRIDGE NSString*)CFNetServiceGetTargetHost(_resolutionService); NSString* name = (__bridge NSString*)CFNetServiceGetTargetHost(_resolutionService);
if (name.length) { if (name.length) {
name = [name substringToIndex:(name.length - 1)]; // Strip trailing period at end of domain name = [name substringToIndex:(name.length - 1)]; // Strip trailing period at end of domain
if (_port != 80) { if (_port != 80) {
@@ -813,7 +801,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![requestMethod isEqualToString:method]) { if (![requestMethod isEqualToString:method]) {
return nil; 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]; } asyncProcessBlock:block];
} }
@@ -834,7 +822,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
if ([urlPath caseInsensitiveCompare:path] != NSOrderedSame) { if ([urlPath caseInsensitiveCompare:path] != NSOrderedSame) {
return nil; 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]; } asyncProcessBlock:block];
} else { } 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]; GCDWebServerRequest* request = [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery];
[request setAttribute:captures forKey:GCDWebServerRequestAttribute_RegexCaptures]; [request setAttribute:captures forKey:GCDWebServerRequestAttribute_RegexCaptures];
return ARC_AUTORELEASE(request); return request;
} asyncProcessBlock:block]; } asyncProcessBlock:block];
} else { } 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 { - (void)addGETHandlerForBasePath:(NSString*)basePath directoryPath:(NSString*)directoryPath indexFilename:(NSString*)indexFilename cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests {
if ([basePath hasPrefix:@"/"] && [basePath hasSuffix:@"/"]) { if ([basePath hasPrefix:@"/"] && [basePath hasSuffix:@"/"]) {
#if __has_feature(objc_arc)
GCDWebServer* __unsafe_unretained server = self; GCDWebServer* __unsafe_unretained server = self;
#else
__block GCDWebServer* server = self;
#endif
[self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { [self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) {
if (![requestMethod isEqualToString:@"GET"]) { if (![requestMethod isEqualToString:@"GET"]) {
@@ -952,7 +936,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (![urlPath hasPrefix:basePath]) { if (![urlPath hasPrefix:basePath]) {
return nil; 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) { } processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
@@ -1000,7 +984,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
[XLSharedFacility setMinLogLevel:level]; [XLSharedFacility setMinLogLevel:level];
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__) #elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
GCDWebServerLogLevel = level; GCDWebServerLogLevel = level;
#else #elif defined(__GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__)
GCDWebServerLogLevel = level; GCDWebServerLogLevel = level;
#endif #endif
} }
@@ -1008,28 +992,28 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (void)logVerbose:(NSString*)format, ... { - (void)logVerbose:(NSString*)format, ... {
va_list arguments; va_list arguments;
va_start(arguments, format); 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); va_end(arguments);
} }
- (void)logInfo:(NSString*)format, ... { - (void)logInfo:(NSString*)format, ... {
va_list arguments; va_list arguments;
va_start(arguments, format); 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); va_end(arguments);
} }
- (void)logWarning:(NSString*)format, ... { - (void)logWarning:(NSString*)format, ... {
va_list arguments; va_list arguments;
va_start(arguments, format); 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); va_end(arguments);
} }
- (void)logError:(NSString*)format, ... { - (void)logError:(NSString*)format, ... {
va_list arguments; va_list arguments;
va_start(arguments, format); 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); va_end(arguments);
} }
@@ -1093,7 +1077,6 @@ static CFHTTPMessageRef _CreateHTTPMessageFromPerformingRequest(NSData* inData,
} else { } else {
GWS_DNOT_REACHED(); GWS_DNOT_REACHED();
} }
ARC_RELEASE(outData);
} }
} }
close(httpSocket); close(httpSocket);
@@ -1107,7 +1090,6 @@ static void _LogResult(NSString* format, ...) {
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments]; NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
va_end(arguments); va_end(arguments);
fprintf(stdout, "%s\n", [message UTF8String]); fprintf(stdout, "%s\n", [message UTF8String]);
ARC_RELEASE(message);
} }
- (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path { - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path {
@@ -1130,8 +1112,8 @@ static void _LogResult(NSString* format, ...) {
if (requestData) { if (requestData) {
CFHTTPMessageRef request = _CreateHTTPMessageFromData(requestData, YES); CFHTTPMessageRef request = _CreateHTTPMessageFromData(requestData, YES);
if (request) { if (request) {
NSString* requestMethod = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(request)); NSString* requestMethod = CFBridgingRelease(CFHTTPMessageCopyRequestMethod(request));
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(request)); NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(request));
_LogResult(@"[%i] %@ %@", (int)[index integerValue], requestMethod, requestURL.path); _LogResult(@"[%i] %@ %@", (int)[index integerValue], requestMethod, requestURL.path);
NSString* prefix = [index stringByAppendingString:@"-"]; NSString* prefix = [index stringByAppendingString:@"-"];
for (NSString* responseFile in files) { for (NSString* responseFile in files) {
@@ -1151,8 +1133,8 @@ static void _LogResult(NSString* format, ...) {
success = NO; success = NO;
} }
NSDictionary* expectedHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(expectedResponse)); NSDictionary* expectedHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(expectedResponse));
NSDictionary* actualHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(actualResponse)); NSDictionary* actualHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(actualResponse));
for (NSString* expectedHeader in expectedHeaders) { for (NSString* expectedHeader in expectedHeaders) {
if ([ignoredHeaders containsObject:expectedHeader]) { if ([ignoredHeaders containsObject:expectedHeader]) {
continue; continue;
@@ -1171,10 +1153,10 @@ static void _LogResult(NSString* format, ...) {
} }
} }
NSString* expectedContentLength = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(expectedResponse, CFSTR("Content-Length"))); NSString* expectedContentLength = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(expectedResponse, CFSTR("Content-Length")));
NSData* expectedBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(expectedResponse)); NSData* expectedBody = CFBridgingRelease(CFHTTPMessageCopyBody(expectedResponse));
NSString* actualContentLength = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(actualResponse, CFSTR("Content-Length"))); NSString* actualContentLength = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(actualResponse, CFSTR("Content-Length")));
NSData* actualBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(actualResponse)); 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) 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)]; actualBody = [actualBody subdataWithRange:NSMakeRange(0, expectedBody.length)];
} }
@@ -1191,7 +1173,6 @@ static void _LogResult(NSString* format, ...) {
[task setLaunchPath:@"/usr/bin/opendiff"]; [task setLaunchPath:@"/usr/bin/opendiff"];
[task setArguments:@[expectedPath, actualPath]]; [task setArguments:@[expectedPath, actualPath]];
[task launch]; [task launch];
ARC_RELEASE(task);
} }
} }
#endif #endif

View File

@@ -25,6 +25,10 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#if !__has_feature(objc_arc)
#error GCDWebServer requires ARC
#endif
#import <TargetConditionals.h> #import <TargetConditionals.h>
#import <netdb.h> #import <netdb.h>
#ifdef __GCDWEBSERVER_ENABLE_TESTING__ #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) { 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) @implementation GCDWebServerConnection (Write)
- (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)block { - (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, ^{ 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 [data self]; // Keeps ARC from releasing data too early
#else
[data release];
#endif
}); });
dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t remainingData, int error) { 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 { - (void)_writeHeadersWithCompletionBlock:(WriteHeadersCompletionBlock)block {
GWS_DCHECK(_responseMessage); GWS_DCHECK(_responseMessage);
CFDataRef data = CFHTTPMessageCopySerializedMessage(_responseMessage); CFDataRef data = CFHTTPMessageCopySerializedMessage(_responseMessage);
[self _writeData:(ARC_BRIDGE NSData*)data withCompletionBlock:block]; [self _writeData:(__bridge NSData*)data withCompletionBlock:block];
CFRelease(data); CFRelease(data);
} }
@@ -349,11 +347,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
} }
if (_continueData == nil) { if (_continueData == nil) {
CFHTTPMessageRef message = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 100, NULL, kCFHTTPVersion1_1); CFHTTPMessageRef message = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 100, NULL, kCFHTTPVersion1_1);
#if __has_feature(objc_arc)
_continueData = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(message)); _continueData = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(message));
#else
_continueData = (NSData*)CFHTTPMessageCopySerializedMessage(message);
#endif
CFRelease(message); CFRelease(message);
GWS_DCHECK(_continueData); GWS_DCHECK(_continueData);
} }
@@ -362,7 +356,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
} }
if (_digestAuthenticationNonce == nil) { if (_digestAuthenticationNonce == nil) {
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
_digestAuthenticationNonce = ARC_RETAIN(GCDWebServerComputeMD5Digest(@"%@", ARC_BRIDGE_RELEASE(CFUUIDCreateString(kCFAllocatorDefault, uuid)))); _digestAuthenticationNonce = GCDWebServerComputeMD5Digest(@"%@", CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)));
CFRelease(uuid); CFRelease(uuid);
} }
} }
@@ -376,8 +370,8 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
_statusCode = statusCode; _statusCode = statusCode;
_responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1); _responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close")); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)_server.serverName); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (__bridge CFStringRef)_server.serverName);
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822([NSDate date])); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (__bridge CFStringRef)GCDWebServerFormatRFC822([NSDate date]));
} }
- (void)_startProcessingRequest { - (void)_startProcessingRequest {
@@ -410,36 +404,36 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
if (hasBody && ![response performOpen:&error]) { if (hasBody && ![response performOpen:&error]) {
GWS_LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error); GWS_LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
} else { } else {
_response = ARC_RETAIN(response); _response = response;
} }
} }
if (_response) { if (_response) {
[self _initializeResponseHeadersWithStatusCode:_response.statusCode]; [self _initializeResponseHeadersWithStatusCode:_response.statusCode];
if (_response.lastModifiedDate) { 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) { 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.statusCode >= 200) && (_response.statusCode < 300)) {
if (_response.cacheControlMaxAge > 0) { 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 { } else {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), CFSTR("no-cache")); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), CFSTR("no-cache"));
} }
} }
if (_response.contentType != nil) { 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) { 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) { if (_response.usesChunkedTransferEncoding) {
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Transfer-Encoding"), CFSTR("chunked")); CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Transfer-Encoding"), CFSTR("chunked"));
} }
[_response.additionalHeaders enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) { [_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) { [self _writeHeadersWithCompletionBlock:^(BOOL success) {
@@ -524,7 +518,6 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
} }
}]; }];
ARC_RELEASE(chunkData);
} }
- (void)_readRequestHeaders { - (void)_readRequestHeaders {
@@ -533,23 +526,23 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
[self _readHeaders:headersData withCompletionBlock:^(NSData* extraData) { [self _readHeaders:headersData withCompletionBlock:^(NSData* extraData) {
if (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"]) { if (_server.shouldAutomaticallyMapHEADToGET && [requestMethod isEqualToString:@"HEAD"]) {
requestMethod = @"GET"; requestMethod = @"GET";
_virtualHEAD = YES; _virtualHEAD = YES;
} }
NSDictionary* requestHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones NSDictionary* requestHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(_requestMessage)); NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(_requestMessage));
if (requestURL) { if (requestURL) {
requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders]; requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders];
GWS_DCHECK(requestURL); 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* requestPath = requestURL ? GCDWebServerUnescapeURLString(CFBridgingRelease(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* 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) : @{}; NSDictionary* requestQuery = queryString ? GCDWebServerParseURLEncodedForm(queryString) : @{};
if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) { if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) {
for (_handler in _server.handlers) { 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) { if (_request) {
break; 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 { - (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket {
if ((self = [super init])) { if ((self = [super init])) {
_server = ARC_RETAIN(server); _server = server;
_localAddress = ARC_RETAIN(localAddress); _localAddress = localAddress;
_remoteAddress = ARC_RETAIN(remoteAddress); _remoteAddress = remoteAddress;
_socket = socket; _socket = socket;
GWS_LOG_DEBUG(@"Did open connection on socket %i", _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]) { if (![self open]) {
close(_socket); close(_socket);
ARC_RELEASE(self);
return nil; return nil;
} }
_opened = YES; _opened = YES;
@@ -650,26 +641,14 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
} }
[_server didEndConnection:self]; [_server didEndConnection:self];
ARC_RELEASE(_server);
ARC_RELEASE(_localAddress);
ARC_RELEASE(_remoteAddress);
if (_requestMessage) { if (_requestMessage) {
CFRelease(_requestMessage); CFRelease(_requestMessage);
} }
ARC_RELEASE(_request);
if (_responseMessage) { if (_responseMessage) {
CFRelease(_responseMessage); CFRelease(_responseMessage);
} }
ARC_RELEASE(_response);
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
ARC_RELEASE(_requestPath);
ARC_RELEASE(_responsePath);
#endif
ARC_DEALLOC(super);
} }
@end @end
@@ -681,11 +660,11 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
if (_server.recordingEnabled) { if (_server.recordingEnabled) {
_connectionIndex = OSAtomicIncrement32(&_connectionCounter); _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); _requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
GWS_DCHECK(_requestFD > 0); 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); _responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
GWS_DCHECK(_responseFD > 0); GWS_DCHECK(_responseFD > 0);
} }

View File

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

View File

@@ -28,35 +28,6 @@
#import <os/object.h> #import <os/object.h>
#import <sys/socket.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. * All GCDWebServer headers.
*/ */
@@ -77,15 +48,28 @@
#import "GCDWebServerFileResponse.h" #import "GCDWebServerFileResponse.h"
#import "GCDWebServerStreamedResponse.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 * Automatically detect if XLFacility is available and if so use it as a
* logging facility. * logging facility.
*/ */
#if defined(__has_include) && __has_include("XLFacilityMacros.h") #elif defined(__has_include) && __has_include("XLFacilityMacros.h")
#define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__ #define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__
#undef XLOG_TAG
#define XLOG_TAG @"gcdwebserver.internal"
#import "XLFacilityMacros.h" #import "XLFacilityMacros.h"
#define GWS_LOG_DEBUG(...) XLOG_DEBUG(__VA_ARGS__) #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_ERROR(...) DDLogError(__VA_ARGS__)
#define GWS_LOG_EXCEPTION(__EXCEPTION__) DDLogError(@"%@", __EXCEPTION__) #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 * If all of the above fail, then use GCDWebServer built-in
* logging facility. * logging facility.
@@ -145,7 +119,7 @@ typedef NS_ENUM(int, GCDWebServerLoggingLevel) {
kGCDWebServerLoggingLevel_Info, kGCDWebServerLoggingLevel_Info,
kGCDWebServerLoggingLevel_Warning, kGCDWebServerLoggingLevel_Warning,
kGCDWebServerLoggingLevel_Error, kGCDWebServerLoggingLevel_Error,
kGCDWebServerLoggingLevel_Exception, kGCDWebServerLoggingLevel_Exception
}; };
extern GCDWebServerLoggingLevel GCDWebServerLogLevel; extern GCDWebServerLoggingLevel GCDWebServerLogLevel;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -178,6 +178,17 @@ function _reload(path) {
$(document).ready(function() { $(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({ $("#fileupload").fileupload({
dropZone: $(document), dropZone: $(document),
pasteZone: null, pasteZone: null,

View File

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

View File

@@ -141,9 +141,10 @@ int main(int argc, const char* argv[]) {
NSString* authenticationRealm = nil; NSString* authenticationRealm = nil;
NSString* authenticationUser = nil; NSString* authenticationUser = nil;
NSString* authenticationPassword = nil; NSString* authenticationPassword = nil;
BOOL bindToLocalhost = NO;
if (argc == 1) { 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 { } else {
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (argv[i][0] != '-') { if (argv[i][0] != '-') {
@@ -188,6 +189,8 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[i], "-authenticationPassword") && (i + 1 < argc)) { } else if (!strcmp(argv[i], "-authenticationPassword") && (i + 1 < argc)) {
++i; ++i;
authenticationPassword = [NSString stringWithUTF8String:argv[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"); fprintf(stdout, "Running in Async Response mode");
webServer = [[GCDWebServer alloc] init]; webServer = [[GCDWebServer alloc] init];
[webServer addHandlerForMethod:@"GET" [webServer addHandlerForMethod:@"GET"
path:@"/" path:@"/async"
requestClass:[GCDWebServerRequest class] requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
@@ -363,16 +366,34 @@ int main(int argc, const char* argv[]) {
completionBlock(response); 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; break;
} }
} }
#if __has_feature(objc_arc)
fprintf(stdout, " (ARC is ON)\n");
#else
fprintf(stdout, " (ARC is OFF)\n");
#endif
if (webServer) { if (webServer) {
Delegate* delegate = [[Delegate alloc] init]; Delegate* delegate = [[Delegate alloc] init];
@@ -391,6 +412,7 @@ int main(int argc, const char* argv[]) {
fprintf(stdout, "\n"); fprintf(stdout, "\n");
NSMutableDictionary* options = [NSMutableDictionary dictionary]; NSMutableDictionary* options = [NSMutableDictionary dictionary];
[options setObject:@8080 forKey:GCDWebServerOption_Port]; [options setObject:@8080 forKey:GCDWebServerOption_Port];
[options setObject:@(bindToLocalhost) forKey:GCDWebServerOption_BindToLocalhost];
[options setObject:@"" forKey:GCDWebServerOption_BonjourName]; [options setObject:@"" forKey:GCDWebServerOption_BonjourName];
if (authenticationUser && authenticationPassword) { if (authenticationUser && authenticationPassword) {
[options setValue:authenticationRealm forKey:GCDWebServerOption_AuthenticationRealm]; [options setValue:authenticationRealm forKey:GCDWebServerOption_AuthenticationRealm];
@@ -406,10 +428,6 @@ int main(int argc, const char* argv[]) {
} }
} }
webServer.delegate = nil; webServer.delegate = nil;
#if !__has_feature(objc_arc)
[delegate release];
[webServer release];
#endif
} }
} }
return result; return result;

View File

@@ -6,8 +6,6 @@ Overview
[![Platform](http://cocoapod-badges.herokuapp.com/p/GCDWebServer/badge.png)](https://github.com/swisspol/GCDWebServer) [![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) [![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: 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) * 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 * 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: Requirements:
* OS X 10.7 or later (x86_64) * OS X 10.7 or later (x86_64)
* iOS 5.0 or later (armv7, armv7s or arm64) * 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 Getting Started
=============== ===============
@@ -187,24 +186,25 @@ New in GCDWebServer 3.0 is the ability to process HTTP requests aysnchronously i
```objectivec ```objectivec
[webServer addDefaultHandlerForMethod:@"GET" [webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class] 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) { 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), ^{ 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 NSString* string = contents.firstObject;
if (string) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [contents removeObjectAtIndex:0];
completionBlock([@"World</p></body></html>" dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 2nd part of the stream data 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 completionBlock([NSData data], nil); // Must pass an empty NSData to signal the end of the stream
}); }
}); });
}]; }];
return response; return response;
}]; }];
``` ```

View File

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

View File

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