Add RSWeb framework.
This commit is contained in:
parent
02503fadb9
commit
074bbca652
|
@ -18,6 +18,8 @@
|
|||
84B06FAF1ED37DBD00F0B54B /* RSCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84B06FA91ED37DAD00F0B54B /* RSCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
84B06FB21ED37DBD00F0B54B /* RSDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84B06F9D1ED37DA000F0B54B /* RSDatabase.framework */; };
|
||||
84B06FB31ED37DBD00F0B54B /* RSDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84B06F9D1ED37DA000F0B54B /* RSDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
84B06FC21ED37E9600F0B54B /* RSWeb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84B06FBD1ED37E8C00F0B54B /* RSWeb.framework */; };
|
||||
84B06FC31ED37E9600F0B54B /* RSWeb.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84B06FBD1ED37E8C00F0B54B /* RSWeb.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -112,6 +114,34 @@
|
|||
remoteGlobalIDString = 84F22C541B52E0D9000060CE;
|
||||
remoteInfo = RSDatabase;
|
||||
};
|
||||
84B06FBC1ED37E8C00F0B54B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 849C08B61E0CAC85006B03FA;
|
||||
remoteInfo = RSWeb;
|
||||
};
|
||||
84B06FBE1ED37E8C00F0B54B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 849C08BF1E0CAC86006B03FA;
|
||||
remoteInfo = RSWebTests;
|
||||
};
|
||||
84B06FC01ED37E8C00F0B54B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 849C08D51E0CACA3006B03FA;
|
||||
remoteInfo = RSWebiOS;
|
||||
};
|
||||
84B06FC41ED37E9600F0B54B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 849C08B51E0CAC85006B03FA;
|
||||
remoteInfo = RSWeb;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -123,6 +153,7 @@
|
|||
files = (
|
||||
84B06FB31ED37DBD00F0B54B /* RSDatabase.framework in Embed Frameworks */,
|
||||
84B06FAF1ED37DBD00F0B54B /* RSCore.framework in Embed Frameworks */,
|
||||
84B06FC31ED37E9600F0B54B /* RSWeb.framework in Embed Frameworks */,
|
||||
84B06F831ED37BDD00F0B54B /* RSXML.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
|
@ -143,6 +174,7 @@
|
|||
84B06F761ED37BCA00F0B54B /* RSXML.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSXML.xcodeproj; path = Frameworks/RSXML/RSXML.xcodeproj; sourceTree = "<group>"; };
|
||||
84B06F961ED37DA000F0B54B /* RSDatabase.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSDatabase.xcodeproj; path = Frameworks/RSDatabase/RSDatabase.xcodeproj; sourceTree = "<group>"; };
|
||||
84B06FA21ED37DAC00F0B54B /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = Frameworks/RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
||||
84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSWeb.xcodeproj; path = Frameworks/RSWeb/RSWeb.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -152,6 +184,7 @@
|
|||
files = (
|
||||
84B06FB21ED37DBD00F0B54B /* RSDatabase.framework in Frameworks */,
|
||||
84B06FAE1ED37DBD00F0B54B /* RSCore.framework in Frameworks */,
|
||||
84B06FC21ED37E9600F0B54B /* RSWeb.framework in Frameworks */,
|
||||
84B06F821ED37BDD00F0B54B /* RSXML.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -178,6 +211,7 @@
|
|||
849C64611ED37A5D003D8FC0 /* Products */,
|
||||
84B06FA21ED37DAC00F0B54B /* RSCore.xcodeproj */,
|
||||
84B06F961ED37DA000F0B54B /* RSDatabase.xcodeproj */,
|
||||
84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */,
|
||||
84B06F761ED37BCA00F0B54B /* RSXML.xcodeproj */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
|
@ -230,6 +264,16 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84B06FB71ED37E8B00F0B54B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84B06FBD1ED37E8C00F0B54B /* RSWeb.framework */,
|
||||
84B06FBF1ED37E8C00F0B54B /* RSWebTests.xctest */,
|
||||
84B06FC11ED37E8C00F0B54B /* RSWeb.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -248,6 +292,7 @@
|
|||
84B06F851ED37BDD00F0B54B /* PBXTargetDependency */,
|
||||
84B06FB11ED37DBD00F0B54B /* PBXTargetDependency */,
|
||||
84B06FB51ED37DBD00F0B54B /* PBXTargetDependency */,
|
||||
84B06FC51ED37E9600F0B54B /* PBXTargetDependency */,
|
||||
);
|
||||
name = Evergreen;
|
||||
productName = Evergreen;
|
||||
|
@ -315,6 +360,10 @@
|
|||
ProductGroup = 84B06F971ED37DA000F0B54B /* Products */;
|
||||
ProjectRef = 84B06F961ED37DA000F0B54B /* RSDatabase.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 84B06FB71ED37E8B00F0B54B /* Products */;
|
||||
ProjectRef = 84B06FB61ED37E8B00F0B54B /* RSWeb.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 84B06F771ED37BCA00F0B54B /* Products */;
|
||||
ProjectRef = 84B06F761ED37BCA00F0B54B /* RSXML.xcodeproj */;
|
||||
|
@ -392,6 +441,27 @@
|
|||
remoteRef = 84B06FAC1ED37DAD00F0B54B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
84B06FBD1ED37E8C00F0B54B /* RSWeb.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = RSWeb.framework;
|
||||
remoteRef = 84B06FBC1ED37E8C00F0B54B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
84B06FBF1ED37E8C00F0B54B /* RSWebTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = RSWebTests.xctest;
|
||||
remoteRef = 84B06FBE1ED37E8C00F0B54B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
84B06FC11ED37E8C00F0B54B /* RSWeb.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = RSWeb.framework;
|
||||
remoteRef = 84B06FC01ED37E8C00F0B54B /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
|
@ -454,6 +524,11 @@
|
|||
name = RSDatabase;
|
||||
targetProxy = 84B06FB41ED37DBD00F0B54B /* PBXContainerItemProxy */;
|
||||
};
|
||||
84B06FC51ED37E9600F0B54B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = RSWeb;
|
||||
targetProxy = 84B06FC41ED37E9600F0B54B /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
.build/
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
# Carthage/Checkouts
|
||||
|
||||
Carthage/Build
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016 Brent Simmons
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,19 @@
|
|||
# RSWeb
|
||||
|
||||
RSWeb is utility code — all Swift — for downloading things from the web. It builds a Mac framework and an iOS framework.
|
||||
|
||||
#### Easy way
|
||||
|
||||
See `OneShotDownload` for a top-level `download` function that takes a URL and a callback. The callback takes `Data`, `URLResponse`, and `Error` parameters. It’s easy.
|
||||
|
||||
#### Slightly less easy way
|
||||
|
||||
See `DownloadSession` and `DownloadSessionDelegate` for when you’re doing a bunch of downloads and you need to track progress.
|
||||
|
||||
#### Extras
|
||||
|
||||
`HTTPConditionalGetInfo` helps with supporting conditional GET, for when you’re downloading things that may not have changed. See [HTTP Conditional Get for RSS Hackers](http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/) for more about conditional GET. This is especially critical when polling for changes, such as with an RSS reader.
|
||||
|
||||
`MimeType` could use expansion, but is useful for some cases right now.
|
||||
|
||||
`MacWebBrowser` makes it easy to open a URL in the default browser. You can specify whether or not to open in background.
|
|
@ -0,0 +1,706 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
842ED2E71E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */; };
|
||||
842ED2E81E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */; };
|
||||
842ED2EA1E12FB91000CF738 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E91E12FB91000CF738 /* HTTPMethod.swift */; };
|
||||
842ED2EB1E12FB91000CF738 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E91E12FB91000CF738 /* HTTPMethod.swift */; };
|
||||
842ED2ED1E12FB97000CF738 /* HTTPResponseCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2EC1E12FB97000CF738 /* HTTPResponseCode.swift */; };
|
||||
842ED2EE1E12FB97000CF738 /* HTTPResponseCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2EC1E12FB97000CF738 /* HTTPResponseCode.swift */; };
|
||||
842ED2F01E12FB9B000CF738 /* HTTPResponseHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2EF1E12FB9B000CF738 /* HTTPResponseHeader.swift */; };
|
||||
842ED2F11E12FB9B000CF738 /* HTTPResponseHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2EF1E12FB9B000CF738 /* HTTPResponseHeader.swift */; };
|
||||
842ED2F31E12FBAA000CF738 /* DownloadSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2F21E12FBAA000CF738 /* DownloadSession.swift */; };
|
||||
842ED2F41E12FBAA000CF738 /* DownloadSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2F21E12FBAA000CF738 /* DownloadSession.swift */; };
|
||||
842ED2F61E12FBAF000CF738 /* OneShotDownload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2F51E12FBAF000CF738 /* OneShotDownload.swift */; };
|
||||
842ED2F71E12FBAF000CF738 /* OneShotDownload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2F51E12FBAF000CF738 /* OneShotDownload.swift */; };
|
||||
842ED2F91E12FBB5000CF738 /* DownloadProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2F81E12FBB5000CF738 /* DownloadProgress.swift */; };
|
||||
842ED2FA1E12FBB5000CF738 /* DownloadProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2F81E12FBB5000CF738 /* DownloadProgress.swift */; };
|
||||
842ED2FC1E12FBBB000CF738 /* DownloadObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2FB1E12FBBB000CF738 /* DownloadObject.swift */; };
|
||||
842ED2FD1E12FBBB000CF738 /* DownloadObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2FB1E12FBBB000CF738 /* DownloadObject.swift */; };
|
||||
842ED2FF1E12FBC1000CF738 /* UserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2FE1E12FBC1000CF738 /* UserAgent.swift */; };
|
||||
842ED3001E12FBC1000CF738 /* UserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2FE1E12FBC1000CF738 /* UserAgent.swift */; };
|
||||
842ED3021E12FBC7000CF738 /* HTTPConditionalGetInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3011E12FBC7000CF738 /* HTTPConditionalGetInfo.swift */; };
|
||||
842ED3031E12FBC7000CF738 /* HTTPConditionalGetInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3011E12FBC7000CF738 /* HTTPConditionalGetInfo.swift */; };
|
||||
842ED3051E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3041E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift */; };
|
||||
842ED3061E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3041E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift */; };
|
||||
842ED3081E12FBD2000CF738 /* URLRequest+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3071E12FBD2000CF738 /* URLRequest+RSWeb.swift */; };
|
||||
842ED3091E12FBD2000CF738 /* URLRequest+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3071E12FBD2000CF738 /* URLRequest+RSWeb.swift */; };
|
||||
842ED30B1E12FBD8000CF738 /* URL+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED30A1E12FBD8000CF738 /* URL+RSWeb.swift */; };
|
||||
842ED30C1E12FBD8000CF738 /* URL+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED30A1E12FBD8000CF738 /* URL+RSWeb.swift */; };
|
||||
842ED30E1E12FBDD000CF738 /* URLResponse+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED30D1E12FBDD000CF738 /* URLResponse+RSWeb.swift */; };
|
||||
842ED30F1E12FBDD000CF738 /* URLResponse+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED30D1E12FBDD000CF738 /* URLResponse+RSWeb.swift */; };
|
||||
842ED3111E12FBE1000CF738 /* MacWebBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3101E12FBE1000CF738 /* MacWebBrowser.swift */; };
|
||||
842ED3141E12FBE7000CF738 /* MimeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3131E12FBE7000CF738 /* MimeType.swift */; };
|
||||
842ED3151E12FBE7000CF738 /* MimeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED3131E12FBE7000CF738 /* MimeType.swift */; };
|
||||
849C08C01E0CAC86006B03FA /* RSWeb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 849C08B61E0CAC85006B03FA /* RSWeb.framework */; };
|
||||
849C08C51E0CAC86006B03FA /* RSWebTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849C08C41E0CAC86006B03FA /* RSWebTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
849C08C11E0CAC86006B03FA /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 849C08AD1E0CAC85006B03FA /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 849C08B51E0CAC85006B03FA;
|
||||
remoteInfo = RSWeb;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPRequestHeader.swift; path = RSWeb/HTTPRequestHeader.swift; sourceTree = "<group>"; };
|
||||
842ED2E91E12FB91000CF738 /* HTTPMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPMethod.swift; path = RSWeb/HTTPMethod.swift; sourceTree = "<group>"; };
|
||||
842ED2EC1E12FB97000CF738 /* HTTPResponseCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPResponseCode.swift; path = RSWeb/HTTPResponseCode.swift; sourceTree = "<group>"; };
|
||||
842ED2EF1E12FB9B000CF738 /* HTTPResponseHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPResponseHeader.swift; path = RSWeb/HTTPResponseHeader.swift; sourceTree = "<group>"; };
|
||||
842ED2F21E12FBAA000CF738 /* DownloadSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DownloadSession.swift; path = RSWeb/DownloadSession.swift; sourceTree = "<group>"; };
|
||||
842ED2F51E12FBAF000CF738 /* OneShotDownload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OneShotDownload.swift; path = RSWeb/OneShotDownload.swift; sourceTree = "<group>"; };
|
||||
842ED2F81E12FBB5000CF738 /* DownloadProgress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DownloadProgress.swift; path = RSWeb/DownloadProgress.swift; sourceTree = "<group>"; };
|
||||
842ED2FB1E12FBBB000CF738 /* DownloadObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DownloadObject.swift; path = RSWeb/DownloadObject.swift; sourceTree = "<group>"; };
|
||||
842ED2FE1E12FBC1000CF738 /* UserAgent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UserAgent.swift; path = RSWeb/UserAgent.swift; sourceTree = "<group>"; };
|
||||
842ED3011E12FBC7000CF738 /* HTTPConditionalGetInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPConditionalGetInfo.swift; path = RSWeb/HTTPConditionalGetInfo.swift; sourceTree = "<group>"; };
|
||||
842ED3041E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSMutableURLRequest+RSWeb.swift"; path = "RSWeb/NSMutableURLRequest+RSWeb.swift"; sourceTree = "<group>"; };
|
||||
842ED3071E12FBD2000CF738 /* URLRequest+RSWeb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "URLRequest+RSWeb.swift"; path = "RSWeb/URLRequest+RSWeb.swift"; sourceTree = "<group>"; };
|
||||
842ED30A1E12FBD8000CF738 /* URL+RSWeb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "URL+RSWeb.swift"; path = "RSWeb/URL+RSWeb.swift"; sourceTree = "<group>"; };
|
||||
842ED30D1E12FBDD000CF738 /* URLResponse+RSWeb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "URLResponse+RSWeb.swift"; path = "RSWeb/URLResponse+RSWeb.swift"; sourceTree = "<group>"; };
|
||||
842ED3101E12FBE1000CF738 /* MacWebBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MacWebBrowser.swift; path = RSWeb/MacWebBrowser.swift; sourceTree = "<group>"; };
|
||||
842ED3131E12FBE7000CF738 /* MimeType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MimeType.swift; path = RSWeb/MimeType.swift; sourceTree = "<group>"; };
|
||||
849C08B61E0CAC85006B03FA /* RSWeb.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RSWeb.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
849C08BA1E0CAC85006B03FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
849C08BF1E0CAC86006B03FA /* RSWebTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RSWebTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
849C08C41E0CAC86006B03FA /* RSWebTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSWebTests.swift; sourceTree = "<group>"; };
|
||||
849C08C61E0CAC86006B03FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
849C08D51E0CACA3006B03FA /* RSWeb.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RSWeb.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
849C08D81E0CACA3006B03FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
849C08B21E0CAC85006B03FA /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08BC1E0CAC86006B03FA /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
849C08C01E0CAC86006B03FA /* RSWeb.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08D11E0CACA3006B03FA /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
842ED2D41E11FE8B000CF738 /* Constants */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */,
|
||||
842ED2E91E12FB91000CF738 /* HTTPMethod.swift */,
|
||||
842ED2EC1E12FB97000CF738 /* HTTPResponseCode.swift */,
|
||||
842ED2EF1E12FB9B000CF738 /* HTTPResponseHeader.swift */,
|
||||
);
|
||||
name = Constants;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
849C08AC1E0CAC85006B03FA = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
842ED2D41E11FE8B000CF738 /* Constants */,
|
||||
849C09231E0CAD67006B03FA /* Downloading */,
|
||||
842ED30A1E12FBD8000CF738 /* URL+RSWeb.swift */,
|
||||
842ED3131E12FBE7000CF738 /* MimeType.swift */,
|
||||
842ED3101E12FBE1000CF738 /* MacWebBrowser.swift */,
|
||||
849C08B81E0CAC85006B03FA /* RSWeb */,
|
||||
849C08C31E0CAC86006B03FA /* RSWebTests */,
|
||||
849C08D61E0CACA3006B03FA /* RSWebiOS */,
|
||||
849C08B71E0CAC85006B03FA /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
849C08B71E0CAC85006B03FA /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
849C08B61E0CAC85006B03FA /* RSWeb.framework */,
|
||||
849C08BF1E0CAC86006B03FA /* RSWebTests.xctest */,
|
||||
849C08D51E0CACA3006B03FA /* RSWeb.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
849C08B81E0CAC85006B03FA /* RSWeb */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
849C08BA1E0CAC85006B03FA /* Info.plist */,
|
||||
);
|
||||
path = RSWeb;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
849C08C31E0CAC86006B03FA /* RSWebTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
849C08C41E0CAC86006B03FA /* RSWebTests.swift */,
|
||||
849C08C61E0CAC86006B03FA /* Info.plist */,
|
||||
);
|
||||
path = RSWebTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
849C08D61E0CACA3006B03FA /* RSWebiOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
849C08D81E0CACA3006B03FA /* Info.plist */,
|
||||
);
|
||||
path = RSWebiOS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
849C09231E0CAD67006B03FA /* Downloading */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
842ED2F21E12FBAA000CF738 /* DownloadSession.swift */,
|
||||
842ED2F81E12FBB5000CF738 /* DownloadProgress.swift */,
|
||||
842ED2F51E12FBAF000CF738 /* OneShotDownload.swift */,
|
||||
842ED2FB1E12FBBB000CF738 /* DownloadObject.swift */,
|
||||
842ED2FE1E12FBC1000CF738 /* UserAgent.swift */,
|
||||
842ED3011E12FBC7000CF738 /* HTTPConditionalGetInfo.swift */,
|
||||
842ED3071E12FBD2000CF738 /* URLRequest+RSWeb.swift */,
|
||||
842ED3041E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift */,
|
||||
842ED30D1E12FBDD000CF738 /* URLResponse+RSWeb.swift */,
|
||||
);
|
||||
name = Downloading;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
849C08B31E0CAC85006B03FA /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08D21E0CACA3006B03FA /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
849C08B51E0CAC85006B03FA /* RSWeb */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 849C08CA1E0CAC86006B03FA /* Build configuration list for PBXNativeTarget "RSWeb" */;
|
||||
buildPhases = (
|
||||
849C08B11E0CAC85006B03FA /* Sources */,
|
||||
849C08B21E0CAC85006B03FA /* Frameworks */,
|
||||
849C08B31E0CAC85006B03FA /* Headers */,
|
||||
849C08B41E0CAC85006B03FA /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RSWeb;
|
||||
productName = RSWeb;
|
||||
productReference = 849C08B61E0CAC85006B03FA /* RSWeb.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
849C08BE1E0CAC86006B03FA /* RSWebTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 849C08CD1E0CAC86006B03FA /* Build configuration list for PBXNativeTarget "RSWebTests" */;
|
||||
buildPhases = (
|
||||
849C08BB1E0CAC86006B03FA /* Sources */,
|
||||
849C08BC1E0CAC86006B03FA /* Frameworks */,
|
||||
849C08BD1E0CAC86006B03FA /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
849C08C21E0CAC86006B03FA /* PBXTargetDependency */,
|
||||
);
|
||||
name = RSWebTests;
|
||||
productName = RSWebTests;
|
||||
productReference = 849C08BF1E0CAC86006B03FA /* RSWebTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
849C08D41E0CACA3006B03FA /* RSWebiOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 849C08DA1E0CACA3006B03FA /* Build configuration list for PBXNativeTarget "RSWebiOS" */;
|
||||
buildPhases = (
|
||||
849C08D01E0CACA3006B03FA /* Sources */,
|
||||
849C08D11E0CACA3006B03FA /* Frameworks */,
|
||||
849C08D21E0CACA3006B03FA /* Headers */,
|
||||
849C08D31E0CACA3006B03FA /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RSWebiOS;
|
||||
productName = RSWebiOS;
|
||||
productReference = 849C08D51E0CACA3006B03FA /* RSWeb.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
849C08AD1E0CAC85006B03FA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0820;
|
||||
LastUpgradeCheck = 0820;
|
||||
ORGANIZATIONNAME = "Ranchero Software";
|
||||
TargetAttributes = {
|
||||
849C08B51E0CAC85006B03FA = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = 9C84TZ7Q6Z;
|
||||
LastSwiftMigration = 0820;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
849C08BE1E0CAC86006B03FA = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = 9C84TZ7Q6Z;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
849C08D41E0CACA3006B03FA = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = 9C84TZ7Q6Z;
|
||||
LastSwiftMigration = 0820;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 849C08B01E0CAC85006B03FA /* Build configuration list for PBXProject "RSWeb" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 849C08AC1E0CAC85006B03FA;
|
||||
productRefGroup = 849C08B71E0CAC85006B03FA /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
849C08B51E0CAC85006B03FA /* RSWeb */,
|
||||
849C08BE1E0CAC86006B03FA /* RSWebTests */,
|
||||
849C08D41E0CACA3006B03FA /* RSWebiOS */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
849C08B41E0CAC85006B03FA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08BD1E0CAC86006B03FA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08D31E0CACA3006B03FA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
849C08B11E0CAC85006B03FA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
842ED2F01E12FB9B000CF738 /* HTTPResponseHeader.swift in Sources */,
|
||||
842ED2FF1E12FBC1000CF738 /* UserAgent.swift in Sources */,
|
||||
842ED2FC1E12FBBB000CF738 /* DownloadObject.swift in Sources */,
|
||||
842ED30E1E12FBDD000CF738 /* URLResponse+RSWeb.swift in Sources */,
|
||||
842ED2F61E12FBAF000CF738 /* OneShotDownload.swift in Sources */,
|
||||
842ED2F31E12FBAA000CF738 /* DownloadSession.swift in Sources */,
|
||||
842ED3081E12FBD2000CF738 /* URLRequest+RSWeb.swift in Sources */,
|
||||
842ED3051E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift in Sources */,
|
||||
842ED2E71E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */,
|
||||
842ED3111E12FBE1000CF738 /* MacWebBrowser.swift in Sources */,
|
||||
842ED3141E12FBE7000CF738 /* MimeType.swift in Sources */,
|
||||
842ED30B1E12FBD8000CF738 /* URL+RSWeb.swift in Sources */,
|
||||
842ED2F91E12FBB5000CF738 /* DownloadProgress.swift in Sources */,
|
||||
842ED2EA1E12FB91000CF738 /* HTTPMethod.swift in Sources */,
|
||||
842ED3021E12FBC7000CF738 /* HTTPConditionalGetInfo.swift in Sources */,
|
||||
842ED2ED1E12FB97000CF738 /* HTTPResponseCode.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08BB1E0CAC86006B03FA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
849C08C51E0CAC86006B03FA /* RSWebTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
849C08D01E0CACA3006B03FA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
842ED3091E12FBD2000CF738 /* URLRequest+RSWeb.swift in Sources */,
|
||||
842ED2F71E12FBAF000CF738 /* OneShotDownload.swift in Sources */,
|
||||
842ED30F1E12FBDD000CF738 /* URLResponse+RSWeb.swift in Sources */,
|
||||
842ED2E81E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */,
|
||||
842ED3001E12FBC1000CF738 /* UserAgent.swift in Sources */,
|
||||
842ED2FA1E12FBB5000CF738 /* DownloadProgress.swift in Sources */,
|
||||
842ED2EB1E12FB91000CF738 /* HTTPMethod.swift in Sources */,
|
||||
842ED2F11E12FB9B000CF738 /* HTTPResponseHeader.swift in Sources */,
|
||||
842ED3061E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift in Sources */,
|
||||
842ED2F41E12FBAA000CF738 /* DownloadSession.swift in Sources */,
|
||||
842ED2EE1E12FB97000CF738 /* HTTPResponseCode.swift in Sources */,
|
||||
842ED30C1E12FBD8000CF738 /* URL+RSWeb.swift in Sources */,
|
||||
842ED3151E12FBE7000CF738 /* MimeType.swift in Sources */,
|
||||
842ED3031E12FBC7000CF738 /* HTTPConditionalGetInfo.swift in Sources */,
|
||||
842ED2FD1E12FBBB000CF738 /* DownloadObject.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
849C08C21E0CAC86006B03FA /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 849C08B51E0CAC85006B03FA /* RSWeb */;
|
||||
targetProxy = 849C08C11E0CAC86006B03FA /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
849C08C81E0CAC86006B03FA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
849C08C91E0CAC86006B03FA /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_STATIC_ANALYZER_MODE = deep;
|
||||
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_SHADOW = YES;
|
||||
GCC_WARN_SIGN_COMPARE = YES;
|
||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_PARAMETER = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
RUN_CLANG_STATIC_ANALYZER = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
849C08CB1E0CAC86006B03FA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 9C84TZ7Q6Z;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = RSWeb/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.RSWeb;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
849C08CC1E0CAC86006B03FA /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 9C84TZ7Q6Z;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_VERSION = A;
|
||||
INFOPLIST_FILE = RSWeb/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.RSWeb;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
849C08CE1E0CAC86006B03FA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = 9C84TZ7Q6Z;
|
||||
INFOPLIST_FILE = RSWebTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.RSWebTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
849C08CF1E0CAC86006B03FA /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = 9C84TZ7Q6Z;
|
||||
INFOPLIST_FILE = RSWebTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.RSWebTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
849C08DB1E0CACA3006B03FA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 9C84TZ7Q6Z;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = RSWebiOS/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.RSWebiOS;
|
||||
PRODUCT_NAME = RSWeb;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
849C08DC1E0CACA3006B03FA /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 9C84TZ7Q6Z;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = RSWebiOS/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.RSWebiOS;
|
||||
PRODUCT_NAME = RSWeb;
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
849C08B01E0CAC85006B03FA /* Build configuration list for PBXProject "RSWeb" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
849C08C81E0CAC86006B03FA /* Debug */,
|
||||
849C08C91E0CAC86006B03FA /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
849C08CA1E0CAC86006B03FA /* Build configuration list for PBXNativeTarget "RSWeb" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
849C08CB1E0CAC86006B03FA /* Debug */,
|
||||
849C08CC1E0CAC86006B03FA /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
849C08CD1E0CAC86006B03FA /* Build configuration list for PBXNativeTarget "RSWebTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
849C08CE1E0CAC86006B03FA /* Debug */,
|
||||
849C08CF1E0CAC86006B03FA /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
849C08DA1E0CACA3006B03FA /* Build configuration list for PBXNativeTarget "RSWebiOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
849C08DB1E0CACA3006B03FA /* Debug */,
|
||||
849C08DC1E0CACA3006B03FA /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 849C08AD1E0CAC85006B03FA /* Project object */;
|
||||
}
|
7
Frameworks/RSWeb/RSWeb.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Executable file
7
Frameworks/RSWeb/RSWeb.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Executable file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:RSWeb.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// DownloadObject.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 8/3/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class DownloadObject: Hashable {
|
||||
|
||||
public let url: URL
|
||||
public var data = Data()
|
||||
|
||||
public var hashValue: Int {
|
||||
get {
|
||||
return url.hashValue
|
||||
}
|
||||
}
|
||||
|
||||
public init(url: URL) {
|
||||
|
||||
self.url = url
|
||||
}
|
||||
|
||||
public static func ==(lhs: DownloadObject, rhs: DownloadObject) -> Bool {
|
||||
|
||||
return lhs.url == rhs.url && lhs.data == rhs.data
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// DownloadProgress.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 9/17/16.
|
||||
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Notification.Name {
|
||||
|
||||
public static let DownloadProgressDidChange = Notification.Name(rawValue: "DownloadProgressDidChangeNotification")
|
||||
}
|
||||
|
||||
public class DownloadProgress {
|
||||
|
||||
public var numberOfTasks = 0 {
|
||||
didSet {
|
||||
if numberOfTasks == 0 {
|
||||
numberRemaining = 0
|
||||
}
|
||||
postDidChangeNotification()
|
||||
}
|
||||
}
|
||||
|
||||
public var numberRemaining = 0 {
|
||||
didSet {
|
||||
postDidChangeNotification()
|
||||
}
|
||||
}
|
||||
|
||||
public var numberCompleted: Int {
|
||||
get {
|
||||
var n = numberOfTasks - numberRemaining
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
if n > numberOfTasks {
|
||||
n = numberOfTasks
|
||||
}
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
public var isComplete: Bool {
|
||||
get {
|
||||
return numberRemaining < 1
|
||||
}
|
||||
}
|
||||
|
||||
public init(numberOfTasks: Int) {
|
||||
|
||||
self.numberOfTasks = numberOfTasks
|
||||
}
|
||||
|
||||
public func addToNumberOfTasks(_ n: Int) {
|
||||
|
||||
numberOfTasks = numberOfTasks + n
|
||||
}
|
||||
|
||||
public func clear() {
|
||||
|
||||
numberOfTasks = 0
|
||||
}
|
||||
}
|
||||
|
||||
private extension DownloadProgress {
|
||||
|
||||
func postDidChangeNotification() {
|
||||
|
||||
NotificationCenter.default.post(name: .DownloadProgressDidChange, object: self)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
//
|
||||
// DownloadSession.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 3/12/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// Create a DownloadSessionDelegate, then create a DownloadSession.
|
||||
// To download things: call downloadObjects, with a set of represented objects, to download things. DownloadSession will call the various delegate methods.
|
||||
|
||||
public protocol DownloadSessionDelegate {
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, requestForRepresentedObject: AnyObject) -> URLRequest?
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, downloadDidCompleteForRepresentedObject: AnyObject, response: URLResponse?, data: Data, error: NSError?)
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, shouldContinueAfterReceivingData: Data, representedObject: AnyObject) -> Bool
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, didReceiveUnexpectedResponse: URLResponse, representedObject: AnyObject)
|
||||
|
||||
func downloadSession(_ downloadSession: DownloadSession, didReceiveNotModifiedResponse: URLResponse, representedObject: AnyObject)
|
||||
}
|
||||
|
||||
|
||||
@objc public final class DownloadSession: NSObject, URLSessionDataDelegate {
|
||||
|
||||
public var progress = DownloadProgress(numberOfTasks: 0)
|
||||
|
||||
fileprivate var urlSession: URLSession!
|
||||
fileprivate var tasksInProgress = Set<URLSessionTask>()
|
||||
fileprivate var tasksPending = Set<URLSessionTask>()
|
||||
fileprivate var taskIdentifierToInfoDictionary = [Int: DownloadInfo]()
|
||||
fileprivate let representedObjects = NSMutableSet()
|
||||
fileprivate let delegate: DownloadSessionDelegate
|
||||
fileprivate var redirectCache = [String: String]()
|
||||
|
||||
public init(delegate: DownloadSessionDelegate) {
|
||||
|
||||
self.delegate = delegate
|
||||
|
||||
super.init()
|
||||
|
||||
let sessionConfiguration = URLSessionConfiguration.default
|
||||
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
|
||||
sessionConfiguration.timeoutIntervalForRequest = 60.0
|
||||
sessionConfiguration.httpShouldSetCookies = false
|
||||
sessionConfiguration.httpCookieAcceptPolicy = .never
|
||||
sessionConfiguration.httpMaximumConnectionsPerHost = 2
|
||||
sessionConfiguration.httpCookieStorage = nil
|
||||
sessionConfiguration.urlCache = nil
|
||||
|
||||
if let userAgent = UserAgent.fromInfoPlist() {
|
||||
var headers = [AnyHashable : Any]()
|
||||
headers[HTTPRequestHeader.userAgent] = userAgent
|
||||
sessionConfiguration.httpAdditionalHeaders = headers
|
||||
}
|
||||
|
||||
urlSession = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
|
||||
}
|
||||
|
||||
deinit {
|
||||
urlSession.invalidateAndCancel()
|
||||
}
|
||||
|
||||
// MARK: URLSessionTaskDelegate
|
||||
|
||||
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
|
||||
|
||||
tasksInProgress.remove(task)
|
||||
|
||||
guard let info = infoForTask(task) else {
|
||||
return
|
||||
}
|
||||
|
||||
info.error = error
|
||||
|
||||
delegate.downloadSession(self, downloadDidCompleteForRepresentedObject: info.representedObject, response: info.urlResponse, data: info.data as Data, error: error as NSError?)
|
||||
|
||||
removeTask(task)
|
||||
}
|
||||
|
||||
public func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
|
||||
|
||||
if response.statusCode == 301 || response.statusCode == 308 {
|
||||
if let oldURLString = task.originalRequest?.url?.absoluteString, let newURLString = request.url?.absoluteString {
|
||||
cacheRedirect(oldURLString, newURLString)
|
||||
}
|
||||
}
|
||||
|
||||
completionHandler(request)
|
||||
}
|
||||
|
||||
// MARK: URLSessionDataDelegate
|
||||
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
|
||||
|
||||
tasksInProgress.insert(dataTask)
|
||||
tasksPending.remove(dataTask)
|
||||
|
||||
if let info = infoForTask(dataTask) {
|
||||
info.urlResponse = response
|
||||
}
|
||||
|
||||
if response.forcedStatusCode == 304 {
|
||||
|
||||
if let representedObject = infoForTask(dataTask)?.representedObject {
|
||||
delegate.downloadSession(self, didReceiveNotModifiedResponse: response, representedObject: representedObject)
|
||||
}
|
||||
|
||||
completionHandler(.cancel)
|
||||
removeTask(dataTask)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !response.statusIsOK {
|
||||
|
||||
if let representedObject = infoForTask(dataTask)?.representedObject {
|
||||
delegate.downloadSession(self, didReceiveUnexpectedResponse: response, representedObject: representedObject)
|
||||
}
|
||||
|
||||
completionHandler(.cancel)
|
||||
removeTask(dataTask)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
completionHandler(.allow)
|
||||
}
|
||||
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
|
||||
|
||||
guard let info = infoForTask(dataTask) else {
|
||||
return
|
||||
}
|
||||
info.addData(data)
|
||||
|
||||
if !delegate.downloadSession(self, shouldContinueAfterReceivingData: info.data as Data, representedObject: info.representedObject) {
|
||||
|
||||
info.canceled = true
|
||||
dataTask.cancel()
|
||||
removeTask(dataTask)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: API
|
||||
|
||||
public func cancel() {
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
public func downloadObjects(_ objects: NSSet) {
|
||||
|
||||
var numberOfTasksAdded = 0
|
||||
|
||||
for oneObject in objects {
|
||||
|
||||
if !representedObjects.contains(oneObject) {
|
||||
representedObjects.add(oneObject)
|
||||
addDataTask(oneObject as AnyObject)
|
||||
numberOfTasksAdded += 1
|
||||
}
|
||||
}
|
||||
|
||||
progress.addToNumberOfTasks(numberOfTasksAdded)
|
||||
updateProgress()
|
||||
}
|
||||
}
|
||||
|
||||
private extension DownloadSession {
|
||||
|
||||
func updateProgress() {
|
||||
|
||||
progress.numberRemaining = tasksInProgress.count + tasksPending.count
|
||||
if progress.numberRemaining < 1 {
|
||||
progress.clear()
|
||||
representedObjects.removeAllObjects()
|
||||
}
|
||||
}
|
||||
|
||||
func addDataTask(_ representedObject: AnyObject) {
|
||||
|
||||
guard let request = delegate.downloadSession(self, requestForRepresentedObject: representedObject) else {
|
||||
return
|
||||
}
|
||||
|
||||
var requestToUse = request
|
||||
|
||||
// If received permanent redirect earlier, use that URL.
|
||||
|
||||
if let urlString = request.url?.absoluteString, let redirectedURLString = cachedRedirectForURLString(urlString) {
|
||||
if let redirectedURL = URL(string: redirectedURLString) {
|
||||
requestToUse.url = redirectedURL
|
||||
}
|
||||
}
|
||||
|
||||
let task = urlSession.dataTask(with: requestToUse)
|
||||
|
||||
let info = DownloadInfo(representedObject, urlRequest: requestToUse)
|
||||
taskIdentifierToInfoDictionary[task.taskIdentifier] = info
|
||||
|
||||
tasksPending.insert(task)
|
||||
task.resume()
|
||||
}
|
||||
|
||||
func infoForTask(_ task: URLSessionTask) -> DownloadInfo? {
|
||||
|
||||
return taskIdentifierToInfoDictionary[task.taskIdentifier]
|
||||
}
|
||||
|
||||
func removeTask(_ task: URLSessionTask) {
|
||||
|
||||
tasksInProgress.remove(task)
|
||||
tasksPending.remove(task)
|
||||
taskIdentifierToInfoDictionary[task.taskIdentifier] = nil
|
||||
updateProgress()
|
||||
}
|
||||
|
||||
func urlStringIsBlackListedRedirect(_ urlString: String) -> Bool {
|
||||
|
||||
// Hotels and similar often do permanent redirects. We can catch some of those.
|
||||
|
||||
let s = urlString.lowercased()
|
||||
let badStrings = ["solutionip", "lodgenet", "monzoon", "landingpage", "btopenzone", "register", "login", "authentic"]
|
||||
|
||||
for oneBadString in badStrings {
|
||||
if s.contains(oneBadString) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func cacheRedirect(_ oldURLString: String, _ newURLString: String) {
|
||||
|
||||
if urlStringIsBlackListedRedirect(newURLString) {
|
||||
return
|
||||
}
|
||||
|
||||
redirectCache[oldURLString] = newURLString
|
||||
}
|
||||
|
||||
func cachedRedirectForURLString(_ urlString: String) -> String? {
|
||||
|
||||
// Follow chains of redirects, but avoid loops.
|
||||
|
||||
var urlStrings = Set<String>()
|
||||
urlStrings.insert(urlString)
|
||||
|
||||
var currentString = urlString
|
||||
|
||||
while(true) {
|
||||
|
||||
if let oneRedirectString = redirectCache[currentString] {
|
||||
|
||||
if urlStrings.contains(oneRedirectString) {
|
||||
// Cycle. Bail.
|
||||
return nil
|
||||
}
|
||||
urlStrings.insert(oneRedirectString)
|
||||
currentString = oneRedirectString
|
||||
}
|
||||
|
||||
else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return currentString == urlString ? nil : currentString
|
||||
}
|
||||
}
|
||||
|
||||
private final class DownloadInfo {
|
||||
|
||||
let representedObject: AnyObject
|
||||
let urlRequest: URLRequest
|
||||
let data = NSMutableData()
|
||||
var error: Error?
|
||||
var urlResponse: URLResponse?
|
||||
var canceled = false
|
||||
|
||||
var statusCode: Int {
|
||||
get {
|
||||
return urlResponse?.forcedStatusCode ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
init(_ representedObject: AnyObject, urlRequest: URLRequest) {
|
||||
|
||||
self.representedObject = representedObject
|
||||
self.urlRequest = urlRequest
|
||||
}
|
||||
|
||||
func addData(_ d: Data) {
|
||||
|
||||
data.append(d)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// HTTPConditionalGetInfo.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 4/11/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct HTTPConditionalGetInfo {
|
||||
|
||||
public let lastModified: String?
|
||||
public let etag: String?
|
||||
public var isEmpty: Bool {
|
||||
get {
|
||||
return lastModified == nil && etag == nil
|
||||
}
|
||||
}
|
||||
|
||||
public init(lastModified: String?, etag: String?) {
|
||||
|
||||
self.lastModified = lastModified
|
||||
self.etag = etag
|
||||
}
|
||||
|
||||
public init(urlResponse: HTTPURLResponse) {
|
||||
|
||||
let lastModified = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.lastModified)
|
||||
let etag = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.etag)
|
||||
|
||||
self.init(lastModified: lastModified, etag: etag)
|
||||
}
|
||||
|
||||
public func addRequestHeadersToURLRequest(_ urlRequest: NSMutableURLRequest) {
|
||||
|
||||
if let lastModified = lastModified {
|
||||
urlRequest.addValue(lastModified, forHTTPHeaderField: HTTPRequestHeader.ifModifiedSince)
|
||||
}
|
||||
if let etag = etag {
|
||||
urlRequest.addValue(etag, forHTTPHeaderField: HTTPRequestHeader.ifNoneMatch)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// HTTPMethod.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/26/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct HTTPMethod {
|
||||
|
||||
public static let get = "GET"
|
||||
public static let post = "POST"
|
||||
public static let put = "PUT"
|
||||
public static let patch = "PATCH"
|
||||
public static let delete = "DELETE"
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// HTTPRequestHeader.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/26/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct HTTPRequestHeader {
|
||||
|
||||
public static let userAgent = "User-Agent"
|
||||
public static let authorization = "Authorization"
|
||||
public static let contentType = "Content-Type"
|
||||
|
||||
// Conditional GET
|
||||
|
||||
public static let ifModifiedSince = "If-Modified-Since"
|
||||
public static let ifNoneMatch = "If-None-Match" //Etag
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// HTTPResponseCode.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/26/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct HTTPResponseCode {
|
||||
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
// Not an enum because the main interest is the actual values.
|
||||
|
||||
public static let responseContinue = 100 //"continue" is a language keyword, hence the weird name
|
||||
public static let switchingProtocols = 101
|
||||
|
||||
public static let OK = 200
|
||||
public static let created = 201
|
||||
public static let accepted = 202
|
||||
public static let nonAuthoritativeInformation = 203
|
||||
public static let noContent = 204
|
||||
public static let resetContent = 205
|
||||
public static let partialContent = 206
|
||||
|
||||
public static let redirectMultipleChoices = 300
|
||||
public static let redirectPermanent = 301
|
||||
public static let redirectTemporary = 302
|
||||
public static let redirectSeeOther = 303
|
||||
public static let notModified = 304
|
||||
public static let useProxy = 305
|
||||
public static let unused = 306
|
||||
public static let redirectVeryTemporary = 307
|
||||
|
||||
public static let badRequest = 400
|
||||
public static let unauthorized = 401
|
||||
public static let paymentRequired = 402
|
||||
public static let forbidden = 403
|
||||
public static let notFound = 404
|
||||
public static let methodNotAllowed = 405
|
||||
public static let notAcceptable = 406
|
||||
public static let proxyAuthenticationRequired = 407
|
||||
public static let requestTimeout = 408
|
||||
public static let conflict = 409
|
||||
public static let goone = 410
|
||||
public static let lengthRequired = 411
|
||||
public static let preconditionFailed = 412
|
||||
public static let entityTooLarge = 413
|
||||
public static let URITooLong = 414
|
||||
public static let unsupportedMediaType = 415
|
||||
public static let requestedRangeNotSatisfiable = 416
|
||||
public static let expectationFailed = 417
|
||||
|
||||
public static let internalServerError = 500
|
||||
public static let notImplemented = 501
|
||||
public static let badGateway = 502
|
||||
public static let serviceUnavailable = 503
|
||||
public static let gatewayTimeout = 504
|
||||
public static let HTTPVersionNotSupported = 505
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// HTTPResponseHeader.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/26/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct HTTPResponseHeader {
|
||||
|
||||
public static let contentType = "Content-Type"
|
||||
|
||||
// Conditional GET. See:
|
||||
// http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/
|
||||
|
||||
public static let lastModified = "Last-Modified"
|
||||
public static let etag = "ETag"
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016 Ranchero Software. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// MacWebBrowser.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/27/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
public class MacWebBrowser {
|
||||
|
||||
public class func openURL(_ url: URL, inBackground: Bool) -> Bool {
|
||||
|
||||
guard let preparedURL = url.preparedForOpeningInBrowser() else {
|
||||
return false
|
||||
}
|
||||
|
||||
if (inBackground) {
|
||||
do {
|
||||
try NSWorkspace.shared().open(preparedURL, options: [.withoutActivation], configuration: [String: Any]())
|
||||
return true
|
||||
}
|
||||
catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return NSWorkspace.shared().open(preparedURL)
|
||||
}
|
||||
}
|
||||
|
||||
private extension URL {
|
||||
|
||||
func preparedForOpeningInBrowser() -> URL? {
|
||||
|
||||
var urlString = absoluteString.replacingOccurrences(of: " ", with: "%20")
|
||||
urlString = urlString.replacingOccurrences(of: "^", with: "%5E")
|
||||
urlString = urlString.replacingOccurrences(of: "&", with: "&")
|
||||
urlString = urlString.replacingOccurrences(of: "&", with: "&")
|
||||
|
||||
return URL(string: urlString)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// MimeType.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/26/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct MimeType {
|
||||
|
||||
// This could certainly use expansion.
|
||||
|
||||
public static let png = "image/png"
|
||||
public static let jpeg = "image/jpeg"
|
||||
public static let jpg = "image/jpg"
|
||||
public static let gif = "image/gif"
|
||||
public static let tiff = "image/tiff"
|
||||
}
|
||||
|
||||
public extension String {
|
||||
|
||||
public func isMimeTypeImage() -> Bool {
|
||||
|
||||
return self.isOfGeneralMimeType("image")
|
||||
}
|
||||
|
||||
public func isMimeTypeAudio() -> Bool {
|
||||
|
||||
return self.isOfGeneralMimeType("audio")
|
||||
}
|
||||
|
||||
public func isMimeTypeVideo() -> Bool {
|
||||
|
||||
return self.isOfGeneralMimeType("video")
|
||||
}
|
||||
|
||||
public func isMimeTypeTimeBasedMedia() -> Bool {
|
||||
|
||||
return self.isMimeTypeAudio() || self.isMimeTypeVideo()
|
||||
}
|
||||
|
||||
private func isOfGeneralMimeType(_ type: String) -> Bool {
|
||||
|
||||
let lower = self.lowercased()
|
||||
if lower.hasPrefix(type) {
|
||||
return true
|
||||
}
|
||||
if lower.hasPrefix("x-\(type)") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// NSMutableURLRequest+RSWeb.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/27/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension NSMutableURLRequest {
|
||||
|
||||
public func addBasicAuthorization(username: String, password: String) -> Bool {
|
||||
|
||||
// Do this *only* with https. And not even then if you can help it.
|
||||
|
||||
let s = "\(username):\(password)"
|
||||
guard let d = s.data(using: String.Encoding.utf8, allowLossyConversion: false) else {
|
||||
return false
|
||||
}
|
||||
|
||||
let base64EncodedString = d.base64EncodedString()
|
||||
let authorization = "Basic \(base64EncodedString)"
|
||||
setValue(authorization, forHTTPHeaderField: HTTPRequestHeader.authorization)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// OneShotDownload.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 8/27/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public typealias OneShotDownloadCallback = (Data?, URLResponse?, Error?) -> Swift.Void
|
||||
|
||||
private final class OneShotDownloadManager {
|
||||
|
||||
private let urlSession: URLSession
|
||||
fileprivate static let shared = OneShotDownloadManager()
|
||||
|
||||
public init() {
|
||||
|
||||
let sessionConfiguration = URLSessionConfiguration.ephemeral
|
||||
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
|
||||
sessionConfiguration.httpShouldSetCookies = false
|
||||
sessionConfiguration.httpCookieAcceptPolicy = .never
|
||||
sessionConfiguration.httpMaximumConnectionsPerHost = 2
|
||||
sessionConfiguration.httpCookieStorage = nil
|
||||
sessionConfiguration.urlCache = nil
|
||||
sessionConfiguration.timeoutIntervalForRequest = 30
|
||||
|
||||
if let userAgent = UserAgent.fromInfoPlist() {
|
||||
var headers = [AnyHashable : Any]()
|
||||
headers[HTTPRequestHeader.userAgent] = userAgent
|
||||
sessionConfiguration.httpAdditionalHeaders = headers
|
||||
}
|
||||
|
||||
urlSession = URLSession(configuration: sessionConfiguration)
|
||||
}
|
||||
|
||||
deinit {
|
||||
urlSession.invalidateAndCancel()
|
||||
}
|
||||
|
||||
public func download(_ url: URL, _ callback: @escaping OneShotDownloadCallback) {
|
||||
|
||||
let task = urlSession.dataTask(with: url) { (data, response, error) in
|
||||
|
||||
DispatchQueue.main.async() {
|
||||
callback(data, response, error)
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
}
|
||||
|
||||
// Call this. It’s easier than referring to OneShotDownloadManager.
|
||||
// callback is called on the main queue.
|
||||
|
||||
public func download(_ url: URL, _ callback: @escaping OneShotDownloadCallback) {
|
||||
|
||||
OneShotDownloadManager.shared.download(url, callback)
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// NSURL+RSWeb.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/26/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private struct URLConstants {
|
||||
static let schemeHTTP = "http"
|
||||
static let schemeHTTPS = "https"
|
||||
static let prefixHTTP = "http://"
|
||||
static let prefixHTTPS = "https://"
|
||||
}
|
||||
|
||||
public extension URL {
|
||||
|
||||
public func isHTTPSURL() -> Bool {
|
||||
|
||||
return self.scheme?.lowercased() == URLConstants.schemeHTTPS
|
||||
}
|
||||
|
||||
public func isHTTPURL() -> Bool {
|
||||
|
||||
return self.scheme?.lowercased() == URLConstants.schemeHTTP
|
||||
}
|
||||
|
||||
public func isHTTPOrHTTPSURL() -> Bool {
|
||||
|
||||
return self.isHTTPSURL() || self.isHTTPURL()
|
||||
}
|
||||
|
||||
public func absoluteStringWithHTTPOrHTTPSPrefixRemoved() -> String? {
|
||||
|
||||
// Case-inensitive. Turns http://example.com/foo into example.com/foo
|
||||
|
||||
if isHTTPSURL() {
|
||||
return absoluteString.stringByRemovingCaseInsensitivePrefix(URLConstants.prefixHTTPS)
|
||||
}
|
||||
else if isHTTPURL() {
|
||||
return absoluteString.stringByRemovingCaseInsensitivePrefix(URLConstants.prefixHTTP)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
|
||||
func stringByRemovingCaseInsensitivePrefix(_ prefix: String) -> String {
|
||||
|
||||
// Returns self if it doesn’t have the given prefix.
|
||||
|
||||
let lowerPrefix = prefix.lowercased()
|
||||
let lowerSelf = self.lowercased()
|
||||
|
||||
if (lowerSelf == lowerPrefix) {
|
||||
return ""
|
||||
}
|
||||
if !lowerSelf.hasPrefix(lowerPrefix) {
|
||||
return self
|
||||
}
|
||||
|
||||
let index = self.index(self.startIndex, offsetBy: prefix.characters.count)
|
||||
return substring(from: index)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// URLRequest+RSWeb.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 12/27/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension URLRequest {
|
||||
|
||||
// Experimental. Returns nil if scheme isn't http or https (about:blank, for instance).
|
||||
|
||||
public func loadingURL() -> URL? {
|
||||
|
||||
guard let url = mainDocumentURL else {
|
||||
return nil
|
||||
}
|
||||
guard url.isHTTPOrHTTPSURL() else {
|
||||
return nil
|
||||
}
|
||||
guard !url.absoluteString.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// URLResponse+RSWeb.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 8/14/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension URLResponse {
|
||||
|
||||
public var statusIsOK: Bool {
|
||||
get {
|
||||
return forcedStatusCode >= 200 && forcedStatusCode <= 299
|
||||
}
|
||||
}
|
||||
|
||||
public var forcedStatusCode: Int {
|
||||
|
||||
get {
|
||||
// Return actual statusCode or -1 if there isn’t one.
|
||||
|
||||
if let response = self as? HTTPURLResponse {
|
||||
return response.statusCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension HTTPURLResponse {
|
||||
|
||||
public func valueForHTTPHeaderField(_ headerField: String) -> String? {
|
||||
|
||||
// Case-insensitive. HTTP headers may not be in the case you expect.
|
||||
|
||||
let lowerHeaderField = headerField.lowercased()
|
||||
|
||||
for (key, value) in allHeaderFields {
|
||||
|
||||
if lowerHeaderField == (key as? String)?.lowercased() {
|
||||
return value as? String
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// UserAgent.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 8/27/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class UserAgent {
|
||||
|
||||
public class func fromInfoPlist() -> String? {
|
||||
|
||||
guard let userAgentName = Bundle.main.object(forInfoDictionaryKey: "UserAgent") else {
|
||||
return nil
|
||||
}
|
||||
guard let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") else {
|
||||
return nil
|
||||
}
|
||||
return "\(userAgentName) \(version)"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// RSWebTests.swift
|
||||
// RSWebTests
|
||||
//
|
||||
// Created by Brent Simmons on 12/22/16.
|
||||
// Copyright © 2016 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import RSWeb
|
||||
|
||||
class RSWebTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>RSWeb</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
Loading…
Reference in New Issue