forked from swiftlang/swift-corelibs-foundation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathURLRequest.swift
309 lines (276 loc) · 11.7 KB
/
URLRequest.swift
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 {
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!
}
}