From c4de08ac11a8125631607779724b6f9a9d67977c Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 5 May 2017 12:20:33 +0200 Subject: [PATCH 1/3] applying https://github.com/meteor/cordova-plugin-meteor-webapp/pull/25 --- src/ios/WebAppLocalServer.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ios/WebAppLocalServer.swift b/src/ios/WebAppLocalServer.swift index 98ebaba..7b51fd3 100644 --- a/src/ios/WebAppLocalServer.swift +++ b/src/ios/WebAppLocalServer.swift @@ -37,7 +37,7 @@ open class WebAppLocalServer: METPlugin, AssetBundleManagerDelegate { configuration.appId = currentAssetBundle.appId configuration.rootURL = currentAssetBundle.rootURL configuration.cordovaCompatibilityVersion = currentAssetBundle.cordovaCompatibilityVersion - + NSLog("Serving asset bundle version: \(currentAssetBundle.version)") } } @@ -112,7 +112,7 @@ open class WebAppLocalServer: METPlugin, AssetBundleManagerDelegate { self?.revertToLastKnownGoodVersion() } } - + NotificationCenter.default.addObserver(self, selector: #selector(WebAppLocalServer.pageDidLoad), name: NSNotification.Name.CDVPageDidLoad, object: webView) NotificationCenter.default.addObserver(self, selector: #selector(WebAppLocalServer.applicationDidEnterBackground), name: NSNotification.Name.UIApplicationDidEnterBackground, object: nil) @@ -326,7 +326,7 @@ open class WebAppLocalServer: METPlugin, AssetBundleManagerDelegate { notifyError(WebAppError.unsuitableAssetBundle(reason: "Skipping downloading blacklisted version", underlyingError: nil)) return false } - + // Don't download versions potentially incompatible with the bundled native code if manifest.cordovaCompatibilityVersion != configuration.cordovaCompatibilityVersion { notifyError(WebAppError.unsuitableAssetBundle(reason: "Skipping downloading new version because the Cordova platform version or plugin versions have changed and are potentially incompatible", underlyingError: nil)) @@ -364,7 +364,8 @@ open class WebAppLocalServer: METPlugin, AssetBundleManagerDelegate { let options = [ GCDWebServerOption_Port: NSNumber(value: localServerPort as UInt), - GCDWebServerOption_BindToLocalhost: true] + GCDWebServerOption_BindToLocalhost: true, + GCDWebServerOption_AutomaticallySuspendInBackground: false] try localServer.start(options: options) // Set localServerPort to the assigned port, in case it is different @@ -488,7 +489,7 @@ open class WebAppLocalServer: METPlugin, AssetBundleManagerDelegate { guard let response = GCDWebServerFileResponse(file: filePath, byteRange: request.byteRange) else { return GCDWebServerResponse(statusCode: GCDWebServerClientErrorHTTPStatusCode.httpStatusCode_NotFound.rawValue) } - + response.setValue("bytes", forAdditionalHeader: "Accept-Ranges") if shouldSetCookie { From 7bb095ce393d17f662cc6bb596ce91acf743d17a Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 6 Jun 2017 14:59:33 +0200 Subject: [PATCH 2/3] use https://github.com/swisspol/GCDWebServer/pull/299 --- src/ios/GCDWebServer/.clang-format | 13 + src/ios/GCDWebServer/.gitignore | 0 src/ios/GCDWebServer/.travis.yml | 2 +- .../GCDWebServer/Frameworks/GCDWebServers.h | 0 src/ios/GCDWebServer/Frameworks/Info.plist | 0 src/ios/GCDWebServer/Frameworks/Tests.m | 0 .../GCDWebDAVServer/GCDWebDAVServer.h | 0 .../GCDWebDAVServer/GCDWebDAVServer.m | 210 +++++---- src/ios/GCDWebServer/GCDWebServer.podspec | 46 +- .../GCDWebServer.xcodeproj/project.pbxproj | 35 +- .../xcschemes/GCDWebServers (Mac).xcscheme | 8 +- .../xcschemes/GCDWebServers (iOS).xcscheme | 8 +- .../xcschemes/GCDWebServers (tvOS).xcscheme | 8 +- .../GCDWebServer/Core/GCDWebServer.h | 35 +- .../GCDWebServer/Core/GCDWebServer.m | 354 ++++++++------- .../Core/GCDWebServerConnection.h | 0 .../Core/GCDWebServerConnection.m | 406 +++++++++--------- .../GCDWebServer/Core/GCDWebServerFunctions.h | 0 .../GCDWebServer/Core/GCDWebServerFunctions.m | 18 +- .../Core/GCDWebServerHTTPStatusCodes.h | 0 .../GCDWebServer/Core/GCDWebServerPrivate.h | 45 +- .../GCDWebServer/Core/GCDWebServerRequest.h | 0 .../GCDWebServer/Core/GCDWebServerRequest.m | 18 +- .../GCDWebServer/Core/GCDWebServerResponse.h | 0 .../GCDWebServer/Core/GCDWebServerResponse.m | 7 +- .../Requests/GCDWebServerDataRequest.h | 0 .../Requests/GCDWebServerDataRequest.m | 6 +- .../Requests/GCDWebServerFileRequest.h | 0 .../Requests/GCDWebServerFileRequest.m | 6 +- .../GCDWebServerMultiPartFormRequest.h | 0 .../GCDWebServerMultiPartFormRequest.m | 30 +- .../GCDWebServerURLEncodedFormRequest.h | 0 .../GCDWebServerURLEncodedFormRequest.m | 6 +- .../Responses/GCDWebServerDataResponse.h | 0 .../Responses/GCDWebServerDataResponse.m | 4 +- .../Responses/GCDWebServerErrorResponse.h | 16 +- .../Responses/GCDWebServerErrorResponse.m | 0 .../Responses/GCDWebServerFileResponse.h | 0 .../Responses/GCDWebServerFileResponse.m | 8 +- .../Responses/GCDWebServerStreamedResponse.h | 0 .../Responses/GCDWebServerStreamedResponse.m | 17 +- .../{ => Contents}/Info.plist | Bin .../Resources}/css/bootstrap-theme.css | 0 .../Resources}/css/bootstrap.css | 0 .../{ => Contents/Resources}/css/index.css | 0 .../Resources}/css/jquery.fileupload.css | 0 .../Resources}/en.lproj/Localizable.strings | 0 .../fonts/glyphicons-halflings-regular.eot | Bin .../fonts/glyphicons-halflings-regular.svg | 0 .../fonts/glyphicons-halflings-regular.ttf | Bin .../fonts/glyphicons-halflings-regular.woff | Bin .../{ => Contents/Resources}/index.html | 0 .../Resources}/js/bootstrap.min.js | 0 .../Resources}/js/html5shiv.min.js | 0 .../{ => Contents/Resources}/js/index.js | 0 .../Resources}/js/jquery.fileupload.js | 0 .../Resources}/js/jquery.iframe-transport.js | 0 .../Resources}/js/jquery.jeditable.js | 0 .../{ => Contents/Resources}/js/jquery.min.js | 0 .../Resources}/js/jquery.ui.widget.js | 0 .../Resources}/js/respond.min.js | 0 .../{ => Contents/Resources}/js/tmpl.min.js | 0 .../GCDWebUploader/GCDWebUploader.h | 0 .../GCDWebUploader/GCDWebUploader.m | 234 +++++----- src/ios/GCDWebServer/LICENSE | 0 src/ios/GCDWebServer/Mac/main.m | 221 +++++----- src/ios/GCDWebServer/README.md | 14 +- src/ios/GCDWebServer/Run-Tests.sh | 2 +- .../Tests/HTMLFileUpload/001-200.response | 0 .../Tests/HTMLFileUpload/001-GET.request | 0 .../Tests/HTMLFileUpload/002-200.response | 0 .../Tests/HTMLFileUpload/002-POST.request | Bin .../Tests/HTMLForm/001-200.response | 0 .../Tests/HTMLForm/001-GET.request | 0 .../Tests/HTMLForm/002-200.response | 0 .../Tests/HTMLForm/002-POST.request | 0 src/ios/GCDWebServer/Tests/Payload.zip | Bin src/ios/GCDWebServer/Tests/Sample-Movie.mp4 | Bin .../Tests/WebDAV-Finder/059-200.response | Bin 107049 -> 0 bytes .../Tests/WebDAV-Finder/059-206.response | Bin 0 -> 8774 bytes .../Tests/WebDAV-Finder/062-200.response | Bin 116315 -> 0 bytes .../Tests/WebDAV-Finder/062-206.response | Bin 0 -> 18041 bytes .../WebServer-Sample-Movie/001-200.response | Bin .../WebServer-Sample-Movie/001-GET.request | 0 .../WebServer-Sample-Movie/002-206.response | Bin .../WebServer-Sample-Movie/002-GET.request | 0 .../WebServer-Sample-Movie/003-206.response | Bin .../WebServer-Sample-Movie/003-GET.request | 0 .../WebServer-Sample-Movie/004-206.response | Bin .../WebServer-Sample-Movie/004-GET.request | 0 .../WebServer-Sample-Movie/005-206.response | Bin .../WebServer-Sample-Movie/005-GET.request | 0 .../Tests/WebServer/001-200.response | 0 .../Tests/WebServer/001-GET.request | 0 .../Tests/WebServer/002-200.response | 0 .../Tests/WebServer/002-GET.request | 0 .../Tests/WebServer/003-200.response | 0 .../Tests/WebServer/003-GET.request | 0 .../Tests/WebServer/004-200.response | Bin .../Tests/WebServer/004-GET.request | 0 .../Tests/WebServer/005-200.response | Bin .../Tests/WebServer/005-GET.request | 0 .../Tests/WebServer/006-304.response | 0 .../Tests/WebServer/006-GET.request | 0 .../Tests/WebServer/007-304.response | 0 .../Tests/WebServer/007-GET.request | 0 .../Tests/WebServer/008-200.response | 0 .../Tests/WebServer/008-GET.request | 0 .../Tests/WebServer/009-200.response | Bin .../Tests/WebServer/009-GET.request | 0 .../Tests/WebServer/010-304.response | 0 .../Tests/WebServer/010-GET.request | 0 .../Tests/WebServer/011-304.response | 0 .../Tests/WebServer/011-GET.request | 0 .../Tests/WebServer/012-200.response | 0 .../Tests/WebServer/012-HEAD.request | 0 src/ios/GCDWebServer/format-source.sh | 40 ++ src/ios/GCDWebServer/iOS/AppDelegate.h | 0 src/ios/GCDWebServer/iOS/AppDelegate.m | 0 .../AppIcon.appiconset/Contents.json | 25 ++ .../iOS/Base.lproj/LaunchScreen.storyboard | 0 .../iOS/Base.lproj/Main.storyboard | 0 src/ios/GCDWebServer/iOS/Info.plist | 0 src/ios/GCDWebServer/iOS/ViewController.h | 0 src/ios/GCDWebServer/iOS/ViewController.m | 4 +- src/ios/GCDWebServer/iOS/main.m | 0 src/ios/GCDWebServer/tvOS/AppDelegate.h | 0 src/ios/GCDWebServer/tvOS/AppDelegate.m | 0 .../Content.imageset/Contents.json | 0 .../Back.imagestacklayer/Contents.json | 0 .../App Icon - Large.imagestack/Contents.json | 0 .../Content.imageset/Contents.json | 0 .../Front.imagestacklayer/Contents.json | 0 .../Content.imageset/Contents.json | 0 .../Middle.imagestacklayer/Contents.json | 0 .../Content.imageset/Contents.json | 0 .../Back.imagestacklayer/Contents.json | 0 .../App Icon - Small.imagestack/Contents.json | 0 .../Content.imageset/Contents.json | 0 .../Front.imagestacklayer/Contents.json | 0 .../Content.imageset/Contents.json | 0 .../Middle.imagestacklayer/Contents.json | 0 .../Contents.json | 8 +- .../Contents.json | 12 + .../Top Shelf Image.imageset/Contents.json | 0 .../tvOS/Assets.xcassets/Contents.json | 0 .../LaunchImage.launchimage/Contents.json | 0 .../tvOS/Base.lproj/Main.storyboard | 0 src/ios/GCDWebServer/tvOS/Info.plist | 0 src/ios/GCDWebServer/tvOS/ViewController.h | 0 src/ios/GCDWebServer/tvOS/ViewController.m | 4 +- src/ios/GCDWebServer/tvOS/main.m | 0 152 files changed, 1046 insertions(+), 824 deletions(-) create mode 100755 src/ios/GCDWebServer/.clang-format mode change 100644 => 100755 src/ios/GCDWebServer/.gitignore mode change 100644 => 100755 src/ios/GCDWebServer/.travis.yml mode change 100644 => 100755 src/ios/GCDWebServer/Frameworks/GCDWebServers.h mode change 100644 => 100755 src/ios/GCDWebServer/Frameworks/Info.plist mode change 100644 => 100755 src/ios/GCDWebServer/Frameworks/Tests.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer.podspec mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer.xcodeproj/project.pbxproj mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (iOS).xcscheme mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (tvOS).xcscheme mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServer.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServer.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents}/Info.plist (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/css/bootstrap-theme.css (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/css/bootstrap.css (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/css/index.css (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/css/jquery.fileupload.css (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/en.lproj/Localizable.strings (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/fonts/glyphicons-halflings-regular.eot (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/fonts/glyphicons-halflings-regular.svg (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/fonts/glyphicons-halflings-regular.ttf (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/fonts/glyphicons-halflings-regular.woff (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/index.html (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/bootstrap.min.js (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/html5shiv.min.js (100%) rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/index.js (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/jquery.fileupload.js (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/jquery.iframe-transport.js (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/jquery.jeditable.js (100%) rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/jquery.min.js (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/jquery.ui.widget.js (100%) mode change 100644 => 100755 rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/respond.min.js (100%) rename src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/{ => Contents/Resources}/js/tmpl.min.js (100%) mode change 100644 => 100755 mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h mode change 100644 => 100755 src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m mode change 100644 => 100755 src/ios/GCDWebServer/LICENSE mode change 100644 => 100755 src/ios/GCDWebServer/Mac/main.m mode change 100644 => 100755 src/ios/GCDWebServer/README.md mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLFileUpload/001-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLFileUpload/001-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLFileUpload/002-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLFileUpload/002-POST.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLForm/001-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLForm/001-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLForm/002-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/HTMLForm/002-POST.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/Payload.zip mode change 100644 => 100755 src/ios/GCDWebServer/Tests/Sample-Movie.mp4 delete mode 100755 src/ios/GCDWebServer/Tests/WebDAV-Finder/059-200.response create mode 100755 src/ios/GCDWebServer/Tests/WebDAV-Finder/059-206.response delete mode 100755 src/ios/GCDWebServer/Tests/WebDAV-Finder/062-200.response create mode 100755 src/ios/GCDWebServer/Tests/WebDAV-Finder/062-206.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/001-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/001-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/002-206.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/002-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/003-206.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/003-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/004-206.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/004-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/005-206.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer-Sample-Movie/005-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/001-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/001-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/002-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/002-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/003-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/003-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/004-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/004-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/005-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/005-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/006-304.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/006-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/007-304.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/007-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/008-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/008-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/009-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/009-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/010-304.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/010-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/011-304.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/011-GET.request mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/012-200.response mode change 100644 => 100755 src/ios/GCDWebServer/Tests/WebServer/012-HEAD.request create mode 100755 src/ios/GCDWebServer/format-source.sh mode change 100644 => 100755 src/ios/GCDWebServer/iOS/AppDelegate.h mode change 100644 => 100755 src/ios/GCDWebServer/iOS/AppDelegate.m mode change 100644 => 100755 src/ios/GCDWebServer/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/iOS/Base.lproj/LaunchScreen.storyboard mode change 100644 => 100755 src/ios/GCDWebServer/iOS/Base.lproj/Main.storyboard mode change 100644 => 100755 src/ios/GCDWebServer/iOS/Info.plist mode change 100644 => 100755 src/ios/GCDWebServer/iOS/ViewController.h mode change 100644 => 100755 src/ios/GCDWebServer/iOS/ViewController.m mode change 100644 => 100755 src/ios/GCDWebServer/iOS/main.m mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/AppDelegate.h mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/AppDelegate.m mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json create mode 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Base.lproj/Main.storyboard mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/Info.plist mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/ViewController.h mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/ViewController.m mode change 100644 => 100755 src/ios/GCDWebServer/tvOS/main.m diff --git a/src/ios/GCDWebServer/.clang-format b/src/ios/GCDWebServer/.clang-format new file mode 100755 index 0000000..5b59614 --- /dev/null +++ b/src/ios/GCDWebServer/.clang-format @@ -0,0 +1,13 @@ +--- +Language: Cpp +BasedOnStyle: Google +Standard: Cpp11 +ColumnLimit: 0 +AlignTrailingComments: false +NamespaceIndentation: All +DerivePointerAlignment: false +AlwaysBreakBeforeMultilineStrings: false +AccessModifierOffset: -2 +ObjCSpaceBeforeProtocolList: true +SortIncludes: false +... diff --git a/src/ios/GCDWebServer/.gitignore b/src/ios/GCDWebServer/.gitignore old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/.travis.yml b/src/ios/GCDWebServer/.travis.yml old mode 100644 new mode 100755 index 05cfcb6..204499b --- a/src/ios/GCDWebServer/.travis.yml +++ b/src/ios/GCDWebServer/.travis.yml @@ -1,3 +1,3 @@ language: objective-c script: ./Run-Tests.sh -osx_image: xcode7.1 +osx_image: xcode8.2 diff --git a/src/ios/GCDWebServer/Frameworks/GCDWebServers.h b/src/ios/GCDWebServer/Frameworks/GCDWebServers.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Frameworks/Info.plist b/src/ios/GCDWebServer/Frameworks/Info.plist old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Frameworks/Tests.m b/src/ios/GCDWebServer/Frameworks/Tests.m old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.h b/src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.m b/src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.m old mode 100644 new mode 100755 index 079607b..110c8b5 --- a/src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.m +++ b/src/ios/GCDWebServer/GCDWebDAVServer/GCDWebDAVServer.m @@ -99,22 +99,27 @@ - (GCDWebServerResponse*)performGET:(GCDWebServerRequest*)request { if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* itemName = [absolutePath lastPathComponent]; if (([itemName hasPrefix:@"."] && !_allowHidden) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Downlading item name \"%@\" is not allowed", itemName]; } - + // Because HEAD requests are mapped to GET ones, we need to handle directories but it's OK to return nothing per http://webdav.org/specs/rfc4918.html#rfc.section.9.4 if (isDirectory) { return [GCDWebServerResponse response]; } - + if ([self.delegate respondsToSelector:@selector(davServer:didDownloadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate davServer:self didDownloadFileAtPath:absolutePath]; }); } + + if ([request hasByteRange]) { + return [GCDWebServerFileResponse responseWithFile:absolutePath byteRange:request.byteRange]; + } + return [GCDWebServerFileResponse responseWithFile:absolutePath]; } @@ -122,7 +127,7 @@ - (GCDWebServerResponse*)performPUT:(GCDWebServerFileRequest*)request { if ([request hasByteRange]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Range uploads not supported"]; } - + NSString* relativePath = request.path; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; if (![self _checkSandboxedPath:absolutePath]) { @@ -132,27 +137,27 @@ - (GCDWebServerResponse*)performPUT:(GCDWebServerFileRequest*)request { if (![[NSFileManager defaultManager] fileExistsAtPath:[absolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Missing intermediate collection(s) for \"%@\"", relativePath]; } - + BOOL existing = [[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]; if (existing && isDirectory) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_MethodNotAllowed message:@"PUT not allowed on existing collection \"%@\"", relativePath]; } - + NSString* fileName = [absolutePath lastPathComponent]; if (([fileName hasPrefix:@"."] && !_allowHidden) || ![self _checkFileExtension:fileName]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file name \"%@\" is not allowed", fileName]; } - + if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:request.temporaryPath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file to \"%@\" is not permitted", relativePath]; } - + [[NSFileManager defaultManager] removeItemAtPath:absolutePath error:NULL]; NSError* error = nil; if (![[NSFileManager defaultManager] moveItemAtPath:request.temporaryPath toPath:absolutePath error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving uploaded file to \"%@\"", relativePath]; } - + if ([self.delegate respondsToSelector:@selector(davServer:didUploadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate davServer:self didUploadFileAtPath:absolutePath]; @@ -166,28 +171,28 @@ - (GCDWebServerResponse*)performDELETE:(GCDWebServerRequest*)request { if (depthHeader && ![depthHeader isEqualToString:@"infinity"]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Unsupported 'Depth' header: %@", depthHeader]; } - + NSString* relativePath = request.path; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; BOOL isDirectory = NO; if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* itemName = [absolutePath lastPathComponent]; if (([itemName hasPrefix:@"."] && !_allowHidden) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Deleting item name \"%@\" is not allowed", itemName]; } - + if (![self shouldDeleteItemAtPath:absolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Deleting \"%@\" is not permitted", relativePath]; } - + NSError* error = nil; if (![[NSFileManager defaultManager] removeItemAtPath:absolutePath error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed deleting \"%@\"", relativePath]; } - + if ([self.delegate respondsToSelector:@selector(davServer:didDeleteItemAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate davServer:self didDeleteItemAtPath:absolutePath]; @@ -200,7 +205,7 @@ - (GCDWebServerResponse*)performMKCOL:(GCDWebServerDataRequest*)request { if ([request hasBody] && (request.contentLength > 0)) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_UnsupportedMediaType message:@"Unexpected request body for MKCOL method"]; } - + NSString* relativePath = request.path; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; if (![self _checkSandboxedPath:absolutePath]) { @@ -210,16 +215,16 @@ - (GCDWebServerResponse*)performMKCOL:(GCDWebServerDataRequest*)request { if (![[NSFileManager defaultManager] fileExistsAtPath:[absolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Missing intermediate collection(s) for \"%@\"", relativePath]; } - + NSString* directoryName = [absolutePath lastPathComponent]; if (!_allowHidden && [directoryName hasPrefix:@"."]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Creating directory name \"%@\" is not allowed", directoryName]; } - + if (![self shouldCreateDirectoryAtPath:absolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Creating directory \"%@\" is not permitted", relativePath]; } - + NSError* error = nil; if (![[NSFileManager defaultManager] createDirectoryAtPath:absolutePath withIntermediateDirectories:NO attributes:nil error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed creating directory \"%@\"", relativePath]; @@ -228,12 +233,12 @@ - (GCDWebServerResponse*)performMKCOL:(GCDWebServerDataRequest*)request { NSString* creationDateHeader = [request.headers objectForKey:@"X-GCDWebServer-CreationDate"]; if (creationDateHeader) { NSDate* date = GCDWebServerParseISO8601(creationDateHeader); - if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileCreationDate: date} ofItemAtPath:absolutePath error:&error]) { + if (!date || ![[NSFileManager defaultManager] setAttributes:@{ NSFileCreationDate : date } ofItemAtPath:absolutePath error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed setting creation date for directory \"%@\"", relativePath]; } } #endif - + if ([self.delegate respondsToSelector:@selector(davServer:didCreateDirectoryAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate davServer:self didCreateDirectoryAtPath:absolutePath]; @@ -249,13 +254,13 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL) return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Unsupported 'Depth' header: %@", depthHeader]; } } - + NSString* srcRelativePath = request.path; NSString* srcAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:srcRelativePath]; if (![self _checkSandboxedPath:srcAbsolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath]; } - + NSString* dstRelativePath = [request.headers objectForKey:@"Destination"]; NSRange range = [dstRelativePath rangeOfString:[request.headers objectForKey:@"Host"]]; if ((dstRelativePath == nil) || (range.location == NSNotFound)) { @@ -269,23 +274,23 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL) if (![self _checkSandboxedPath:dstAbsolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath]; } - + BOOL isDirectory; if (![[NSFileManager defaultManager] fileExistsAtPath:[dstAbsolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Invalid destination \"%@\"", dstRelativePath]; } - + NSString* itemName = [dstAbsolutePath lastPathComponent]; if ((!_allowHidden && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"%@ to item name \"%@\" is not allowed", isMove ? @"Moving" : @"Copying", itemName]; } - + NSString* overwriteHeader = [request.headers objectForKey:@"Overwrite"]; BOOL existing = [[NSFileManager defaultManager] fileExistsAtPath:dstAbsolutePath]; if (existing && ((isMove && ![overwriteHeader isEqualToString:@"T"]) || (!isMove && [overwriteHeader isEqualToString:@"F"]))) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_PreconditionFailed message:@"Destination \"%@\" already exists", dstRelativePath]; } - + if (isMove) { if (![self shouldMoveItemFromPath:srcAbsolutePath toPath:dstAbsolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Moving \"%@\" to \"%@\" is not permitted", srcRelativePath, dstRelativePath]; @@ -295,7 +300,7 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL) return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Copying \"%@\" to \"%@\" is not permitted", srcRelativePath, dstRelativePath]; } } - + NSError* error = nil; if (isMove) { [[NSFileManager defaultManager] removeItemAtPath:dstAbsolutePath error:NULL]; @@ -307,7 +312,7 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL) return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden underlyingError:error message:@"Failed copying \"%@\" to \"%@\"", srcRelativePath, dstRelativePath]; } } - + if (isMove) { if ([self.delegate respondsToSelector:@selector(davServer:didMoveItemFromPath:toPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -321,7 +326,7 @@ - (GCDWebServerResponse*)performCOPY:(GCDWebServerRequest*)request isMove:(BOOL) }); } } - + return [GCDWebServerResponse responseWithStatusCode:(existing ? kGCDWebServerHTTPStatusCode_NoContent : kGCDWebServerHTTPStatusCode_Created)]; } @@ -350,7 +355,7 @@ - (void)_addPropertyResponseForItem:(NSString*)itemPath resource:(NSString*)reso [xmlString appendFormat:@"%@", escapedPath]; [xmlString appendString:@""]; [xmlString appendString:@""]; - + if (properties & kDAVProperty_ResourceType) { if (isDirectory) { [xmlString appendString:@""]; @@ -358,19 +363,19 @@ - (void)_addPropertyResponseForItem:(NSString*)itemPath resource:(NSString*)reso [xmlString appendString:@""]; } } - + if ((properties & kDAVProperty_CreationDate) && [attributes objectForKey:NSFileCreationDate]) { [xmlString appendFormat:@"%@", GCDWebServerFormatISO8601([attributes fileCreationDate])]; } - + if ((properties & kDAVProperty_LastModified) && isFile && [attributes objectForKey:NSFileModificationDate]) { // Last modification date is not useful for directories as it changes implicitely and 'Last-Modified' header is not provided for directories anyway [xmlString appendFormat:@"%@", GCDWebServerFormatRFC822([attributes fileModificationDate])]; } - + if ((properties & kDAVProperty_ContentLength) && !isDirectory && [attributes objectForKey:NSFileSize]) { [xmlString appendFormat:@"%llu", [attributes fileSize]]; } - + [xmlString appendString:@""]; [xmlString appendString:@"HTTP/1.1 200 OK"]; [xmlString appendString:@""]; @@ -392,7 +397,7 @@ - (GCDWebServerResponse*)performPROPFIND:(GCDWebServerDataRequest*)request { } else { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Unsupported 'Depth' header: %@", depthHeader]; // TODO: Return 403 / propfind-finite-depth for "infinity" depth } - + DAVProperties properties = 0; if (request.data.length) { BOOL success = YES; @@ -433,19 +438,19 @@ - (GCDWebServerResponse*)performPROPFIND:(GCDWebServerDataRequest*)request { } else { properties = kDAVAllProperties; } - + NSString* relativePath = request.path; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; BOOL isDirectory = NO; if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* itemName = [absolutePath lastPathComponent]; if (([itemName hasPrefix:@"."] && !_allowHidden) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Retrieving properties for item name \"%@\" is not allowed", itemName]; } - + NSArray* items = nil; if (isDirectory) { NSError* error = nil; @@ -454,7 +459,7 @@ - (GCDWebServerResponse*)performPROPFIND:(GCDWebServerDataRequest*)request { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed listing directory \"%@\"", relativePath]; } } - + NSMutableString* xmlString = [NSMutableString stringWithString:@""]; [xmlString appendString:@"\n"]; if (![relativePath hasPrefix:@"/"]) { @@ -472,7 +477,7 @@ - (GCDWebServerResponse*)performPROPFIND:(GCDWebServerDataRequest*)request { } } [xmlString appendString:@""]; - + GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithData:[xmlString dataUsingEncoding:NSUTF8StringEncoding] contentType:@"application/xml; charset=\"utf-8\""]; response.statusCode = kGCDWebServerHTTPStatusCode_MultiStatus; @@ -483,14 +488,14 @@ - (GCDWebServerResponse*)performLOCK:(GCDWebServerDataRequest*)request { if (!_IsMacFinder(request)) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_MethodNotAllowed message:@"LOCK method only allowed for Mac Finder"]; } - + NSString* relativePath = request.path; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; BOOL isDirectory = NO; if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* depthHeader = [request.headers objectForKey:@"Depth"]; NSString* timeoutHeader = [request.headers objectForKey:@"Timeout"]; NSString* scope = nil; @@ -528,16 +533,16 @@ - (GCDWebServerResponse*)performLOCK:(GCDWebServerDataRequest*)request { NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string]; } - + if (![scope isEqualToString:@"exclusive"] || ![type isEqualToString:@"write"] || ![depthHeader isEqualToString:@"0"]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Locking request \"%@/%@/%@\" for \"%@\" is not allowed", scope, type, depthHeader, relativePath]; } - + NSString* itemName = [absolutePath lastPathComponent]; if ((!_allowHidden && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Locking item name \"%@\" is not allowed", itemName]; } - + #ifdef __GCDWEBSERVER_ENABLE_TESTING__ NSString* lockTokenHeader = [request.headers objectForKey:@"X-GCDWebServer-LockToken"]; if (lockTokenHeader) { @@ -551,7 +556,7 @@ - (GCDWebServerResponse*)performLOCK:(GCDWebServerDataRequest*)request { CFRelease(string); CFRelease(uuid); } - + NSMutableString* xmlString = [NSMutableString stringWithString:@""]; [xmlString appendString:@"\n"]; [xmlString appendString:@"\n\n"]; @@ -569,7 +574,7 @@ - (GCDWebServerResponse*)performLOCK:(GCDWebServerDataRequest*)request { [xmlString appendFormat:@"%@\n", lockroot]; [xmlString appendString:@"\n\n"]; [xmlString appendString:@""]; - + [self logVerbose:@"WebDAV pretending to lock \"%@\"", relativePath]; GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithData:[xmlString dataUsingEncoding:NSUTF8StringEncoding] contentType:@"application/xml; charset=\"utf-8\""]; @@ -580,24 +585,24 @@ - (GCDWebServerResponse*)performUNLOCK:(GCDWebServerRequest*)request { if (!_IsMacFinder(request)) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_MethodNotAllowed message:@"UNLOCK method only allowed for Mac Finder"]; } - + NSString* relativePath = request.path; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; BOOL isDirectory = NO; if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* tokenHeader = [request.headers objectForKey:@"Lock-Token"]; if (!tokenHeader.length) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Missing 'Lock-Token' header"]; } - + NSString* itemName = [absolutePath lastPathComponent]; if ((!_allowHidden && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Unlocking item name \"%@\" is not allowed", itemName]; } - + [self logVerbose:@"WebDAV pretending to unlock \"%@\"", relativePath]; return [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_NoContent]; } @@ -606,7 +611,7 @@ - (GCDWebServerResponse*)performUNLOCK:(GCDWebServerRequest*)request { @implementation GCDWebDAVServer -@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden; +@synthesize uploadDirectory = _uploadDirectory, allowedFileExtensions = _allowedExtensions, allowHiddenItems = _allowHidden; @dynamic delegate; @@ -614,57 +619,76 @@ - (instancetype)initWithUploadDirectory:(NSString*)path { if ((self = [super init])) { _uploadDirectory = [[path stringByStandardizingPath] copy]; GCDWebDAVServer* __unsafe_unretained server = self; - + // 9.1 PROPFIND method - [self addDefaultHandlerForMethod:@"PROPFIND" requestClass:[GCDWebServerDataRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performPROPFIND:(GCDWebServerDataRequest*)request]; - }]; - + [self addDefaultHandlerForMethod:@"PROPFIND" + requestClass:[GCDWebServerDataRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performPROPFIND:(GCDWebServerDataRequest*)request]; + }]; + // 9.3 MKCOL Method - [self addDefaultHandlerForMethod:@"MKCOL" requestClass:[GCDWebServerDataRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performMKCOL:(GCDWebServerDataRequest*)request]; - }]; - + [self addDefaultHandlerForMethod:@"MKCOL" + requestClass:[GCDWebServerDataRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performMKCOL:(GCDWebServerDataRequest*)request]; + }]; + // 9.4 GET & HEAD methods - [self addDefaultHandlerForMethod:@"GET" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performGET:request]; - }]; - + [self addDefaultHandlerForMethod:@"GET" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performGET:request]; + }]; + // 9.6 DELETE method - [self addDefaultHandlerForMethod:@"DELETE" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performDELETE:request]; - }]; - + [self addDefaultHandlerForMethod:@"DELETE" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performDELETE:request]; + }]; + // 9.7 PUT method - [self addDefaultHandlerForMethod:@"PUT" requestClass:[GCDWebServerFileRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performPUT:(GCDWebServerFileRequest*)request]; - }]; - + [self addDefaultHandlerForMethod:@"PUT" + requestClass:[GCDWebServerFileRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performPUT:(GCDWebServerFileRequest*)request]; + }]; + // 9.8 COPY method - [self addDefaultHandlerForMethod:@"COPY" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performCOPY:request isMove:NO]; - }]; - + [self addDefaultHandlerForMethod:@"COPY" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performCOPY:request isMove:NO]; + }]; + // 9.9 MOVE method - [self addDefaultHandlerForMethod:@"MOVE" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performCOPY:request isMove:YES]; - }]; - + [self addDefaultHandlerForMethod:@"MOVE" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performCOPY:request isMove:YES]; + }]; + // 9.10 LOCK method - [self addDefaultHandlerForMethod:@"LOCK" requestClass:[GCDWebServerDataRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performLOCK:(GCDWebServerDataRequest*)request]; - }]; - + [self addDefaultHandlerForMethod:@"LOCK" + requestClass:[GCDWebServerDataRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performLOCK:(GCDWebServerDataRequest*)request]; + }]; + // 9.11 UNLOCK method - [self addDefaultHandlerForMethod:@"UNLOCK" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performUNLOCK:request]; - }]; - + [self addDefaultHandlerForMethod:@"UNLOCK" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performUNLOCK:request]; + }]; + // 10.1 OPTIONS method / DAV Header - [self addDefaultHandlerForMethod:@"OPTIONS" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server performOPTIONS:request]; - }]; - + [self addDefaultHandlerForMethod:@"OPTIONS" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server performOPTIONS:request]; + }]; } return self; } diff --git a/src/ios/GCDWebServer/GCDWebServer.podspec b/src/ios/GCDWebServer/GCDWebServer.podspec old mode 100644 new mode 100755 index 3fd4b9e..3cacb0b --- a/src/ios/GCDWebServer/GCDWebServer.podspec +++ b/src/ios/GCDWebServer/GCDWebServer.podspec @@ -2,12 +2,12 @@ # http://guides.cocoapods.org/making/getting-setup-with-trunk.html # $ sudo gem update cocoapods # (optional) $ pod trunk register {email} {name} --description={computer} -# $ pod trunk push +# $ pod trunk --verbose push # DELETE THIS SECTION BEFORE PROCEEDING! Pod::Spec.new do |s| s.name = 'GCDWebServer' - s.version = '3.3.1' + s.version = '3.3.4' s.author = { 'Pierre-Olivier Latour' => 'info@pol-online.net' } s.license = { :type => 'BSD', :file => 'LICENSE' } s.homepage = 'https://github.com/swisspol/GCDWebServer' @@ -33,21 +33,39 @@ Pod::Spec.new do |s| cs.osx.framework = 'SystemConfiguration' end - s.subspec 'WebDAV' do |cs| + s.subspec "CocoaLumberjack" do |cs| cs.dependency 'GCDWebServer/Core' - cs.source_files = 'GCDWebDAVServer/*.{h,m}' - cs.requires_arc = true - cs.ios.library = 'xml2' - cs.tvos.library = 'xml2' - cs.osx.library = 'xml2' - cs.compiler_flags = '-I$(SDKROOT)/usr/include/libxml2' + cs.dependency 'CocoaLumberjack', '~> 2' end - s.subspec 'WebUploader' do |cs| - cs.dependency 'GCDWebServer/Core' - cs.source_files = 'GCDWebUploader/*.{h,m}' - cs.requires_arc = true - cs.resource = "GCDWebUploader/GCDWebUploader.bundle" + s.subspec 'WebDAV' do |cs| + cs.subspec "Core" do |ccs| + ccs.dependency 'GCDWebServer/Core' + ccs.source_files = 'GCDWebDAVServer/*.{h,m}' + ccs.requires_arc = true + ccs.ios.library = 'xml2' + ccs.tvos.library = 'xml2' + ccs.osx.library = 'xml2' + ccs.compiler_flags = '-I$(SDKROOT)/usr/include/libxml2' + end + + cs.subspec "CocoaLumberjack" do |cscl| + cscl.dependency 'GCDWebServer/WebDAV/Core' + cscl.dependency 'GCDWebServer/CocoaLumberjack' + end end + s.subspec 'WebUploader' do |cs| + cs.subspec "Core" do |ccs| + ccs.dependency 'GCDWebServer/Core' + ccs.source_files = 'GCDWebUploader/*.{h,m}' + ccs.requires_arc = true + ccs.resource = "GCDWebUploader/GCDWebUploader.bundle" + end + + cs.subspec "CocoaLumberjack" do |cscl| + cscl.dependency 'GCDWebServer/WebUploader/Core' + cscl.dependency 'GCDWebServer/CocoaLumberjack' + end + end end diff --git a/src/ios/GCDWebServer/GCDWebServer.xcodeproj/project.pbxproj b/src/ios/GCDWebServer/GCDWebServer.xcodeproj/project.pbxproj old mode 100644 new mode 100755 index 2977a13..68d0203 --- a/src/ios/GCDWebServer/GCDWebServer.xcodeproj/project.pbxproj +++ b/src/ios/GCDWebServer/GCDWebServer.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXAggregateTarget section */ @@ -854,14 +854,13 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; TargetAttributes = { CEE28CD01AE004D800F4023C = { CreatedOnToolsVersion = 6.3; }; CEE28CEE1AE0051F00F4023C = { CreatedOnToolsVersion = 6.3; - DevelopmentTeam = 88W3E55T4B; }; E24039241BA09207000B7089 = { CreatedOnToolsVersion = 6.4; @@ -871,7 +870,6 @@ }; E2DDD1C61BE698A8002CE867 = { CreatedOnToolsVersion = 7.1; - DevelopmentTeam = 88W3E55T4B; }; E2DDD1F51BE69EE4002CE867 = { CreatedOnToolsVersion = 7.1; @@ -879,7 +877,7 @@ }; }; buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "GCDWebServer" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( @@ -1208,7 +1206,7 @@ 1DEB928A08733DD80010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_VERSION_STRING = 3.3.1; + BUNDLE_VERSION_STRING = 3.3.4; CLANG_ENABLE_OBJC_ARC = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -1238,6 +1236,7 @@ "-Wno-reserved-id-macro", "-Wno-cast-qual", "-Wno-nullable-to-nonnull-conversion", + "-Wno-partial-availability", ); }; name = Debug; @@ -1245,7 +1244,7 @@ 1DEB928B08733DD80010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - BUNDLE_VERSION_STRING = 3.3.1; + BUNDLE_VERSION_STRING = 3.3.4; CLANG_ENABLE_OBJC_ARC = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = __GCDWEBSERVER_ENABLE_TESTING__; @@ -1268,6 +1267,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = GCDWebServers; SDKROOT = macosx; + SKIP_INSTALL = YES; }; name = Debug; }; @@ -1283,13 +1283,13 @@ MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = GCDWebServers; SDKROOT = macosx; + SKIP_INSTALL = YES; }; name = Release; }; CEE28D031AE0052000F4023C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1298,15 +1298,14 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = GCDWebServers; - PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; + SKIP_INSTALL = YES; }; name = Debug; }; CEE28D041AE0052000F4023C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1315,8 +1314,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = GCDWebServers; - PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; + SKIP_INSTALL = YES; }; name = Release; }; @@ -1373,7 +1372,6 @@ E2DDD1901BE69404002CE867 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1381,8 +1379,8 @@ INFOPLIST_FILE = Frameworks/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = GCDWebServers; - PROVISIONING_PROFILE = ""; SDKROOT = appletvos; + SKIP_INSTALL = YES; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -1390,7 +1388,6 @@ E2DDD1911BE69404002CE867 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -1398,8 +1395,8 @@ INFOPLIST_FILE = Frameworks/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = GCDWebServers; - PROVISIONING_PROFILE = ""; SDKROOT = appletvos; + SKIP_INSTALL = YES; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; @@ -1407,7 +1404,6 @@ E2DDD1D91BE698A8002CE867 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = tvOS/Info.plist; PRODUCT_NAME = GCDWebServer; PROVISIONING_PROFILE = ""; @@ -1419,7 +1415,6 @@ E2DDD1DA1BE698A8002CE867 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; INFOPLIST_FILE = tvOS/Info.plist; PRODUCT_NAME = GCDWebServer; PROVISIONING_PROFILE = ""; @@ -1431,10 +1426,9 @@ E2DDD20B1BE69EE5002CE867 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; ENABLE_BITCODE = YES; INFOPLIST_FILE = iOS/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = GCDWebServer; PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; @@ -1445,10 +1439,9 @@ E2DDD20C1BE69EE5002CE867 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; ENABLE_BITCODE = YES; INFOPLIST_FILE = iOS/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = GCDWebServer; PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; diff --git a/src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme b/src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme old mode 100644 new mode 100755 index 0086ec7..a1d9d06 --- a/src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme +++ b/src/ios/GCDWebServer/GCDWebServer.xcodeproj/xcshareddata/xcschemes/GCDWebServers (Mac).xcscheme @@ -1,6 +1,6 @@ @@ -63,11 +62,6 @@ - - @@ -62,11 +61,6 @@ - - @@ -62,11 +61,6 @@ - - = 0); if (_activeConnections == 0) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -280,7 +284,7 @@ - (void)willStartConnection:(GCDWebServerConnection*)connection { }); } _activeConnections += 1; - + }); } @@ -307,11 +311,11 @@ - (void)_didDisconnect { GWS_DCHECK(_connected == YES); _connected = NO; GWS_LOG_DEBUG(@"Did disconnect"); - + #if TARGET_OS_IPHONE [self _endBackgroundTask]; #endif - + if ([_delegate respondsToSelector:@selector(webServerDidDisconnect:)]) { [_delegate webServerDidDisconnect:self]; } @@ -354,9 +358,10 @@ - (NSString*)bonjourType { } - (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock { - [self addHandlerWithMatchBlock:matchBlock asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { - completionBlock(processBlock(request)); - }]; + [self addHandlerWithMatchBlock:matchBlock + asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { + completionBlock(processBlock(request)); + }]; } - (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock asyncProcessBlock:(GCDWebServerAsyncProcessBlock)processBlock { @@ -460,9 +465,14 @@ - (int)_createListeningSocket:(BOOL)useIPv6 error:(NSError**)error { int listeningSocket = socket(useIPv6 ? PF_INET6 : PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listeningSocket > 0) { + if (!useIPv6) { + ipv4ListeningSocket = listeningSocket; + } else { + ipv6ListeningSocket = listeningSocket; + } int yes = 1; setsockopt(listeningSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - + if (bind(listeningSocket, address, length) == 0) { if (listen(listeningSocket, (int)maxPendingConnections) == 0) { GWS_LOG_DEBUG(@"Did open %s listening socket %i", useIPv6 ? "IPv6" : "IPv4", listeningSocket); @@ -481,7 +491,7 @@ - (int)_createListeningSocket:(BOOL)useIPv6 GWS_LOG_ERROR(@"Failed binding %s listening socket: %s (%i)", useIPv6 ? "IPv6" : "IPv4", strerror(errno), errno); close(listeningSocket); } - + } else { if (error) { *error = GCDWebServerMakePosixError(errno); @@ -493,9 +503,9 @@ - (int)_createListeningSocket:(BOOL)useIPv6 - (dispatch_source_t)_createDispatchSourceWithListeningSocket:(int)listeningSocket isIPv6:(BOOL)isIPv6 { dispatch_group_enter(_sourceGroup); - dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, listeningSocket, 0, kGCDWebServerGCDQueue); + dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, listeningSocket, 0, dispatch_get_global_queue(_dispatchQueuePriority, 0)); dispatch_source_set_cancel_handler(source, ^{ - + @autoreleasepool { int result = close(listeningSocket); if (result != 0) { @@ -505,17 +515,17 @@ - (dispatch_source_t)_createDispatchSourceWithListeningSocket:(int)listeningSock } } dispatch_group_leave(_sourceGroup); - + }); dispatch_source_set_event_handler(source, ^{ - + @autoreleasepool { struct sockaddr_storage remoteSockAddr; socklen_t remoteAddrLen = sizeof(remoteSockAddr); int socket = accept(listeningSocket, (struct sockaddr*)&remoteSockAddr, &remoteAddrLen); if (socket > 0) { NSData* remoteAddress = [NSData dataWithBytes:&remoteSockAddr length:remoteAddrLen]; - + struct sockaddr_storage localSockAddr; socklen_t localAddrLen = sizeof(localSockAddr); NSData* localAddress = nil; @@ -525,28 +535,28 @@ - (dispatch_source_t)_createDispatchSourceWithListeningSocket:(int)listeningSock } else { GWS_DNOT_REACHED(); } - + int noSigPipe = 1; setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &noSigPipe, sizeof(noSigPipe)); // Make sure this socket cannot generate SIG_PIPE - + GCDWebServerConnection* connection = [[_connectionClass alloc] initWithServer:self localAddress:localAddress remoteAddress:remoteAddress socket:socket]; // Connection will automatically retain itself while opened [connection self]; // Prevent compiler from complaining about unused variable / useless statement } else { GWS_LOG_ERROR(@"Failed accepting %s socket: %s (%i)", isIPv6 ? "IPv6" : "IPv4", strerror(errno), errno); } } - + }); return source; } - (BOOL)_start:(NSError**)error { 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; bzero(&addr4, sizeof(addr4)); addr4.sin_len = sizeof(addr4); @@ -566,19 +576,14 @@ - (BOOL)_start:(NSError**)error { GWS_LOG_ERROR(@"Failed retrieving socket address: %s (%i)", strerror(errno), errno); } } - - struct sockaddr_in6 addr6; - bzero(&addr6, sizeof(addr6)); - addr6.sin6_len = sizeof(addr6); - addr6.sin6_family = AF_INET6; - addr6.sin6_port = htons(port); - addr6.sin6_addr = bindToLocalhost ? in6addr_loopback : in6addr_any; + + struct sockaddr_in6 addr6 = [self generateAddressWithPort:port bindToLocalhost:bindToLocalhost]; int listeningSocket6 = [self _createListeningSocket:YES localAddress:&addr6 length:sizeof(addr6) maxPendingConnections:maxPendingConnections error:error]; if (listeningSocket6 <= 0) { close(listeningSocket4); return NO; } - + _serverName = [_GetOption(_options, GCDWebServerOption_ServerName, NSStringFromClass([self class])) copy]; NSString* authenticationMethod = _GetOption(_options, GCDWebServerOption_AuthenticationMethod, nil); if ([authenticationMethod isEqualToString:GCDWebServerAuthenticationMethod_Basic]) { @@ -599,24 +604,25 @@ - (BOOL)_start:(NSError**)error { _connectionClass = _GetOption(_options, GCDWebServerOption_ConnectionClass, [GCDWebServerConnection class]); _mapHEADToGET = [_GetOption(_options, GCDWebServerOption_AutomaticallyMapHEADToGET, @YES) boolValue]; _disconnectDelay = [_GetOption(_options, GCDWebServerOption_ConnectedStateCoalescingInterval, @1.0) doubleValue]; - + _dispatchQueuePriority = [_GetOption(_options, GCDWebServerOption_DispatchQueuePriority, @(DISPATCH_QUEUE_PRIORITY_DEFAULT)) longValue]; + _source4 = [self _createDispatchSourceWithListeningSocket:listeningSocket4 isIPv6:NO]; _source6 = [self _createDispatchSourceWithListeningSocket:listeningSocket6 isIPv6:YES]; _port = port; _bindToLocalhost = bindToLocalhost; - + 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); if (_registrationService) { CFNetServiceClientContext context = {0, (__bridge void*)self, NULL, NULL, NULL}; - + CFNetServiceSetClient(_registrationService, _NetServiceRegisterCallBack, &context); CFNetServiceScheduleWithRunLoop(_registrationService, CFRunLoopGetMain(), kCFRunLoopCommonModes); CFStreamError streamError = {0}; CFNetServiceRegisterWithOptions(_registrationService, 0, &streamError); - + _resolutionService = CFNetServiceCreateCopy(kCFAllocatorDefault, _registrationService); if (_resolutionService) { CFNetServiceSetClient(_resolutionService, _NetServiceResolveCallBack, &context); @@ -628,7 +634,7 @@ - (BOOL)_start:(NSError**)error { 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) { @@ -651,7 +657,7 @@ - (BOOL)_start:(NSError**)error { GWS_LOG_ERROR(@"Failed creating NAT port mapping (%i)", status); } } - + dispatch_resume(_source4); dispatch_resume(_source6); GWS_LOG_INFO(@"%@ started on port %i and reachable at %@", [self class], (int)_port, self.serverURL); @@ -660,13 +666,13 @@ - (BOOL)_start:(NSError**)error { [_delegate webServerDidStart:self]; }); } - + return YES; } - (void)_stop { GWS_DCHECK(_source4 != NULL); - + if (_dnsService) { _dnsAddress = nil; _dnsPort = 0; @@ -682,7 +688,7 @@ - (void)_stop { DNSServiceRefDeallocate(_dnsService); _dnsService = NULL; } - + if (_registrationService) { if (_resolutionService) { CFNetServiceUnscheduleFromRunLoop(_resolutionService, CFRunLoopGetMain(), kCFRunLoopCommonModes); @@ -697,7 +703,7 @@ - (void)_stop { CFRelease(_registrationService); _registrationService = NULL; } - + dispatch_source_cancel(_source6); dispatch_source_cancel(_source4); dispatch_group_wait(_sourceGroup, DISPATCH_TIME_FOREVER); // Wait until the cancellation handlers have been called which guarantees the listening sockets are closed @@ -711,12 +717,12 @@ - (void)_stop { _source4 = NULL; _port = 0; _bindToLocalhost = NO; - + _serverName = nil; _authenticationRealm = nil; _authenticationBasicAccounts = nil; _authenticationDigestAccounts = nil; - + dispatch_async(dispatch_get_main_queue(), ^{ if (_disconnectTimer) { CFRunLoopTimerInvalidate(_disconnectTimer); @@ -725,7 +731,7 @@ - (void)_stop { [self _didDisconnect]; } }); - + GWS_LOG_INFO(@"%@ stopped", [self class]); if ([_delegate respondsToSelector:@selector(webServerDidStop:)]) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -736,6 +742,24 @@ - (void)_stop { #if TARGET_OS_IPHONE +- (BOOL)hasSocketError:(int)socket { + int error = 0; + socklen_t len = sizeof(error); + int retval = getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len); + + if (retval != 0 ) { + /* there was a problem getting the error code */ + GWS_LOG_ERROR(@"error getting socket error code: %s\n", strerror(retval)); + return YES; + } + + if (error != 0) { + GWS_LOG_INFO(@"Socket error: %s on socket %d\n", strerror(error), socket); + return YES; + } + return NO; +} + - (void)_didEnterBackground:(NSNotification*)notification { GWS_DCHECK([NSThread isMainThread]); GWS_LOG_DEBUG(@"Did enter background"); @@ -747,13 +771,39 @@ - (void)_didEnterBackground:(NSNotification*)notification { - (void)_willEnterForeground:(NSNotification*)notification { GWS_DCHECK([NSThread isMainThread]); GWS_LOG_DEBUG(@"Will enter foreground"); - if (!_source4) { + + if (_suspendInBackground && !_source4) { [self _start:NULL]; // TODO: There's probably nothing we can do on failure } + + if ([self isRunning] && ([self hasSocketError:ipv4ListeningSocket] || [self hasSocketError:ipv6ListeningSocket])) { + [self _stop]; + [self _start:nil]; + } } #endif +- (struct sockaddr_in)generateIpv4AddressWithPort:(NSInteger)port bindToLocalhost:(BOOL)bindToLocalhost { + struct sockaddr_in addr4; + bzero(&addr4, sizeof(addr4)); + addr4.sin_len = sizeof(addr4); + addr4.sin_family = AF_INET; + addr4.sin_port = htons(port); + addr4.sin_addr.s_addr = bindToLocalhost ? htonl(INADDR_LOOPBACK) : htonl(INADDR_ANY); + return addr4; +} + +- (struct sockaddr_in6)generateAddressWithPort:(NSInteger)port bindToLocalhost:(BOOL)bindToLocalhost { + struct sockaddr_in6 addr6; + bzero(&addr6, sizeof(addr6)); + addr6.sin6_len = sizeof(addr6); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(port); + addr6.sin6_addr = bindToLocalhost ? in6addr_loopback : in6addr_any; + return addr6; +} + - (BOOL)startWithOptions:(NSDictionary*)options error:(NSError**)error { if (_options == nil) { _options = options ? [options copy] : @{}; @@ -770,8 +820,8 @@ - (BOOL)startWithOptions:(NSDictionary*)options error:(NSError**)error { #if TARGET_OS_IPHONE if (_suspendInBackground) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; #endif return YES; } else { @@ -787,10 +837,7 @@ - (BOOL)isRunning { - (void)stop { if (_options) { #if TARGET_OS_IPHONE - if (_suspendInBackground) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil]; - } + [[NSNotificationCenter defaultCenter] removeObserver:self]; #endif if (_source4) { [self _stop]; @@ -893,32 +940,38 @@ - (BOOL)runWithOptions:(NSDictionary*)options error:(NSError**)error { @implementation GCDWebServer (Handlers) - (void)addDefaultHandlerForMethod:(NSString*)method requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block { - [self addDefaultHandlerForMethod:method requestClass:aClass asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { - completionBlock(block(request)); - }]; + [self addDefaultHandlerForMethod:method + requestClass:aClass + asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { + completionBlock(block(request)); + }]; } - (void)addDefaultHandlerForMethod:(NSString*)method requestClass:(Class)aClass asyncProcessBlock:(GCDWebServerAsyncProcessBlock)block { - [self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { - + [self addHandlerWithMatchBlock:^GCDWebServerRequest*(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { + if (![requestMethod isEqualToString:method]) { return nil; } return [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]; - - } asyncProcessBlock:block]; + + } + asyncProcessBlock:block]; } - (void)addHandlerForMethod:(NSString*)method path:(NSString*)path requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block { - [self addHandlerForMethod:method path:path requestClass:aClass asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { - completionBlock(block(request)); - }]; + [self addHandlerForMethod:method + path:path + requestClass:aClass + asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { + completionBlock(block(request)); + }]; } - (void)addHandlerForMethod:(NSString*)method path:(NSString*)path requestClass:(Class)aClass asyncProcessBlock:(GCDWebServerAsyncProcessBlock)block { if ([path hasPrefix:@"/"] && [aClass isSubclassOfClass:[GCDWebServerRequest class]]) { - [self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { - + [self addHandlerWithMatchBlock:^GCDWebServerRequest*(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { + if (![requestMethod isEqualToString:method]) { return nil; } @@ -926,24 +979,28 @@ - (void)addHandlerForMethod:(NSString*)method path:(NSString*)path requestClass: return nil; } return [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]; - - } asyncProcessBlock:block]; + + } + asyncProcessBlock:block]; } else { GWS_DNOT_REACHED(); } } - (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block { - [self addHandlerForMethod:method pathRegex:regex requestClass:aClass asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { - completionBlock(block(request)); - }]; + [self addHandlerForMethod:method + pathRegex:regex + requestClass:aClass + asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { + completionBlock(block(request)); + }]; } - (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex requestClass:(Class)aClass asyncProcessBlock:(GCDWebServerAsyncProcessBlock)block { NSRegularExpression* expression = [NSRegularExpression regularExpressionWithPattern:regex options:NSRegularExpressionCaseInsensitive error:NULL]; if (expression && [aClass isSubclassOfClass:[GCDWebServerRequest class]]) { - [self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { - + [self addHandlerWithMatchBlock:^GCDWebServerRequest*(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { + if (![requestMethod isEqualToString:method]) { return nil; } @@ -957,15 +1014,21 @@ - (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex request 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]]; + } } } GCDWebServerRequest* request = [[aClass alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]; [request setAttribute:captures forKey:GCDWebServerRequestAttribute_RegexCaptures]; return request; - - } asyncProcessBlock:block]; + + } + asyncProcessBlock:block]; } else { GWS_DNOT_REACHED(); } @@ -976,29 +1039,35 @@ - (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex request @implementation GCDWebServer (GETHandlers) - (void)addGETHandlerForPath:(NSString*)path staticData:(NSData*)staticData contentType:(NSString*)contentType cacheAge:(NSUInteger)cacheAge { - [self addHandlerForMethod:@"GET" path:path requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - GCDWebServerResponse* response = [GCDWebServerDataResponse responseWithData:staticData contentType:contentType]; - response.cacheControlMaxAge = cacheAge; - return response; - - }]; + [self addHandlerForMethod:@"GET" + path:path + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + GCDWebServerResponse* response = [GCDWebServerDataResponse responseWithData:staticData contentType:contentType]; + response.cacheControlMaxAge = cacheAge; + return response; + + }]; } - (void)addGETHandlerForPath:(NSString*)path filePath:(NSString*)filePath isAttachment:(BOOL)isAttachment cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests { - [self addHandlerForMethod:@"GET" path:path requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - GCDWebServerResponse* response = nil; - if (allowRangeRequests) { - response = [GCDWebServerFileResponse responseWithFile:filePath byteRange:request.byteRange isAttachment:isAttachment]; - [response setValue:@"bytes" forAdditionalHeader:@"Accept-Ranges"]; - } else { - response = [GCDWebServerFileResponse responseWithFile:filePath isAttachment:isAttachment]; - } - response.cacheControlMaxAge = cacheAge; - return response; - - }]; + [self addHandlerForMethod:@"GET" + path:path + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + GCDWebServerResponse* response = nil; + if (allowRangeRequests) { + response = [GCDWebServerFileResponse responseWithFile:filePath byteRange:request.byteRange isAttachment:isAttachment]; + [response setValue:@"bytes" forAdditionalHeader:@"Accept-Ranges"]; + } else { + response = [GCDWebServerFileResponse responseWithFile:filePath isAttachment:isAttachment]; + } + response.cacheControlMaxAge = cacheAge; + return response; + + }]; } - (GCDWebServerResponse*)_responseWithContentsOfDirectory:(NSString*)path { @@ -1034,8 +1103,8 @@ - (GCDWebServerResponse*)_responseWithContentsOfDirectory:(NSString*)path { - (void)addGETHandlerForBasePath:(NSString*)basePath directoryPath:(NSString*)directoryPath indexFilename:(NSString*)indexFilename cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests { if ([basePath hasPrefix:@"/"] && [basePath hasSuffix:@"/"]) { GCDWebServer* __unsafe_unretained server = self; - [self addHandlerWithMatchBlock:^GCDWebServerRequest *(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { - + [self addHandlerWithMatchBlock:^GCDWebServerRequest*(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery) { + if (![requestMethod isEqualToString:@"GET"]) { return nil; } @@ -1043,39 +1112,40 @@ - (void)addGETHandlerForBasePath:(NSString*)basePath directoryPath:(NSString*)di return nil; } return [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:urlPath query:urlQuery]; - - } processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - GCDWebServerResponse* response = nil; - NSString* filePath = [directoryPath stringByAppendingPathComponent:[request.path substringFromIndex:basePath.length]]; - NSString* fileType = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] fileType]; - if (fileType) { - if ([fileType isEqualToString:NSFileTypeDirectory]) { - if (indexFilename) { - NSString* indexPath = [filePath stringByAppendingPathComponent:indexFilename]; - NSString* indexType = [[[NSFileManager defaultManager] attributesOfItemAtPath:indexPath error:NULL] fileType]; - if ([indexType isEqualToString:NSFileTypeRegular]) { - return [GCDWebServerFileResponse responseWithFile:indexPath]; + + } + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + GCDWebServerResponse* response = nil; + NSString* filePath = [directoryPath stringByAppendingPathComponent:[request.path substringFromIndex:basePath.length]]; + NSString* fileType = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] fileType]; + if (fileType) { + if ([fileType isEqualToString:NSFileTypeDirectory]) { + if (indexFilename) { + NSString* indexPath = [filePath stringByAppendingPathComponent:indexFilename]; + NSString* indexType = [[[NSFileManager defaultManager] attributesOfItemAtPath:indexPath error:NULL] fileType]; + if ([indexType isEqualToString:NSFileTypeRegular]) { + return [GCDWebServerFileResponse responseWithFile:indexPath]; + } + } + response = [server _responseWithContentsOfDirectory:filePath]; + } else if ([fileType isEqualToString:NSFileTypeRegular]) { + if (allowRangeRequests) { + response = [GCDWebServerFileResponse responseWithFile:filePath byteRange:request.byteRange]; + [response setValue:@"bytes" forAdditionalHeader:@"Accept-Ranges"]; + } else { + response = [GCDWebServerFileResponse responseWithFile:filePath]; + } } } - response = [server _responseWithContentsOfDirectory:filePath]; - } else if ([fileType isEqualToString:NSFileTypeRegular]) { - if (allowRangeRequests) { - response = [GCDWebServerFileResponse responseWithFile:filePath byteRange:request.byteRange]; - [response setValue:@"bytes" forAdditionalHeader:@"Accept-Ranges"]; + if (response) { + response.cacheControlMaxAge = cacheAge; } else { - response = [GCDWebServerFileResponse responseWithFile:filePath]; + response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_NotFound]; } - } - } - if (response) { - response.cacheControlMaxAge = cacheAge; - } else { - response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_NotFound]; - } - return response; - - }]; + return response; + + }]; } else { GWS_DNOT_REACHED(); } @@ -1123,10 +1193,6 @@ - (void)logError:(NSString*)format, ... { va_end(arguments); } -- (void)logException:(NSException*)exception { - GWS_LOG_EXCEPTION(exception); -} - @end #ifdef __GCDWEBSERVER_ENABLE_TESTING__ @@ -1200,11 +1266,11 @@ static void _LogResult(NSString* format, ...) { - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path { GWS_DCHECK([NSThread isMainThread]); - NSArray* ignoredHeaders = @[@"Date", @"Etag"]; // Dates are always different by definition and ETags depend on file system node IDs + NSArray* ignoredHeaders = @[ @"Date", @"Etag" ]; // Dates are always different by definition and ETags depend on file system node IDs NSInteger result = -1; if ([self startWithOptions:options error:NULL]) { _ExecuteMainThreadRunLoopSources(); - + result = 0; NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL]; for (NSString* requestFile in files) { @@ -1226,19 +1292,19 @@ - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)p if ([responseFile hasPrefix:prefix] && [responseFile hasSuffix:@".response"]) { NSData* responseData = [NSData dataWithContentsOfFile:[path stringByAppendingPathComponent:responseFile]]; if (responseData) { - CFHTTPMessageRef expectedResponse = _CreateHTTPMessageFromData(responseData, NO); + CFHTTPMessageRef expectedResponse = _CreateHTTPMessageFromData(responseData, NO); if (expectedResponse) { CFHTTPMessageRef actualResponse = _CreateHTTPMessageFromPerformingRequest(requestData, self.port); if (actualResponse) { success = YES; - + CFIndex expectedStatusCode = CFHTTPMessageGetResponseStatusCode(expectedResponse); CFIndex actualStatusCode = CFHTTPMessageGetResponseStatusCode(actualResponse); if (actualStatusCode != expectedStatusCode) { _LogResult(@" Status code not matching:\n Expected: %i\n Actual: %i", (int)expectedStatusCode, (int)actualStatusCode); success = NO; } - + NSDictionary* expectedHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(expectedResponse)); NSDictionary* actualHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(actualResponse)); for (NSString* expectedHeader in expectedHeaders) { @@ -1258,7 +1324,7 @@ - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)p success = NO; } } - + NSString* expectedContentLength = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(expectedResponse, CFSTR("Content-Length"))); NSData* expectedBody = CFBridgingRelease(CFHTTPMessageCopyBody(expectedResponse)); NSString* actualContentLength = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(actualResponse, CFSTR("Content-Length"))); @@ -1277,14 +1343,14 @@ - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)p if ([expectedBody writeToFile:expectedPath atomically:YES] && [actualBody writeToFile:actualPath atomically:YES]) { NSTask* task = [[NSTask alloc] init]; [task setLaunchPath:@"/usr/bin/opendiff"]; - [task setArguments:@[expectedPath, actualPath]]; + [task setArguments:@[ expectedPath, actualPath ]]; [task launch]; } } #endif #endif } - + CFRelease(actualResponse); } CFRelease(expectedResponse); @@ -1307,9 +1373,9 @@ - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)p } _ExecuteMainThreadRunLoopSources(); } - + [self stop]; - + _ExecuteMainThreadRunLoopSources(); } return result; diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.h b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m old mode 100644 new mode 100755 index d6c369e..e3e21f4 --- a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m +++ b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m @@ -66,14 +66,14 @@ @interface GCDWebServerConnection () { NSUInteger _bytesRead; NSUInteger _bytesWritten; BOOL _virtualHEAD; - + CFHTTPMessageRef _requestMessage; GCDWebServerRequest* _request; GCDWebServerHandler* _handler; CFHTTPMessageRef _responseMessage; GCDWebServerResponse* _response; NSInteger _statusCode; - + BOOL _opened; #ifdef __GCDWEBSERVER_ENABLE_TESTING__ NSUInteger _connectionIndex; @@ -88,8 +88,8 @@ @interface GCDWebServerConnection () { @implementation GCDWebServerConnection (Read) - (void)_readData:(NSMutableData*)data withLength:(NSUInteger)length completionBlock:(ReadDataCompletionBlock)block { - dispatch_read(_socket, length, kGCDWebServerGCDQueue, ^(dispatch_data_t buffer, int error) { - + dispatch_read(_socket, length, dispatch_get_global_queue(_server.dispatchQueuePriority, 0), ^(dispatch_data_t buffer, int error) { + @autoreleasepool { if (error == 0) { size_t size = dispatch_data_get_size(buffer); @@ -114,68 +114,72 @@ - (void)_readData:(NSMutableData*)data withLength:(NSUInteger)length completionB block(NO); } } - + }); } - (void)_readHeaders:(NSMutableData*)headersData withCompletionBlock:(ReadHeadersCompletionBlock)block { GWS_DCHECK(_requestMessage); - [self _readData:headersData withLength:NSUIntegerMax completionBlock:^(BOOL success) { - - if (success) { - NSRange range = [headersData rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(0, headersData.length)]; - if (range.location == NSNotFound) { - [self _readHeaders:headersData withCompletionBlock:block]; - } else { - NSUInteger length = range.location + range.length; - if (CFHTTPMessageAppendBytes(_requestMessage, headersData.bytes, length)) { - if (CFHTTPMessageIsHeaderComplete(_requestMessage)) { - block([headersData subdataWithRange:NSMakeRange(length, headersData.length - length)]); + [self _readData:headersData + withLength:NSUIntegerMax + completionBlock:^(BOOL success) { + + if (success) { + NSRange range = [headersData rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(0, headersData.length)]; + if (range.location == NSNotFound) { + [self _readHeaders:headersData withCompletionBlock:block]; } else { - GWS_LOG_ERROR(@"Failed parsing request headers from socket %i", _socket); - block(nil); + NSUInteger length = range.location + range.length; + if (CFHTTPMessageAppendBytes(_requestMessage, headersData.bytes, length)) { + if (CFHTTPMessageIsHeaderComplete(_requestMessage)) { + block([headersData subdataWithRange:NSMakeRange(length, headersData.length - length)]); + } else { + GWS_LOG_ERROR(@"Failed parsing request headers from socket %i", _socket); + block(nil); + } + } else { + GWS_LOG_ERROR(@"Failed appending request headers data from socket %i", _socket); + block(nil); + } } } else { - GWS_LOG_ERROR(@"Failed appending request headers data from socket %i", _socket); block(nil); } - } - } else { - block(nil); - } - - }]; + + }]; } - (void)_readBodyWithRemainingLength:(NSUInteger)length completionBlock:(ReadBodyCompletionBlock)block { GWS_DCHECK([_request hasBody] && ![_request usesChunkedTransferEncoding]); NSMutableData* bodyData = [[NSMutableData alloc] initWithCapacity:kBodyReadCapacity]; - [self _readData:bodyData withLength:length completionBlock:^(BOOL success) { - - if (success) { - if (bodyData.length <= length) { - NSError* error = nil; - if ([_request performWriteData:bodyData error:&error]) { - NSUInteger remainingLength = length - bodyData.length; - if (remainingLength) { - [self _readBodyWithRemainingLength:remainingLength completionBlock:block]; + [self _readData:bodyData + withLength:length + completionBlock:^(BOOL success) { + + if (success) { + if (bodyData.length <= length) { + NSError* error = nil; + if ([_request performWriteData:bodyData error:&error]) { + NSUInteger remainingLength = length - bodyData.length; + if (remainingLength) { + [self _readBodyWithRemainingLength:remainingLength completionBlock:block]; + } else { + block(YES); + } + } else { + GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error); + block(NO); + } } else { - block(YES); + GWS_LOG_ERROR(@"Unexpected extra content reading request body on socket %i", _socket); + block(NO); + GWS_DNOT_REACHED(); } } else { - GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error); block(NO); } - } else { - GWS_LOG_ERROR(@"Unexpected extra content reading request body on socket %i", _socket); - block(NO); - GWS_DNOT_REACHED(); - } - } else { - block(NO); - } - - }]; + + }]; } static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) { @@ -189,7 +193,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) { - (void)_readNextBodyChunk:(NSMutableData*)chunkData completionBlock:(ReadBodyCompletionBlock)block { GWS_DCHECK([_request hasBody] && [_request usesChunkedTransferEncoding]); - + while (1) { NSRange range = [chunkData rangeOfData:_CRLFData options:0 range:NSMakeRange(0, chunkData.length)]; if (range.location == NSNotFound) { @@ -230,16 +234,18 @@ - (void)_readNextBodyChunk:(NSMutableData*)chunkData completionBlock:(ReadBodyCo return; } } - - [self _readData:chunkData withLength:NSUIntegerMax completionBlock:^(BOOL success) { - - if (success) { - [self _readNextBodyChunk:chunkData completionBlock:block]; - } else { - block(NO); - } - - }]; + + [self _readData:chunkData + withLength:NSUIntegerMax + completionBlock:^(BOOL success) { + + if (success) { + [self _readNextBodyChunk:chunkData completionBlock:block]; + } else { + block(NO); + } + + }]; } @end @@ -247,11 +253,11 @@ - (void)_readNextBodyChunk:(NSMutableData*)chunkData completionBlock:(ReadBodyCo @implementation GCDWebServerConnection (Write) - (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)block { - dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, kGCDWebServerGCDQueue, ^{ + dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, dispatch_get_global_queue(_server.dispatchQueuePriority, 0), ^{ [data self]; // Keeps ARC from releasing data too early }); - dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t remainingData, int error) { - + dispatch_write(_socket, buffer, dispatch_get_global_queue(_server.dispatchQueuePriority, 0), ^(dispatch_data_t remainingData, int error) { + @autoreleasepool { if (error == 0) { GWS_DCHECK(remainingData == NULL); @@ -262,7 +268,7 @@ - (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)b block(NO); } } - + }); #if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE dispatch_release(buffer); @@ -279,7 +285,7 @@ - (void)_writeHeadersWithCompletionBlock:(WriteHeadersCompletionBlock)block { - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block { GWS_DCHECK([_response hasBody]); [_response performReadDataWithCompletion:^(NSData* data, NSError* error) { - + if (data) { if (data.length) { if (_response.usesChunkedTransferEncoding) { @@ -302,22 +308,24 @@ - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block { *ptr = '\n'; data = chunk; } - [self _writeData:data withCompletionBlock:^(BOOL success) { - - if (success) { - [self _writeBodyWithCompletionBlock:block]; - } else { - block(NO); - } - - }]; + [self _writeData:data + withCompletionBlock:^(BOOL success) { + + if (success) { + [self _writeBodyWithCompletionBlock:block]; + } else { + block(NO); + } + + }]; } else { if (_response.usesChunkedTransferEncoding) { - [self _writeData:_lastChunkData withCompletionBlock:^(BOOL success) { - - block(success); - - }]; + [self _writeData:_lastChunkData + withCompletionBlock:^(BOOL success) { + + block(success); + + }]; } else { block(YES); } @@ -326,7 +334,7 @@ - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block { GWS_LOG_ERROR(@"Failed reading response body for socket %i: %@", _socket, error); block(NO); } - + }]; } @@ -334,7 +342,7 @@ - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block { @implementation GCDWebServerConnection -@synthesize server=_server, localAddressData=_localAddress, remoteAddressData=_remoteAddress, totalBytesRead=_bytesRead, totalBytesWritten=_bytesWritten; +@synthesize server = _server, localAddressData = _localAddress, remoteAddressData = _remoteAddress, totalBytesRead = _bytesRead, totalBytesWritten = _bytesWritten; + (void)initialize { if (_CRLFData == nil) { @@ -376,14 +384,15 @@ - (void)_initializeResponseHeadersWithStatusCode:(NSInteger)statusCode { - (void)_startProcessingRequest { GWS_DCHECK(_responseMessage == NULL); - + GCDWebServerResponse* preflightResponse = [self preflightRequest:_request]; if (preflightResponse) { [self _finishProcessingRequest:preflightResponse]; } else { - [self processRequest:_request completion:^(GCDWebServerResponse* processResponse) { - [self _finishProcessingRequest:processResponse]; - }]; + [self processRequest:_request + completion:^(GCDWebServerResponse* processResponse) { + [self _finishProcessingRequest:processResponse]; + }]; } } @@ -391,7 +400,7 @@ - (void)_startProcessingRequest { - (void)_finishProcessingRequest:(GCDWebServerResponse*)response { GWS_DCHECK(_responseMessage == NULL); BOOL hasBody = NO; - + if (response) { response = [self overrideResponse:response forRequest:_request]; } @@ -407,7 +416,7 @@ - (void)_finishProcessingRequest:(GCDWebServerResponse*)response { _response = response; } } - + if (_response) { [self _initializeResponseHeadersWithStatusCode:_response.statusCode]; if (_response.lastModifiedDate) { @@ -436,24 +445,23 @@ - (void)_finishProcessingRequest:(GCDWebServerResponse*)response { CFHTTPMessageSetHeaderFieldValue(_responseMessage, (__bridge CFStringRef)key, (__bridge CFStringRef)obj); }]; [self _writeHeadersWithCompletionBlock:^(BOOL success) { - + if (success) { if (hasBody) { [self _writeBodyWithCompletionBlock:^(BOOL successInner) { - + [_response performClose]; // TODO: There's nothing we can do on failure as headers have already been sent - + }]; } } else if (hasBody) { [_response performClose]; } - + }]; } else { [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; } - } - (void)_readBodyWithLength:(NSUInteger)length initialData:(NSData*)initialData { @@ -463,7 +471,7 @@ - (void)_readBodyWithLength:(NSUInteger)length initialData:(NSData*)initialData [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; return; } - + if (initialData.length) { if (![_request performWriteData:initialData error:&error]) { GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error); @@ -475,19 +483,20 @@ - (void)_readBodyWithLength:(NSUInteger)length initialData:(NSData*)initialData } length -= initialData.length; } - + if (length) { - [self _readBodyWithRemainingLength:length completionBlock:^(BOOL success) { - - NSError* localError = nil; - if ([_request performClose:&localError]) { - [self _startProcessingRequest]; - } else { - GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error); - [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; - } - - }]; + [self _readBodyWithRemainingLength:length + completionBlock:^(BOOL success) { + + NSError* localError = nil; + if ([_request performClose:&localError]) { + [self _startProcessingRequest]; + } else { + GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error); + [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; + } + + }]; } else { if ([_request performClose:&error]) { [self _startProcessingRequest]; @@ -505,100 +514,103 @@ - (void)_readChunkedBodyWithInitialData:(NSData*)initialData { [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; return; } - + NSMutableData* chunkData = [[NSMutableData alloc] initWithData:initialData]; - [self _readNextBodyChunk:chunkData completionBlock:^(BOOL success) { - - NSError* localError = nil; - if ([_request performClose:&localError]) { - [self _startProcessingRequest]; - } else { - GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error); - [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; - } - - }]; + [self _readNextBodyChunk:chunkData + completionBlock:^(BOOL success) { + + NSError* localError = nil; + if ([_request performClose:&localError]) { + [self _startProcessingRequest]; + } else { + GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error); + [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; + } + + }]; } - (void)_readRequestHeaders { _requestMessage = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, true); NSMutableData* headersData = [[NSMutableData alloc] initWithCapacity:kHeadersReadCapacity]; - [self _readHeaders:headersData withCompletionBlock:^(NSData* extraData) { - - if (extraData) { - NSString* requestMethod = CFBridgingRelease(CFHTTPMessageCopyRequestMethod(_requestMessage)); // Method verbs are case-sensitive and uppercase - if (_server.shouldAutomaticallyMapHEADToGET && [requestMethod isEqualToString:@"HEAD"]) { - requestMethod = @"GET"; - _virtualHEAD = YES; - } - NSDictionary* requestHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones - NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(_requestMessage)); - if (requestURL) { - requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders]; - GWS_DCHECK(requestURL); - } - NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(CFBridgingRelease(CFURLCopyPath((CFURLRef)requestURL))) : nil; // Don't use -[NSURL path] which strips the ending slash - NSString* queryString = requestURL ? CFBridgingRelease(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil; // Don't use -[NSURL query] to make sure query is not unescaped; - NSDictionary* requestQuery = queryString ? GCDWebServerParseURLEncodedForm(queryString) : @{}; - if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) { - for (_handler in _server.handlers) { - _request = _handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery); - if (_request) { - break; + [self _readHeaders:headersData + withCompletionBlock:^(NSData* extraData) { + + if (extraData) { + NSString* requestMethod = CFBridgingRelease(CFHTTPMessageCopyRequestMethod(_requestMessage)); // Method verbs are case-sensitive and uppercase + if (_server.shouldAutomaticallyMapHEADToGET && [requestMethod isEqualToString:@"HEAD"]) { + requestMethod = @"GET"; + _virtualHEAD = YES; } - } - if (_request) { - _request.localAddressData = self.localAddressData; - _request.remoteAddressData = self.remoteAddressData; - if ([_request hasBody]) { - [_request prepareForWriting]; - if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) { - NSString* expectHeader = [requestHeaders objectForKey:@"Expect"]; - if (expectHeader) { - if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) { // TODO: Actually validate request before continuing - [self _writeData:_continueData withCompletionBlock:^(BOOL success) { - - if (success) { - if (_request.usesChunkedTransferEncoding) { - [self _readChunkedBodyWithInitialData:extraData]; - } else { - [self _readBodyWithLength:_request.contentLength initialData:extraData]; - } + NSDictionary* requestHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones + NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(_requestMessage)); + if (requestURL) { + requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders]; + GWS_DCHECK(requestURL); + } + NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(CFBridgingRelease(CFURLCopyPath((CFURLRef)requestURL))) : nil; // Don't use -[NSURL path] which strips the ending slash + NSString* queryString = requestURL ? CFBridgingRelease(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil; // Don't use -[NSURL query] to make sure query is not unescaped; + NSDictionary* requestQuery = queryString ? GCDWebServerParseURLEncodedForm(queryString) : @{}; + if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) { + for (_handler in _server.handlers) { + _request = _handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery); + if (_request) { + break; + } + } + if (_request) { + _request.localAddressData = self.localAddressData; + _request.remoteAddressData = self.remoteAddressData; + if ([_request hasBody]) { + [_request prepareForWriting]; + if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) { + NSString* expectHeader = [requestHeaders objectForKey:@"Expect"]; + if (expectHeader) { + if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) { // TODO: Actually validate request before continuing + [self _writeData:_continueData + withCompletionBlock:^(BOOL success) { + + if (success) { + if (_request.usesChunkedTransferEncoding) { + [self _readChunkedBodyWithInitialData:extraData]; + } else { + [self _readBodyWithLength:_request.contentLength initialData:extraData]; + } + } + + }]; + } else { + GWS_LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket); + [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_ExpectationFailed]; + } + } else { + if (_request.usesChunkedTransferEncoding) { + [self _readChunkedBodyWithInitialData:extraData]; + } else { + [self _readBodyWithLength:_request.contentLength initialData:extraData]; } - - }]; + } } else { - GWS_LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket); - [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_ExpectationFailed]; + GWS_LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket); + [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_BadRequest]; } } else { - if (_request.usesChunkedTransferEncoding) { - [self _readChunkedBodyWithInitialData:extraData]; - } else { - [self _readBodyWithLength:_request.contentLength initialData:extraData]; - } + [self _startProcessingRequest]; } } else { - GWS_LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket); - [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_BadRequest]; + _request = [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:requestPath query:requestQuery]; + GWS_DCHECK(_request); + [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_MethodNotAllowed]; } } else { - [self _startProcessingRequest]; + [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; + GWS_DNOT_REACHED(); } } else { - _request = [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:requestPath query:requestQuery]; - GWS_DCHECK(_request); - [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_MethodNotAllowed]; + [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; } - } else { - [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; - GWS_DNOT_REACHED(); - } - } else { - [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError]; - } - - }]; + + }]; } - (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket { @@ -608,15 +620,15 @@ - (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress re _remoteAddress = remoteAddress; _socket = socket; GWS_LOG_DEBUG(@"Did open connection on socket %i", _socket); - + [_server willStartConnection:self]; - + if (![self open]) { close(_socket); return nil; } _opened = YES; - + [self _readRequestHeaders]; } return self; @@ -637,17 +649,17 @@ - (void)dealloc { } else { GWS_LOG_DEBUG(@"Did close connection on socket %i", _socket); } - + if (_opened) { [self close]; } - + [_server didEndConnection:self]; - + if (_requestMessage) { CFRelease(_requestMessage); } - + if (_responseMessage) { CFRelease(_responseMessage); } @@ -660,25 +672,28 @@ @implementation GCDWebServerConnection (Subclassing) - (BOOL)open { #ifdef __GCDWEBSERVER_ENABLE_TESTING__ if (_server.recordingEnabled) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" _connectionIndex = OSAtomicIncrement32(&_connectionCounter); - +#pragma clang diagnostic pop + _requestPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]; _requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); GWS_DCHECK(_requestFD > 0); - + _responsePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]; _responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); GWS_DCHECK(_responseFD > 0); } #endif - + return YES; } - (void)didReadBytes:(const void*)bytes length:(NSUInteger)length { GWS_LOG_DEBUG(@"Connection received %lu bytes on socket %i", (unsigned long)length, _socket); _bytesRead += length; - + #ifdef __GCDWEBSERVER_ENABLE_TESTING__ if ((_requestFD > 0) && (write(_requestFD, bytes, length) != (ssize_t)length)) { GWS_LOG_ERROR(@"Failed recording request data: %s (%i)", strerror(errno), errno); @@ -691,7 +706,7 @@ - (void)didReadBytes:(const void*)bytes length:(NSUInteger)length { - (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length { GWS_LOG_DEBUG(@"Connection sent %lu bytes on socket %i", (unsigned long)length, _socket); _bytesWritten += length; - + #ifdef __GCDWEBSERVER_ENABLE_TESTING__ if ((_responseFD > 0) && (write(_responseFD, bytes, length) != (ssize_t)length)) { GWS_LOG_ERROR(@"Failed recording response data: %s (%i)", strerror(errno), errno); @@ -758,12 +773,7 @@ - (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request { - (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 copy]); - } - @catch (NSException* exception) { - GWS_LOG_EXCEPTION(exception); - } + _handler.asyncProcessBlock(request, [completion copy]); } // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 @@ -824,7 +834,7 @@ - (void)close { } unlink([_requestPath fileSystemRepresentation]); } - + if (_responsePath) { BOOL success = NO; NSError* error = nil; @@ -840,7 +850,7 @@ - (void)close { unlink([_responsePath fileSystemRepresentation]); } #endif - + if (_request) { GWS_LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten); } else { diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m old mode 100644 new mode 100755 index 291167d..bcfc102 --- a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m +++ b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m @@ -163,8 +163,8 @@ BOOL GCDWebServerIsTextContentType(NSString* type) { static NSDictionary* _overrides = nil; if (_overrides == nil) { _overrides = [[NSDictionary alloc] initWithObjectsAndKeys: - @"text/css", @"css", - nil]; + @"text/css", @"css", + nil]; } NSString* mimeType = nil; extension = [extension lowercaseString]; @@ -205,13 +205,13 @@ BOOL GCDWebServerIsTextContentType(NSString* type) { break; } [scanner setScanLocation:([scanner scanLocation] + 1)]; - + NSString* value = nil; [scanner scanUpToString:@"&" intoString:&value]; if (value == nil) { value = @""; } - + key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "]; NSString* unescapedKey = key ? GCDWebServerUnescapeURLString(key) : nil; value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "]; @@ -222,7 +222,7 @@ BOOL GCDWebServerIsTextContentType(NSString* type) { GWS_LOG_WARNING(@"Failed parsing URL encoded form for key \"%@\" and value \"%@\"", key, value); GWS_DNOT_REACHED(); } - + if ([scanner isAtEnd]) { break; } @@ -246,7 +246,7 @@ BOOL GCDWebServerIsTextContentType(NSString* type) { 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 @@ -267,9 +267,9 @@ BOOL GCDWebServerIsTextContentType(NSString* type) { struct ifaddrs* list; if (getifaddrs(&list) >= 0) { for (struct ifaddrs* ifap = list; ifap; ifap = ifap->ifa_next) { -#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 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)) diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h old mode 100644 new mode 100755 index c9c6868..a7e5016 --- a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h +++ b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h @@ -77,7 +77,6 @@ #define GWS_LOG_INFO(...) XLOG_INFO(__VA_ARGS__) #define GWS_LOG_WARNING(...) XLOG_WARNING(__VA_ARGS__) #define GWS_LOG_ERROR(...) XLOG_ERROR(__VA_ARGS__) -#define GWS_LOG_EXCEPTION(__EXCEPTION__) XLOG_EXCEPTION(__EXCEPTION__) #define GWS_DCHECK(__CONDITION__) XLOG_DEBUG_CHECK(__CONDITION__) #define GWS_DNOT_REACHED() XLOG_DEBUG_UNREACHABLE() @@ -102,7 +101,6 @@ extern DDLogLevel GCDWebServerLogLevel; #define GWS_LOG_INFO(...) DDLogInfo(__VA_ARGS__) #define GWS_LOG_WARNING(...) DDLogWarn(__VA_ARGS__) #define GWS_LOG_ERROR(...) DDLogError(__VA_ARGS__) -#define GWS_LOG_EXCEPTION(__EXCEPTION__) DDLogError(@"%@", __EXCEPTION__) /** * If all of the above fail, then use GCDWebServer built-in @@ -118,23 +116,36 @@ typedef NS_ENUM(int, GCDWebServerLoggingLevel) { kGCDWebServerLoggingLevel_Verbose, kGCDWebServerLoggingLevel_Info, kGCDWebServerLoggingLevel_Warning, - kGCDWebServerLoggingLevel_Error, - kGCDWebServerLoggingLevel_Exception + kGCDWebServerLoggingLevel_Error }; extern GCDWebServerLoggingLevel GCDWebServerLogLevel; extern void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* format, ...) NS_FORMAT_FUNCTION(2, 3); #if DEBUG -#define GWS_LOG_DEBUG(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Debug) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Debug, __VA_ARGS__); } while (0) +#define GWS_LOG_DEBUG(...) \ + do { \ + if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Debug) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Debug, __VA_ARGS__); \ + } while (0) #else #define GWS_LOG_DEBUG(...) #endif -#define GWS_LOG_VERBOSE(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Verbose) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Verbose, __VA_ARGS__); } while (0) -#define GWS_LOG_INFO(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Info) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Info, __VA_ARGS__); } while (0) -#define GWS_LOG_WARNING(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Warning) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Warning, __VA_ARGS__); } while (0) -#define GWS_LOG_ERROR(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Error) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Error, __VA_ARGS__); } while (0) -#define GWS_LOG_EXCEPTION(__EXCEPTION__) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Exception) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Exception, @"%@", __EXCEPTION__); } while (0) +#define GWS_LOG_VERBOSE(...) \ + do { \ + if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Verbose) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Verbose, __VA_ARGS__); \ + } while (0) +#define GWS_LOG_INFO(...) \ + do { \ + if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Info) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Info, __VA_ARGS__); \ + } while (0) +#define GWS_LOG_WARNING(...) \ + do { \ + if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Warning) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Warning, __VA_ARGS__); \ + } while (0) +#define GWS_LOG_ERROR(...) \ + do { \ + if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Error) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Error, __VA_ARGS__); \ + } while (0) #endif @@ -147,10 +158,10 @@ extern void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* for #if DEBUG #define GWS_DCHECK(__CONDITION__) \ - do { \ - if (!(__CONDITION__)) { \ - abort(); \ - } \ + do { \ + if (!(__CONDITION__)) { \ + abort(); \ + } \ } while (0) #define GWS_DNOT_REACHED() abort() @@ -168,7 +179,6 @@ extern void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* for */ #define kGCDWebServerDefaultMimeType @"application/octet-stream" -#define kGCDWebServerGCDQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) #define kGCDWebServerErrorDomain @"GCDWebServerErrorDomain" static inline BOOL GCDWebServerIsValidByteRange(NSRange range) { @@ -176,7 +186,7 @@ static inline BOOL GCDWebServerIsValidByteRange(NSRange range) { } static inline NSError* GCDWebServerMakePosixError(int code) { - return [NSError errorWithDomain:NSPOSIXErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:strerror(code)]}]; + return [NSError errorWithDomain:NSPOSIXErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithUTF8String:strerror(code)]}]; } extern void GCDWebServerInitializeFunctions(); @@ -186,7 +196,7 @@ extern NSString* GCDWebServerExtractHeaderValueParameter(NSString* header, NSStr extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset); extern BOOL GCDWebServerIsTextContentType(NSString* type); extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType); -extern NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +extern NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2); extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOOL includeService); @interface GCDWebServerConnection () @@ -200,6 +210,7 @@ extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOO @property(nonatomic, readonly) NSDictionary* authenticationBasicAccounts; @property(nonatomic, readonly) NSDictionary* authenticationDigestAccounts; @property(nonatomic, readonly) BOOL shouldAutomaticallyMapHEADToGET; +@property(nonatomic, readonly) dispatch_queue_priority_t dispatchQueuePriority; - (void)willStartConnection:(GCDWebServerConnection*)connection; - (void)didEndConnection:(GCDWebServerConnection*)connection; @end diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m old mode 100644 new mode 100755 index dc929a7..5365f59 --- a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m +++ b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m @@ -94,7 +94,7 @@ - (BOOL)open:(NSError**)error { return NO; } if (![super open:error]) { - deflateEnd(&_stream); + inflateEnd(&_stream); return NO; } return YES; @@ -159,7 +159,7 @@ @interface GCDWebServerRequest () { BOOL _gzipAccepted; NSData* _localAddress; NSData* _remoteAddress; - + BOOL _opened; NSMutableArray* _decoders; NSMutableDictionary* _attributes; @@ -169,8 +169,8 @@ @interface GCDWebServerRequest () { @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, localAddressData=_localAddress, remoteAddressData=_remoteAddress; +@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, localAddressData = _localAddress, remoteAddressData = _remoteAddress; - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query { if ((self = [super init])) { @@ -179,7 +179,7 @@ - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDict _headers = headers; _path = [path copy]; _query = query; - + _type = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Content-Type"]); _chunked = [GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Transfer-Encoding"]) isEqualToString:@"chunked"]; NSString* lengthHeader = [_headers objectForKey:@"Content-Length"]; @@ -206,13 +206,13 @@ - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDict } _length = NSUIntegerMax; } - + NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"]; if (modifiedHeader) { _modifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy]; } _noneMatch = [_headers objectForKey:@"If-None-Match"]; - + _range = NSMakeRange(NSUIntegerMax, 0); NSString* rangeHeader = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Range"]); if (rangeHeader) { @@ -242,11 +242,11 @@ - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDict GWS_LOG_WARNING(@"Failed to parse 'Range' header \"%@\" for url: %@", rangeHeader, url); } } - + if ([[_headers objectForKey:@"Accept-Encoding"] rangeOfString:@"gzip"].location != NSNotFound) { _gzipAccepted = YES; } - + _decoders = [[NSMutableArray alloc] init]; _attributes = [[NSMutableDictionary alloc] init]; } diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m old mode 100644 new mode 100755 index 8357ab7..b5eb57c --- a/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m +++ b/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m @@ -168,7 +168,7 @@ @interface GCDWebServerResponse () { NSMutableDictionary* _headers; BOOL _chunked; BOOL _gzipped; - + BOOL _opened; NSMutableArray* _encoders; id __unsafe_unretained _reader; @@ -177,8 +177,8 @@ @interface GCDWebServerResponse () { @implementation GCDWebServerResponse -@synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, lastModifiedDate=_lastModified, eTag=_eTag, - gzipContentEncodingEnabled=_gzipped, additionalHeaders=_headers; +@synthesize contentType = _type, contentLength = _length, statusCode = _status, cacheControlMaxAge = _maxAge, lastModifiedDate = _lastModified, eTag = _eTag, + gzipContentEncodingEnabled = _gzipped, additionalHeaders = _headers; + (instancetype)response { return [[[self class] alloc] init]; @@ -241,6 +241,7 @@ - (BOOL)performOpen:(NSError**)error { } - (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block { + GWS_DCHECK(_opened); if ([_reader respondsToSelector:@selector(asyncReadDataWithCompletion:)]) { [_reader asyncReadDataWithCompletion:[block copy]]; } else { diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m old mode 100644 new mode 100755 index 840e985..861ab52 --- a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m +++ b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m @@ -34,7 +34,7 @@ @interface GCDWebServerDataRequest () { @private NSMutableData* _data; - + NSString* _text; id _jsonObject; } @@ -42,7 +42,7 @@ @interface GCDWebServerDataRequest () { @implementation GCDWebServerDataRequest -@synthesize data=_data; +@synthesize data = _data; - (BOOL)open:(NSError**)error { if (self.contentLength != NSUIntegerMax) { @@ -52,7 +52,7 @@ - (BOOL)open:(NSError**)error { } if (_data == nil) { if (error) { - *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}]; + *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed allocating memory" }]; } return NO; } diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m old mode 100644 new mode 100755 index adf67a5..0309d64 --- a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m +++ b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m @@ -40,7 +40,7 @@ @interface GCDWebServerFileRequest () { @implementation GCDWebServerFileRequest -@synthesize temporaryPath=_temporaryPath; +@synthesize temporaryPath = _temporaryPath; - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query { if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) { @@ -85,14 +85,14 @@ - (BOOL)close:(NSError**)error { NSString* creationDateHeader = [self.headers objectForKey:@"X-GCDWebServer-CreationDate"]; if (creationDateHeader) { NSDate* date = GCDWebServerParseISO8601(creationDateHeader); - if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileCreationDate: date} ofItemAtPath:_temporaryPath error:error]) { + if (!date || ![[NSFileManager defaultManager] setAttributes:@{ NSFileCreationDate : date } ofItemAtPath:_temporaryPath error:error]) { return NO; } } NSString* modifiedDateHeader = [self.headers objectForKey:@"X-GCDWebServer-ModifiedDate"]; if (modifiedDateHeader) { NSDate* date = GCDWebServerParseRFC822(modifiedDateHeader); - if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: date} ofItemAtPath:_temporaryPath error:error]) { + if (!date || ![[NSFileManager defaultManager] setAttributes:@{ NSFileModificationDate : date } ofItemAtPath:_temporaryPath error:error]) { return NO; } } diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m old mode 100644 new mode 100755 index c2fc9bf..c6cb485 --- a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m +++ b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m @@ -61,7 +61,7 @@ @interface GCDWebServerMultiPart () { @implementation GCDWebServerMultiPart -@synthesize controlName=_controlName, contentType=_contentType, mimeType=_mimeType; +@synthesize controlName = _controlName, contentType = _contentType, mimeType = _mimeType; - (id)initWithControlName:(NSString*)name contentType:(NSString*)type { if ((self = [super init])) { @@ -83,12 +83,12 @@ @interface GCDWebServerMultiPartArgument () { @implementation GCDWebServerMultiPartArgument -@synthesize data=_data, string=_string; +@synthesize data = _data, string = _string; - (id)initWithControlName:(NSString*)name contentType:(NSString*)type data:(NSData*)data { if ((self = [super initWithControlName:name contentType:type])) { _data = data; - + if ([self.contentType hasPrefix:@"text/"]) { NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset"); _string = [[NSString alloc] initWithData:_data encoding:GCDWebServerStringEncodingFromCharset(charset)]; @@ -112,7 +112,7 @@ @interface GCDWebServerMultiPartFile () { @implementation GCDWebServerMultiPartFile -@synthesize fileName=_fileName, temporaryPath=_temporaryPath; +@synthesize fileName = _fileName, temporaryPath = _temporaryPath; - (id)initWithControlName:(NSString*)name contentType:(NSString*)type fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath { if ((self = [super initWithControlName:name contentType:type])) { @@ -140,7 +140,7 @@ @interface GCDWebServerMIMEStreamParser () { NSMutableData* _data; NSMutableArray* _arguments; NSMutableArray* _files; - + NSString* _controlName; NSString* _fileName; NSString* _contentType; @@ -194,11 +194,10 @@ - (void)dealloc { // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 - (BOOL)_parseData { BOOL success = YES; - + if (_state == kParserState_Headers) { NSRange range = [_data rangeOfData:_newlinesData options:0 range:NSMakeRange(0, _data.length)]; if (range.location != NSNotFound) { - _controlName = nil; _fileName = nil; _contentType = nil; @@ -256,12 +255,12 @@ - (BOOL)_parseData { GWS_DNOT_REACHED(); success = NO; } - + [_data replaceBytesInRange:NSMakeRange(0, range.location + range.length) withBytes:NULL length:0]; _state = kParserState_Content; } } - + if ((_state == kParserState_Start) || (_state == kParserState_Content)) { NSRange range = [_data rangeOfData:_boundary options:0 range:NSMakeRange(0, _data.length)]; if (range.location != NSNotFound) { @@ -269,7 +268,6 @@ - (BOOL)_parseData { NSRange subRange1 = [_data rangeOfData:_newlineData options:NSDataSearchAnchored range:subRange]; NSRange subRange2 = [_data rangeOfData:_dashNewlineData options:NSDataSearchAnchored range:subRange]; if ((subRange1.location != NSNotFound) || (subRange2.location != NSNotFound)) { - if (_state == kParserState_Content) { const void* dataBytes = _data.bytes; NSUInteger dataLength = range.location - 2; @@ -301,7 +299,7 @@ - (BOOL)_parseData { [_arguments addObject:argument]; } } - + if (subRange1.location != NSNotFound) { [_data replaceBytesInRange:NSMakeRange(0, subRange1.location + subRange1.length) withBytes:NULL length:0]; _state = kParserState_Headers; @@ -333,7 +331,7 @@ - (BOOL)_parseData { } } } - + return success; } @@ -358,7 +356,7 @@ @interface GCDWebServerMultiPartFormRequest () { @implementation GCDWebServerMultiPartFormRequest -@synthesize arguments=_arguments, files=_files; +@synthesize arguments = _arguments, files = _files; + (NSString*)mimeType { return @"multipart/form-data"; @@ -377,7 +375,7 @@ - (BOOL)open:(NSError**)error { _parser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:nil arguments:_arguments files:_files]; if (_parser == nil) { if (error) { - *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}]; + *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed starting to parse multipart form data" }]; } return NO; } @@ -387,7 +385,7 @@ - (BOOL)open:(NSError**)error { - (BOOL)writeData:(NSData*)data error:(NSError**)error { if (![_parser appendBytes:data.bytes length:data.length]) { if (error) { - *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}]; + *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed continuing to parse multipart form data" }]; } return NO; } @@ -399,7 +397,7 @@ - (BOOL)close:(NSError**)error { _parser = nil; if (!atEnd) { if (error) { - *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}]; + *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed finishing to parse multipart form data" }]; } return NO; } diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m old mode 100644 new mode 100755 index 2c5fcc5..328fd75 --- a/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m +++ b/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m @@ -39,7 +39,7 @@ @interface GCDWebServerURLEncodedFormRequest () { @implementation GCDWebServerURLEncodedFormRequest -@synthesize arguments=_arguments; +@synthesize arguments = _arguments; + (NSString*)mimeType { return @"application/x-www-form-urlencoded"; @@ -49,12 +49,12 @@ - (BOOL)close:(NSError**)error { if (![super close:error]) { return NO; } - + NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset"); NSString* string = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)]; _arguments = GCDWebServerParseURLEncodedForm(string); GWS_DCHECK(_arguments); - + return YES; } diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m old mode 100644 new mode 100755 index 12cd12b..3bffb25 --- a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m +++ b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m @@ -49,10 +49,10 @@ - (instancetype)initWithData:(NSData*)data contentType:(NSString*)type { GWS_DNOT_REACHED(); return nil; } - + if ((self = [super init])) { _data = data; - + self.contentType = type; self.contentLength = data.length; } diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h old mode 100644 new mode 100755 index dad0114..f80c7ff --- a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h +++ b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h @@ -37,45 +37,45 @@ /** * Creates a client error response with the corresponding HTTP status code. */ -+ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3); ++ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3); /** * Creates a server error response with the corresponding HTTP status code. */ -+ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3); ++ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3); /** * Creates a client error response with the corresponding HTTP status code * and an underlying NSError. */ -+ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4); ++ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4); /** * Creates a server error response with the corresponding HTTP status code * and an underlying NSError. */ -+ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4); ++ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4); /** * Initializes a client error response with the corresponding HTTP status code. */ -- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3); +- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3); /** * Initializes a server error response with the corresponding HTTP status code. */ -- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3); +- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3); /** * Initializes a client error response with the corresponding HTTP status code * and an underlying NSError. */ -- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4); +- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4); /** * Initializes a server error response with the corresponding HTTP status code * and an underlying NSError. */ -- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4); +- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4); @end diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m old mode 100644 new mode 100755 index a2b7c3c..3e717a3 --- a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m +++ b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m @@ -91,7 +91,7 @@ - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachme } #endif NSUInteger fileSize = (NSUInteger)info.st_size; - + BOOL hasByteRange = GCDWebServerIsValidByteRange(range); if (hasByteRange) { if (range.location != NSUIntegerMax) { @@ -108,7 +108,7 @@ - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachme range.location = 0; range.length = fileSize; } - + if ((self = [super init])) { _path = [path copy]; _offset = range.location; @@ -118,7 +118,7 @@ - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachme [self setValue:[NSString stringWithFormat:@"bytes %lu-%lu/%lu", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), (unsigned long)fileSize] forAdditionalHeader:@"Content-Range"]; GWS_LOG_DEBUG(@"Using content bytes range [%lu-%lu] for file \"%@\"", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), path); } - + if (attachment) { NSString* fileName = [path lastPathComponent]; NSData* data = [[fileName stringByReplacingOccurrencesOfString:@"\"" withString:@""] dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:YES]; @@ -130,7 +130,7 @@ - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachme GWS_DNOT_REACHED(); } } - + self.contentType = GCDWebServerGetMimeTypeForExtension([_path pathExtension]); self.contentLength = _size; self.lastModifiedDate = _NSDateFromTimeSpec(&info.st_mtimespec); diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m old mode 100644 new mode 100755 index 4669617..2ed01c1 --- a/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m +++ b/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m @@ -48,19 +48,20 @@ + (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWeb } - (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block { - return [self initWithContentType:type asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) { - - NSError* error = nil; - NSData* data = block(&error); - completionBlock(data, error); - - }]; + return [self initWithContentType:type + asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) { + + NSError* error = nil; + NSData* data = block(&error); + completionBlock(data, error); + + }]; } - (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block { if ((self = [super init])) { _block = [block copy]; - + self.contentType = type; } return self; diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Info.plist b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Info.plist old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Info.plist rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Info.plist diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/bootstrap-theme.css b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/bootstrap-theme.css old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/bootstrap-theme.css rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/bootstrap-theme.css diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/bootstrap.css b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/bootstrap.css old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/bootstrap.css rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/bootstrap.css diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/index.css b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/index.css old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/index.css rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/index.css diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/jquery.fileupload.css b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/jquery.fileupload.css old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/jquery.fileupload.css rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/jquery.fileupload.css diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/en.lproj/Localizable.strings b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/en.lproj/Localizable.strings old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/en.lproj/Localizable.strings rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/en.lproj/Localizable.strings diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.eot b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.eot old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.eot rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.eot diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.svg b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.svg old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.svg rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.svg diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.ttf b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.ttf old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.ttf rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.ttf diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.woff b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.woff old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/fonts/glyphicons-halflings-regular.woff rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/fonts/glyphicons-halflings-regular.woff diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/index.html b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/index.html old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/index.html rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/index.html diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/bootstrap.min.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/bootstrap.min.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/bootstrap.min.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/bootstrap.min.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/html5shiv.min.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/html5shiv.min.js similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/html5shiv.min.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/html5shiv.min.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/index.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/index.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/index.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/index.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.fileupload.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.fileupload.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.fileupload.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.fileupload.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.iframe-transport.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.iframe-transport.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.iframe-transport.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.iframe-transport.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.jeditable.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.jeditable.js similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.jeditable.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.jeditable.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.min.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.min.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.min.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.min.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.ui.widget.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.ui.widget.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/jquery.ui.widget.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/jquery.ui.widget.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/respond.min.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/respond.min.js similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/respond.min.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/respond.min.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/tmpl.min.js b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/tmpl.min.js old mode 100644 new mode 100755 similarity index 100% rename from src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/tmpl.min.js rename to src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/js/tmpl.min.js diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m old mode 100644 new mode 100755 index 9bb4453..e6dc497 --- a/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m +++ b/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m @@ -73,7 +73,7 @@ - (BOOL)_checkFileExtension:(NSString*)fileName { return YES; } -- (NSString*) _uniquePathForPath:(NSString*)path { +- (NSString*)_uniquePathForPath:(NSString*)path { if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { NSString* directory = [path stringByDeletingLastPathComponent]; NSString* file = [path lastPathComponent]; @@ -101,18 +101,18 @@ - (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request { if (!isDirectory) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"\"%@\" is not a directory", relativePath]; } - + NSString* directoryName = [absolutePath lastPathComponent]; if (!_allowHidden && [directoryName hasPrefix:@"."]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Listing directory name \"%@\" is not allowed", directoryName]; } - + NSError* error = nil; NSArray* contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:absolutePath error:&error]; if (contents == nil) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed listing directory \"%@\"", relativePath]; } - + NSMutableArray* array = [NSMutableArray array]; for (NSString* item in [contents sortedArrayUsingSelector:@selector(localizedStandardCompare:)]) { if (_allowHidden || ![item hasPrefix:@"."]) { @@ -120,15 +120,15 @@ - (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request { NSString* type = [attributes objectForKey:NSFileType]; if ([type isEqualToString:NSFileTypeRegular] && [self _checkFileExtension:item]) { [array addObject:@{ - @"path": [relativePath stringByAppendingPathComponent:item], - @"name": item, - @"size": [attributes objectForKey:NSFileSize] - }]; + @"path" : [relativePath stringByAppendingPathComponent:item], + @"name" : item, + @"size" : [attributes objectForKey:NSFileSize] + }]; } else if ([type isEqualToString:NSFileTypeDirectory]) { [array addObject:@{ - @"path": [[relativePath stringByAppendingPathComponent:item] stringByAppendingString:@"/"], - @"name": item - }]; + @"path" : [[relativePath stringByAppendingPathComponent:item] stringByAppendingString:@"/"], + @"name" : item + }]; } } } @@ -145,13 +145,13 @@ - (GCDWebServerResponse*)downloadFile:(GCDWebServerRequest*)request { if (isDirectory) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"\"%@\" is a directory", relativePath]; } - + NSString* fileName = [absolutePath lastPathComponent]; if (([fileName hasPrefix:@"."] && !_allowHidden) || ![self _checkFileExtension:fileName]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Downlading file name \"%@\" is not allowed", fileName]; } - - if ([self.delegate respondsToSelector:@selector(webUploader:didDownloadFileAtPath: )]) { + + if ([self.delegate respondsToSelector:@selector(webUploader:didDownloadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate webUploader:self didDownloadFileAtPath:absolutePath]; }); @@ -162,7 +162,7 @@ - (GCDWebServerResponse*)downloadFile:(GCDWebServerRequest*)request { - (GCDWebServerResponse*)uploadFile:(GCDWebServerMultiPartFormRequest*)request { NSRange range = [[request.headers objectForKey:@"Accept"] rangeOfString:@"application/json" options:NSCaseInsensitiveSearch]; NSString* contentType = (range.location != NSNotFound ? @"application/json" : @"text/plain; charset=utf-8"); // Required when using iFrame transport (see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup) - + GCDWebServerMultiPartFile* file = [request firstFileForControlName:@"files[]"]; if ((!_allowHidden && [file.fileName hasPrefix:@"."]) || ![self _checkFileExtension:file.fileName]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName]; @@ -172,16 +172,16 @@ - (GCDWebServerResponse*)uploadFile:(GCDWebServerMultiPartFormRequest*)request { if (![self _checkSandboxedPath:absolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file \"%@\" to \"%@\" is not permitted", file.fileName, relativePath]; } - + NSError* error = nil; if (![[NSFileManager defaultManager] moveItemAtPath:file.temporaryPath toPath:absolutePath error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving uploaded file to \"%@\"", relativePath]; } - + if ([self.delegate respondsToSelector:@selector(webUploader:didUploadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate webUploader:self didUploadFileAtPath:absolutePath]; @@ -197,27 +197,27 @@ - (GCDWebServerResponse*)moveItem:(GCDWebServerURLEncodedFormRequest*)request { if (![self _checkSandboxedPath:oldAbsolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:oldAbsolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", oldRelativePath]; } - + NSString* newRelativePath = [request.arguments objectForKey:@"newPath"]; NSString* newAbsolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:newRelativePath]]; if (![self _checkSandboxedPath:newAbsolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", newRelativePath]; } - + NSString* itemName = [newAbsolutePath lastPathComponent]; if ((!_allowHidden && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Moving to item name \"%@\" is not allowed", itemName]; } - + if (![self shouldMoveItemFromPath:oldAbsolutePath toPath:newAbsolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Moving \"%@\" to \"%@\" is not permitted", oldRelativePath, newRelativePath]; } - + NSError* error = nil; if (![[NSFileManager defaultManager] moveItemAtPath:oldAbsolutePath toPath:newAbsolutePath error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving \"%@\" to \"%@\"", oldRelativePath, newRelativePath]; } - + if ([self.delegate respondsToSelector:@selector(webUploader:didMoveItemFromPath:toPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate webUploader:self didMoveItemFromPath:oldAbsolutePath toPath:newAbsolutePath]; @@ -233,21 +233,21 @@ - (GCDWebServerResponse*)deleteItem:(GCDWebServerURLEncodedFormRequest*)request if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* itemName = [absolutePath lastPathComponent]; if (([itemName hasPrefix:@"."] && !_allowHidden) || (!isDirectory && ![self _checkFileExtension:itemName])) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Deleting item name \"%@\" is not allowed", itemName]; } - + if (![self shouldDeleteItemAtPath:absolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Deleting \"%@\" is not permitted", relativePath]; } - + NSError* error = nil; if (![[NSFileManager defaultManager] removeItemAtPath:absolutePath error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed deleting \"%@\"", relativePath]; } - + if ([self.delegate respondsToSelector:@selector(webUploader:didDeleteItemAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate webUploader:self didDeleteItemAtPath:absolutePath]; @@ -262,21 +262,21 @@ - (GCDWebServerResponse*)createDirectory:(GCDWebServerURLEncodedFormRequest*)req if (![self _checkSandboxedPath:absolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; } - + NSString* directoryName = [absolutePath lastPathComponent]; if (!_allowHidden && [directoryName hasPrefix:@"."]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Creating directory name \"%@\" is not allowed", directoryName]; } - + if (![self shouldCreateDirectoryAtPath:absolutePath]) { return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Creating directory \"%@\" is not permitted", relativePath]; } - + NSError* error = nil; if (![[NSFileManager defaultManager] createDirectoryAtPath:absolutePath withIntermediateDirectories:NO attributes:nil error:&error]) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed creating directory \"%@\"", relativePath]; } - + if ([self.delegate respondsToSelector:@selector(webUploader:didCreateDirectoryAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate webUploader:self didCreateDirectoryAtPath:absolutePath]; @@ -289,8 +289,8 @@ - (GCDWebServerResponse*)createDirectory:(GCDWebServerURLEncodedFormRequest*)req @implementation GCDWebUploader -@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden, - title=_title, header=_header, prologue=_prologue, epilogue=_epilogue, footer=_footer; +@synthesize uploadDirectory = _uploadDirectory, allowedFileExtensions = _allowedExtensions, allowHiddenItems = _allowHidden, + title = _title, header = _header, prologue = _prologue, epilogue = _epilogue, footer = _footer; @dynamic delegate; @@ -302,96 +302,116 @@ - (instancetype)initWithUploadDirectory:(NSString*)path { } _uploadDirectory = [[path stringByStandardizingPath] copy]; GCDWebUploader* __unsafe_unretained server = self; - + // Resource files [self addGETHandlerForBasePath:@"/" directoryPath:[siteBundle resourcePath] indexFilename:nil cacheAge:3600 allowRangeRequests:NO]; - + // Web page - [self addHandlerForMethod:@"GET" path:@"/" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - + [self addHandlerForMethod:@"GET" + path:@"/" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + #if TARGET_OS_IPHONE - NSString* device = [[UIDevice currentDevice] name]; + NSString* device = [[UIDevice currentDevice] name]; #else - NSString* device = CFBridgingRelease(SCDynamicStoreCopyComputerName(NULL, NULL)); + NSString* device = CFBridgingRelease(SCDynamicStoreCopyComputerName(NULL, NULL)); #endif - NSString* title = server.title; - if (title == nil) { - title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - if (title == nil) { - title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; - } + NSString* title = server.title; + if (title == nil) { + title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + if (title == nil) { + title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + } #if !TARGET_OS_IPHONE - if (title == nil) { - title = [[NSProcessInfo processInfo] processName]; - } + if (title == nil) { + title = [[NSProcessInfo processInfo] processName]; + } #endif - } - NSString* header = server.header; - if (header == nil) { - header = title; - } - NSString* prologue = server.prologue; - if (prologue == nil) { - prologue = [siteBundle localizedStringForKey:@"PROLOGUE" value:@"" table:nil]; - } - NSString* epilogue = server.epilogue; - if (epilogue == nil) { - epilogue = [siteBundle localizedStringForKey:@"EPILOGUE" value:@"" table:nil]; - } - NSString* footer = server.footer; - if (footer == nil) { - NSString* name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - NSString* version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + } + NSString* header = server.header; + if (header == nil) { + header = title; + } + NSString* prologue = server.prologue; + if (prologue == nil) { + prologue = [siteBundle localizedStringForKey:@"PROLOGUE" value:@"" table:nil]; + } + NSString* epilogue = server.epilogue; + if (epilogue == nil) { + epilogue = [siteBundle localizedStringForKey:@"EPILOGUE" value:@"" table:nil]; + } + NSString* footer = server.footer; + if (footer == nil) { + NSString* name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + NSString* version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; #if !TARGET_OS_IPHONE - if (!name && !version) { - name = @"OS X"; - version = [[NSProcessInfo processInfo] operatingSystemVersionString]; - } + if (!name && !version) { + name = @"OS X"; + version = [[NSProcessInfo processInfo] operatingSystemVersionString]; + } #endif - footer = [NSString stringWithFormat:[siteBundle localizedStringForKey:@"FOOTER_FORMAT" value:@"" table:nil], name, version]; - } - return [GCDWebServerDataResponse responseWithHTMLTemplate:[siteBundle pathForResource:@"index" ofType:@"html"] - variables:@{ - @"device": device, - @"title": title, - @"header": header, - @"prologue": prologue, - @"epilogue": epilogue, - @"footer": footer - }]; - - }]; - + footer = [NSString stringWithFormat:[siteBundle localizedStringForKey:@"FOOTER_FORMAT" value:@"" table:nil], name, version]; + } + return [GCDWebServerDataResponse responseWithHTMLTemplate:[siteBundle pathForResource:@"index" ofType:@"html"] + variables:@{ + @"device" : device, + @"title" : title, + @"header" : header, + @"prologue" : prologue, + @"epilogue" : epilogue, + @"footer" : footer + }]; + + }]; + // File listing - [self addHandlerForMethod:@"GET" path:@"/list" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server listDirectory:request]; - }]; - + [self addHandlerForMethod:@"GET" + path:@"/list" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server listDirectory:request]; + }]; + // File download - [self addHandlerForMethod:@"GET" path:@"/download" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server downloadFile:request]; - }]; - + [self addHandlerForMethod:@"GET" + path:@"/download" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server downloadFile:request]; + }]; + // File upload - [self addHandlerForMethod:@"POST" path:@"/upload" requestClass:[GCDWebServerMultiPartFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server uploadFile:(GCDWebServerMultiPartFormRequest*)request]; - }]; - + [self addHandlerForMethod:@"POST" + path:@"/upload" + requestClass:[GCDWebServerMultiPartFormRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server uploadFile:(GCDWebServerMultiPartFormRequest*)request]; + }]; + // File and folder moving - [self addHandlerForMethod:@"POST" path:@"/move" requestClass:[GCDWebServerURLEncodedFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server moveItem:(GCDWebServerURLEncodedFormRequest*)request]; - }]; - + [self addHandlerForMethod:@"POST" + path:@"/move" + requestClass:[GCDWebServerURLEncodedFormRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server moveItem:(GCDWebServerURLEncodedFormRequest*)request]; + }]; + // File and folder deletion - [self addHandlerForMethod:@"POST" path:@"/delete" requestClass:[GCDWebServerURLEncodedFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server deleteItem:(GCDWebServerURLEncodedFormRequest*)request]; - }]; - + [self addHandlerForMethod:@"POST" + path:@"/delete" + requestClass:[GCDWebServerURLEncodedFormRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server deleteItem:(GCDWebServerURLEncodedFormRequest*)request]; + }]; + // Directory creation - [self addHandlerForMethod:@"POST" path:@"/create" requestClass:[GCDWebServerURLEncodedFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - return [server createDirectory:(GCDWebServerURLEncodedFormRequest*)request]; - }]; - + [self addHandlerForMethod:@"POST" + path:@"/create" + requestClass:[GCDWebServerURLEncodedFormRequest class] + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + return [server createDirectory:(GCDWebServerURLEncodedFormRequest*)request]; + }]; } return self; } diff --git a/src/ios/GCDWebServer/LICENSE b/src/ios/GCDWebServer/LICENSE old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Mac/main.m b/src/ios/GCDWebServer/Mac/main.m old mode 100644 new mode 100755 index 33b25e5..5d43831 --- a/src/ios/GCDWebServer/Mac/main.m +++ b/src/ios/GCDWebServer/Mac/main.m @@ -147,7 +147,7 @@ int main(int argc, const char* argv[]) { 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] [--localhost]\n\n", basename((char*)argv[0])); } else { @@ -201,10 +201,9 @@ int main(int argc, const char* argv[]) { } } } - + GCDWebServer* webServer = nil; switch (mode) { - // Simply serve contents of home directory case kMode_WebServer: { fprintf(stdout, "Running in Web Server mode from \"%s\"", [rootDirectory UTF8String]); @@ -212,21 +211,21 @@ int main(int argc, const char* argv[]) { [webServer addGETHandlerForBasePath:@"/" directoryPath:rootDirectory indexFilename:nil cacheAge:0 allowRangeRequests:YES]; break; } - + // Renders a HTML page case kMode_HTMLPage: { fprintf(stdout, "Running in HTML Page mode"); webServer = [[GCDWebServer alloc] init]; [webServer addDefaultHandlerForMethod:@"GET" requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - return [GCDWebServerDataResponse responseWithHTML:@"

