forked from organicmaps/organicmaps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp_session_manager.mm
198 lines (168 loc) · 6.33 KB
/
http_session_manager.mm
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
#import "platform/http_session_manager.h"
@interface DataTaskInfo : NSObject
@property(nonatomic, weak) id<NSURLSessionDataDelegate> delegate;
@property(nonatomic) NSURLSessionDataTask * task;
- (instancetype)initWithTask:(NSURLSessionDataTask *)task
delegate:(id<NSURLSessionDataDelegate>)delegate;
@end
@implementation DataTaskInfo
- (instancetype)initWithTask:(NSURLSessionDataTask *)task
delegate:(id<NSURLSessionDataDelegate>)delegate
{
self = [super init];
if (self)
{
_task = task;
_delegate = delegate;
}
return self;
}
@end
@interface HttpSessionManager ()<NSURLSessionDataDelegate>
@property(nonatomic) NSURLSession * session;
@property(nonatomic) NSMutableDictionary * taskInfoByTaskID;
@property(nonatomic) dispatch_queue_t taskInfoQueue;
@property(nonatomic) dispatch_queue_t delegateQueue;
@end
@implementation HttpSessionManager
+ (HttpSessionManager *)sharedManager
{
static dispatch_once_t sOnceToken;
static HttpSessionManager * sManager;
dispatch_once(&sOnceToken, ^{
sManager = [[HttpSessionManager alloc] init];
});
return sManager;
}
- (instancetype)init
{
self = [super init];
if (self)
{
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]
delegate:self
delegateQueue:nil];
_taskInfoByTaskID = [NSMutableDictionary dictionary];
_taskInfoQueue = dispatch_queue_create("http_session_manager.queue", DISPATCH_QUEUE_CONCURRENT);
// TODO(AB): As the main thread in tests that are using synchronous HTTP calls is blocked
// by dispatch_group_wait(group, DISPATCH_TIME_FOREVER) in http_client_apple.mm,
// and delegate should not strictly use only one (main) thread and can be run on
// any thread, this workaround is needed.
// Refactor out the whole sync HTTP implementation to use async + lambdas/callbacks.
BOOL const isSyncHttpTest = [NSBundle.mainBundle.executableURL.lastPathComponent hasSuffix:@"osm_auth_tests"];
_delegateQueue = isSyncHttpTest ? _taskInfoQueue : dispatch_get_main_queue();
}
return self;
}
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
delegate:(id<NSURLSessionDataDelegate>)delegate
completionHandler:(void (^)(NSData * data, NSURLResponse * response,
NSError * error))completionHandler
{
NSURLSessionDataTask * task = [self.session dataTaskWithRequest:request
completionHandler:completionHandler];
DataTaskInfo * taskInfo = [[DataTaskInfo alloc] initWithTask:task delegate:delegate];
[self setDataTaskInfo:taskInfo forTask:task];
return task;
}
- (void)setDataTaskInfo:(DataTaskInfo *)taskInfo forTask:(NSURLSessionTask *)task
{
dispatch_barrier_sync(self.taskInfoQueue, ^{
self.taskInfoByTaskID[@(task.taskIdentifier)] = taskInfo;
});
}
- (void)removeTaskInfoForTask:(NSURLSessionTask *)task
{
dispatch_barrier_sync(self.taskInfoQueue, ^{
[self.taskInfoByTaskID removeObjectForKey:@(task.taskIdentifier)];
});
}
- (DataTaskInfo *)taskInfoForTask:(NSURLSessionTask *)task
{
__block DataTaskInfo * taskInfo = nil;
dispatch_sync(self.taskInfoQueue, ^{
taskInfo = self.taskInfoByTaskID[@(task.taskIdentifier)];
});
return taskInfo;
}
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)newRequest
completionHandler:(void (^)(NSURLRequest *))completionHandler
{
DataTaskInfo * taskInfo = [self taskInfoForTask:task];
if ([taskInfo.delegate
respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)])
{
dispatch_async(self.delegateQueue, ^{
[taskInfo.delegate URLSession:session
task:task
willPerformHTTPRedirection:response
newRequest:newRequest
completionHandler:completionHandler];
});
}
else
{
completionHandler(newRequest);
}
}
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
DataTaskInfo * taskInfo = [self taskInfoForTask:task];
[self removeTaskInfoForTask:task];
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)])
{
dispatch_async(self.delegateQueue, ^{
[taskInfo.delegate URLSession:session task:task didCompleteWithError:error];
});
}
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
DataTaskInfo * taskInfo = [self taskInfoForTask:dataTask];
if ([taskInfo.delegate
respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)])
{
dispatch_async(self.delegateQueue, ^{
[taskInfo.delegate URLSession:session
dataTask:dataTask
didReceiveResponse:response
completionHandler:completionHandler];
});
}
else
{
completionHandler(NSURLSessionResponseAllow);
}
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
DataTaskInfo * taskInfo = [self taskInfoForTask:dataTask];
if ([taskInfo.delegate respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)])
{
dispatch_async(self.delegateQueue, ^{
[taskInfo.delegate URLSession:session dataTask:dataTask didReceiveData:data];
});
}
}
#if DEBUG
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * _Nullable credential))completionHandler
{
NSURLCredential * credential =
[[NSURLCredential alloc] initWithTrust:[challenge protectionSpace].serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}
#endif
@end