| // 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. | |
| #import "CUPHTTPClientDelegate.h" | |
| #import <Foundation/Foundation.h> | |
| #include <os/log.h> | |
| #import "CUPHTTPCompletionHelper.h" | |
| #import "CUPHTTPForwardedDelegate.h" | |
| static Dart_CObject MessageTypeToCObject(MessageType messageType) { | |
| Dart_CObject cobj; | |
| cobj.type = Dart_CObject_kInt64; | |
| cobj.value.as_int64 = messageType; | |
| return cobj; | |
| } | |
| @implementation CUPHTTPTaskConfiguration | |
| - (id) initWithPort:(Dart_Port)sendPort { | |
| self = [super init]; | |
| if (self != nil) { | |
| self->_sendPort = sendPort; | |
| } | |
| return self; | |
| } | |
| @end | |
| @implementation CUPHTTPClientDelegate { | |
| NSMapTable<NSURLSessionTask *, CUPHTTPTaskConfiguration *> *taskConfigurations; | |
| } | |
| - (instancetype)init { | |
| self = [super init]; | |
| if (self != nil) { | |
| taskConfigurations = [[NSMapTable strongToStrongObjectsMapTable] retain]; | |
| } | |
| return self; | |
| } | |
| - (void)dealloc { | |
| [taskConfigurations release]; | |
| [super dealloc]; | |
| } | |
| - (void)registerTask:(NSURLSessionTask *) task | |
| withConfiguration:(CUPHTTPTaskConfiguration *)config { | |
| [taskConfigurations setObject:config forKey:task]; | |
| } | |
| -(void)unregisterTask:(NSURLSessionTask *) task { | |
| [taskConfigurations removeObjectForKey:task]; | |
| } | |
| - (void)URLSession:(NSURLSession *)session | |
| task:(NSURLSessionTask *)task | |
| willPerformHTTPRedirection:(NSHTTPURLResponse *)response | |
| newRequest:(NSURLRequest *)request | |
| completionHandler:(void (^)(NSURLRequest *))completionHandler { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:task]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedRedirect *forwardedRedirect = [[CUPHTTPForwardedRedirect alloc] | |
| initWithSession:session task:task | |
| response:response request:request]; | |
| Dart_CObject ctype = MessageTypeToCObject(RedirectMessage); | |
| Dart_CObject credirect = NSObjectToCObject(forwardedRedirect); | |
| Dart_CObject* message_carray[] = { &ctype, &credirect }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| [forwardedRedirect.lock lock]; // After this line, any attempt to acquire the lock will wait. | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| // Will be unlocked by [CUPHTTPRedirect continueWithRequest:], which will | |
| // set `redirect.redirectRequest`. | |
| // | |
| // See the @interface description for CUPHTTPRedirect. | |
| [forwardedRedirect.lock lock]; | |
| completionHandler(forwardedRedirect.redirectRequest); | |
| [forwardedRedirect release]; | |
| } | |
| - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)task | |
| didReceiveResponse:(NSURLResponse *)response | |
| completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler | |
| { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:task]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedResponse *forwardedResponse = [[CUPHTTPForwardedResponse alloc] | |
| initWithSession:session | |
| task:task | |
| response:response]; | |
| Dart_CObject ctype = MessageTypeToCObject(ResponseMessage); | |
| Dart_CObject cRsponseReceived = NSObjectToCObject(forwardedResponse); | |
| Dart_CObject* message_carray[] = { &ctype, &cRsponseReceived }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| [forwardedResponse.lock lock]; // After this line, any attempt to acquire the lock will wait. | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| // Will be unlocked by [CUPHTTPRedirect continueWithRequest:], which will | |
| // set `redirect.redirectRequest`. | |
| // | |
| // See the @interface description for CUPHTTPRedirect. | |
| [forwardedResponse.lock lock]; | |
| completionHandler(forwardedResponse.disposition); | |
| [forwardedResponse release]; | |
| } | |
| - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)task | |
| didReceiveData:(NSData *)data { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:task]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedData *forwardedData = [[CUPHTTPForwardedData alloc] | |
| initWithSession:session task:task data: data] | |
| ; | |
| Dart_CObject ctype = MessageTypeToCObject(DataMessage); | |
| Dart_CObject cReceiveData = NSObjectToCObject(forwardedData); | |
| Dart_CObject* message_carray[] = { &ctype, &cReceiveData }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| [forwardedData.lock lock]; // After this line, any attempt to acquire the lock will wait. | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| // Will be unlocked by [CUPHTTPRedirect continueWithRequest:], which will | |
| // set `redirect.redirectRequest`. | |
| // | |
| // See the @interface description for CUPHTTPRedirect. | |
| [forwardedData.lock lock]; | |
| [forwardedData release]; | |
| } | |
| - (void)URLSession:(NSURLSession *)session | |
| downloadTask:(NSURLSessionDownloadTask *)downloadTask | |
| didFinishDownloadingToURL:(NSURL *)location { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:downloadTask]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedFinishedDownloading *forwardedFinishedDownload = [ | |
| [CUPHTTPForwardedFinishedDownloading alloc] | |
| initWithSession:session downloadTask:downloadTask url: location]; | |
| Dart_CObject ctype = MessageTypeToCObject(FinishedDownloading); | |
| Dart_CObject cReceiveData = NSObjectToCObject(forwardedFinishedDownload); | |
| Dart_CObject* message_carray[] = { &ctype, &cReceiveData }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| // After this line, any attempt to acquire the lock will wait. | |
| [forwardedFinishedDownload.lock lock]; | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| [forwardedFinishedDownload.lock lock]; | |
| [forwardedFinishedDownload release]; | |
| } | |
| - (void)URLSession:(NSURLSession *)session | |
| task:(NSURLSessionTask *)task | |
| didCompleteWithError:(nullable NSError *)error { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:task]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedComplete *forwardedComplete = [[CUPHTTPForwardedComplete alloc] | |
| initWithSession:session task:task error: error]; | |
| Dart_CObject ctype = MessageTypeToCObject(CompletedMessage); | |
| Dart_CObject cComplete = NSObjectToCObject(forwardedComplete); | |
| Dart_CObject* message_carray[] = { &ctype, &cComplete }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| [forwardedComplete.lock lock]; // After this line, any attempt to acquire the lock will wait. | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| // Will be unlocked by [CUPHTTPRedirect continueWithRequest:], which will | |
| // set `redirect.redirectRequest`. | |
| // | |
| // See the @interface description for CUPHTTPRedirect. | |
| [forwardedComplete.lock lock]; | |
| [forwardedComplete release]; | |
| } | |
| // https://developer.apple.com/documentation/foundation/nsurlsessionwebsocketdelegate?language=objc | |
| - (void)URLSession:(NSURLSession *)session | |
| webSocketTask:(NSURLSessionWebSocketTask *)task | |
| didOpenWithProtocol:(nullable NSString *)protocol { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:task]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedWebSocketOpened *opened = [[CUPHTTPForwardedWebSocketOpened alloc] | |
| initWithSession:session webSocketTask:task | |
| didOpenWithProtocol: protocol]; | |
| Dart_CObject ctype = MessageTypeToCObject(WebSocketOpened); | |
| Dart_CObject cComplete = NSObjectToCObject(opened); | |
| Dart_CObject* message_carray[] = { &ctype, &cComplete }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| [opened.lock lock]; // After this line, any attempt to acquire the lock will wait. | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| [opened.lock lock]; | |
| [opened release]; | |
| } | |
| - (void)URLSession:(NSURLSession *)session | |
| webSocketTask:(NSURLSessionWebSocketTask *)task | |
| didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode | |
| reason:(nullable NSData *)reason { | |
| CUPHTTPTaskConfiguration *config = [taskConfigurations objectForKey:task]; | |
| NSAssert(config != nil, @"No configuration for task."); | |
| CUPHTTPForwardedWebSocketClosed *closed = [[CUPHTTPForwardedWebSocketClosed alloc] | |
| initWithSession:session webSocketTask:task | |
| code: closeCode | |
| reason: reason]; | |
| Dart_CObject ctype = MessageTypeToCObject(WebSocketClosed); | |
| Dart_CObject cComplete = NSObjectToCObject(closed); | |
| Dart_CObject* message_carray[] = { &ctype, &cComplete }; | |
| Dart_CObject message_cobj; | |
| message_cobj.type = Dart_CObject_kArray; | |
| message_cobj.value.as_array.length = 2; | |
| message_cobj.value.as_array.values = message_carray; | |
| [closed.lock lock]; // After this line, any attempt to acquire the lock will wait. | |
| const bool success = Dart_PostCObject_DL(config.sendPort, &message_cobj); | |
| NSAssert(success, @"Dart_PostCObject_DL failed."); | |
| [closed.lock lock]; | |
| [closed release]; | |
| } | |
| @end |