mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-02-11 00:00:07 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a6786488a | ||
|
|
472c7855a7 | ||
|
|
2fdeb9581c | ||
|
|
c4310fcdf4 | ||
|
|
33645d3c6b | ||
|
|
3618dcac7e | ||
|
|
432e3826c9 | ||
|
|
4e31508195 | ||
|
|
628f6673b0 | ||
|
|
1944cd8a6e | ||
|
|
d2001e38ca | ||
|
|
18889793b7 | ||
|
|
14d538b0fb | ||
|
|
3b7198b4cc | ||
|
|
abb891334a | ||
|
|
059f5c8d01 | ||
|
|
9d9546bb6d | ||
|
|
2ff05b1aa0 | ||
|
|
bf2c9a170d | ||
|
|
15caa9cd20 | ||
|
|
32ba49ae34 |
@@ -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)
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
86
GCDWebServer.xcodeproj/xcshareddata/xcschemes/Bot.xcscheme
Normal file
86
GCDWebServer.xcodeproj/xcshareddata/xcschemes/Bot.xcscheme
Normal 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>
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:¶meter];
|
[scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:¶meter];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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__
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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…
|
<span class="glyphicon glyphicon-upload"></span> Upload Files…
|
||||||
<input id="fileupload" type="file" name="files[]" multiple>
|
<input id="fileupload" type="file" name="files[]" multiple>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
40
Mac/main.m
40
Mac/main.m
@@ -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;
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -6,8 +6,6 @@ Overview
|
|||||||
[](https://github.com/swisspol/GCDWebServer)
|
[](https://github.com/swisspol/GCDWebServer)
|
||||||
[](LICENSE)
|
[](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;
|
||||||
|
|
||||||
}];
|
}];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
74
Run-Tests.sh
74
Run-Tests.sh
@@ -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!"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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];
|
||||||
|
|||||||
Reference in New Issue
Block a user