Hello World

"]; - - }]; + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + return [GCDWebServerDataResponse responseWithHTML:@"

Hello World

"]; + + }]; break; } - + // Implements an HTML form case kMode_HTMLForm: { fprintf(stdout, "Running in HTML Form mode"); @@ -234,9 +233,9 @@ int main(int argc, const char* argv[]) { [webServer addHandlerForMethod:@"GET" path:@"/" requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - NSString* html = @" \ + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + NSString* html = @" \ \
\ Value: \ @@ -244,22 +243,22 @@ int main(int argc, const char* argv[]) {
\ \ "; - return [GCDWebServerDataResponse responseWithHTML:html]; - - }]; + return [GCDWebServerDataResponse responseWithHTML:html]; + + }]; [webServer addHandlerForMethod:@"POST" path:@"/" requestClass:[GCDWebServerURLEncodedFormRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - NSString* value = [[(GCDWebServerURLEncodedFormRequest*)request arguments] objectForKey:@"value"]; - NSString* html = [NSString stringWithFormat:@"

%@

", value]; - return [GCDWebServerDataResponse responseWithHTML:html]; - - }]; + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + NSString* value = [[(GCDWebServerURLEncodedFormRequest*)request arguments] objectForKey:@"value"]; + NSString* html = [NSString stringWithFormat:@"

