mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-02-11 00:00:07 +08:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00b2c38109 | ||
|
|
0a9d3105fc | ||
|
|
0f0a9840e4 | ||
|
|
047fdddb0e | ||
|
|
79d6075a84 | ||
|
|
594497d234 | ||
|
|
1f7c0366f0 | ||
|
|
fe472cdd54 | ||
|
|
9c33c83351 | ||
|
|
9719406303 | ||
|
|
0b8f7ff6ad | ||
|
|
71c08cff73 |
@@ -602,6 +602,8 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
|
|||||||
|
|
||||||
@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden;
|
@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden;
|
||||||
|
|
||||||
|
@dynamic delegate;
|
||||||
|
|
||||||
- (instancetype)initWithUploadDirectory:(NSString*)path {
|
- (instancetype)initWithUploadDirectory:(NSString*)path {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_uploadDirectory = [[path stringByStandardizingPath] copy];
|
_uploadDirectory = [[path stringByStandardizingPath] copy];
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'GCDWebServer'
|
s.name = 'GCDWebServer'
|
||||||
s.version = '3.2.2'
|
s.version = '3.2.3'
|
||||||
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'
|
||||||
|
|||||||
@@ -535,6 +535,7 @@
|
|||||||
"-Wno-documentation",
|
"-Wno-documentation",
|
||||||
"-Wno-documentation-unknown-command",
|
"-Wno-documentation-unknown-command",
|
||||||
"-Wno-objc-missing-property-synthesis",
|
"-Wno-objc-missing-property-synthesis",
|
||||||
|
"-Wno-cstring-format-directive",
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -74,9 +74,9 @@ GCDWebServerLoggingLevel GCDWebServerLogLevel = kGCDWebServerLoggingLevel_Info;
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
|
#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
int GCDWebServerLogLevel = LOG_LEVEL_DEBUG;
|
DDLogLevel GCDWebServerLogLevel = DDLogLevelDebug;
|
||||||
#else
|
#else
|
||||||
int GCDWebServerLogLevel = LOG_LEVEL_INFO;
|
DDLogLevel GCDWebServerLogLevel = DDLogLevelInfo;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -171,6 +171,7 @@ static void _ExecuteMainThreadRunLoopSources() {
|
|||||||
dispatch_source_t _source6;
|
dispatch_source_t _source6;
|
||||||
CFNetServiceRef _registrationService;
|
CFNetServiceRef _registrationService;
|
||||||
CFNetServiceRef _resolutionService;
|
CFNetServiceRef _resolutionService;
|
||||||
|
BOOL _bindToLocalhost;
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
BOOL _suspendInBackground;
|
BOOL _suspendInBackground;
|
||||||
UIBackgroundTaskIdentifier _backgroundTask;
|
UIBackgroundTaskIdentifier _backgroundTask;
|
||||||
@@ -554,6 +555,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
|||||||
_source4 = [self _createDispatchSourceWithListeningSocket:listeningSocket4 isIPv6:NO];
|
_source4 = [self _createDispatchSourceWithListeningSocket:listeningSocket4 isIPv6:NO];
|
||||||
_source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES];
|
_source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES];
|
||||||
_port = port;
|
_port = port;
|
||||||
|
_bindToLocalhost = bindToLocalhost;
|
||||||
|
|
||||||
NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, nil);
|
NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, nil);
|
||||||
NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp");
|
NSString* bonjourType = _GetOption(_options, GCDWebServerOption_BonjourType, @"_http._tcp");
|
||||||
@@ -619,6 +621,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
|||||||
#endif
|
#endif
|
||||||
_source4 = NULL;
|
_source4 = NULL;
|
||||||
_port = 0;
|
_port = 0;
|
||||||
|
_bindToLocalhost = NO;
|
||||||
|
|
||||||
_serverName = nil;
|
_serverName = nil;
|
||||||
_authenticationRealm = nil;
|
_authenticationRealm = nil;
|
||||||
@@ -664,7 +667,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
|||||||
|
|
||||||
- (BOOL)startWithOptions:(NSDictionary*)options error:(NSError**)error {
|
- (BOOL)startWithOptions:(NSDictionary*)options error:(NSError**)error {
|
||||||
if (_options == nil) {
|
if (_options == nil) {
|
||||||
_options = [options copy];
|
_options = options ? [options copy] : @{};
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
_suspendInBackground = [_GetOption(_options, GCDWebServerOption_AutomaticallySuspendInBackground, @YES) boolValue];
|
_suspendInBackground = [_GetOption(_options, GCDWebServerOption_AutomaticallySuspendInBackground, @YES) boolValue];
|
||||||
if (((_suspendInBackground == NO) || ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground)) && ![self _start:error])
|
if (((_suspendInBackground == NO) || ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground)) && ![self _start:error])
|
||||||
@@ -715,7 +718,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
|
|||||||
|
|
||||||
- (NSURL*)serverURL {
|
- (NSURL*)serverURL {
|
||||||
if (_source4) {
|
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 (ipAddress) {
|
||||||
if (_port != 80) {
|
if (_port != 80) {
|
||||||
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%i/", ipAddress, (int)_port]];
|
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%i/", ipAddress, (int)_port]];
|
||||||
|
|||||||
@@ -548,6 +548,8 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_request) {
|
if (_request) {
|
||||||
|
_request.localAddressData = self.localAddressData;
|
||||||
|
_request.remoteAddressData = self.remoteAddressData;
|
||||||
if ([_request hasBody]) {
|
if ([_request hasBody]) {
|
||||||
[_request prepareForWriting];
|
[_request prepareForWriting];
|
||||||
if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) {
|
if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) {
|
||||||
@@ -764,15 +766,19 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
|
||||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
|
||||||
static inline BOOL _CompareResources(NSString* responseETag, NSString* requestETag, NSDate* responseLastModified, NSDate* requestLastModified) {
|
static inline BOOL _CompareResources(NSString* responseETag, NSString* requestETag, NSDate* responseLastModified, NSDate* requestLastModified) {
|
||||||
if ([requestETag isEqualToString:@"*"] && (!responseLastModified || !requestLastModified || ([responseLastModified compare:requestLastModified] != NSOrderedDescending))) {
|
if (requestLastModified && responseLastModified) {
|
||||||
return YES;
|
if ([responseLastModified compare:requestLastModified] != NSOrderedDescending) {
|
||||||
} else {
|
|
||||||
if ([responseETag isEqualToString:requestETag]) {
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
if (responseLastModified && requestLastModified && ([responseLastModified compare:requestLastModified] != NSOrderedDescending)) {
|
}
|
||||||
|
if (requestETag && responseETag) { // Per the specs "If-None-Match" must be checked after "If-Modified-Since"
|
||||||
|
if ([requestETag isEqualToString:@"*"]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
if ([responseETag isEqualToString:requestETag]) {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,15 +87,15 @@
|
|||||||
* it as a logging facility.
|
* 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__
|
#define __GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__
|
||||||
|
|
||||||
#undef LOG_LEVEL_DEF
|
#undef LOG_LEVEL_DEF
|
||||||
#define LOG_LEVEL_DEF GCDWebServerLogLevel
|
#define LOG_LEVEL_DEF GCDWebServerLogLevel
|
||||||
extern int GCDWebServerLogLevel;
|
extern DDLogLevel GCDWebServerLogLevel;
|
||||||
|
|
||||||
#define GWS_LOG_DEBUG(...) DDLogDebug(__VA_ARGS__)
|
#define GWS_LOG_DEBUG(...) DDLogDebug(__VA_ARGS__)
|
||||||
#define GWS_LOG_VERBOSE(...) DDLogVerbose(__VA_ARGS__)
|
#define GWS_LOG_VERBOSE(...) DDLogVerbose(__VA_ARGS__)
|
||||||
@@ -211,6 +211,8 @@ extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOO
|
|||||||
|
|
||||||
@interface GCDWebServerRequest ()
|
@interface GCDWebServerRequest ()
|
||||||
@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
|
@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
|
||||||
|
@property(nonatomic, readwrite) NSData* localAddressData;
|
||||||
|
@property(nonatomic, readwrite) NSData* remoteAddressData;
|
||||||
- (void)prepareForWriting;
|
- (void)prepareForWriting;
|
||||||
- (BOOL)performOpen:(NSError**)error;
|
- (BOOL)performOpen:(NSError**)error;
|
||||||
- (BOOL)performWriteData:(NSData*)data error:(NSError**)error;
|
- (BOOL)performWriteData:(NSData*)data error:(NSError**)error;
|
||||||
|
|||||||
@@ -157,6 +157,30 @@ extern NSString* const GCDWebServerRequestAttribute_RegexCaptures;
|
|||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding;
|
@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.
|
* This method is the designated initializer for the class.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -157,6 +157,8 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
|
|||||||
NSString* _noneMatch;
|
NSString* _noneMatch;
|
||||||
NSRange _range;
|
NSRange _range;
|
||||||
BOOL _gzipAccepted;
|
BOOL _gzipAccepted;
|
||||||
|
NSData* _localAddress;
|
||||||
|
NSData* _remoteAddress;
|
||||||
|
|
||||||
BOOL _opened;
|
BOOL _opened;
|
||||||
NSMutableArray* _decoders;
|
NSMutableArray* _decoders;
|
||||||
@@ -168,7 +170,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
|
|||||||
@implementation GCDWebServerRequest : NSObject
|
@implementation GCDWebServerRequest : NSObject
|
||||||
|
|
||||||
@synthesize method=_method, URL=_url, headers=_headers, path=_path, query=_query, contentType=_type, contentLength=_length, ifModifiedSince=_modifiedSince, ifNoneMatch=_noneMatch,
|
@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 {
|
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
@@ -308,6 +310,14 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
|
|||||||
[_attributes setValue:attribute forKey:key];
|
[_attributes setValue:attribute forKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString*)localAddressString {
|
||||||
|
return GCDWebServerStringFromSockAddr(_localAddress.bytes, YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*)remoteAddressString {
|
||||||
|
return GCDWebServerStringFromSockAddr(_remoteAddress.bytes, YES);
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString*)description {
|
- (NSString*)description {
|
||||||
NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path];
|
NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path];
|
||||||
for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
|
for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
|
||||||
|
|||||||
@@ -292,6 +292,8 @@
|
|||||||
@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden,
|
@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden,
|
||||||
title=_title, header=_header, prologue=_prologue, epilogue=_epilogue, footer=_footer;
|
title=_title, header=_header, prologue=_prologue, epilogue=_epilogue, footer=_footer;
|
||||||
|
|
||||||
|
@dynamic delegate;
|
||||||
|
|
||||||
- (instancetype)initWithUploadDirectory:(NSString*)path {
|
- (instancetype)initWithUploadDirectory:(NSString*)path {
|
||||||
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"]];
|
||||||
|
|||||||
122
README.md
122
README.md
@@ -135,7 +135,7 @@ import Foundation
|
|||||||
|
|
||||||
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>")
|
return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World</p></body></html>")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,66 +150,6 @@ println("Visit \(webServer.serverURL) in your web browser")
|
|||||||
#import "GCDWebServerDataResponse.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]
|
|
||||||
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!*
|
|
||||||
|
|
||||||
Web Based Uploads in iOS Apps
|
Web Based Uploads in iOS Apps
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@@ -317,6 +257,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.
|
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
|
GCDWebServer & Background Mode for iOS Apps
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user