You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sh...@apache.org on 2016/07/25 07:57:31 UTC
[45/57] [abbrv] cordova-plugins git commit: Squashed
'local-webserver/src/ios/GCDWebServer/' changes from 15caa9c..55104e5
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme
----------------------------------------------------------------------
diff --git a/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme b/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme
new file mode 100644
index 0000000..b905059
--- /dev/null
+++ b/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0720"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "NO"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CD01AE004D800F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (Mac)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E24039241BA09207000B7089"
+ BuildableName = "Tests.xctest"
+ BlueprintName = "Tests (Mac)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CD01AE004D800F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (Mac)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CD01AE004D800F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (Mac)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (iOS).xcscheme
----------------------------------------------------------------------
diff --git a/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (iOS).xcscheme b/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (iOS).xcscheme
new file mode 100644
index 0000000..73e3e0a
--- /dev/null
+++ b/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (iOS).xcscheme
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0720"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "NO"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CEE1AE0051F00F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (iOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CEE1AE0051F00F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (iOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CEE1AE0051F00F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (iOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "CEE28CEE1AE0051F00F4023C"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (iOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (tvOS).xcscheme
----------------------------------------------------------------------
diff --git a/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (tvOS).xcscheme b/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (tvOS).xcscheme
new file mode 100644
index 0000000..920fa99
--- /dev/null
+++ b/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (tvOS).xcscheme
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0720"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "NO"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E2DDD18A1BE69404002CE867"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (tvOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E2DDD18A1BE69404002CE867"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (tvOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E2DDD18A1BE69404002CE867"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (tvOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E2DDD18A1BE69404002CE867"
+ BuildableName = "GCDWebServers.framework"
+ BlueprintName = "GCDWebServers (tvOS)"
+ ReferencedContainer = "container:GCDWebServer.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServer.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServer.h b/GCDWebServer/Core/GCDWebServer.h
index ff414c9..b4afb4c 100644
--- a/GCDWebServer/Core/GCDWebServer.h
+++ b/GCDWebServer/Core/GCDWebServer.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,7 @@ typedef GCDWebServerRequest* (^GCDWebServerMatchBlock)(NSString* requestMethod,
* recommended to return a GCDWebServerErrorResponse on error so more useful
* information can be returned to the client.
*/
-typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* request);
+typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(__kindof GCDWebServerRequest* request);
/**
* The GCDWebServerAsynchronousProcessBlock works like the GCDWebServerProcessBlock
@@ -65,7 +65,7 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r
* useful information can be returned to the client.
*/
typedef void (^GCDWebServerCompletionBlock)(GCDWebServerResponse* response);
-typedef void (^GCDWebServerAsyncProcessBlock)(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock);
+typedef void (^GCDWebServerAsyncProcessBlock)(__kindof GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock);
/**
* The port used by the GCDWebServer (NSNumber / NSUInteger).
@@ -79,7 +79,7 @@ extern NSString* const GCDWebServerOption_Port;
* the name will automatically take the value of the GCDWebServerOption_ServerName
* option. If this option is set to nil, Bonjour will be disabled.
*
- * The default value is an empty string.
+ * The default value is nil.
*/
extern NSString* const GCDWebServerOption_BonjourName;
@@ -91,6 +91,29 @@ extern NSString* const GCDWebServerOption_BonjourName;
extern NSString* const GCDWebServerOption_BonjourType;
/**
+ * Request a port mapping in the NAT gateway (NSNumber / BOOL).
+ *
+ * This uses the DNSService API under the hood which supports IPv4 mappings only.
+ *
+ * The default value is NO.
+ *
+ * @warning The external port set up by the NAT gateway may be different than
+ * the one used by the GCDWebServer.
+ */
+extern NSString* const GCDWebServerOption_RequestNATPortMapping;
+
+/**
+ * Only accept HTTP requests coming from localhost i.e. not from the outside
+ * network (NSNumber / BOOL).
+ *
+ * The default value is NO.
+ *
+ * @warning Bonjour and NAT port mapping should be disabled if using this option
+ * since the server will not be reachable from the outside network anyway.
+ */
+extern NSString* const GCDWebServerOption_BindToLocalhost;
+
+/**
* The maximum number of incoming HTTP requests that can be queued waiting to
* be handled before new ones are dropped (NSNumber / NSUInteger).
*
@@ -202,10 +225,22 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
/**
* This method is called after the Bonjour registration for the server has
* successfully completed.
+ *
+ * Use the "bonjourServerURL" property to retrieve the Bonjour address of the
+ * server.
*/
- (void)webServerDidCompleteBonjourRegistration:(GCDWebServer*)server;
/**
+ * This method is called after the NAT port mapping for the server has been
+ * updated.
+ *
+ * Use the "publicServerURL" property to retrieve the public address of the
+ * server.
+ */
+- (void)webServerDidUpdateNATPortMapping:(GCDWebServer*)server;
+
+/**
* This method is called when the first GCDWebServerConnection is opened by the
* server to serve a series of HTTP requests.
*
@@ -352,6 +387,14 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
@property(nonatomic, readonly) NSURL* bonjourServerURL;
/**
+ * Returns the server's public URL.
+ *
+ * @warning This property is only valid if the server is running and NAT port
+ * mapping is active.
+ */
+@property(nonatomic, readonly) NSURL* publicServerURL;
+
+/**
* Starts the server on port 8080 (OS X & iOS Simulator) or port 80 (iOS)
* using the default Bonjour name.
*
@@ -512,6 +555,14 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
*
* @warning The interpretation of the "level" argument depends on the logging
* facility used at compile time.
+ *
+ * If using the built-in logging facility, the log levels are as follow:
+ * DEBUG = 0
+ * VERBOSE = 1
+ * INFO = 2
+ * WARNING = 3
+ * ERROR = 4
+ * EXCEPTION = 5
*/
+ (void)setLogLevel:(int)level;
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServer.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServer.m b/GCDWebServer/Core/GCDWebServer.m
index 852a9db..815fab3 100644
--- a/GCDWebServer/Core/GCDWebServer.m
+++ b/GCDWebServer/Core/GCDWebServer.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@
#endif
#endif
#import <netinet/in.h>
+#import <dns_sd.h>
#import "GCDWebServerPrivate.h"
@@ -47,9 +48,13 @@
#define kDefaultPort 8080
#endif
+#define kBonjourResolutionTimeout 5.0
+
NSString* const GCDWebServerOption_Port = @"Port";
NSString* const GCDWebServerOption_BonjourName = @"BonjourName";
NSString* const GCDWebServerOption_BonjourType = @"BonjourType";
+NSString* const GCDWebServerOption_RequestNATPortMapping = @"RequestNATPortMapping";
+NSString* const GCDWebServerOption_BindToLocalhost = @"BindToLocalhost";
NSString* const GCDWebServerOption_MaxPendingConnections = @"MaxPendingConnections";
NSString* const GCDWebServerOption_ServerName = @"ServerName";
NSString* const GCDWebServerOption_AuthenticationMethod = @"AuthenticationMethod";
@@ -73,9 +78,9 @@ GCDWebServerLoggingLevel GCDWebServerLogLevel = kGCDWebServerLoggingLevel_Info;
#endif
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
#if DEBUG
-int GCDWebServerLogLevel = LOG_LEVEL_DEBUG;
+DDLogLevel GCDWebServerLogLevel = DDLogLevelDebug;
#else
-int GCDWebServerLogLevel = LOG_LEVEL_INFO;
+DDLogLevel GCDWebServerLogLevel = DDLogLevelInfo;
#endif
#endif
@@ -170,6 +175,12 @@ static void _ExecuteMainThreadRunLoopSources() {
dispatch_source_t _source6;
CFNetServiceRef _registrationService;
CFNetServiceRef _resolutionService;
+ DNSServiceRef _dnsService;
+ CFSocketRef _dnsSocket;
+ CFRunLoopSourceRef _dnsSource;
+ NSString* _dnsAddress;
+ NSUInteger _dnsPort;
+ BOOL _bindToLocalhost;
#if TARGET_OS_IPHONE
BOOL _suspendInBackground;
UIBackgroundTaskIdentifier _backgroundTask;
@@ -242,7 +253,9 @@ static void _ExecuteMainThreadRunLoopSources() {
GWS_LOG_DEBUG(@"Did connect");
#if TARGET_OS_IPHONE
- [self _startBackgroundTask];
+ if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) {
+ [self _startBackgroundTask];
+ }
#endif
if ([_delegate respondsToSelector:@selector(webServerDidConnect:)]) {
@@ -283,8 +296,6 @@ static void _ExecuteMainThreadRunLoopSources() {
[[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
_backgroundTask = UIBackgroundTaskInvalid;
GWS_LOG_DEBUG(@"Did end background task");
- } else {
- GWS_DNOT_REACHED();
}
}
@@ -367,7 +378,10 @@ static void _NetServiceRegisterCallBack(CFNetServiceRef service, CFStreamError*
} else {
GCDWebServer* server = (__bridge GCDWebServer*)info;
GWS_LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]);
- CFNetServiceResolveWithTimeout(server->_resolutionService, 1.0, NULL);
+ if (!CFNetServiceResolveWithTimeout(server->_resolutionService, kBonjourResolutionTimeout, NULL)) {
+ GWS_LOG_ERROR(@"Failed starting Bonjour resolution");
+ GWS_DNOT_REACHED();
+ }
}
}
}
@@ -381,7 +395,7 @@ static void _NetServiceResolveCallBack(CFNetServiceRef service, CFStreamError* e
}
} else {
GCDWebServer* server = (__bridge GCDWebServer*)info;
- GWS_LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL);
+ GWS_LOG_INFO(@"%@ now locally reachable at %@", [server class], server.bonjourServerURL);
if ([server.delegate respondsToSelector:@selector(webServerDidCompleteBonjourRegistration:)]) {
[server.delegate webServerDidCompleteBonjourRegistration:server];
}
@@ -389,6 +403,41 @@ static void _NetServiceResolveCallBack(CFNetServiceRef service, CFStreamError* e
}
}
+static void _DNSServiceCallBack(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, uint32_t externalAddress, DNSServiceProtocol protocol, uint16_t internalPort, uint16_t externalPort, uint32_t ttl, void* context) {
+ GWS_DCHECK([NSThread isMainThread]);
+ @autoreleasepool {
+ GCDWebServer* server = (__bridge GCDWebServer*)context;
+ if ((errorCode == kDNSServiceErr_NoError) || (errorCode == kDNSServiceErr_DoubleNAT)) {
+ struct sockaddr_in addr4;
+ bzero(&addr4, sizeof(addr4));
+ addr4.sin_len = sizeof(addr4);
+ addr4.sin_family = AF_INET;
+ addr4.sin_addr.s_addr = externalAddress; // Already in network byte order
+ server->_dnsAddress = GCDWebServerStringFromSockAddr((const struct sockaddr*)&addr4, NO);
+ server->_dnsPort = ntohs(externalPort);
+ GWS_LOG_INFO(@"%@ now publicly reachable at %@", [server class], server.publicServerURL);
+ } else {
+ GWS_LOG_ERROR(@"DNS service error %i", errorCode);
+ server->_dnsAddress = nil;
+ server->_dnsPort = 0;
+ }
+ if ([server.delegate respondsToSelector:@selector(webServerDidUpdateNATPortMapping:)]) {
+ [server.delegate webServerDidUpdateNATPortMapping:server];
+ }
+ }
+}
+
+static void _SocketCallBack(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void* data, void* info) {
+ GWS_DCHECK([NSThread isMainThread]);
+ @autoreleasepool {
+ GCDWebServer* server = (__bridge GCDWebServer*)info;
+ DNSServiceErrorType status = DNSServiceProcessResult(server->_dnsService);
+ if (status != kDNSServiceErr_NoError) {
+ GWS_LOG_ERROR(@"DNS service error %i", status);
+ }
+ }
+}
+
static inline id _GetOption(NSDictionary* options, NSString* key, id defaultValue) {
id value = [options objectForKey:key];
return value ? value : defaultValue;
@@ -461,18 +510,18 @@ static inline NSString* _EncodeBase64(NSString* string) {
dispatch_source_set_event_handler(source, ^{
@autoreleasepool {
- struct sockaddr remoteSockAddr;
+ struct sockaddr_storage remoteSockAddr;
socklen_t remoteAddrLen = sizeof(remoteSockAddr);
- int socket = accept(listeningSocket, &remoteSockAddr, &remoteAddrLen);
+ int socket = accept(listeningSocket, (struct sockaddr*)&remoteSockAddr, &remoteAddrLen);
if (socket > 0) {
NSData* remoteAddress = [NSData dataWithBytes:&remoteSockAddr length:remoteAddrLen];
- struct sockaddr localSockAddr;
+ struct sockaddr_storage localSockAddr;
socklen_t localAddrLen = sizeof(localSockAddr);
NSData* localAddress = nil;
- if (getsockname(socket, &localSockAddr, &localAddrLen) == 0) {
+ if (getsockname(socket, (struct sockaddr*)&localSockAddr, &localAddrLen) == 0) {
localAddress = [NSData dataWithBytes:&localSockAddr length:localAddrLen];
- GWS_DCHECK((!isIPv6 && localSockAddr.sa_family == AF_INET) || (isIPv6 && localSockAddr.sa_family == AF_INET6));
+ GWS_DCHECK((!isIPv6 && localSockAddr.ss_family == AF_INET) || (isIPv6 && localSockAddr.ss_family == AF_INET6));
} else {
GWS_DNOT_REACHED();
}
@@ -495,6 +544,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
GWS_DCHECK(_source4 == NULL);
NSUInteger port = [_GetOption(_options, GCDWebServerOption_Port, @0) unsignedIntegerValue];
+ BOOL bindToLocalhost = [_GetOption(_options, GCDWebServerOption_BindToLocalhost, @NO) boolValue];
NSUInteger maxPendingConnections = [_GetOption(_options, GCDWebServerOption_MaxPendingConnections, @16) unsignedIntegerValue];
struct sockaddr_in addr4;
@@ -502,17 +552,16 @@ static inline NSString* _EncodeBase64(NSString* string) {
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = htons(port);
- addr4.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr4.sin_addr.s_addr = bindToLocalhost ? htonl(INADDR_LOOPBACK) : htonl(INADDR_ANY);
int listeningSocket4 = [self _createListeningSocket:NO localAddress:&addr4 length:sizeof(addr4) maxPendingConnections:maxPendingConnections error:error];
if (listeningSocket4 <= 0) {
return NO;
}
if (port == 0) {
- struct sockaddr addr;
+ struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
- if (getsockname(listeningSocket4, &addr, &addrlen) == 0) {
- struct sockaddr_in* sockaddr = (struct sockaddr_in*)&addr;
- port = ntohs(sockaddr->sin_port);
+ if (getsockname(listeningSocket4, (struct sockaddr*)&addr, &addrlen) == 0) {
+ port = ntohs(addr.sin_port);
} else {
GWS_LOG_ERROR(@"Failed retrieving socket address: %s (%i)", strerror(errno), errno);
}
@@ -523,7 +572,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
addr6.sin6_len = sizeof(addr6);
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
- addr6.sin6_addr = in6addr_any;
+ addr6.sin6_addr = bindToLocalhost ? in6addr_loopback : in6addr_any;
int listeningSocket6 = [self _createListeningSocket:YES localAddress:&addr6 length:sizeof(addr6) maxPendingConnections:maxPendingConnections error:error];
if (listeningSocket6 <= 0) {
close(listeningSocket4);
@@ -554,8 +603,9 @@ static inline NSString* _EncodeBase64(NSString* string) {
_source4 = [self _createDispatchSourceWithListeningSocket:listeningSocket4 isIPv6:NO];
_source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES];
_port = port;
+ _bindToLocalhost = bindToLocalhost;
- NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, @"");
+ NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, nil);
NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp");
if (bonjourName) {
_registrationService = CFNetServiceCreate(kCFAllocatorDefault, CFSTR("local."), (__bridge CFStringRef)bonjourType, (__bridge CFStringRef)(bonjourName.length ? bonjourName : _serverName), (SInt32)_port);
@@ -571,9 +621,34 @@ static inline NSString* _EncodeBase64(NSString* string) {
if (_resolutionService) {
CFNetServiceSetClient(_resolutionService, _NetServiceResolveCallBack, &context);
CFNetServiceScheduleWithRunLoop(_resolutionService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+ } else {
+ GWS_LOG_ERROR(@"Failed creating CFNetService for resolution");
}
} else {
- GWS_LOG_ERROR(@"Failed creating CFNetService");
+ GWS_LOG_ERROR(@"Failed creating CFNetService for registration");
+ }
+ }
+
+ if ([_GetOption(_options, GCDWebServerOption_RequestNATPortMapping, @NO) boolValue]) {
+ DNSServiceErrorType status = DNSServiceNATPortMappingCreate(&_dnsService, 0, 0, kDNSServiceProtocol_TCP, htons(port), htons(port), 0, _DNSServiceCallBack, (__bridge void*)self);
+ if (status == kDNSServiceErr_NoError) {
+ CFSocketContext context = {0, (__bridge void*)self, NULL, NULL, NULL};
+ _dnsSocket = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(_dnsService), kCFSocketReadCallBack, _SocketCallBack, &context);
+ if (_dnsSocket) {
+ CFSocketSetSocketFlags(_dnsSocket, CFSocketGetSocketFlags(_dnsSocket) & ~kCFSocketCloseOnInvalidate);
+ _dnsSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _dnsSocket, 0);
+ if (_dnsSource) {
+ CFRunLoopAddSource(CFRunLoopGetMain(), _dnsSource, kCFRunLoopCommonModes);
+ } else {
+ GWS_LOG_ERROR(@"Failed creating CFRunLoopSource");
+ GWS_DNOT_REACHED();
+ }
+ } else {
+ GWS_LOG_ERROR(@"Failed creating CFSocket");
+ GWS_DNOT_REACHED();
+ }
+ } else {
+ GWS_LOG_ERROR(@"Failed creating NAT port mapping (%i)", status);
}
}
@@ -592,6 +667,22 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (void)_stop {
GWS_DCHECK(_source4 != NULL);
+ if (_dnsService) {
+ _dnsAddress = nil;
+ _dnsPort = 0;
+ if (_dnsSource) {
+ CFRunLoopSourceInvalidate(_dnsSource);
+ CFRelease(_dnsSource);
+ _dnsSource = NULL;
+ }
+ if (_dnsSocket) {
+ CFRelease(_dnsSocket);
+ _dnsSocket = NULL;
+ }
+ DNSServiceRefDeallocate(_dnsService);
+ _dnsService = NULL;
+ }
+
if (_registrationService) {
if (_resolutionService) {
CFNetServiceUnscheduleFromRunLoop(_resolutionService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
@@ -619,6 +710,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
#endif
_source4 = NULL;
_port = 0;
+ _bindToLocalhost = NO;
_serverName = nil;
_authenticationRealm = nil;
@@ -664,7 +756,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (BOOL)startWithOptions:(NSDictionary*)options error:(NSError**)error {
if (_options == nil) {
- _options = [options copy];
+ _options = options ? [options copy] : @{};
#if TARGET_OS_IPHONE
_suspendInBackground = [_GetOption(_options, GCDWebServerOption_AutomaticallySuspendInBackground, @YES) boolValue];
if (((_suspendInBackground == NO) || ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground)) && ![self _start:error])
@@ -715,7 +807,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
- (NSURL*)serverURL {
if (_source4) {
- NSString* ipAddress = GCDWebServerGetPrimaryIPAddress(NO); // We can't really use IPv6 anyway as it doesn't work great with HTTP URLs in practice
+ NSString* ipAddress = _bindToLocalhost ? @"localhost" : GCDWebServerGetPrimaryIPAddress(NO); // We can't really use IPv6 anyway as it doesn't work great with HTTP URLs in practice
if (ipAddress) {
if (_port != 80) {
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%i/", ipAddress, (int)_port]];
@@ -742,6 +834,17 @@ static inline NSString* _EncodeBase64(NSString* string) {
return nil;
}
+- (NSURL*)publicServerURL {
+ if (_source4 && _dnsService && _dnsAddress && _dnsPort) {
+ if (_dnsPort != 80) {
+ return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%i/", _dnsAddress, (int)_dnsPort]];
+ } else {
+ return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/", _dnsAddress]];
+ }
+ }
+ return nil;
+}
+
- (BOOL)start {
return [self startWithPort:kDefaultPort bonjourName:@""];
}
@@ -854,7 +957,12 @@ static inline NSString* _EncodeBase64(NSString* string) {
for (NSTextCheckingResult* result in matches) {
// Start at 1; index 0 is the whole string
for (NSUInteger i = 1; i < result.numberOfRanges; i++) {
- [captures addObject:[urlPath substringWithRange:[result rangeAtIndex:i]]];
+ NSRange range = [result rangeAtIndex:i];
+ // range is {NSNotFound, 0} "if one of the capture groups did not participate in this particular match"
+ // see discussion in -[NSRegularExpression firstMatchInString:options:range:]
+ if (range.location != NSNotFound) {
+ [captures addObject:[urlPath substringWithRange:range]];
+ }
}
}
@@ -910,7 +1018,10 @@ static inline NSString* _EncodeBase64(NSString* string) {
for (NSString* file in enumerator) {
if (![file hasPrefix:@"."]) {
NSString* type = [[enumerator fileAttributes] objectForKey:NSFileType];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSString* escapedFile = [file stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+#pragma clang diagnostic pop
GWS_DCHECK(escapedFile);
if ([type isEqualToString:NSFileTypeRegular]) {
[html appendFormat:@"<li><a href=\"%@\">%@</a></li>\n", escapedFile, file];
@@ -984,7 +1095,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
[XLSharedFacility setMinLogLevel:level];
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
GCDWebServerLogLevel = level;
-#else
+#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__)
GCDWebServerLogLevel = level;
#endif
}
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerConnection.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerConnection.h b/GCDWebServer/Core/GCDWebServerConnection.h
index 8e4aaf5..d353c8b 100644
--- a/GCDWebServer/Core/GCDWebServerConnection.h
+++ b/GCDWebServer/Core/GCDWebServerConnection.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerConnection.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerConnection.m b/GCDWebServer/Core/GCDWebServerConnection.m
index d4e3f39..d6c369e 100644
--- a/GCDWebServer/Core/GCDWebServerConnection.m
+++ b/GCDWebServer/Core/GCDWebServerConnection.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -548,6 +548,8 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
}
}
if (_request) {
+ _request.localAddressData = self.localAddressData;
+ _request.remoteAddressData = self.remoteAddressData;
if ([_request hasBody]) {
[_request prepareForWriting];
if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) {
@@ -757,22 +759,26 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
- (void)processRequest:(GCDWebServerRequest*)request completion:(GCDWebServerCompletionBlock)completion {
GWS_LOG_DEBUG(@"Connection on socket %i processing request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
@try {
- _handler.asyncProcessBlock(request, completion);
+ _handler.asyncProcessBlock(request, [completion copy]);
}
@catch (NSException* exception) {
GWS_LOG_EXCEPTION(exception);
}
}
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
static inline BOOL _CompareResources(NSString* responseETag, NSString* requestETag, NSDate* responseLastModified, NSDate* requestLastModified) {
- if ([requestETag isEqualToString:@"*"] && (!responseLastModified || !requestLastModified || ([responseLastModified compare:requestLastModified] != NSOrderedDescending))) {
- return YES;
- } else {
- if ([responseETag isEqualToString:requestETag]) {
+ if (requestLastModified && responseLastModified) {
+ if ([responseLastModified compare:requestLastModified] != NSOrderedDescending) {
+ return YES;
+ }
+ }
+ if (requestETag && responseETag) { // Per the specs "If-None-Match" must be checked after "If-Modified-Since"
+ if ([requestETag isEqualToString:@"*"]) {
return YES;
}
- if (responseLastModified && requestLastModified && ([responseLastModified compare:requestLastModified] != NSOrderedDescending)) {
+ if ([responseETag isEqualToString:requestETag]) {
return YES;
}
}
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerFunctions.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerFunctions.h b/GCDWebServer/Core/GCDWebServerFunctions.h
index a8b2857..e5be05c 100644
--- a/GCDWebServer/Core/GCDWebServerFunctions.h
+++ b/GCDWebServer/Core/GCDWebServerFunctions.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerFunctions.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerFunctions.m b/GCDWebServer/Core/GCDWebServerFunctions.m
index d81af0b..25e41ca 100644
--- a/GCDWebServer/Core/GCDWebServerFunctions.m
+++ b/GCDWebServer/Core/GCDWebServerFunctions.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -182,11 +182,17 @@ NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
}
NSString* GCDWebServerEscapeURLString(NSString* string) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
+#pragma clang diagnostic pop
}
NSString* GCDWebServerUnescapeURLString(NSString* string) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
+#pragma clang diagnostic pop
}
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
@@ -240,7 +246,7 @@ NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOOL inclu
NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6) {
NSString* address = nil;
#if TARGET_OS_IPHONE
-#if !TARGET_IPHONE_SIMULATOR
+#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_TV
const char* primaryInterface = "en0"; // WiFi interface on iOS
#endif
#else
@@ -261,8 +267,10 @@ NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6) {
struct ifaddrs* list;
if (getifaddrs(&list) >= 0) {
for (struct ifaddrs* ifap = list; ifap; ifap = ifap->ifa_next) {
-#if TARGET_IPHONE_SIMULATOR
- if (strcmp(ifap->ifa_name, "en0") && strcmp(ifap->ifa_name, "en1")) // Assume en0 is Ethernet and en1 is WiFi since there is no way to use SystemConfiguration framework in iOS Simulator
+#if TARGET_IPHONE_SIMULATOR || TARGET_OS_TV
+ // Assume en0 is Ethernet and en1 is WiFi since there is no way to use SystemConfiguration framework in iOS Simulator
+ // Assumption holds for Apple TV running tvOS
+ if (strcmp(ifap->ifa_name, "en0") && strcmp(ifap->ifa_name, "en1"))
#else
if (strcmp(ifap->ifa_name, primaryInterface))
#endif
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h b/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
index 7af51a2..6e98381 100644
--- a/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
+++ b/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerPrivate.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerPrivate.h b/GCDWebServer/Core/GCDWebServerPrivate.h
index 1ed54e8..c9c6868 100644
--- a/GCDWebServer/Core/GCDWebServerPrivate.h
+++ b/GCDWebServer/Core/GCDWebServerPrivate.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -49,11 +49,21 @@
#import "GCDWebServerStreamedResponse.h"
/**
+ * Check if a custom logging facility should be used instead.
+ */
+
+#if defined(__GCDWEBSERVER_LOGGING_HEADER__)
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
+
+#import __GCDWEBSERVER_LOGGING_HEADER__
+
+/**
* Automatically detect if XLFacility is available and if so use it as a
* logging facility.
*/
-#if defined(__has_include) && __has_include("XLFacilityMacros.h")
+#elif defined(__has_include) && __has_include("XLFacilityMacros.h")
#define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__
@@ -77,15 +87,15 @@
* it as a logging facility.
*/
-#elif defined(__has_include) && __has_include("DDLogMacros.h")
+#elif defined(__has_include) && __has_include("CocoaLumberjack/CocoaLumberjack.h")
-#import "DDLogMacros.h"
+#import <CocoaLumberjack/CocoaLumberjack.h>
#define __GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__
#undef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF GCDWebServerLogLevel
-extern int GCDWebServerLogLevel;
+extern DDLogLevel GCDWebServerLogLevel;
#define GWS_LOG_DEBUG(...) DDLogDebug(__VA_ARGS__)
#define GWS_LOG_VERBOSE(...) DDLogVerbose(__VA_ARGS__)
@@ -95,16 +105,6 @@ extern int GCDWebServerLogLevel;
#define GWS_LOG_EXCEPTION(__EXCEPTION__) DDLogError(@"%@", __EXCEPTION__)
/**
- * Check if a custom logging facility should be used instead.
- */
-
-#elif defined(__GCDWEBSERVER_LOGGING_HEADER__)
-
-#define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
-
-#import __GCDWEBSERVER_LOGGING_HEADER__
-
-/**
* If all of the above fail, then use GCDWebServer built-in
* logging facility.
*/
@@ -119,7 +119,7 @@ typedef NS_ENUM(int, GCDWebServerLoggingLevel) {
kGCDWebServerLoggingLevel_Info,
kGCDWebServerLoggingLevel_Warning,
kGCDWebServerLoggingLevel_Error,
- kGCDWebServerLoggingLevel_Exception,
+ kGCDWebServerLoggingLevel_Exception
};
extern GCDWebServerLoggingLevel GCDWebServerLogLevel;
@@ -211,6 +211,8 @@ extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOO
@interface GCDWebServerRequest ()
@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
+@property(nonatomic, readwrite) NSData* localAddressData;
+@property(nonatomic, readwrite) NSData* remoteAddressData;
- (void)prepareForWriting;
- (BOOL)performOpen:(NSError**)error;
- (BOOL)performWriteData:(NSData*)data error:(NSError**)error;
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerRequest.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerRequest.h b/GCDWebServer/Core/GCDWebServerRequest.h
index 3b517b6..c7bc31b 100644
--- a/GCDWebServer/Core/GCDWebServerRequest.h
+++ b/GCDWebServer/Core/GCDWebServerRequest.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -158,6 +158,30 @@ extern NSString* const GCDWebServerRequestAttribute_RegexCaptures;
@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding;
/**
+ * Returns the address of the local peer (i.e. server) for the request
+ * as a raw "struct sockaddr".
+ */
+@property(nonatomic, readonly) NSData* localAddressData;
+
+/**
+ * Returns the address of the local peer (i.e. server) for the request
+ * as a string.
+ */
+@property(nonatomic, readonly) NSString* localAddressString;
+
+/**
+ * Returns the address of the remote peer (i.e. client) for the request
+ * as a raw "struct sockaddr".
+ */
+@property(nonatomic, readonly) NSData* remoteAddressData;
+
+/**
+ * Returns the address of the remote peer (i.e. client) for the request
+ * as a string.
+ */
+@property(nonatomic, readonly) NSString* remoteAddressString;
+
+/**
* This method is the designated initializer for the class.
*/
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query;
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerRequest.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerRequest.m b/GCDWebServer/Core/GCDWebServerRequest.m
index cc14993..dc929a7 100644
--- a/GCDWebServer/Core/GCDWebServerRequest.m
+++ b/GCDWebServer/Core/GCDWebServerRequest.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -88,7 +88,9 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
- (BOOL)open:(NSError**)error {
int result = inflateInit2(&_stream, 15 + 16);
if (result != Z_OK) {
- *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ if (error) {
+ *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ }
return NO;
}
if (![super open:error]) {
@@ -114,7 +116,9 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
_stream.avail_out = (uInt)maxLength;
int result = inflate(&_stream, Z_NO_FLUSH);
if ((result != Z_OK) && (result != Z_STREAM_END)) {
- *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ if (error) {
+ *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ }
return NO;
}
length += maxLength - _stream.avail_out;
@@ -153,6 +157,8 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
NSString* _noneMatch;
NSRange _range;
BOOL _gzipAccepted;
+ NSData* _localAddress;
+ NSData* _remoteAddress;
BOOL _opened;
NSMutableArray* _decoders;
@@ -164,7 +170,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
@implementation GCDWebServerRequest : NSObject
@synthesize method=_method, URL=_url, headers=_headers, path=_path, query=_query, contentType=_type, contentLength=_length, ifModifiedSince=_modifiedSince, ifNoneMatch=_noneMatch,
- byteRange=_range, acceptsGzipContentEncoding=_gzipAccepted, usesChunkedTransferEncoding=_chunked;
+ byteRange=_range, acceptsGzipContentEncoding=_gzipAccepted, usesChunkedTransferEncoding=_chunked, localAddressData=_localAddress, remoteAddressData=_remoteAddress;
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
if ((self = [super init])) {
@@ -180,6 +186,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
if (lengthHeader) {
NSInteger length = [lengthHeader integerValue];
if (_chunked || (length < 0)) {
+ GWS_LOG_WARNING(@"Invalid 'Content-Length' header '%@' for '%@' request on \"%@\"", lengthHeader, _method, _url);
GWS_DNOT_REACHED();
return nil;
}
@@ -194,8 +201,8 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
_length = NSUIntegerMax;
} else {
if (_type) {
- GWS_DNOT_REACHED();
- return nil;
+ GWS_LOG_WARNING(@"Ignoring 'Content-Type' header for '%@' request on \"%@\"", _method, _url);
+ _type = nil; // Content-Type without Content-Length or chunked-encoding doesn't make sense
}
_length = NSUIntegerMax;
}
@@ -304,6 +311,14 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
[_attributes setValue:attribute forKey:key];
}
+- (NSString*)localAddressString {
+ return GCDWebServerStringFromSockAddr(_localAddress.bytes, YES);
+}
+
+- (NSString*)remoteAddressString {
+ return GCDWebServerStringFromSockAddr(_remoteAddress.bytes, YES);
+}
+
- (NSString*)description {
NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path];
for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerResponse.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerResponse.h b/GCDWebServer/Core/GCDWebServerResponse.h
index 01ef2ab..2ec2dee 100644
--- a/GCDWebServer/Core/GCDWebServerResponse.h
+++ b/GCDWebServer/Core/GCDWebServerResponse.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Core/GCDWebServerResponse.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Core/GCDWebServerResponse.m b/GCDWebServer/Core/GCDWebServerResponse.m
index b0a220b..8357ab7 100644
--- a/GCDWebServer/Core/GCDWebServerResponse.m
+++ b/GCDWebServer/Core/GCDWebServerResponse.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -94,7 +94,9 @@
- (BOOL)open:(NSError**)error {
int result = deflateInit2(&_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
if (result != Z_OK) {
- *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ if (error) {
+ *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ }
return NO;
}
if (![super open:error]) {
@@ -130,7 +132,9 @@
if (result == Z_STREAM_END) {
_finished = YES;
} else if (result != Z_OK) {
- *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ if (error) {
+ *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+ }
return nil;
}
length += maxLength - _stream.avail_out;
@@ -238,7 +242,7 @@
- (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
if ([_reader respondsToSelector:@selector(asyncReadDataWithCompletion:)]) {
- [_reader asyncReadDataWithCompletion:block];
+ [_reader asyncReadDataWithCompletion:[block copy]];
} else {
NSError* error = nil;
NSData* data = [_reader readData:&error];
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerDataRequest.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerDataRequest.h b/GCDWebServer/Requests/GCDWebServerDataRequest.h
index ef94b97..5048d08 100644
--- a/GCDWebServer/Requests/GCDWebServerDataRequest.h
+++ b/GCDWebServer/Requests/GCDWebServerDataRequest.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerDataRequest.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerDataRequest.m b/GCDWebServer/Requests/GCDWebServerDataRequest.m
index 4f0ed75..840e985 100644
--- a/GCDWebServer/Requests/GCDWebServerDataRequest.m
+++ b/GCDWebServer/Requests/GCDWebServerDataRequest.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,9 @@
_data = [[NSMutableData alloc] init];
}
if (_data == nil) {
- *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}];
+ if (error) {
+ *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}];
+ }
return NO;
}
return YES;
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerFileRequest.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerFileRequest.h b/GCDWebServer/Requests/GCDWebServerFileRequest.h
index 427a800..ad29eab 100644
--- a/GCDWebServer/Requests/GCDWebServerFileRequest.h
+++ b/GCDWebServer/Requests/GCDWebServerFileRequest.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerFileRequest.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerFileRequest.m b/GCDWebServer/Requests/GCDWebServerFileRequest.m
index d0c2118..adf67a5 100644
--- a/GCDWebServer/Requests/GCDWebServerFileRequest.m
+++ b/GCDWebServer/Requests/GCDWebServerFileRequest.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -56,7 +56,9 @@
- (BOOL)open:(NSError**)error {
_file = open([_temporaryPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (_file <= 0) {
- *error = GCDWebServerMakePosixError(errno);
+ if (error) {
+ *error = GCDWebServerMakePosixError(errno);
+ }
return NO;
}
return YES;
@@ -64,7 +66,9 @@
- (BOOL)writeData:(NSData*)data error:(NSError**)error {
if (write(_file, data.bytes, data.length) != (ssize_t)data.length) {
- *error = GCDWebServerMakePosixError(errno);
+ if (error) {
+ *error = GCDWebServerMakePosixError(errno);
+ }
return NO;
}
return YES;
@@ -72,7 +76,9 @@
- (BOOL)close:(NSError**)error {
if (close(_file) < 0) {
- *error = GCDWebServerMakePosixError(errno);
+ if (error) {
+ *error = GCDWebServerMakePosixError(errno);
+ }
return NO;
}
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
index 2463ca2..832c2e7 100644
--- a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
+++ b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
index e1c0015..c2fc9bf 100644
--- a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
+++ b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -376,7 +376,9 @@ static NSData* _dashNewlineData = nil;
NSString* boundary = GCDWebServerExtractHeaderValueParameter(self.contentType, @"boundary");
_parser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:nil arguments:_arguments files:_files];
if (_parser == nil) {
- *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}];
+ if (error) {
+ *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}];
+ }
return NO;
}
return YES;
@@ -384,7 +386,9 @@ static NSData* _dashNewlineData = nil;
- (BOOL)writeData:(NSData*)data error:(NSError**)error {
if (![_parser appendBytes:data.bytes length:data.length]) {
- *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}];
+ if (error) {
+ *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}];
+ }
return NO;
}
return YES;
@@ -394,7 +398,9 @@ static NSData* _dashNewlineData = nil;
BOOL atEnd = [_parser isAtEnd];
_parser = nil;
if (!atEnd) {
- *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}];
+ if (error) {
+ *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}];
+ }
return NO;
}
return YES;
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h b/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
index e36eac3..9735380 100644
--- a/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
+++ b/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m b/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
index f210fa0..2c5fcc5 100644
--- a/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
+++ b/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerDataResponse.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerDataResponse.h b/GCDWebServer/Responses/GCDWebServerDataResponse.h
index b0c6493..6e06cd8 100644
--- a/GCDWebServer/Responses/GCDWebServerDataResponse.h
+++ b/GCDWebServer/Responses/GCDWebServerDataResponse.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerDataResponse.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerDataResponse.m b/GCDWebServer/Responses/GCDWebServerDataResponse.m
index ea02799..12cd12b 100644
--- a/GCDWebServer/Responses/GCDWebServerDataResponse.m
+++ b/GCDWebServer/Responses/GCDWebServerDataResponse.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerErrorResponse.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerErrorResponse.h b/GCDWebServer/Responses/GCDWebServerErrorResponse.h
index 381b122..dad0114 100644
--- a/GCDWebServer/Responses/GCDWebServerErrorResponse.h
+++ b/GCDWebServer/Responses/GCDWebServerErrorResponse.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerErrorResponse.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerErrorResponse.m b/GCDWebServer/Responses/GCDWebServerErrorResponse.m
index c2e4422..ef6a991 100644
--- a/GCDWebServer/Responses/GCDWebServerErrorResponse.m
+++ b/GCDWebServer/Responses/GCDWebServerErrorResponse.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerFileResponse.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerFileResponse.h b/GCDWebServer/Responses/GCDWebServerFileResponse.h
index 19d284d..050e92f 100644
--- a/GCDWebServer/Responses/GCDWebServerFileResponse.h
+++ b/GCDWebServer/Responses/GCDWebServerFileResponse.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerFileResponse.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerFileResponse.m b/GCDWebServer/Responses/GCDWebServerFileResponse.m
index 2004327..a2b7c3c 100644
--- a/GCDWebServer/Responses/GCDWebServerFileResponse.m
+++ b/GCDWebServer/Responses/GCDWebServerFileResponse.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -142,11 +142,15 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
- (BOOL)open:(NSError**)error {
_file = open([_path fileSystemRepresentation], O_NOFOLLOW | O_RDONLY);
if (_file <= 0) {
- *error = GCDWebServerMakePosixError(errno);
+ if (error) {
+ *error = GCDWebServerMakePosixError(errno);
+ }
return NO;
}
if (lseek(_file, _offset, SEEK_SET) != (off_t)_offset) {
- *error = GCDWebServerMakePosixError(errno);
+ if (error) {
+ *error = GCDWebServerMakePosixError(errno);
+ }
close(_file);
return NO;
}
@@ -158,7 +162,9 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
NSMutableData* data = [[NSMutableData alloc] initWithLength:length];
ssize_t result = read(_file, data.mutableBytes, length);
if (result < 0) {
- *error = GCDWebServerMakePosixError(errno);
+ if (error) {
+ *error = GCDWebServerMakePosixError(errno);
+ }
return nil;
}
if (result > 0) {
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerStreamedResponse.h b/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
index 4f39625..2731b7c 100644
--- a/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
+++ b/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,8 @@
/**
* The GCDWebServerStreamBlock is called to stream the data for the HTTP body.
- * The block must return empty NSData when done or nil on error and set the
- * "error" argument which is guaranteed to be non-NULL.
+ * The block must return either a chunk of data, an empty NSData when done, or
+ * nil on error and set the "error" argument which is guaranteed to be non-NULL.
*/
typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
@@ -39,13 +39,10 @@ typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
* except the streamed data can be returned at a later time allowing for
* truly asynchronous generation of the data.
*
- * The block must return empty NSData when done or nil on error and set the
- * "error" argument which is guaranteed to be non-NULL.
+ * The block must call "completionBlock" passing the new chunk of data when ready,
+ * an empty NSData when done, or nil on error and pass a NSError.
*
- * The block must regularly call "completionBlock" passing new streamed data.
- * Eventually it must call "completionBlock" passing an empty NSData indicating
- * the end of the stream has been reached, or pass nil and an NSError in case of
- * error.
+ * The block cannot call "completionBlock" more than once per invocation.
*/
typedef void (^GCDWebServerAsyncStreamBlock)(GCDWebServerBodyReaderCompletionBlock completionBlock);
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
----------------------------------------------------------------------
diff --git a/GCDWebServer/Responses/GCDWebServerStreamedResponse.m b/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
index 7f96943..4669617 100644
--- a/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
+++ b/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebUploader/GCDWebUploader.bundle/css/index.css
----------------------------------------------------------------------
diff --git a/GCDWebUploader/GCDWebUploader.bundle/css/index.css b/GCDWebUploader/GCDWebUploader.bundle/css/index.css
index aed15e4..53b0247 100644
--- a/GCDWebUploader/GCDWebUploader.bundle/css/index.css
+++ b/GCDWebUploader/GCDWebUploader.bundle/css/index.css
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebUploader/GCDWebUploader.bundle/index.html
----------------------------------------------------------------------
diff --git a/GCDWebUploader/GCDWebUploader.bundle/index.html b/GCDWebUploader/GCDWebUploader.bundle/index.html
index 28d371c..1bfd28e 100644
--- a/GCDWebUploader/GCDWebUploader.bundle/index.html
+++ b/GCDWebUploader/GCDWebUploader.bundle/index.html
@@ -1,5 +1,5 @@
<!--
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -65,7 +65,7 @@
<div id="alerts"></div>
<div class="btn-toolbar">
- <button type="button" class="btn btn-primary fileinput-button">
+ <button type="button" class="btn btn-primary fileinput-button" id="upload-file">
<span class="glyphicon glyphicon-upload"></span> Upload Files…
<input id="fileupload" type="file" name="files[]" multiple>
</button>
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebUploader/GCDWebUploader.bundle/js/index.js
----------------------------------------------------------------------
diff --git a/GCDWebUploader/GCDWebUploader.bundle/js/index.js b/GCDWebUploader/GCDWebUploader.bundle/js/index.js
index 5bd9218..012926d 100644
--- a/GCDWebUploader/GCDWebUploader.bundle/js/index.js
+++ b/GCDWebUploader/GCDWebUploader.bundle/js/index.js
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -178,6 +178,17 @@ function _reload(path) {
$(document).ready(function() {
+ // Workaround Firefox and IE not showing file selection dialog when clicking on "upload-file" <button>
+ // Making it a <div> instead also works but then it the button doesn't work anymore with tab selection or accessibility
+ $("#upload-file").click(function(event) {
+ $("#fileupload").click();
+ });
+
+ // Prevent event bubbling when using workaround above
+ $("#fileupload").click(function(event) {
+ event.stopPropagation();
+ });
+
$("#fileupload").fileupload({
dropZone: $(document),
pasteZone: null,
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebUploader/GCDWebUploader.h
----------------------------------------------------------------------
diff --git a/GCDWebUploader/GCDWebUploader.h b/GCDWebUploader/GCDWebUploader.h
index 02ff30d..d2c92e9 100644
--- a/GCDWebUploader/GCDWebUploader.h
+++ b/GCDWebUploader/GCDWebUploader.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/GCDWebUploader/GCDWebUploader.m
----------------------------------------------------------------------
diff --git a/GCDWebUploader/GCDWebUploader.m b/GCDWebUploader/GCDWebUploader.m
index d88a45a..9bb4453 100644
--- a/GCDWebUploader/GCDWebUploader.m
+++ b/GCDWebUploader/GCDWebUploader.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -292,9 +292,11 @@
@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden,
title=_title, header=_header, prologue=_prologue, epilogue=_epilogue, footer=_footer;
+@dynamic delegate;
+
- (instancetype)initWithUploadDirectory:(NSString*)path {
if ((self = [super init])) {
- NSBundle* siteBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"GCDWebUploader" ofType:@"bundle"]];
+ NSBundle* siteBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[GCDWebUploader class]] pathForResource:@"GCDWebUploader" ofType:@"bundle"]];
if (siteBundle == nil) {
return nil;
}
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/Mac/main.m
----------------------------------------------------------------------
diff --git a/Mac/main.m b/Mac/main.m
index f446ce0..33b25e5 100644
--- a/Mac/main.m
+++ b/Mac/main.m
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
+ Copyright (c) 2012-2015, Pierre-Olivier Latour
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -72,6 +72,10 @@ typedef enum {
[self _logDelegateCall:_cmd];
}
+- (void)webServerDidUpdateNATPortMapping:(GCDWebServer*)server {
+ [self _logDelegateCall:_cmd];
+}
+
- (void)webServerDidConnect:(GCDWebServer*)server {
[self _logDelegateCall:_cmd];
}
@@ -141,9 +145,11 @@ int main(int argc, const char* argv[]) {
NSString* authenticationRealm = nil;
NSString* authenticationUser = nil;
NSString* authenticationPassword = nil;
+ BOOL bindToLocalhost = NO;
+ BOOL requestNATPortMapping = NO;
if (argc == 1) {
- fprintf(stdout, "Usage: %s [-mode webServer | htmlPage | htmlForm | htmlFileUpload | webDAV | webUploader | streamingResponse | asyncResponse] [-record] [-root directory] [-tests directory] [-authenticationMethod Basic | Digest] [-authenticationRealm realm] [-authenticationUser user] [-authenticationPassword password]\n\n", basename((char*)argv[0]));
+ fprintf(stdout, "Usage: %s [-mode webServer | htmlPage | htmlForm | htmlFileUpload | webDAV | webUploader | streamingResponse | asyncResponse] [-record] [-root directory] [-tests directory] [-authenticationMethod Basic | Digest] [-authenticationRealm realm] [-authenticationUser user] [-authenticationPassword password] [--localhost]\n\n", basename((char*)argv[0]));
} else {
for (int i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
@@ -188,6 +194,10 @@ int main(int argc, const char* argv[]) {
} else if (!strcmp(argv[i], "-authenticationPassword") && (i + 1 < argc)) {
++i;
authenticationPassword = [NSString stringWithUTF8String:argv[i]];
+ } else if (!strcmp(argv[i], "--localhost")) {
+ bindToLocalhost = YES;
+ } else if (!strcmp(argv[i], "--nat")) {
+ requestNATPortMapping = YES;
}
}
}
@@ -354,7 +364,7 @@ int main(int argc, const char* argv[]) {
fprintf(stdout, "Running in Async Response mode");
webServer = [[GCDWebServer alloc] init];
[webServer addHandlerForMethod:@"GET"
- path:@"/"
+ path:@"/async"
requestClass:[GCDWebServerRequest class]
asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
@@ -364,6 +374,29 @@ int main(int argc, const char* argv[]) {
});
}];
+ [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;
}
@@ -386,6 +419,8 @@ int main(int argc, const char* argv[]) {
fprintf(stdout, "\n");
NSMutableDictionary* options = [NSMutableDictionary dictionary];
[options setObject:@8080 forKey:GCDWebServerOption_Port];
+ [options setObject:@(requestNATPortMapping) forKey:GCDWebServerOption_RequestNATPortMapping];
+ [options setObject:@(bindToLocalhost) forKey:GCDWebServerOption_BindToLocalhost];
[options setObject:@"" forKey:GCDWebServerOption_BonjourName];
if (authenticationUser && authenticationPassword) {
[options setValue:authenticationRealm forKey:GCDWebServerOption_AuthenticationRealm];
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/394cfb12/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 357586a..acaa870 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,6 @@ Overview
[![Platform](http://cocoapod-badges.herokuapp.com/p/GCDWebServer/badge.png)](https://github.com/swisspol/GCDWebServer)
[![License](http://img.shields.io/cocoapods/l/GCDWebServer.svg)](LICENSE)
-*ANNOUNCEMENT: If you like GCDWebServer, check out [XLFacility](https://github.com/swisspol/XLFacility), an elegant and powerful logging facility for OS X & iOS by the same author and also open-source. XLFacility can be used seemlessly to handle logging from GCDWebServer (see "Logging in GCDWebServer" below).*
-
GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in OS X & iOS apps. It was written from scratch with the following goals in mind:
* Elegant and easy to use architecture with only 4 core classes: server, connection, request and response (see "Understanding GCDWebServer's Architecture" below)
* Well designed API with fully documented headers for easy integration and customization
@@ -26,6 +24,7 @@ Extra built-in features:
* [Basic](https://en.wikipedia.org/wiki/Basic_access_authentication) and [Digest Access](https://en.wikipedia.org/wiki/Digest_access_authentication) authentications for password protection
* Automatically handle transitions between foreground, background and suspended modes in iOS apps
* Full support for both IPv4 and IPv6
+* NAT port mapping (IPv4 only)
Included extensions:
* [GCDWebUploader](GCDWebUploader/GCDWebUploader.h): subclass of ```GCDWebServer``` that implements an interface for uploading and downloading files using a web browser
@@ -45,7 +44,9 @@ Getting Started
Download or check out the [latest release](https://github.com/swisspol/GCDWebServer/releases) of GCDWebServer then add the entire "GCDWebServer" subfolder to your Xcode project. If you intend to use one of the extensions like GCDWebDAVServer or GCDWebUploader, add these subfolders as well.
-Alternatively, you can install GCDWebServer using [CocoaPods](http://cocoapods.org/) by simply adding this line to your Xcode project's Podfile:
+If you add the files directly then (1) link to `libz` (via Target > Build Phases > Link Binary With Libraries) and (2) add `$(SDKROOT)/usr/include/libxml2` to your header search paths (via Target > Build Settings > HEADER_SEARCH_PATHS).
+
+Alternatively, you can install GCDWebServer using [CocoaPods](http://cocoapods.org/) by simply adding this line to your Podfile:
```
pod "GCDWebServer", "~> 3.0"
```
@@ -58,11 +59,29 @@ Or this line for GCDWebDAVServer:
pod "GCDWebServer/WebDAV", "~> 3.0"
```
+And finally run `$ pod install`.
+
+You can also use [Carthage](https://github.com/Carthage/Carthage) by adding this line to your Cartfile (3.2.5 is the first release with Carthage support):
+```
+github "swisspol/GCDWebServer" ~> 3.2.5
+```
+
+Then run `$ carthage update` and add the generated frameworks to your Xcode projects (see [Carthage instructions](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application)).
+
+Help & Support
+==============
+
+For help with using GCDWebServer, it's best to ask your question on Stack Overflow with the [`gcdwebserver`](http://stackoverflow.com/questions/tagged/gcdwebserver) tag.
+
+Be sure to read this entire README first though!
+
Hello World
===========
These code snippets show how to implement a custom HTTP server that runs on port 8080 and returns a "Hello World" HTML page to any request. Since GCDWebServer uses GCD blocks to handle requests, no subclassing or delegates are needed, which results in very clean code.
+**IMPORTANT:** If not using CocoaPods, be sure to add the `libz` shared system library to the Xcode target for your app.
+
**OS X version (command line tool):**
```objectivec
#import "GCDWebServer.h"
@@ -134,83 +153,29 @@ int main(int argc, const char* argv[]) {
***webServer.swift***
```swift
import Foundation
+import GCDWebServers
+
+func initWebServer() {
-let webServer = GCDWebServer()
+ let webServer = GCDWebServer()
-webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self) { request in
+ webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World</p></body></html>")
+
+ })
+
+ webServer.runWithPort(8080, bonjourName: "GCD Web Server")
+
+ print("Visit \(webServer.serverURL) in your web browser")
}
-
-webServer.runWithPort(8080, bonjourName: nil)
-
-println("Visit \(webServer.serverURL) in your web browser")
```
***WebServer-Bridging-Header.h***
```objectivec
-#import "GCDWebServer.h"
-#import "GCDWebServerDataResponse.h"
-```
-
-Asynchronous HTTP Responses
-===========================
-
-New in GCDWebServer 3.0 is the ability to process HTTP requests aysnchronously i.e. add handlers to the server which generate their ```GCDWebServerResponse``` asynchronously. This is achieved by adding handlers that use a ```GCDWebServerAsyncProcessBlock``` instead of a ```GCDWebServerProcessBlock```. Here's an example:
-
-**(Synchronous version)** The handler blocks while generating the HTTP response:
-```objectivec
-[webServer addDefaultHandlerForMethod:@"GET"
- requestClass:[GCDWebServerRequest class]
- processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
-
- GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World</p></body></html>"];
- return response;
-
-}];
-```
-
-**(Asynchronous version)** The handler returns immediately and calls back GCDWebServer later with the generated HTTP response:
-```objectivec
-[webServer addDefaultHandlerForMethod:@"GET"
- requestClass:[GCDWebServerRequest class]
- asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
-
- // Do some async operation like network access or file I/O (simulated here using dispatch_after())
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World</p></body></html>"];
- completionBlock(response);
- });
-
-}];
-```
-
-**(Advanced asynchronous version)** The handler returns immediately a streamed HTTP response which itself generates its contents asynchronously:
-```objectivec
-[webServer addDefaultHandlerForMethod:@"GET"
- requestClass:[GCDWebServerRequest class]
- asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
-
- GCDWebServerStreamedResponse* response = [GCDWebServerStreamedResponse responseWithContentType:@"text/html" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- completionBlock([@"<html><body><p>Hello" dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 1st part of the stream data
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- completionBlock([@"World</p></body></html>" dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 2nd part of the stream data
-
- completionBlock([NSData data], nil); // Must pass an empty NSData to signal the end of the stream
- });
-
- });
-
- }];
- return response;
-
-}];
+#import <GCDWebServers/GCDWebServer.h>
+#import <GCDWebServers/GCDWebServerDataResponse.h>
```
-*Note that you can even combine both the asynchronous and advanced asynchronous versions to return asynchronously an asynchronous HTTP response!*
-
Web Based Uploads in iOS Apps
=============================
@@ -274,6 +239,7 @@ Serving a Static Website
GCDWebServer includes a built-in handler that can recursively serve a directory (it also lets you control how the ["Cache-Control"](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) header should be set):
+**OS X version (command line tool):**
```objectivec
#import "GCDWebServer.h"
@@ -318,6 +284,66 @@ Handlers require 2 GCD blocks:
Note that most methods on ```GCDWebServer``` to add handlers only require the ```GCDWebServerProcessBlock``` or ```GCDWebServerAsyncProcessBlock``` as they already provide a built-in ```GCDWebServerMatchBlock``` e.g. to match a URL path with a Regex.
+Asynchronous HTTP Responses
+===========================
+
+New in GCDWebServer 3.0 is the ability to process HTTP requests aysnchronously i.e. add handlers to the server which generate their ```GCDWebServerResponse``` asynchronously. This is achieved by adding handlers that use a ```GCDWebServerAsyncProcessBlock``` instead of a ```GCDWebServerProcessBlock```. Here's an example:
+
+**(Synchronous version)** The handler blocks while generating the HTTP response:
+```objectivec
+[webServer addDefaultHandlerForMethod:@"GET"
+ requestClass:[GCDWebServerRequest class]
+ processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+
+ GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World</p></body></html>"];
+ return response;
+
+}];
+```
+
+**(Asynchronous version)** The handler returns immediately and calls back GCDWebServer later with the generated HTTP response:
+```objectivec
+[webServer addDefaultHandlerForMethod:@"GET"
+ requestClass:[GCDWebServerRequest class]
+ asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
+
+ // Do some async operation like network access or file I/O (simulated here using dispatch_after())
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World</p></body></html>"];
+ completionBlock(response);
+ });
+
+}];
+```
+
+**(Advanced asynchronous version)** The handler returns immediately a streamed HTTP response which itself generates its contents asynchronously:
+```objectivec
+[webServer addDefaultHandlerForMethod:@"GET"
+ requestClass:[GCDWebServerRequest class]
+ processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+
+ NSMutableArray* contents = [NSMutableArray arrayWithObjects:@"<html><body><p>\n", @"Hello World!\n", @"</p></body></html>\n", nil]; // Fake data source we are reading from
+ GCDWebServerStreamedResponse* response = [GCDWebServerStreamedResponse responseWithContentType:@"text/html" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
+
+ // Simulate a delay reading from the fake data source
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ NSString* string = contents.firstObject;
+ if (string) {
+ [contents removeObjectAtIndex:0];
+ completionBlock([string dataUsingEncoding:NSUTF8StringEncoding], nil); // Generate the 2nd part of the stream data
+ } else {
+ completionBlock([NSData data], nil); // Must pass an empty NSData to signal the end of the stream
+ }
+ });
+
+ }];
+ return response;
+
+}];
+```
+
+*Note that you can even combine both the asynchronous and advanced asynchronous versions to return asynchronously an asynchronous HTTP response!*
+
GCDWebServer & Background Mode for iOS Apps
===========================================
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org