| // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| /// Provides access to the |
| /// [Foundation URL Loading System](https://developer.apple.com/documentation/foundation/url_loading_system). |
| /// |
| /// For example: |
| /// ``` |
| /// void main() { |
| /// final url = Uri.https('www.example.com', '/'); |
| /// final session = URLSession.sharedSession(); |
| /// final task = session.dataTaskWithCompletionHandler( |
| /// URLRequest.fromUrl(url), |
| /// (data, response, error) { |
| /// if (error == null) { |
| /// if (response != null && response.statusCode == 200) { |
| /// print(response); // Do something with the response. |
| /// return; |
| /// } |
| /// } |
| /// print(error); // Handle errors. |
| /// }); |
| /// task.resume(); |
| /// } |
| /// ``` |
| library; |
| |
| import 'dart:async'; |
| import 'dart:isolate'; |
| |
| import 'package:objective_c/objective_c.dart' as objc; |
| |
| import 'native_cupertino_bindings.dart' as ncb; |
| import 'native_cupertino_bindings.dart' |
| show |
| NSHTTPCookieAcceptPolicy, |
| NSURLRequestCachePolicy, |
| NSURLRequestNetworkServiceType, |
| NSURLSessionMultipathServiceType, |
| NSURLSessionResponseDisposition, |
| NSURLSessionTaskState, |
| NSURLSessionWebSocketMessageType; |
| import 'utils.dart'; |
| |
| export 'native_cupertino_bindings.dart' |
| show |
| NSHTTPCookieAcceptPolicy, |
| NSURLRequestCachePolicy, |
| NSURLRequestNetworkServiceType, |
| NSURLSessionMultipathServiceType, |
| NSURLSessionResponseDisposition, |
| NSURLSessionTaskState, |
| NSURLSessionWebSocketCloseCode, |
| NSURLSessionWebSocketMessageType; |
| |
| abstract class _ObjectHolder<T extends objc.NSObject> { |
| final T _nsObject; |
| |
| _ObjectHolder(this._nsObject); |
| |
| @override |
| bool operator ==(Object other) { |
| if (other is _ObjectHolder) { |
| return _nsObject == other._nsObject; |
| } |
| return false; |
| } |
| |
| @override |
| int get hashCode => _nsObject.hashCode; |
| } |
| |
| /// A cache for [URLRequest]s. Used by [URLSessionConfiguration.cache]. |
| /// |
| /// See [NSURLCache](https://developer.apple.com/documentation/foundation/nsurlcache) |
| class URLCache extends _ObjectHolder<ncb.NSURLCache> { |
| URLCache._(super.c); |
| |
| /// The default URLCache. |
| /// |
| /// See [NSURLCache.sharedURLCache](https://developer.apple.com/documentation/foundation/nsurlcache/1413377-sharedurlcache) |
| static URLCache? get sharedURLCache { |
| final sharedCache = ncb.NSURLCache.getSharedURLCache(); |
| return URLCache._(sharedCache); |
| } |
| |
| /// Create a new [URLCache] with the given memory and disk cache sizes. |
| /// |
| /// [memoryCapacity] and [diskCapacity] are specified in bytes. |
| /// |
| /// [directory] is the file system location where the disk cache will be |
| /// stored. If `null` then the default directory will be used. |
| /// |
| /// See [NSURLCache initWithMemoryCapacity:diskCapacity:directoryURL:](https://developer.apple.com/documentation/foundation/nsurlcache/3240612-initwithmemorycapacity) |
| factory URLCache.withCapacity( |
| {int memoryCapacity = 0, int diskCapacity = 0, Uri? directory}) => |
| URLCache._(ncb.NSURLCache.alloc() |
| .initWithMemoryCapacity_diskCapacity_directoryURL_(memoryCapacity, |
| diskCapacity, directory == null ? null : uriToNSURL(directory))); |
| } |
| |
| /// Controls the behavior of a URLSession. |
| /// |
| /// See [NSURLSessionConfiguration](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration) |
| class URLSessionConfiguration |
| extends _ObjectHolder<ncb.NSURLSessionConfiguration> { |
| // A configuration created with |
| // [`backgroundSessionConfigurationWithIdentifier`](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1407496-backgroundsessionconfigurationwi) |
| final bool _isBackground; |
| |
| URLSessionConfiguration._(super.c, {required bool isBackground}) |
| : _isBackground = isBackground; |
| |
| /// A configuration suitable for performing HTTP uploads and downloads in |
| /// the background. |
| /// |
| /// See [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1407496-backgroundsessionconfigurationwi) |
| factory URLSessionConfiguration.backgroundSession(String identifier) => |
| URLSessionConfiguration._( |
| ncb.NSURLSessionConfiguration |
| .backgroundSessionConfigurationWithIdentifier_( |
| identifier.toNSString()), |
| isBackground: true); |
| |
| /// A configuration that uses caching and saves cookies and credentials. |
| /// |
| /// See [NSURLSessionConfiguration defaultSessionConfiguration](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411560-defaultsessionconfiguration) |
| factory URLSessionConfiguration.defaultSessionConfiguration() => |
| URLSessionConfiguration._( |
| ncb.NSURLSessionConfiguration.castFrom( |
| ncb.NSURLSessionConfiguration.getDefaultSessionConfiguration()), |
| isBackground: false); |
| |
| /// A session configuration that uses no persistent storage for caches, |
| /// cookies, or credentials. |
| /// |
| /// See [NSURLSessionConfiguration ephemeralSessionConfiguration](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1410529-ephemeralsessionconfiguration) |
| factory URLSessionConfiguration.ephemeralSessionConfiguration() => |
| URLSessionConfiguration._( |
| ncb.NSURLSessionConfiguration.castFrom( |
| ncb.NSURLSessionConfiguration.getEphemeralSessionConfiguration()), |
| isBackground: false); |
| |
| /// Whether connections over a cellular network are allowed. |
| /// |
| /// See [NSURLSessionConfiguration.allowsCellularAccess](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1409406-allowscellularaccess) |
| bool get allowsCellularAccess => _nsObject.allowsCellularAccess; |
| set allowsCellularAccess(bool value) => |
| _nsObject.allowsCellularAccess = value; |
| |
| /// Whether connections are allowed when the user has selected Low Data Mode. |
| /// |
| /// See [NSURLSessionConfiguration.allowsConstrainedNetworkAccess](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/3235751-allowsconstrainednetworkaccess) |
| bool get allowsConstrainedNetworkAccess => |
| _nsObject.allowsConstrainedNetworkAccess; |
| set allowsConstrainedNetworkAccess(bool value) => |
| _nsObject.allowsConstrainedNetworkAccess = value; |
| |
| /// Whether connections are allowed over expensive networks. |
| /// |
| /// See [NSURLSessionConfiguration.allowsExpensiveNetworkAccess](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/3235752-allowsexpensivenetworkaccess) |
| bool get allowsExpensiveNetworkAccess => |
| _nsObject.allowsExpensiveNetworkAccess; |
| set allowsExpensiveNetworkAccess(bool value) => |
| _nsObject.allowsExpensiveNetworkAccess = value; |
| |
| /// The [URLCache] used to cache the results of [URLSessionTask]s. |
| /// |
| /// A value of `nil` indicates that no cache will be used. |
| /// |
| /// See [NSURLSessionConfiguration.URLCache](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1410148-urlcache) |
| URLCache? get cache => |
| _nsObject.URLCache == null ? null : URLCache._(_nsObject.URLCache!); |
| set cache(URLCache? cache) => _nsObject.URLCache = cache?._nsObject; |
| |
| /// Whether background tasks can be delayed by the system. |
| /// |
| /// See [NSURLSessionConfiguration.discretionary](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411552-discretionary) |
| bool get discretionary => _nsObject.discretionary; |
| set discretionary(bool value) => _nsObject.discretionary = value; |
| |
| /// Additional headers to send with each request. |
| /// |
| /// Note that the getter for this field returns a **copy** of the headers. |
| /// |
| /// See [NSURLSessionConfiguration.HTTPAdditionalHeaders](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411532-httpadditionalheaders) |
| Map<String, String>? get httpAdditionalHeaders { |
| if (_nsObject.HTTPAdditionalHeaders case var additionalHeaders?) { |
| final headers = objc.NSDictionary.castFrom(additionalHeaders); |
| return stringNSDictionaryToMap(headers); |
| } |
| return null; |
| } |
| |
| set httpAdditionalHeaders(Map<String, String>? headers) { |
| if (headers == null) { |
| _nsObject.HTTPAdditionalHeaders = null; |
| return; |
| } |
| final d = objc.NSMutableDictionary.alloc().init(); |
| headers.forEach((key, value) { |
| d.setObject_forKey_(value.toNSString(), key.toNSString()); |
| }); |
| _nsObject.HTTPAdditionalHeaders = d; |
| } |
| |
| /// What policy to use when deciding whether to accept cookies. |
| /// |
| /// See [NSURLSessionConfiguration.HTTPCookieAcceptPolicy](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408933-httpcookieacceptpolicy). |
| NSHTTPCookieAcceptPolicy get httpCookieAcceptPolicy => |
| _nsObject.HTTPCookieAcceptPolicy; |
| set httpCookieAcceptPolicy(NSHTTPCookieAcceptPolicy value) => |
| _nsObject.HTTPCookieAcceptPolicy = value; |
| |
| /// The maximum number of connections that a URLSession can have open to the |
| /// same host. |
| // |
| /// See [NSURLSessionConfiguration.HTTPMaximumConnectionsPerHost](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1407597-httpmaximumconnectionsperhost). |
| int get httpMaximumConnectionsPerHost => |
| _nsObject.HTTPMaximumConnectionsPerHost; |
| set httpMaximumConnectionsPerHost(int value) => |
| _nsObject.HTTPMaximumConnectionsPerHost = value; |
| |
| /// Whether requests should include cookies from the cookie store. |
| /// |
| /// See [NSURLSessionConfiguration.HTTPShouldSetCookies](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411589-httpshouldsetcookies) |
| bool get httpShouldSetCookies => _nsObject.HTTPShouldSetCookies; |
| set httpShouldSetCookies(bool value) => |
| _nsObject.HTTPShouldSetCookies = value; |
| |
| /// Whether to use [HTTP pipelining](https://en.wikipedia.org/wiki/HTTP_pipelining). |
| /// |
| /// See [NSURLSessionConfiguration.HTTPShouldUsePipelining](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411657-httpshouldusepipelining) |
| bool get httpShouldUsePipelining => _nsObject.HTTPShouldUsePipelining; |
| set httpShouldUsePipelining(bool value) => |
| _nsObject.HTTPShouldUsePipelining = value; |
| |
| /// What type of Multipath TCP connections to use. |
| /// |
| /// See [NSURLSessionConfiguration.multipathServiceType](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/2875967-multipathservicetype) |
| NSURLSessionMultipathServiceType get multipathServiceType => |
| _nsObject.multipathServiceType; |
| set multipathServiceType(NSURLSessionMultipathServiceType value) => |
| _nsObject.multipathServiceType = value; |
| |
| /// Provides in indication to the operating system on what type of requests |
| /// are being sent. |
| /// |
| /// See [NSURLSessionConfiguration.networkServiceType](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411606-networkservicetype). |
| NSURLRequestNetworkServiceType get networkServiceType => |
| _nsObject.networkServiceType; |
| set networkServiceType(NSURLRequestNetworkServiceType value) => |
| _nsObject.networkServiceType = value; |
| |
| /// Controls how to deal with response caching. |
| /// |
| /// See [NSURLSessionConfiguration.requestCachePolicy](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411655-requestcachepolicy) |
| NSURLRequestCachePolicy get requestCachePolicy => |
| _nsObject.requestCachePolicy; |
| set requestCachePolicy(NSURLRequestCachePolicy value) => |
| _nsObject.requestCachePolicy = value; |
| |
| /// Whether the app should be resumed when background tasks complete. |
| /// |
| /// See [NSURLSessionConfiguration.sessionSendsLaunchEvents](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1617174-sessionsendslaunchevents) |
| bool get sessionSendsLaunchEvents => _nsObject.sessionSendsLaunchEvents; |
| set sessionSendsLaunchEvents(bool value) => |
| _nsObject.sessionSendsLaunchEvents = value; |
| |
| /// Whether connections will be preserved if the app moves to the background. |
| /// |
| /// See [NSURLSessionConfiguration.shouldUseExtendedBackgroundIdleMode](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1409517-shoulduseextendedbackgroundidlem) |
| bool get shouldUseExtendedBackgroundIdleMode => |
| _nsObject.shouldUseExtendedBackgroundIdleMode; |
| set shouldUseExtendedBackgroundIdleMode(bool value) => |
| _nsObject.shouldUseExtendedBackgroundIdleMode = value; |
| |
| /// The timeout interval if data is not received. |
| /// |
| /// See [NSURLSessionConfiguration.timeoutIntervalForRequest](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408259-timeoutintervalforrequest) |
| Duration get timeoutIntervalForRequest => Duration( |
| microseconds: |
| (_nsObject.timeoutIntervalForRequest * Duration.microsecondsPerSecond) |
| .round()); |
| |
| set timeoutIntervalForRequest(Duration interval) { |
| _nsObject.timeoutIntervalForRequest = |
| interval.inMicroseconds.toDouble() / Duration.microsecondsPerSecond; |
| } |
| |
| /// Whether tasks should wait for connectivity or fail immediately. |
| /// |
| /// See [NSURLSessionConfiguration.waitsForConnectivity](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/2908812-waitsforconnectivity) |
| bool get waitsForConnectivity => _nsObject.waitsForConnectivity; |
| set waitsForConnectivity(bool value) => |
| _nsObject.waitsForConnectivity = value; |
| |
| @override |
| String toString() => '[URLSessionConfiguration ' |
| 'allowsCellularAccess=$allowsCellularAccess ' |
| 'allowsConstrainedNetworkAccess=$allowsConstrainedNetworkAccess ' |
| 'allowsExpensiveNetworkAccess=$allowsExpensiveNetworkAccess ' |
| 'discretionary=$discretionary ' |
| 'httpAdditionalHeaders=$httpAdditionalHeaders ' |
| 'httpCookieAcceptPolicy=$httpCookieAcceptPolicy ' |
| 'httpShouldSetCookies=$httpShouldSetCookies ' |
| 'httpMaximumConnectionsPerHost=$httpMaximumConnectionsPerHost ' |
| 'httpShouldUsePipelining=$httpShouldUsePipelining ' |
| 'requestCachePolicy=$requestCachePolicy ' |
| 'sessionSendsLaunchEvents=$sessionSendsLaunchEvents ' |
| 'shouldUseExtendedBackgroundIdleMode=' |
| '$shouldUseExtendedBackgroundIdleMode ' |
| 'timeoutIntervalForRequest=$timeoutIntervalForRequest ' |
| 'waitsForConnectivity=$waitsForConnectivity' |
| ']'; |
| } |
| |
| /// The response associated with loading an URL. |
| /// |
| /// See [NSURLResponse](https://developer.apple.com/documentation/foundation/nsurlresponse) |
| class URLResponse extends _ObjectHolder<ncb.NSURLResponse> { |
| URLResponse._(super.c); |
| |
| factory URLResponse._exactURLResponseType(ncb.NSURLResponse response) { |
| if (ncb.NSHTTPURLResponse.isInstance(response)) { |
| return HTTPURLResponse._(ncb.NSHTTPURLResponse.castFrom(response)); |
| } |
| return URLResponse._(response); |
| } |
| |
| /// The expected amount of data returned with the response. |
| /// |
| /// See [NSURLResponse.expectedContentLength](https://developer.apple.com/documentation/foundation/nsurlresponse/1413507-expectedcontentlength) |
| int get expectedContentLength => _nsObject.expectedContentLength; |
| |
| /// The MIME type of the response. |
| /// |
| /// See [NSURLResponse.MIMEType](https://developer.apple.com/documentation/foundation/nsurlresponse/1411613-mimetype) |
| String? get mimeType => _nsObject.MIMEType?.toString(); |
| |
| @override |
| String toString() => '[URLResponse ' |
| 'mimeType=$mimeType ' |
| 'expectedContentLength=$expectedContentLength' |
| ']'; |
| } |
| |
| /// The response associated with loading a HTTP URL. |
| /// |
| /// See [NSHTTPURLResponse](https://developer.apple.com/documentation/foundation/nshttpurlresponse) |
| class HTTPURLResponse extends URLResponse { |
| final ncb.NSHTTPURLResponse _httpUrlResponse; |
| |
| HTTPURLResponse._(ncb.NSHTTPURLResponse super.c) |
| : _httpUrlResponse = c, |
| super._(); |
| |
| /// The HTTP status code of the response (e.g. 200). |
| /// |
| /// See [HTTPURLResponse.statusCode](https://developer.apple.com/documentation/foundation/nshttpurlresponse/1409395-statuscode) |
| int get statusCode => _httpUrlResponse.statusCode; |
| |
| /// The HTTP headers of the response. |
| /// |
| /// See [HTTPURLResponse.allHeaderFields](https://developer.apple.com/documentation/foundation/nshttpurlresponse/1417930-allheaderfields) |
| Map<String, String> get allHeaderFields { |
| final headers = |
| objc.NSDictionary.castFrom(_httpUrlResponse.allHeaderFields); |
| return stringNSDictionaryToMap(headers); |
| } |
| |
| @override |
| String toString() => '[HTTPURLResponse ' |
| 'statusCode=$statusCode ' |
| 'mimeType=$mimeType ' |
| 'expectedContentLength=$expectedContentLength' |
| ']'; |
| } |
| |
| /// A WebSocket message. |
| /// |
| /// See [NSURLSessionWebSocketMessage](https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketmessage) |
| class URLSessionWebSocketMessage |
| extends _ObjectHolder<ncb.NSURLSessionWebSocketMessage> { |
| URLSessionWebSocketMessage._(super.nsObject); |
| |
| /// Create a WebSocket data message. |
| /// |
| /// See [NSURLSessionWebSocketMessage initWithData:](https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketmessage/3181192-initwithdata) |
| factory URLSessionWebSocketMessage.fromData(objc.NSData d) => |
| URLSessionWebSocketMessage._( |
| ncb.NSURLSessionWebSocketMessage.alloc().initWithData_(d)); |
| |
| /// Create a WebSocket string message. |
| /// |
| /// See [NSURLSessionWebSocketMessage initWitString:](https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketmessage/3181193-initwithstring) |
| factory URLSessionWebSocketMessage.fromString(String s) => |
| URLSessionWebSocketMessage._(ncb.NSURLSessionWebSocketMessage.alloc() |
| .initWithString_(s.toNSString())); |
| |
| /// The data associated with the WebSocket message. |
| /// |
| /// Will be `null` if the [URLSessionWebSocketMessage] is a string message. |
| /// |
| /// See [NSURLSessionWebSocketMessage.data](https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketmessage/3181191-data) |
| objc.NSData? get data => _nsObject.data; |
| |
| /// The string associated with the WebSocket message. |
| /// |
| /// Will be `null` if the [URLSessionWebSocketMessage] is a data message. |
| /// |
| /// See [NSURLSessionWebSocketMessage.string](https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketmessage/3181194-string) |
| String? get string => _nsObject.string?.toString(); |
| |
| /// The type of the WebSocket message. |
| /// |
| /// See [NSURLSessionWebSocketMessage.type](https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketmessage/3181195-type) |
| NSURLSessionWebSocketMessageType get type => _nsObject.type; |
| |
| @override |
| String toString() => |
| '[URLSessionWebSocketMessage type=$type string=$string data=$data]'; |
| } |
| |
| /// A task associated with downloading a URI. |
| /// |
| /// See [NSURLSessionTask](https://developer.apple.com/documentation/foundation/nsurlsessiontask) |
| class URLSessionTask extends _ObjectHolder<ncb.NSURLSessionTask> { |
| URLSessionTask._(super.c); |
| |
| /// Cancels the task. |
| /// |
| /// See [NSURLSessionTask cancel](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411591-cancel) |
| void cancel() { |
| _nsObject.cancel(); |
| } |
| |
| /// Resumes a suspended task (new tasks start as suspended). |
| /// |
| /// See [NSURLSessionTask resume](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411121-resume) |
| void resume() { |
| _nsObject.resume(); |
| } |
| |
| /// Suspends a task (prevents it from transferring data). |
| /// |
| /// See [NSURLSessionTask suspend](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411565-suspend) |
| void suspend() { |
| _nsObject.suspend(); |
| } |
| |
| /// The current state of the task. |
| /// |
| /// See [NSURLSessionTask.state](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1409888-state) |
| NSURLSessionTaskState get state => _nsObject.state; |
| |
| /// The relative priority [0, 1] that the host should use to handle the |
| /// request. |
| /// |
| /// See [NSURLSessionTask.priority](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1410569-priority) |
| double get priority => _nsObject.priority; |
| |
| /// The relative priority [0, 1] that the host should use to handle the |
| /// request. |
| /// |
| /// See [NSURLSessionTask.priority](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1410569-priority) |
| set priority(double value) => _nsObject.priority = value; |
| |
| /// The request currently being handled by the task. |
| /// |
| /// May be different from [originalRequest] if the server responds with a |
| /// redirect. |
| /// |
| /// See [NSURLSessionTask.currentRequest](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411649-currentrequest) |
| URLRequest? get currentRequest { |
| final request = _nsObject.currentRequest; |
| if (request == null) { |
| return null; |
| } else { |
| return URLRequest._(request); |
| } |
| } |
| |
| /// The original request associated with the task. |
| /// |
| /// May be different from [currentRequest] if the server responds with a |
| /// redirect. |
| /// |
| /// See [NSURLSessionTask.originalRequest](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411572-originalrequest) |
| URLRequest? get originalRequest { |
| final request = _nsObject.originalRequest; |
| if (request == null) { |
| return null; |
| } else { |
| return URLRequest._(request); |
| } |
| } |
| |
| /// The server response to the request associated with this task. |
| /// |
| /// See [NSURLSessionTask.response](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1410586-response) |
| URLResponse? get response { |
| final nsResponse = _nsObject.response; |
| if (nsResponse == null) { |
| return null; |
| } |
| return URLResponse._exactURLResponseType(nsResponse); |
| } |
| |
| /// An error indicating why the task failed or `null` on success. |
| /// |
| /// See [NSURLSessionTask.error](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1408145-error) |
| objc.NSError? get error => _nsObject.error; |
| |
| /// The user-assigned description for the task. |
| /// |
| /// See [NSURLSessionTask.taskDescription](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1409798-taskdescription) |
| String get taskDescription => _nsObject.taskDescription.toString(); |
| |
| /// The user-assigned description for the task. |
| /// |
| /// See [NSURLSessionTask.taskDescription](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1409798-taskdescription) |
| set taskDescription(String value) => |
| _nsObject.taskDescription = value.toNSString(); |
| |
| /// A unique ID for the [URLSessionTask] in a [URLSession]. |
| /// |
| /// See [NSURLSessionTask.taskIdentifier](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411231-taskidentifier) |
| int get taskIdentifier => _nsObject.taskIdentifier; |
| |
| /// The number of content bytes that are expected to be received from the |
| /// server. |
| /// |
| /// See [NSURLSessionTask.countOfBytesReceived](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1410663-countofbytesexpectedtoreceive) |
| int get countOfBytesExpectedToReceive => |
| _nsObject.countOfBytesExpectedToReceive; |
| |
| /// The number of content bytes that have been received from the server. |
| /// |
| /// See [NSURLSessionTask.countOfBytesReceived](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411581-countofbytesreceived) |
| int get countOfBytesReceived => _nsObject.countOfBytesReceived; |
| |
| /// The number of content bytes that the task expects to send to the server. |
| /// |
| /// See [NSURLSessionTask.countOfBytesExpectedToSend](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411534-countofbytesexpectedtosend) |
| int get countOfBytesExpectedToSend => _nsObject.countOfBytesExpectedToSend; |
| |
| /// Whether the body of the response should be delivered incrementally or not. |
| /// |
| /// [NSURLSessionTask.countOfBytesSent](https://developer.apple.com/documentation/foundation/nsurlsessiontask/1410444-countofbytessent) |
| int get countOfBytesSent => _nsObject.countOfBytesSent; |
| |
| /// Whether the body of the response should be delivered incrementally or not. |
| /// |
| /// See [NSURLSessionTask.prefersIncrementalDelivery](https://developer.apple.com/documentation/foundation/nsurlsessiontask/3735881-prefersincrementaldelivery) |
| bool get prefersIncrementalDelivery => _nsObject.prefersIncrementalDelivery; |
| |
| /// Whether the body of the response should be delivered incrementally or not. |
| /// |
| /// See [NSURLSessionTask.prefersIncrementalDelivery](https://developer.apple.com/documentation/foundation/nsurlsessiontask/3735881-prefersincrementaldelivery) |
| set prefersIncrementalDelivery(bool value) => |
| _nsObject.prefersIncrementalDelivery = value; |
| |
| String _toStringHelper(String className) => '[$className ' |
| 'taskDescription=$taskDescription ' |
| 'taskIdentifier=$taskIdentifier ' |
| 'countOfBytesExpectedToReceive=$countOfBytesExpectedToReceive ' |
| 'countOfBytesReceived=$countOfBytesReceived ' |
| 'countOfBytesExpectedToSend=$countOfBytesExpectedToSend ' |
| 'countOfBytesSent=$countOfBytesSent ' |
| 'priority=$priority ' |
| 'state=$state ' |
| 'prefersIncrementalDelivery=$prefersIncrementalDelivery' |
| ']'; |
| |
| @override |
| String toString() => _toStringHelper('URLSessionTask'); |
| } |
| |
| /// A task associated with downloading a URI to a file. |
| /// |
| /// See [NSURLSessionDownloadTask](https://developer.apple.com/documentation/foundation/nsurlsessiondownloadtask) |
| class URLSessionDownloadTask extends URLSessionTask { |
| URLSessionDownloadTask._(ncb.NSURLSessionDownloadTask super.c) : super._(); |
| |
| @override |
| String toString() => _toStringHelper('URLSessionDownloadTask'); |
| } |
| |
| /// A task associated with a WebSocket connection. |
| /// |
| /// See [NSURLSessionWebSocketTask](https://developer.apple.com/documentation/foundation/nsurlsessionwebsockettask) |
| class URLSessionWebSocketTask extends URLSessionTask { |
| final ncb.NSURLSessionWebSocketTask _urlSessionWebSocketTask; |
| |
| URLSessionWebSocketTask._(ncb.NSURLSessionWebSocketTask super.c) |
| : _urlSessionWebSocketTask = c, |
| super._(); |
| |
| /// The close code set when the WebSocket connection is closed. |
| /// |
| /// See [NSURLSessionWebSocketTask.closeCode](https://developer.apple.com/documentation/foundation/nsurlsessionwebsockettask/3181201-closecode) |
| int get closeCode => _urlSessionWebSocketTask.closeCode; |
| |
| /// The close reason set when the WebSocket connection is closed. |
| /// If there is no close reason available this property will be null. |
| /// |
| /// See [NSURLSessionWebSocketTask.closeReason](https://developer.apple.com/documentation/foundation/nsurlsessionwebsockettask/3181202-closereason) |
| objc.NSData? get closeReason => _urlSessionWebSocketTask.closeReason; |
| |
| /// Sends a single WebSocket message. |
| /// |
| /// The returned future will complete successfully when the message is sent |
| /// and with an [Error] on failure. |
| /// |
| /// See [NSURLSessionWebSocketTask.sendMessage:completionHandler:](https://developer.apple.com/documentation/foundation/nsurlsessionwebsockettask/3181205-sendmessage) |
| Future<void> sendMessage(URLSessionWebSocketMessage message) async { |
| final completer = Completer<void>(); |
| _urlSessionWebSocketTask.sendMessage_completionHandler_(message._nsObject, |
| ncb.ObjCBlock_ffiVoid_NSError.listener((error) { |
| if (error == null) { |
| completer.complete(); |
| } else { |
| completer.completeError(error); |
| } |
| })); |
| |
| await completer.future; |
| } |
| |
| /// Receives a single WebSocket message. |
| /// |
| /// Throws an [Error] on failure. |
| /// |
| /// See [NSURLSessionWebSocketTask.receiveMessageWithCompletionHandler:](https://developer.apple.com/documentation/foundation/nsurlsessionwebsockettask/3181204-receivemessagewithcompletionhand) |
| Future<URLSessionWebSocketMessage> receiveMessage() async { |
| final completer = Completer<URLSessionWebSocketMessage>(); |
| _urlSessionWebSocketTask.receiveMessageWithCompletionHandler_( |
| ncb.ObjCBlock_ffiVoid_NSURLSessionWebSocketMessage_NSError.listener( |
| (message, error) { |
| if (error != null) { |
| completer.completeError(error); |
| } else if (message != null) { |
| completer.complete(URLSessionWebSocketMessage._(message)); |
| } else { |
| completer.completeError( |
| StateError('one of message or error must be non-null')); |
| } |
| })); |
| return completer.future; |
| } |
| |
| /// Sends close frame with the given code and optional reason. |
| /// |
| /// See [NSURLSessionWebSocketTask.cancelWithCloseCode:reason:](https://developer.apple.com/documentation/foundation/nsurlsessionwebsockettask/3181200-cancelwithclosecode) |
| void cancelWithCloseCode(int closeCode, objc.NSData? reason) { |
| _urlSessionWebSocketTask.cancelWithCloseCode_reason_(closeCode, reason); |
| } |
| |
| @override |
| String toString() => _toStringHelper('NSURLSessionWebSocketTask'); |
| } |
| |
| /// A request to load a URL. |
| /// |
| /// See [NSURLRequest](https://developer.apple.com/documentation/foundation/nsurlrequest) |
| class URLRequest extends _ObjectHolder<ncb.NSURLRequest> { |
| URLRequest._(super.c); |
| |
| /// Creates a request for a URL. |
| /// |
| /// See [NSURLRequest.requestWithURL:](https://developer.apple.com/documentation/foundation/nsurlrequest/1528603-requestwithurl) |
| factory URLRequest.fromUrl(Uri uri) => |
| URLRequest._(ncb.NSURLRequest.requestWithURL_(uriToNSURL(uri))); |
| |
| /// Returns all of the HTTP headers for the request. |
| /// |
| /// See [NSURLRequest.allHTTPHeaderFields](https://developer.apple.com/documentation/foundation/nsurlrequest/1418477-allhttpheaderfields) |
| Map<String, String>? get allHttpHeaderFields { |
| if (_nsObject.allHTTPHeaderFields == null) { |
| return null; |
| } else { |
| return stringNSDictionaryToMap(_nsObject.allHTTPHeaderFields!); |
| } |
| } |
| |
| /// Controls how to deal with caching for the request. |
| /// |
| /// See [NSURLSession.cachePolicy](https://developer.apple.com/documentation/foundation/nsurlrequest/1407944-cachepolicy) |
| NSURLRequestCachePolicy get cachePolicy => _nsObject.cachePolicy; |
| |
| /// The body of the request. |
| /// |
| /// See [NSURLRequest.HTTPBody](https://developer.apple.com/documentation/foundation/nsurlrequest/1411317-httpbody) |
| objc.NSData? get httpBody => _nsObject.HTTPBody; |
| |
| /// The HTTP request method (e.g. 'GET'). |
| /// |
| /// See [NSURLRequest.HTTPMethod](https://developer.apple.com/documentation/foundation/nsurlrequest/1413030-httpmethod) |
| /// |
| /// NOTE: The documentation for `NSURLRequest.HTTPMethod` says that the |
| /// property is nullable but, in practice, assigning it to null will produce |
| /// an error. |
| String get httpMethod => _nsObject.HTTPMethod!.toString(); |
| |
| /// The timeout interval during the connection attempt. |
| /// |
| /// See [NSURLSession.timeoutInterval](https://developer.apple.com/documentation/foundation/nsurlrequest/1418229-timeoutinterval) |
| Duration get timeoutInterval => Duration( |
| microseconds: |
| (_nsObject.timeoutInterval * Duration.microsecondsPerSecond).round()); |
| |
| /// The requested URL. |
| /// |
| /// See [URLRequest.URL](https://developer.apple.com/documentation/foundation/nsurlrequest/1408996-url) |
| Uri? get url { |
| final nsUrl = _nsObject.URL; |
| if (nsUrl == null) { |
| return null; |
| } |
| return nsurlToUri(nsUrl); |
| } |
| |
| @override |
| String toString() => '[URLRequest ' |
| 'allHttpHeaderFields=$allHttpHeaderFields ' |
| 'cachePolicy=$cachePolicy ' |
| 'httpBody=$httpBody ' |
| 'httpMethod=$httpMethod ' |
| 'timeoutInterval=$timeoutInterval ' |
| 'url=$url ' |
| ']'; |
| } |
| |
| /// A mutable request to load a URL. |
| /// |
| /// See [NSMutableURLRequest](https://developer.apple.com/documentation/foundation/nsmutableurlrequest) |
| class MutableURLRequest extends URLRequest { |
| final ncb.NSMutableURLRequest _mutableUrlRequest; |
| |
| MutableURLRequest._(ncb.NSMutableURLRequest super.c) |
| : _mutableUrlRequest = c, |
| super._(); |
| |
| /// Creates a request for a URL. |
| /// |
| /// See [NSMutableURLRequest.requestWithURL:](https://developer.apple.com/documentation/foundation/nsmutableurlrequest/1414617-allhttpheaderfields) |
| factory MutableURLRequest.fromUrl(Uri uri) { |
| final url = objc.NSURL.URLWithString_(uri.toString().toNSString())!; |
| return MutableURLRequest._(ncb.NSMutableURLRequest.requestWithURL_(url)); |
| } |
| |
| set cachePolicy(NSURLRequestCachePolicy value) => |
| _mutableUrlRequest.cachePolicy = value; |
| |
| set httpBody(objc.NSData? data) { |
| _mutableUrlRequest.HTTPBody = data; |
| } |
| |
| /// Sets the body of the request to the given [Stream]. |
| /// |
| /// See [NSMutableURLRequest.HTTPBodyStream](https://developer.apple.com/documentation/foundation/nsurlrequest/1407341-httpbodystream). |
| set httpBodyStream(objc.NSInputStream stream) { |
| _mutableUrlRequest.HTTPBodyStream = stream; |
| } |
| |
| set httpMethod(String method) { |
| _mutableUrlRequest.HTTPMethod = method.toNSString(); |
| } |
| |
| set timeoutInterval(Duration interval) { |
| _mutableUrlRequest.timeoutInterval = |
| interval.inMicroseconds.toDouble() / Duration.microsecondsPerSecond; |
| } |
| |
| /// Set the value of a header field. |
| /// |
| /// See [NSMutableURLRequest setValue:forHTTPHeaderField:](https://developer.apple.com/documentation/foundation/nsmutableurlrequest/1408793-setvalue) |
| void setValueForHttpHeaderField(String value, String field) { |
| _mutableUrlRequest.setValue_forHTTPHeaderField_( |
| field.toNSString(), value.toNSString()); |
| } |
| |
| @override |
| String toString() => '[MutableURLRequest ' |
| 'allHttpHeaderFields=$allHttpHeaderFields ' |
| 'cachePolicy=$cachePolicy ' |
| 'httpBody=$httpBody ' |
| 'httpMethod=$httpMethod ' |
| 'timeoutInterval=$timeoutInterval ' |
| 'url=$url ' |
| ']'; |
| } |
| |
| /// A client that can make network requests to a server. |
| /// |
| /// See [NSURLSession](https://developer.apple.com/documentation/foundation/nsurlsession) |
| class URLSession extends _ObjectHolder<ncb.NSURLSession> { |
| // Provide our own native delegate to `NSURLSession` because delegates can be |
| // called on arbitrary threads and Dart code cannot be. |
| // Indicates if the session is a background session. Copied from the |
| // [URLSessionConfiguration._isBackground] associated with this [URLSession]. |
| final bool _isBackground; |
| final bool _hasDelegate; |
| // Pending Dart-implemented protocols/blocks do not keep the isolate alive. |
| // So we create a `ReceivePort` to keep the isolate alive. |
| // When a new task is created in a `URLSession` with a delegate installed |
| // (`_hasDelegate`), `_taskCount` is incremented. When a task completes, |
| // `_taskCount` is decremented. When `_taskCount` is 0 then the `ReceivePort` |
| // is closed. |
| static var _taskCount = 0; |
| static ReceivePort? _port; |
| |
| static void _incrementTaskCount() { |
| _port ??= ReceivePort(); |
| ++_taskCount; |
| } |
| |
| static void _decrementTaskCount() { |
| assert(_taskCount > 0); |
| assert(_port != null); |
| --_taskCount; |
| if (_taskCount == 0) { |
| _port?.close(); |
| _port = null; |
| } |
| } |
| |
| static objc.ObjCObjectBase delegate( |
| bool isBackground, { |
| URLRequest? Function(URLSession session, URLSessionTask task, |
| HTTPURLResponse response, URLRequest newRequest)? |
| onRedirect, |
| NSURLSessionResponseDisposition Function( |
| URLSession session, URLSessionTask task, URLResponse response)? |
| onResponse, |
| void Function(URLSession session, URLSessionTask task, objc.NSData error)? |
| onData, |
| void Function(URLSession session, URLSessionDownloadTask task, Uri uri)? |
| onFinishedDownloading, |
| void Function(URLSession session, URLSessionTask task, objc.NSError? error)? |
| onComplete, |
| void Function( |
| URLSession session, URLSessionWebSocketTask task, String? protocol)? |
| onWebSocketTaskOpened, |
| void Function(URLSession session, URLSessionWebSocketTask task, |
| int closeCode, objc.NSData? reason)? |
| onWebSocketTaskClosed, |
| }) { |
| final protoBuilder = objc.ObjCProtocolBuilder(); |
| |
| ncb.NSURLSessionDataDelegate.URLSession_task_didCompleteWithError_ |
| .implementAsListener(protoBuilder, (nsSession, nsTask, nsError) { |
| _decrementTaskCount(); |
| if (onComplete != null) { |
| onComplete( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionTask._(nsTask), |
| nsError); |
| } |
| }); |
| |
| if (onRedirect != null) { |
| ncb |
| .NSURLSessionDataDelegate |
| // ignore: lines_longer_than_80_chars |
| .URLSession_task_willPerformHTTPRedirection_newRequest_completionHandler_ |
| .implementAsListener(protoBuilder, |
| // ignore: lines_longer_than_80_chars |
| |
| (nsSession, nsTask, nsResponse, nsRequest, nsRequestCompleter) { |
| final request = URLRequest._(nsRequest); |
| URLRequest? redirectRequest; |
| |
| try { |
| final response = |
| URLResponse._exactURLResponseType(nsResponse) as HTTPURLResponse; |
| redirectRequest = onRedirect( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionTask._(nsTask), |
| response, |
| request); |
| nsRequestCompleter.call(redirectRequest?._nsObject); |
| } catch (e) { |
| // TODO(https://github.com/dart-lang/ffigen/issues/386): Package |
| // this exception as an `Error` and call the completion function |
| // with it. |
| } |
| }); |
| } |
| |
| if (onResponse != null) { |
| ncb.NSURLSessionDataDelegate |
| .URLSession_dataTask_didReceiveResponse_completionHandler_ |
| .implementAsListener(protoBuilder, |
| (nsSession, nsDataTask, nsResponse, nsCompletionHandler) { |
| final exactResponse = URLResponse._exactURLResponseType(nsResponse); |
| final disposition = onResponse( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionTask._(nsDataTask), |
| exactResponse); |
| nsCompletionHandler.call(disposition); |
| }); |
| } |
| |
| if (onData != null) { |
| ncb.NSURLSessionDataDelegate.URLSession_dataTask_didReceiveData_ |
| .implementAsListener(protoBuilder, (nsSession, nsDataTask, nsData) { |
| onData( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionTask._(nsDataTask), |
| nsData); |
| }); |
| } |
| |
| if (onFinishedDownloading != null) { |
| final asyncFinishDownloading = |
| // ignore: lines_longer_than_80_chars |
| ncb.ObjCBlock_ffiVoid_NSCondition_NSURLSession_NSURLSessionDownloadTask_NSURL |
| .listener((nsCondition, nsSession, nsTask, nsUrl) { |
| try { |
| onFinishedDownloading( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionDownloadTask._(nsTask), |
| nsurlToUri(nsUrl)); |
| } finally { |
| nsCondition.unlock(); |
| } |
| }); |
| |
| final downloadDelegate = objc.getProtocol('NSURLSessionDownloadDelegate'); |
| final didFinishDownloadingToURL = objc |
| .registerName('URLSession:downloadTask:didFinishDownloadingToURL:'); |
| final signature = objc.getProtocolMethodSignature( |
| downloadDelegate, didFinishDownloadingToURL, |
| isRequired: true, isInstanceMethod: true)!; |
| protoBuilder.implementMethod(didFinishDownloadingToURL, signature, |
| linkedLibs.adaptFinishWithLock(asyncFinishDownloading)); |
| } |
| |
| if (onWebSocketTaskOpened != null) { |
| ncb.NSURLSessionWebSocketDelegate |
| .URLSession_webSocketTask_didOpenWithProtocol_ |
| .implementAsListener(protoBuilder, (nsSession, nsTask, nsProtocol) { |
| onWebSocketTaskOpened( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionWebSocketTask._(nsTask), |
| nsProtocol?.toString()); |
| }); |
| } |
| |
| if (onWebSocketTaskClosed != null) { |
| ncb.NSURLSessionWebSocketDelegate |
| .URLSession_webSocketTask_didCloseWithCode_reason_ |
| .implementAsListener(protoBuilder, |
| (nsSession, nsTask, closeCode, reason) { |
| onWebSocketTaskClosed( |
| URLSession._(nsSession, |
| isBackground: isBackground, hasDelegate: true), |
| URLSessionWebSocketTask._(nsTask), |
| closeCode, |
| reason); |
| }); |
| } |
| |
| return protoBuilder.build(); |
| } |
| |
| URLSession._( |
| super.c, { |
| required bool isBackground, |
| required bool hasDelegate, |
| }) : _isBackground = isBackground, |
| _hasDelegate = hasDelegate; |
| |
| /// A client with reasonable default behavior. |
| /// |
| /// See [NSURLSession.sharedSession](https://developer.apple.com/documentation/foundation/nsurlsession/1409000-sharedsession) |
| factory URLSession.sharedSession() => |
| URLSession._(ncb.NSURLSession.getSharedSession(), |
| isBackground: false, hasDelegate: false); |
| |
| /// A client with a given configuration. |
| /// |
| /// If [onRedirect] is set then it will be called whenever a HTTP |
| /// request returns a redirect response (e.g. 302). The `response` parameter |
| /// contains the response from the server. The `newRequest` parameter contains |
| /// a follow-up request that would honor the server's redirect. If the return |
| /// value of this function is `null` then the redirect will not occur. |
| /// Otherwise, the returned [URLRequest] (usually `newRequest`) will be |
| /// executed. [onRedirect] will not be called for background sessions, which |
| /// automatically follow redirects. See |
| /// [URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:](https://developer.apple.com/documentation/foundation/nsurlsessiontaskdelegate/1411626-urlsession) |
| /// |
| /// If [onResponse] is set then it will be called whenever a valid response |
| /// is received. The returned [NSURLSessionResponseDisposition] will decide |
| /// how the content of the response is processed. See |
| /// [URLSession:dataTask:didReceiveResponse:completionHandler:](https://developer.apple.com/documentation/foundation/nsurlsessiondatadelegate/1410027-urlsession) |
| /// |
| /// If [onData] is set then it will be called whenever response data is |
| /// received. If the amount of received data is large, then it may be |
| /// called more than once. See |
| /// [URLSession:dataTask:didReceiveData:](https://developer.apple.com/documentation/foundation/nsurlsessiondatadelegate/1411528-urlsession) |
| /// |
| /// If [onFinishedDownloading] is set then it will be called whenever a |
| /// [URLSessionDownloadTask] has finished downloading. |
| /// |
| /// If [onComplete] is set then it will be called when a task completes. If |
| /// `error` is `null` then the request completed successfully. See |
| /// [URLSession:task:didCompleteWithError:](https://developer.apple.com/documentation/foundation/nsurlsessiontaskdelegate/1411610-urlsession) |
| /// |
| /// See [sessionWithConfiguration:delegate:delegateQueue:](https://developer.apple.com/documentation/foundation/nsurlsession/1411597-sessionwithconfiguration) |
| /// |
| /// If [onWebSocketTaskOpened] is set then it will be called when a |
| /// [URLSessionWebSocketTask] successfully negotiated the handshake with the |
| /// server. |
| /// |
| /// If [onWebSocketTaskClosed] is set then it will be called if a |
| /// [URLSessionWebSocketTask] receives a close control frame from the server. |
| /// NOTE: A [URLSessionWebSocketTask.receiveMessage] must be in flight for |
| /// [onWebSocketTaskClosed] to be called. |
| factory URLSession.sessionWithConfiguration( |
| URLSessionConfiguration config, { |
| URLRequest? Function(URLSession session, URLSessionTask task, |
| HTTPURLResponse response, URLRequest newRequest)? |
| onRedirect, |
| NSURLSessionResponseDisposition Function( |
| URLSession session, URLSessionTask task, URLResponse response)? |
| onResponse, |
| void Function(URLSession session, URLSessionTask task, objc.NSData data)? |
| onData, |
| void Function(URLSession session, URLSessionDownloadTask task, Uri uri)? |
| onFinishedDownloading, |
| void Function(URLSession session, URLSessionTask task, objc.NSError? error)? |
| onComplete, |
| void Function( |
| URLSession session, URLSessionWebSocketTask task, String? protocol)? |
| onWebSocketTaskOpened, |
| void Function(URLSession session, URLSessionWebSocketTask task, |
| int? closeCode, objc.NSData? reason)? |
| onWebSocketTaskClosed, |
| }) { |
| // Avoid the complexity of simultaneous or out-of-order delegate callbacks |
| // by only allowing callbacks to execute sequentially. |
| // See https://developer.apple.com/forums/thread/47252 |
| final queue = ncb.NSOperationQueue.new1() |
| ..maxConcurrentOperationCount = 1 |
| ..name = 'cupertino_http.NSURLSessionDelegateQueue'.toNSString(); |
| |
| final hasDelegate = (onRedirect ?? |
| onResponse ?? |
| onData ?? |
| onFinishedDownloading ?? |
| onComplete ?? |
| onWebSocketTaskOpened ?? |
| onWebSocketTaskClosed) != |
| null; |
| |
| if (hasDelegate) { |
| return URLSession._( |
| ncb.NSURLSession.sessionWithConfiguration_delegate_delegateQueue_( |
| config._nsObject, |
| delegate(config._isBackground, |
| onRedirect: onRedirect, |
| onResponse: onResponse, |
| onData: onData, |
| onFinishedDownloading: onFinishedDownloading, |
| onComplete: onComplete, |
| onWebSocketTaskOpened: onWebSocketTaskOpened, |
| onWebSocketTaskClosed: onWebSocketTaskClosed), |
| queue), |
| isBackground: config._isBackground, |
| hasDelegate: true, |
| ); |
| } else { |
| return URLSession._( |
| ncb.NSURLSession.sessionWithConfiguration_(config._nsObject), |
| isBackground: config._isBackground, |
| hasDelegate: false); |
| } |
| } |
| |
| /// A **copy** of the configuration for this session. |
| /// |
| /// See [NSURLSession.configuration](https://developer.apple.com/documentation/foundation/nsurlsession/1411477-configuration) |
| URLSessionConfiguration get configuration => URLSessionConfiguration._( |
| ncb.NSURLSessionConfiguration.castFrom(_nsObject.configuration), |
| isBackground: _isBackground); |
| |
| /// A description of the session that may be useful for debugging. |
| /// |
| /// See [NSURLSession.sessionDescription](https://developer.apple.com/documentation/foundation/nsurlsession/1408277-sessiondescription) |
| String? get sessionDescription => _nsObject.sessionDescription?.toString(); |
| set sessionDescription(String? value) => |
| _nsObject.sessionDescription = value?.toNSString(); |
| |
| /// Create a [URLSessionTask] that accesses a server URL. |
| /// |
| /// See [NSURLSession dataTaskWithRequest:](https://developer.apple.com/documentation/foundation/nsurlsession/1410592-datataskwithrequest) |
| URLSessionTask dataTaskWithRequest(URLRequest request) { |
| final task = |
| URLSessionTask._(_nsObject.dataTaskWithRequest_(request._nsObject)); |
| if (_hasDelegate) { |
| _incrementTaskCount(); |
| } |
| return task; |
| } |
| |
| /// Creates a [URLSessionTask] that accesses a server URL and calls |
| /// [completion] when done. |
| /// |
| /// See [NSURLSession dataTaskWithRequest:completionHandler:](https://developer.apple.com/documentation/foundation/nsurlsession/1407613-datataskwithrequest) |
| URLSessionTask dataTaskWithCompletionHandler( |
| URLRequest request, |
| void Function( |
| objc.NSData? data, URLResponse? response, objc.NSError? error) |
| completion) { |
| if (_isBackground) { |
| throw UnsupportedError( |
| 'dataTaskWithCompletionHandler is not supported in background ' |
| 'sessions'); |
| } |
| final completer = |
| ncb.ObjCBlock_ffiVoid_NSData_NSURLResponse_NSError.listener( |
| (data, response, error) { |
| _decrementTaskCount(); |
| completion( |
| data, |
| response == null ? null : URLResponse._exactURLResponseType(response), |
| error, |
| ); |
| }); |
| |
| final task = _nsObject.dataTaskWithRequest_completionHandler_( |
| request._nsObject, |
| completer, |
| ); |
| |
| _incrementTaskCount(); |
| return URLSessionTask._(task); |
| } |
| |
| /// Creates a [URLSessionDownloadTask] that downloads the data from a server |
| /// URL. |
| /// |
| /// Provide a `onFinishedDownloading` handler in the [URLSession] factory to |
| /// receive notifications when the data has completed downloaded. |
| /// |
| /// See [NSURLSession downloadTaskWithRequest:](https://developer.apple.com/documentation/foundation/nsurlsession/1411481-downloadtaskwithrequest) |
| URLSessionDownloadTask downloadTaskWithRequest(URLRequest request) { |
| final task = URLSessionDownloadTask._( |
| _nsObject.downloadTaskWithRequest_(request._nsObject)); |
| if (_hasDelegate) { |
| _incrementTaskCount(); |
| } |
| return task; |
| } |
| |
| /// Creates a [URLSessionWebSocketTask] that represents a connection to a |
| /// WebSocket endpoint. |
| /// |
| /// To add custom protocols, add a "Sec-WebSocket-Protocol" header with a list |
| /// of protocols to [request]. |
| /// |
| /// See [NSURLSession webSocketTaskWithRequest:](https://developer.apple.com/documentation/foundation/nsurlsession/3235750-websockettaskwithrequest) |
| URLSessionWebSocketTask webSocketTaskWithRequest(URLRequest request) { |
| if (_isBackground) { |
| throw UnsupportedError( |
| 'WebSocket tasks are not supported in background sessions'); |
| } |
| final task = URLSessionWebSocketTask._( |
| _nsObject.webSocketTaskWithRequest_(request._nsObject)); |
| if (_hasDelegate) { |
| _incrementTaskCount(); |
| } |
| return task; |
| } |
| |
| /// Creates a [URLSessionWebSocketTask] that represents a connection to a |
| /// WebSocket endpoint. |
| /// |
| /// See [NSURLSession webSocketTaskWithURL:protocols:](https://developer.apple.com/documentation/foundation/nsurlsession/3181172-websockettaskwithurl) |
| URLSessionWebSocketTask webSocketTaskWithURL(Uri uri, |
| {Iterable<String>? protocols}) { |
| if (_isBackground) { |
| throw UnsupportedError( |
| 'WebSocket tasks are not supported in background sessions'); |
| } |
| final URLSessionWebSocketTask task; |
| if (protocols == null) { |
| task = URLSessionWebSocketTask._( |
| _nsObject.webSocketTaskWithURL_(uriToNSURL(uri))); |
| } else { |
| task = URLSessionWebSocketTask._( |
| _nsObject.webSocketTaskWithURL_protocols_( |
| uriToNSURL(uri), stringIterableToNSArray(protocols))); |
| } |
| if (_hasDelegate) { |
| _incrementTaskCount(); |
| } |
| return task; |
| } |
| |
| /// Free resources related to this session after the last task completes. |
| /// Returns immediately. |
| /// |
| /// See [NSURLSession finishTasksAndInvalidate](https://developer.apple.com/documentation/foundation/nsurlsession/1407428-finishtasksandinvalidate) |
| void finishTasksAndInvalidate() { |
| _nsObject.finishTasksAndInvalidate(); |
| } |
| } |