1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
import SwiftFoundation
#else
import Foundation
#endif
public struct URLRequest : ReferenceConvertible, Equatable, Hashable, Sendable {
public typealias ReferenceType = NSURLRequest
public typealias CachePolicy = NSURLRequest.CachePolicy
public typealias NetworkServiceType = NSURLRequest.NetworkServiceType
/*
NSURLRequest has a fragile ivar layout that prevents the swift subclass approach here, so instead we keep an always mutable copy
*/
internal var _handle: _MutableHandle<NSMutableURLRequest>
internal mutating func _applyMutation<ReturnType>(_ whatToDo : (NSMutableURLRequest) -> ReturnType) -> ReturnType {
if !isKnownUniquelyReferenced(&_handle) {
let ref = _handle._uncopiedReference()
_handle = _MutableHandle(reference: ref)
}
return whatToDo(_handle._uncopiedReference())
}
/// Creates and initializes a URLRequest with the given URL and cache policy.
/// - parameter url: The URL for the request.
/// - parameter cachePolicy: The cache policy for the request. Defaults to `.useProtocolCachePolicy`
/// - parameter timeoutInterval: The timeout interval for the request. See the commentary for the `timeoutInterval` for more information on timeout intervals. Defaults to 60.0
public init(url: URL, cachePolicy: CachePolicy = .useProtocolCachePolicy, timeoutInterval: TimeInterval = 60.0) {
_handle = _MutableHandle(adoptingReference: NSMutableURLRequest(url: url, cachePolicy: cachePolicy, timeoutInterval: timeoutInterval))
}
fileprivate init(_bridged request: NSURLRequest) {
_handle = _MutableHandle(reference: request.mutableCopy() as! NSMutableURLRequest)
}
/// The URL of the receiver.
public var url: URL? {
get {
return _handle.map { $0.url }
}
set {
_applyMutation { $0.url = newValue }
}
}
/// The cache policy of the receiver.
public var cachePolicy: CachePolicy {
get {
return _handle.map { $0.cachePolicy }
}
set {
_applyMutation { $0.cachePolicy = newValue }
}
}
//URLRequest.timeoutInterval should be given precedence over the URLSessionConfiguration.timeoutIntervalForRequest regardless of the value set,
// if it has been set at least once. Even though the default value is 60 ,if the user sets URLRequest.timeoutInterval
// to explicitly 60 then the precedence should be given to URLRequest.timeoutInterval.
internal var isTimeoutIntervalSet = false
/// Returns the timeout interval of the receiver.
/// - discussion: The timeout interval specifies the limit on the idle
/// interval allotted to a request in the process of loading. The "idle
/// interval" is defined as the period of time that has passed since the
/// last instance of load activity occurred for a request that is in the
/// process of loading. Hence, when an instance of load activity occurs
/// (e.g. bytes are received from the network for a request), the idle
/// interval for a request is reset to 0. If the idle interval ever
/// becomes greater than or equal to the timeout interval, the request
/// is considered to have timed out. This timeout interval is measured
/// in seconds.
public var timeoutInterval: TimeInterval {
get {
return _handle.map { $0.timeoutInterval }
}
set {
_applyMutation { $0.timeoutInterval = newValue }
isTimeoutIntervalSet = true
}
}
/// The main document URL associated with this load.
/// - discussion: This URL is used for the cookie "same domain as main
/// document" policy.
public var mainDocumentURL: URL? {
get {
return _handle.map { $0.mainDocumentURL }
}
set {
_applyMutation { $0.mainDocumentURL = newValue }
}
}
/// The URLRequest.NetworkServiceType associated with this request.
/// - discussion: This will return URLRequest.NetworkServiceType.default for requests that have
/// not explicitly set a networkServiceType
public var networkServiceType: NetworkServiceType {
get {
return _handle.map { $0.networkServiceType }
}
set {
_applyMutation { $0.networkServiceType = newValue }
}
}
/// `true` if the receiver is allowed to use the built in cellular radios to
/// satisfy the request, `false` otherwise.
public var allowsCellularAccess: Bool {
get {
return _handle.map { $0.allowsCellularAccess }
}
set {
_applyMutation { $0.allowsCellularAccess = newValue }
}
}
/// The HTTP request method of the receiver.
public var httpMethod: String? {
get {
return _handle.map { $0.httpMethod }
}
set {
_applyMutation {
if let value = newValue {
$0.httpMethod = value
} else {
$0.httpMethod = "GET"
}
}
}
}
/// A dictionary containing all the HTTP header fields of the
/// receiver.
public var allHTTPHeaderFields: [String : String]? {
get {
return _handle.map { $0.allHTTPHeaderFields }
}
set {
_applyMutation { $0.allHTTPHeaderFields = newValue }
}
}
/// The value which corresponds to the given header
/// field. Note that, in keeping with the HTTP RFC, HTTP header field
/// names are case-insensitive.
/// - parameter field: the header field name to use for the lookup (case-insensitive).
public func value(forHTTPHeaderField field: String) -> String? {
return _handle.map { $0.value(forHTTPHeaderField: field) }
}
/// If a value was previously set for the given header
/// field, that value is replaced with the given value. Note that, in
/// keeping with the HTTP RFC, HTTP header field names are
/// case-insensitive.
public mutating func setValue(_ value: String?, forHTTPHeaderField field: String) {
_applyMutation {
$0.setValue(value, forHTTPHeaderField: field)
}
}
/// This method provides a way to add values to header
/// fields incrementally. If a value was previously set for the given
/// header field, the given value is appended to the previously-existing
/// value. The appropriate field delimiter, a comma in the case of HTTP,
/// is added by the implementation, and should not be added to the given
/// value by the caller. Note that, in keeping with the HTTP RFC, HTTP
/// header field names are case-insensitive.
public mutating func addValue(_ value: String, forHTTPHeaderField field: String) {
_applyMutation {
$0.addValue(value, forHTTPHeaderField: field)
}
}
/// This data is sent as the message body of the request, as
/// in done in an HTTP POST request.
public var httpBody: Data? {
get {
return _handle.map { $0.httpBody }
}
set {
_applyMutation { $0.httpBody = newValue }
}
}
/// The stream is returned for examination only; it is
/// not safe for the caller to manipulate the stream in any way. Also
/// note that the HTTPBodyStream and HTTPBody are mutually exclusive - only
/// one can be set on a given request. Also note that the body stream is
/// preserved across copies, but is LOST when the request is coded via the
/// NSCoding protocol
public var httpBodyStream: InputStream? {
get {
return _handle.map { $0.httpBodyStream }
}
set {
_applyMutation { $0.httpBodyStream = newValue }
}
}
/// `true` if cookies will be sent with and set for this request; otherwise `false`.
public var httpShouldHandleCookies: Bool {
get {
return _handle.map { $0.httpShouldHandleCookies }
}
set {
_applyMutation { $0.httpShouldHandleCookies = newValue }
}
}
/// `true` if the receiver should transmit before the previous response
/// is received. `false` if the receiver should wait for the previous response
/// before transmitting.
public var httpShouldUsePipelining: Bool {
get {
return _handle.map { $0.httpShouldUsePipelining }
}
set {
_applyMutation { $0.httpShouldUsePipelining = newValue }
}
}
public func hash(into hasher: inout Hasher) {
hasher.combine(_handle.map { $0 })
}
public static func ==(lhs: URLRequest, rhs: URLRequest) -> Bool {
return lhs._handle._uncopiedReference().isEqual(rhs._handle._uncopiedReference())
}
var protocolProperties: [String: Any] {
get {
return _handle.map { $0.protocolProperties }
}
set {
_applyMutation { $0.protocolProperties = newValue }
}
}
}
extension URLRequest : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
public var description: String {
if let u = url {
return u.description
} else {
return "url: nil"
}
}
public var debugDescription: String {
return self.description
}
public var customMirror: Mirror {
var c: [(label: String?, value: Any)] = []
c.append((label: "url", value: url as Any))
c.append((label: "cachePolicy", value: cachePolicy.rawValue))
c.append((label: "timeoutInterval", value: timeoutInterval))
c.append((label: "mainDocumentURL", value: mainDocumentURL as Any))
c.append((label: "networkServiceType", value: networkServiceType))
c.append((label: "allowsCellularAccess", value: allowsCellularAccess))
c.append((label: "httpMethod", value: httpMethod as Any))
c.append((label: "allHTTPHeaderFields", value: allHTTPHeaderFields as Any))
c.append((label: "httpBody", value: httpBody as Any))
c.append((label: "httpBodyStream", value: httpBodyStream as Any))
c.append((label: "httpShouldHandleCookies", value: httpShouldHandleCookies))
c.append((label: "httpShouldUsePipelining", value: httpShouldUsePipelining))
return Mirror(self, children: c, displayStyle: .struct)
}
}
extension URLRequest : _ObjectiveCBridgeable {
public static func _getObjectiveCType() -> Any.Type {
return NSURLRequest.self
}
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSURLRequest {
return _handle._copiedReference()
}
public static func _forceBridgeFromObjectiveC(_ input: NSURLRequest, result: inout URLRequest?) {
result = URLRequest(_bridged: input)
}
public static func _conditionallyBridgeFromObjectiveC(_ input: NSURLRequest, result: inout URLRequest?) -> Bool {
result = URLRequest(_bridged: input)
return true
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSURLRequest?) -> URLRequest {
var result: URLRequest? = nil
_forceBridgeFromObjectiveC(source!, result: &result)
return result!
}
}
|