Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(346)

Side by Side Diff: components/cronet/ios/Cronet.mm

Issue 2146643002: [Cronet] Integrate CrNet functionality into Cronet on iOS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Simplify TestServer. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "components/cronet/ios/Cronet.h" 5 #import "components/cronet/ios/Cronet.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/mac/bundle_locations.h"
12 #include "base/mac/scoped_block.h"
13 #include "base/memory/ptr_util.h"
11 #include "base/memory/scoped_vector.h" 14 #include "base/memory/scoped_vector.h"
12 #include "base/strings/sys_string_conversions.h" 15 #include "base/strings/sys_string_conversions.h"
13 #include "components/cronet/ios/cronet_environment.h" 16 #include "components/cronet/ios/cronet_environment.h"
14 #include "components/cronet/url_request_context_config.h" 17 #include "components/cronet/url_request_context_config.h"
18 #include "ios/net/crn_http_protocol_handler.h"
19 #include "ios/net/empty_nsurlcache.h"
20 #include "net/cert/cert_verifier.h"
21 #include "net/url_request/url_request_context_getter.h"
15 22
16 namespace { 23 namespace {
17 24
25 class CronetHttpProtocolHandlerDelegate;
26
18 // Currently there is one and only one instance of CronetEnvironment, 27 // Currently there is one and only one instance of CronetEnvironment,
19 // which is leaked at the shutdown. We should consider allowing multiple 28 // which is leaked at the shutdown. We should consider allowing multiple
20 // instances if that makes sense in the future. 29 // instances if that makes sense in the future.
21 base::LazyInstance<std::unique_ptr<cronet::CronetEnvironment>>::Leaky 30 base::LazyInstance<std::unique_ptr<cronet::CronetEnvironment>>::Leaky
22 gChromeNet = LAZY_INSTANCE_INITIALIZER; 31 gChromeNet = LAZY_INSTANCE_INITIALIZER;
23 32
24 BOOL gHttp2Enabled = YES; 33 BOOL gHttp2Enabled = YES;
25 BOOL gQuicEnabled = NO; 34 BOOL gQuicEnabled = NO;
26 ScopedVector<cronet::URLRequestContextConfig::QuicHint> gQuicHints; 35 ScopedVector<cronet::URLRequestContextConfig::QuicHint> gQuicHints;
27 NSString* gUserAgent = nil; 36 NSString* gUserAgent = nil;
37 BOOL gUserAgentPartial = NO;
28 NSString* gSslKeyLogFileName = nil; 38 NSString* gSslKeyLogFileName = nil;
39 RequestFilterBlock gRequestFilterBlock = nil;
40 std::unique_ptr<CronetHttpProtocolHandlerDelegate> gHttpProtocolHandlerDelegate;
41 NSURLCache* gPreservedSharedURLCache = nil;
42 BOOL gEnableTestCertVerifierForTesting = FALSE;
43 NSString* gHostResolverRulesForTesting = @"";
44
45 // CertVerifier, which allows any certificates for testing.
46 class TestCertVerifier : public net::CertVerifier {
47 int Verify(const RequestParams& params,
48 net::CRLSet* crl_set,
49 net::CertVerifyResult* verify_result,
50 const net::CompletionCallback& callback,
51 std::unique_ptr<Request>* out_req,
52 const net::NetLogWithSource& net_log) override {
53 net::Error result = net::OK;
54 verify_result->verified_cert = params.certificate();
55 verify_result->cert_status = net::MapNetErrorToCertStatus(result);
56 return result;
57 }
58 };
59
60 // net::HTTPProtocolHandlerDelegate for Cronet.
61 class CronetHttpProtocolHandlerDelegate
62 : public net::HTTPProtocolHandlerDelegate {
63 public:
64 CronetHttpProtocolHandlerDelegate(net::URLRequestContextGetter* getter,
65 RequestFilterBlock filter)
66 : getter_(getter), filter_(filter, base::scoped_policy::RETAIN) {}
67
68 void SetRequestFilterBlock(RequestFilterBlock filter) {
69 filter_.reset(filter);
70 }
71
72 private:
73 // net::HTTPProtocolHandlerDelegate implementation:
74 bool CanHandleRequest(NSURLRequest* request) override {
75 if (filter_) {
76 RequestFilterBlock block = filter_.get();
77 return block(request);
78 }
79 return true;
80 }
81
82 bool IsRequestSupported(NSURLRequest* request) override {
83 NSString* scheme = [[request URL] scheme];
84 if (!scheme)
85 return false;
86 return [scheme caseInsensitiveCompare:@"data"] == NSOrderedSame ||
87 [scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
88 [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame;
89 }
90
91 net::URLRequestContextGetter* GetDefaultURLRequestContext() override {
92 return getter_.get();
93 }
94
95 scoped_refptr<net::URLRequestContextGetter> getter_;
96 base::mac::ScopedBlock<RequestFilterBlock> filter_;
97 };
29 98
30 } // namespace 99 } // namespace
31 100
32 @implementation Cronet 101 @implementation Cronet
33 102
103 + (void)configureCronetEnvironmentForTesting:
104 (cronet::CronetEnvironment*)cronetEnvironment {
105 cronetEnvironment->set_host_resolver_rules(
106 [gHostResolverRulesForTesting UTF8String]);
107 if (gEnableTestCertVerifierForTesting) {
108 std::unique_ptr<TestCertVerifier> test_cert_verifier =
109 base::MakeUnique<TestCertVerifier>();
110 cronetEnvironment->set_cert_verifier(std::move(test_cert_verifier));
111 }
112 }
113
114 + (NSString*)getAcceptLanguages {
115 // Use the framework bundle to search for resources.
116 NSBundle* frameworkBundle = [NSBundle bundleForClass:self];
117 NSString* bundlePath =
118 [frameworkBundle pathForResource:@"cronet_resources" ofType:@"bundle"];
119 NSBundle* bundle = [NSBundle bundleWithPath:bundlePath];
120 NSString* acceptLanguages = NSLocalizedStringWithDefaultValue(
121 @"IDS_ACCEPT_LANGUAGES", @"Localizable", bundle, @"en-US,en",
122 @"These values are copied from Chrome's .xtb files, so the same "
123 "values are used in the |Accept-Language| header. Key name matches "
124 "Chrome's.");
125 if (acceptLanguages == Nil)
126 acceptLanguages = @"";
kapishnikov 2016/10/19 18:28:53 Why don't we set @"en-US,en" here? Also, should we
mef 2016/10/19 20:12:59 My motivation is that if we run into some unknown
kapishnikov 2016/10/19 21:12:29 I think it is a good idea to give the client an op
127 return acceptLanguages;
128 }
129
34 + (void)checkNotStarted { 130 + (void)checkNotStarted {
35 CHECK(gChromeNet == NULL) << "Cronet is already started."; 131 CHECK(gChromeNet == NULL) << "Cronet is already started.";
36 } 132 }
37 133
38 + (void)setHttp2Enabled:(BOOL)http2Enabled { 134 + (void)setHttp2Enabled:(BOOL)http2Enabled {
39 [self checkNotStarted]; 135 [self checkNotStarted];
40 gHttp2Enabled = http2Enabled; 136 gHttp2Enabled = http2Enabled;
41 } 137 }
42 138
43 + (void)setQuicEnabled:(BOOL)quicEnabled { 139 + (void)setQuicEnabled:(BOOL)quicEnabled {
44 [self checkNotStarted]; 140 [self checkNotStarted];
45 gQuicEnabled = quicEnabled; 141 gQuicEnabled = quicEnabled;
46 } 142 }
47 143
48 + (void)addQuicHint:(NSString*)host port:(int)port altPort:(int)altPort { 144 + (void)addQuicHint:(NSString*)host port:(int)port altPort:(int)altPort {
49 [self checkNotStarted]; 145 [self checkNotStarted];
50 gQuicHints.push_back(new cronet::URLRequestContextConfig::QuicHint( 146 gQuicHints.push_back(new cronet::URLRequestContextConfig::QuicHint(
51 base::SysNSStringToUTF8(host), port, altPort)); 147 base::SysNSStringToUTF8(host), port, altPort));
52 } 148 }
53 149
54 + (void)setPartialUserAgent:(NSString*)userAgent { 150 + (void)setUserAgent:(NSString*)userAgent partial:(BOOL)partial {
55 [self checkNotStarted]; 151 [self checkNotStarted];
56 gUserAgent = userAgent; 152 gUserAgent = userAgent;
153 gUserAgentPartial = partial;
57 } 154 }
58 155
59 + (void)setSslKeyLogFileName:(NSString*)sslKeyLogFileName { 156 + (void)setSslKeyLogFileName:(NSString*)sslKeyLogFileName {
60 [self checkNotStarted]; 157 [self checkNotStarted];
61 gSslKeyLogFileName = sslKeyLogFileName; 158 gSslKeyLogFileName = sslKeyLogFileName;
62 } 159 }
63 160
161 + (void)setRequestFilterBlock:(RequestFilterBlock)block {
kapishnikov 2016/10/19 18:28:53 Is this method thread safe? What if there are pend
mef 2016/10/19 20:12:59 Good catch! Done.
162 if (gHttpProtocolHandlerDelegate.get())
163 gHttpProtocolHandlerDelegate.get()->SetRequestFilterBlock(block);
164 else
165 gRequestFilterBlock = block;
166 }
167
64 + (void)startInternal { 168 + (void)startInternal {
65 cronet::CronetEnvironment::Initialize(); 169 cronet::CronetEnvironment::Initialize();
66 std::string partialUserAgent = base::SysNSStringToUTF8(gUserAgent); 170 std::string user_agent = base::SysNSStringToUTF8(gUserAgent);
67 gChromeNet.Get().reset(new cronet::CronetEnvironment(partialUserAgent)); 171 gChromeNet.Get().reset(
172 new cronet::CronetEnvironment(user_agent, gUserAgentPartial));
173 gChromeNet.Get()->set_accept_language(
174 base::SysNSStringToUTF8([self getAcceptLanguages]));
68 175
69 gChromeNet.Get()->set_http2_enabled(gHttp2Enabled); 176 gChromeNet.Get()->set_http2_enabled(gHttp2Enabled);
70 gChromeNet.Get()->set_quic_enabled(gQuicEnabled); 177 gChromeNet.Get()->set_quic_enabled(gQuicEnabled);
71 gChromeNet.Get()->set_ssl_key_log_file_name( 178 gChromeNet.Get()->set_ssl_key_log_file_name(
72 base::SysNSStringToUTF8(gSslKeyLogFileName)); 179 base::SysNSStringToUTF8(gSslKeyLogFileName));
73 for (const auto* quicHint : gQuicHints) { 180 for (const auto* quicHint : gQuicHints) {
74 gChromeNet.Get()->AddQuicHint(quicHint->host, quicHint->port, 181 gChromeNet.Get()->AddQuicHint(quicHint->host, quicHint->port,
75 quicHint->alternate_port); 182 quicHint->alternate_port);
76 } 183 }
184
185 [self configureCronetEnvironmentForTesting:gChromeNet.Get().get()];
77 gChromeNet.Get()->Start(); 186 gChromeNet.Get()->Start();
187 gHttpProtocolHandlerDelegate.reset(new CronetHttpProtocolHandlerDelegate(
188 gChromeNet.Get()->GetURLRequestContextGetter(), gRequestFilterBlock));
189 net::HTTPProtocolHandlerDelegate::SetInstance(
190 gHttpProtocolHandlerDelegate.get());
191 gRequestFilterBlock = nil;
78 } 192 }
79 193
80 + (void)start { 194 + (void)start {
81 static dispatch_once_t onceToken; 195 static dispatch_once_t onceToken;
82 dispatch_once(&onceToken, ^{ 196 dispatch_once(&onceToken, ^{
83 if (![NSThread isMainThread]) { 197 if (![NSThread isMainThread]) {
84 dispatch_sync(dispatch_get_main_queue(), ^(void) { 198 dispatch_sync(dispatch_get_main_queue(), ^(void) {
85 [self startInternal]; 199 [self startInternal];
86 }); 200 });
87 } else { 201 } else {
88 [self startInternal]; 202 [self startInternal];
89 } 203 }
90 }); 204 });
91 } 205 }
92 206
207 + (void)registerHttpProtocolHandler {
208 if (gPreservedSharedURLCache == nil) {
209 gPreservedSharedURLCache = [NSURLCache sharedURLCache];
210 }
211 // Disable the default cache.
212 [NSURLCache setSharedURLCache:[EmptyNSURLCache emptyNSURLCache]];
213 // Register the chrome http protocol handler to replace the default one.
214 BOOL success =
215 [NSURLProtocol registerClass:[CRNPauseableHTTPProtocolHandler class]];
216 DCHECK(success);
217 }
218
219 + (void)unregisterHttpProtocolHandler {
220 // Set up SharedURLCache preserved in registerHttpProtocolHandler.
221 if (gPreservedSharedURLCache != nil) {
222 [NSURLCache setSharedURLCache:gPreservedSharedURLCache];
223 gPreservedSharedURLCache = nil;
224 }
225 [NSURLProtocol unregisterClass:[CRNPauseableHTTPProtocolHandler class]];
226 }
227
228 + (void)installIntoSessionConfiguration:(NSURLSessionConfiguration*)config {
229 config.protocolClasses = @[ [CRNPauseableHTTPProtocolHandler class] ];
kapishnikov 2016/10/19 18:28:53 Should we append to the list of protocols rather t
mef 2016/10/19 20:12:59 But wouldn't this require Cronet to handle that cu
kapishnikov 2016/10/19 21:12:29 Cronet handles "http://", "https://" and "data://"
230 }
231
93 + (void)startNetLogToFile:(NSString*)fileName logBytes:(BOOL)logBytes { 232 + (void)startNetLogToFile:(NSString*)fileName logBytes:(BOOL)logBytes {
94 if (gChromeNet.Get().get() && [fileName length]) { 233 if (gChromeNet.Get().get() && [fileName length]) {
95 gChromeNet.Get()->StartNetLog([fileName UTF8String], logBytes); 234 gChromeNet.Get()->StartNetLog([fileName UTF8String], logBytes);
96 } 235 }
97 } 236 }
98 237
99 + (void)stopNetLog { 238 + (void)stopNetLog {
100 if (gChromeNet.Get().get()) { 239 if (gChromeNet.Get().get()) {
101 gChromeNet.Get()->StopNetLog(); 240 gChromeNet.Get()->StopNetLog();
102 } 241 }
(...skipping 11 matching lines...) Expand all
114 + (cronet_engine*)getGlobalEngine { 253 + (cronet_engine*)getGlobalEngine {
115 DCHECK(gChromeNet.Get().get()); 254 DCHECK(gChromeNet.Get().get());
116 if (gChromeNet.Get().get()) { 255 if (gChromeNet.Get().get()) {
117 static cronet_engine engine; 256 static cronet_engine engine;
118 engine.obj = gChromeNet.Get().get(); 257 engine.obj = gChromeNet.Get().get();
119 return &engine; 258 return &engine;
120 } 259 }
121 return nil; 260 return nil;
122 } 261 }
123 262
263 + (NSData*)getGlobalMetricsDeltas {
264 if (!gChromeNet.Get().get()) {
265 return nil;
266 }
267 std::vector<uint8_t> deltas(gChromeNet.Get()->GetHistogramDeltas());
268 return [NSData dataWithBytes:deltas.data() length:deltas.size()];
269 }
270
271 + (void)enableTestCertVerifierForTesting {
272 gEnableTestCertVerifierForTesting = TRUE;
kapishnikov 2016/10/19 18:28:53 TRUE -> YES
mef 2016/10/19 20:12:58 Done.
273 }
274
275 + (void)setHostResolverRulesForTesting:(NSString*)hostResolverRulesForTesting {
276 gHostResolverRulesForTesting = hostResolverRulesForTesting;
277 }
278
124 // This is a non-public dummy method that prevents the linker from stripping out 279 // This is a non-public dummy method that prevents the linker from stripping out
125 // the otherwise non-referenced methods from 'cronet_bidirectional_stream.cc'. 280 // the otherwise non-referenced methods from 'cronet_bidirectional_stream.cc'.
126 + (void)preventStrippingCronetBidirectionalStream { 281 + (void)preventStrippingCronetBidirectionalStream {
127 cronet_bidirectional_stream_create(NULL, 0, 0); 282 cronet_bidirectional_stream_create(NULL, 0, 0);
128 } 283 }
129 284
130 @end 285 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698