%@

", value]; + return [GCDWebServerDataResponse responseWithHTML:html]; + + }]; break; } - + // Implements HTML file upload case kMode_HTMLFileUpload: { fprintf(stdout, "Running in HTML File Upload mode"); @@ -274,48 +273,48 @@ int main(int argc, const char* argv[]) { [webServer addHandlerForMethod:@"GET" path:@"/" requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - NSString* html = [NSString stringWithFormat:@"%@", formHTML]; - return [GCDWebServerDataResponse responseWithHTML:html]; - - }]; + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + NSString* html = [NSString stringWithFormat:@"%@", formHTML]; + return [GCDWebServerDataResponse responseWithHTML:html]; + + }]; [webServer addHandlerForMethod:@"POST" path:@"/" requestClass:[GCDWebServerMultiPartFormRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - NSMutableString* string = [NSMutableString string]; - for (GCDWebServerMultiPartArgument* argument in [(GCDWebServerMultiPartFormRequest*)request arguments]) { - [string appendFormat:@"%@ = %@
", argument.controlName, argument.string]; - } - for (GCDWebServerMultiPartFile* file in [(GCDWebServerMultiPartFormRequest*)request files]) { - NSDictionary* attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:file.temporaryPath error:NULL]; - [string appendFormat:@"%@ = "%@" (%@ | %llu %@)
", file.controlName, file.fileName, file.mimeType, - attributes.fileSize >= 1000 ? attributes.fileSize / 1000 : attributes.fileSize, - attributes.fileSize >= 1000 ? @"KB" : @"Bytes"]; - }; - NSString* html = [NSString stringWithFormat:@"

%@


%@", string, formHTML]; - return [GCDWebServerDataResponse responseWithHTML:html]; - - }]; + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + NSMutableString* string = [NSMutableString string]; + for (GCDWebServerMultiPartArgument* argument in [(GCDWebServerMultiPartFormRequest*)request arguments]) { + [string appendFormat:@"%@ = %@
", argument.controlName, argument.string]; + } + for (GCDWebServerMultiPartFile* file in [(GCDWebServerMultiPartFormRequest*)request files]) { + NSDictionary* attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:file.temporaryPath error:NULL]; + [string appendFormat:@"%@ = "%@" (%@ | %llu %@)
", file.controlName, file.fileName, file.mimeType, + attributes.fileSize >= 1000 ? attributes.fileSize / 1000 : attributes.fileSize, + attributes.fileSize >= 1000 ? @"KB" : @"Bytes"]; + }; + NSString* html = [NSString stringWithFormat:@"

%@


%@", string, formHTML]; + return [GCDWebServerDataResponse responseWithHTML:html]; + + }]; break; } - + // Serve home directory through WebDAV case kMode_WebDAV: { fprintf(stdout, "Running in WebDAV mode from \"%s\"", [rootDirectory UTF8String]); webServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:rootDirectory]; break; } - + // Serve home directory through web uploader case kMode_WebUploader: { fprintf(stdout, "Running in Web Uploader mode from \"%s\"", [rootDirectory UTF8String]); webServer = [[GCDWebUploader alloc] initWithUploadDirectory:rootDirectory]; break; } - + // Test streaming responses case kMode_StreamingResponse: { fprintf(stdout, "Running in Streaming Response mode"); @@ -323,42 +322,44 @@ int main(int argc, const char* argv[]) { [webServer addHandlerForMethod:@"GET" path:@"/sync" requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - __block int countDown = 10; - return [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" streamBlock:^NSData *(NSError** error) { - - usleep(100 * 1000); - if (countDown) { - return [[NSString stringWithFormat:@"%i\n", countDown--] dataUsingEncoding:NSUTF8StringEncoding]; - } else { - return [NSData data]; - } - - }]; - - }]; + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + __block int countDown = 10; + return [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" + streamBlock:^NSData*(NSError** error) { + + usleep(100 * 1000); + if (countDown) { + return [[NSString stringWithFormat:@"%i\n", countDown--] dataUsingEncoding:NSUTF8StringEncoding]; + } else { + return [NSData data]; + } + + }]; + + }]; [webServer addHandlerForMethod:@"GET" path:@"/async" requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { - - __block int countDown = 10; - return [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) { - - 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]; - completionBlock(data, nil); - - }); - - }]; - - }]; + processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { + + __block int countDown = 10; + return [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" + asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) { + + 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]; + completionBlock(data, nil); + + }); + + }]; + + }]; break; } - + // Test async responses case kMode_AsyncResponse: { fprintf(stdout, "Running in Async Response mode"); @@ -367,41 +368,41 @@ int main(int argc, const char* argv[]) { path:@"/async" requestClass:[GCDWebServerRequest class] asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) { - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithData:[@"Hello World!" dataUsingEncoding:NSUTF8StringEncoding] contentType:@"text/plain"]; - completionBlock(response); - }); - - }]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithData:[@"Hello World!" dataUsingEncoding:NSUTF8StringEncoding] contentType:@"text/plain"]; + completionBlock(response); + }); + + }]; [webServer addHandlerForMethod:@"GET" path:@"/async2" requestClass:[GCDWebServerRequest class] asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock handlerCompletionBlock) { - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - - __block int countDown = 10; - GCDWebServerStreamedResponse* response = [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock readerCompletionBlock) { - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - - NSData* data = countDown ? [[NSString stringWithFormat:@"%i\n", countDown--] dataUsingEncoding:NSUTF8StringEncoding] : [NSData data]; - readerCompletionBlock(data, nil); - - }); - - }]; - handlerCompletionBlock(response); - - }); - - }]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + __block int countDown = 10; + GCDWebServerStreamedResponse* response = [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" + asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock readerCompletionBlock) { + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + + NSData* data = countDown ? [[NSString stringWithFormat:@"%i\n", countDown--] dataUsingEncoding:NSUTF8StringEncoding] : [NSData data]; + readerCompletionBlock(data, nil); + + }); + + }]; + handlerCompletionBlock(response); + + }); + + }]; break; } - } - + if (webServer) { Delegate* delegate = [[Delegate alloc] init]; if (testDirectory) { @@ -409,7 +410,7 @@ int main(int argc, const char* argv[]) { webServer.delegate = delegate; #endif fprintf(stdout, "\n\n", [testDirectory UTF8String]); - result = (int)[webServer runTestsWithOptions:@{GCDWebServerOption_Port: @8080} inDirectory:testDirectory]; + result = (int)[webServer runTestsWithOptions:@{ GCDWebServerOption_Port : @8080 } inDirectory:testDirectory]; } else { webServer.delegate = delegate; if (recording) { @@ -424,7 +425,7 @@ int main(int argc, const char* argv[]) { [options setObject:@"" forKey:GCDWebServerOption_BonjourName]; if (authenticationUser && authenticationPassword) { [options setValue:authenticationRealm forKey:GCDWebServerOption_AuthenticationRealm]; - [options setObject:@{authenticationUser: authenticationPassword} forKey:GCDWebServerOption_AuthenticationAccounts]; + [options setObject:@{ authenticationUser : authenticationPassword } forKey:GCDWebServerOption_AuthenticationAccounts]; if ([authenticationMethod isEqualToString:@"Basic"]) { [options setObject:GCDWebServerAuthenticationMethod_Basic forKey:GCDWebServerOption_AuthenticationMethod]; } else if ([authenticationMethod isEqualToString:@"Digest"]) { diff --git a/src/ios/GCDWebServer/README.md b/src/ios/GCDWebServer/README.md old mode 100644 new mode 100755 index b18020d..2031831 --- a/src/ios/GCDWebServer/README.md +++ b/src/ios/GCDWebServer/README.md @@ -71,9 +71,9 @@ Then run `$ carthage update` and add the generated frameworks to your Xcode proj 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! +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. For bug reports and enhancement requests you can use [issues](https://github.com/swisspol/GCDWebServer/issues) in this project. -For bug reports or enhancement requests, please use [GitHub issues](https://github.com/swisspol/GCDWebServer/issues) instead. +Be sure to read this entire README first though! Hello World =========== @@ -153,7 +153,7 @@ int main(int argc, const char* argv[]) { ***webServer.swift*** ```swift import Foundation -import GCDWebServers +import GCDWebServer func initWebServer() { @@ -172,8 +172,8 @@ func initWebServer() { ***WebServer-Bridging-Header.h*** ```objectivec -#import -#import +#import +#import ``` Web Based Uploads in iOS Apps @@ -276,7 +276,7 @@ GCDWebServer's architecture consists of only 4 core classes: Implementing Handlers ===================== -GCDWebServer relies on "handlers" to process incoming web requests and generating responses. Handlers are implemented with GCD blocks which makes it very easy to provide your owns. However, they are executed on arbitrary threads within GCD so __special attention must be paid to thread-safety and re-entrancy__. +GCDWebServer relies on "handlers" to process incoming web requests and generating responses. Handlers are implemented with GCD blocks which makes it very easy to provide your own. However, they are executed on arbitrary threads within GCD so __special attention must be paid to thread-safety and re-entrancy__. Handlers require 2 GCD blocks: * The ```GCDWebServerMatchBlock``` is called on every handler added to the ```GCDWebServer``` instance whenever a web request has started (i.e. HTTP headers have been received). It is passed the basic info for the web request (HTTP method, URL, headers...) and must decide if it wants to handle it or not. If yes, it must return a new ```GCDWebServerRequest``` instance (see above) created with this info. Otherwise, it simply returns nil. @@ -287,7 +287,7 @@ Note that most methods on ```GCDWebServer``` to add handlers only require the `` 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: +New in GCDWebServer 3.0 is the ability to process HTTP requests asynchronously 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 diff --git a/src/ios/GCDWebServer/Run-Tests.sh b/src/ios/GCDWebServer/Run-Tests.sh index 0e180fe..3119d88 100755 --- a/src/ios/GCDWebServer/Run-Tests.sh +++ b/src/ios/GCDWebServer/Run-Tests.sh @@ -58,7 +58,7 @@ xcodebuild build -sdk "$OSX_SDK" -target "$OSX_TARGET" -configuration "$CONFIGUR # Build for iOS for oldest supported deployment target rm -rf "$BUILD_DIR" -xcodebuild build -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" "SYMROOT=$BUILD_DIR" "IPHONEOS_DEPLOYMENT_TARGET=6.0" > /dev/null +xcodebuild build -sdk "$IOS_SDK" -target "$IOS_TARGET" -configuration "$CONFIGURATION" "SYMROOT=$BUILD_DIR" "IPHONEOS_DEPLOYMENT_TARGET=8.0" > /dev/null # Build for iOS for current deployment target rm -rf "$BUILD_DIR" diff --git a/src/ios/GCDWebServer/Tests/HTMLFileUpload/001-200.response b/src/ios/GCDWebServer/Tests/HTMLFileUpload/001-200.response old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLFileUpload/001-GET.request b/src/ios/GCDWebServer/Tests/HTMLFileUpload/001-GET.request old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLFileUpload/002-200.response b/src/ios/GCDWebServer/Tests/HTMLFileUpload/002-200.response old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLFileUpload/002-POST.request b/src/ios/GCDWebServer/Tests/HTMLFileUpload/002-POST.request old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLForm/001-200.response b/src/ios/GCDWebServer/Tests/HTMLForm/001-200.response old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLForm/001-GET.request b/src/ios/GCDWebServer/Tests/HTMLForm/001-GET.request old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLForm/002-200.response b/src/ios/GCDWebServer/Tests/HTMLForm/002-200.response old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/HTMLForm/002-POST.request b/src/ios/GCDWebServer/Tests/HTMLForm/002-POST.request old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/Payload.zip b/src/ios/GCDWebServer/Tests/Payload.zip old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/Sample-Movie.mp4 b/src/ios/GCDWebServer/Tests/Sample-Movie.mp4 old mode 100644 new mode 100755 diff --git a/src/ios/GCDWebServer/Tests/WebDAV-Finder/059-200.response b/src/ios/GCDWebServer/Tests/WebDAV-Finder/059-200.response deleted file mode 100755 index 92ae6ab59a6f39803014af0328e0b8eecddca414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107049 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%0A}{Gt^-(8PgB{mR{)|2K>lM)%y3fux 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%0D;eV>UW$OQQqVE0XJ&wZh!=XG^S^}SeqX(V?x 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 Date: Wed, 10 Jan 2018 16:55:11 +0100 Subject: [PATCH 3/3] make it compatible with meteor 1.6.1 (breaking: not compatible with <1.6.1 anymore) --- src/ios/AssetBundleManager.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ios/AssetBundleManager.swift b/src/ios/AssetBundleManager.swift index 0e45975..210cfda 100644 --- a/src/ios/AssetBundleManager.swift +++ b/src/ios/AssetBundleManager.swift @@ -6,7 +6,7 @@ protocol AssetBundleManagerDelegate: class { final class AssetBundleManager: AssetBundleDownloaderDelegate { let configuration: WebAppConfiguration - + /// The directory used to store downloaded asset bundles let versionsDirectoryURL: URL @@ -20,9 +20,9 @@ final class AssetBundleManager: AssetBundleDownloaderDelegate { private let fileManager = FileManager() private var downloadedAssetBundlesByVersion: [String: AssetBundle] - + private var session: URLSession! - + private var downloadDirectoryURL: URL private var assetBundleDownloader: AssetBundleDownloader? private var partiallyDownloadedAssetBundle: AssetBundle? @@ -42,17 +42,17 @@ final class AssetBundleManager: AssetBundleDownloaderDelegate { downloadedAssetBundlesByVersion = [String: AssetBundle]() loadDownloadedAssetBundles() - + let operationQueue = OperationQueue() operationQueue.maxConcurrentOperationCount = 1 operationQueue.underlyingQueue = queue - + // We use a separate to download the manifest, so we can use caching - // (which we disable for the session we use to download the other files + // (which we disable for the session we use to download the other files // in AssetBundleDownloader) session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: operationQueue) } - + deinit { assetBundleDownloader?.cancel() } @@ -90,7 +90,7 @@ final class AssetBundleManager: AssetBundleDownloaderDelegate { } func checkForUpdatesWithBaseURL(_ baseURL: URL) { - let manifestURL = URL(string: "manifest.json", relativeTo: baseURL)! + let manifestURL = URL(string: "__meteor__/webapp/manifest.json", relativeTo: baseURL)! NSLog("Start downloading asset manifest from: \(manifestURL)") @@ -147,10 +147,10 @@ final class AssetBundleManager: AssetBundleDownloaderDelegate { self.didFinishDownloadingAssetBundle(assetBundle) return } - + // Else, get ready to download the new asset bundle self.moveExistingDownloadDirectoryIfNeeded() - + // Create download directory do { try self.fileManager.createDirectory(at: self.downloadDirectoryURL, withIntermediateDirectories: true, attributes: nil) @@ -172,7 +172,7 @@ final class AssetBundleManager: AssetBundleDownloaderDelegate { self.didFailWithError(error) } } - }) + }) // If a new version is available, we want to know as soon as possible even // if other downloads are in progress