OLD | NEW |
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" |
| 16 #include "base/synchronization/lock.h" |
13 #include "components/cronet/ios/cronet_environment.h" | 17 #include "components/cronet/ios/cronet_environment.h" |
14 #include "components/cronet/url_request_context_config.h" | 18 #include "components/cronet/url_request_context_config.h" |
| 19 #include "ios/net/crn_http_protocol_handler.h" |
| 20 #include "ios/net/empty_nsurlcache.h" |
| 21 #include "net/cert/cert_verifier.h" |
| 22 #include "net/url_request/url_request_context_getter.h" |
15 | 23 |
16 namespace { | 24 namespace { |
17 | 25 |
| 26 class CronetHttpProtocolHandlerDelegate; |
| 27 |
18 // Currently there is one and only one instance of CronetEnvironment, | 28 // Currently there is one and only one instance of CronetEnvironment, |
19 // which is leaked at the shutdown. We should consider allowing multiple | 29 // which is leaked at the shutdown. We should consider allowing multiple |
20 // instances if that makes sense in the future. | 30 // instances if that makes sense in the future. |
21 base::LazyInstance<std::unique_ptr<cronet::CronetEnvironment>>::Leaky | 31 base::LazyInstance<std::unique_ptr<cronet::CronetEnvironment>>::Leaky |
22 gChromeNet = LAZY_INSTANCE_INITIALIZER; | 32 gChromeNet = LAZY_INSTANCE_INITIALIZER; |
23 | 33 |
24 BOOL gHttp2Enabled = YES; | 34 BOOL gHttp2Enabled = YES; |
25 BOOL gQuicEnabled = NO; | 35 BOOL gQuicEnabled = NO; |
26 ScopedVector<cronet::URLRequestContextConfig::QuicHint> gQuicHints; | 36 ScopedVector<cronet::URLRequestContextConfig::QuicHint> gQuicHints; |
27 NSString* gUserAgent = nil; | 37 NSString* gUserAgent = nil; |
| 38 BOOL gUserAgentPartial = NO; |
28 NSString* gSslKeyLogFileName = nil; | 39 NSString* gSslKeyLogFileName = nil; |
| 40 RequestFilterBlock gRequestFilterBlock = nil; |
| 41 std::unique_ptr<CronetHttpProtocolHandlerDelegate> gHttpProtocolHandlerDelegate; |
| 42 NSURLCache* gPreservedSharedURLCache = nil; |
| 43 BOOL gEnableTestCertVerifierForTesting = FALSE; |
| 44 NSString* gHostResolverRulesForTesting = @""; |
| 45 |
| 46 // CertVerifier, which allows any certificates for testing. |
| 47 class TestCertVerifier : public net::CertVerifier { |
| 48 int Verify(const RequestParams& params, |
| 49 net::CRLSet* crl_set, |
| 50 net::CertVerifyResult* verify_result, |
| 51 const net::CompletionCallback& callback, |
| 52 std::unique_ptr<Request>* out_req, |
| 53 const net::NetLogWithSource& net_log) override { |
| 54 net::Error result = net::OK; |
| 55 verify_result->verified_cert = params.certificate(); |
| 56 verify_result->cert_status = net::MapNetErrorToCertStatus(result); |
| 57 return result; |
| 58 } |
| 59 }; |
| 60 |
| 61 // net::HTTPProtocolHandlerDelegate for Cronet. |
| 62 class CronetHttpProtocolHandlerDelegate |
| 63 : public net::HTTPProtocolHandlerDelegate { |
| 64 public: |
| 65 CronetHttpProtocolHandlerDelegate(net::URLRequestContextGetter* getter, |
| 66 RequestFilterBlock filter) |
| 67 : getter_(getter), filter_(filter, base::scoped_policy::RETAIN) {} |
| 68 |
| 69 void SetRequestFilterBlock(RequestFilterBlock filter) { |
| 70 base::AutoLock auto_lock(lock_); |
| 71 filter_.reset(filter); |
| 72 } |
| 73 |
| 74 private: |
| 75 // net::HTTPProtocolHandlerDelegate implementation: |
| 76 bool CanHandleRequest(NSURLRequest* request) override { |
| 77 base::AutoLock auto_lock(lock_); |
| 78 if (filter_) { |
| 79 RequestFilterBlock block = filter_.get(); |
| 80 return block(request); |
| 81 } |
| 82 return true; |
| 83 } |
| 84 |
| 85 bool IsRequestSupported(NSURLRequest* request) override { |
| 86 NSString* scheme = [[request URL] scheme]; |
| 87 if (!scheme) |
| 88 return false; |
| 89 return [scheme caseInsensitiveCompare:@"data"] == NSOrderedSame || |
| 90 [scheme caseInsensitiveCompare:@"http"] == NSOrderedSame || |
| 91 [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame; |
| 92 } |
| 93 |
| 94 net::URLRequestContextGetter* GetDefaultURLRequestContext() override { |
| 95 return getter_.get(); |
| 96 } |
| 97 |
| 98 scoped_refptr<net::URLRequestContextGetter> getter_; |
| 99 base::mac::ScopedBlock<RequestFilterBlock> filter_; |
| 100 base::Lock lock_; |
| 101 }; |
29 | 102 |
30 } // namespace | 103 } // namespace |
31 | 104 |
32 @implementation Cronet | 105 @implementation Cronet |
33 | 106 |
| 107 + (void)configureCronetEnvironmentForTesting: |
| 108 (cronet::CronetEnvironment*)cronetEnvironment { |
| 109 cronetEnvironment->set_host_resolver_rules( |
| 110 [gHostResolverRulesForTesting UTF8String]); |
| 111 if (gEnableTestCertVerifierForTesting) { |
| 112 std::unique_ptr<TestCertVerifier> test_cert_verifier = |
| 113 base::MakeUnique<TestCertVerifier>(); |
| 114 cronetEnvironment->set_cert_verifier(std::move(test_cert_verifier)); |
| 115 } |
| 116 } |
| 117 |
| 118 + (NSString*)getAcceptLanguages { |
| 119 // Use the framework bundle to search for resources. |
| 120 NSBundle* frameworkBundle = [NSBundle bundleForClass:self]; |
| 121 NSString* bundlePath = |
| 122 [frameworkBundle pathForResource:@"cronet_resources" ofType:@"bundle"]; |
| 123 NSBundle* bundle = [NSBundle bundleWithPath:bundlePath]; |
| 124 NSString* acceptLanguages = NSLocalizedStringWithDefaultValue( |
| 125 @"IDS_ACCEPT_LANGUAGES", @"Localizable", bundle, @"en-US,en", |
| 126 @"These values are copied from Chrome's .xtb files, so the same " |
| 127 "values are used in the |Accept-Language| header. Key name matches " |
| 128 "Chrome's."); |
| 129 if (acceptLanguages == Nil) |
| 130 acceptLanguages = @""; |
| 131 return acceptLanguages; |
| 132 } |
| 133 |
34 + (void)checkNotStarted { | 134 + (void)checkNotStarted { |
35 CHECK(gChromeNet == NULL) << "Cronet is already started."; | 135 CHECK(gChromeNet == NULL) << "Cronet is already started."; |
36 } | 136 } |
37 | 137 |
38 + (void)setHttp2Enabled:(BOOL)http2Enabled { | 138 + (void)setHttp2Enabled:(BOOL)http2Enabled { |
39 [self checkNotStarted]; | 139 [self checkNotStarted]; |
40 gHttp2Enabled = http2Enabled; | 140 gHttp2Enabled = http2Enabled; |
41 } | 141 } |
42 | 142 |
43 + (void)setQuicEnabled:(BOOL)quicEnabled { | 143 + (void)setQuicEnabled:(BOOL)quicEnabled { |
44 [self checkNotStarted]; | 144 [self checkNotStarted]; |
45 gQuicEnabled = quicEnabled; | 145 gQuicEnabled = quicEnabled; |
46 } | 146 } |
47 | 147 |
48 + (void)addQuicHint:(NSString*)host port:(int)port altPort:(int)altPort { | 148 + (void)addQuicHint:(NSString*)host port:(int)port altPort:(int)altPort { |
49 [self checkNotStarted]; | 149 [self checkNotStarted]; |
50 gQuicHints.push_back(new cronet::URLRequestContextConfig::QuicHint( | 150 gQuicHints.push_back(new cronet::URLRequestContextConfig::QuicHint( |
51 base::SysNSStringToUTF8(host), port, altPort)); | 151 base::SysNSStringToUTF8(host), port, altPort)); |
52 } | 152 } |
53 | 153 |
54 + (void)setPartialUserAgent:(NSString*)userAgent { | 154 + (void)setUserAgent:(NSString*)userAgent partial:(BOOL)partial { |
55 [self checkNotStarted]; | 155 [self checkNotStarted]; |
56 gUserAgent = userAgent; | 156 gUserAgent = userAgent; |
| 157 gUserAgentPartial = partial; |
57 } | 158 } |
58 | 159 |
59 + (void)setSslKeyLogFileName:(NSString*)sslKeyLogFileName { | 160 + (void)setSslKeyLogFileName:(NSString*)sslKeyLogFileName { |
60 [self checkNotStarted]; | 161 [self checkNotStarted]; |
61 gSslKeyLogFileName = sslKeyLogFileName; | 162 gSslKeyLogFileName = sslKeyLogFileName; |
62 } | 163 } |
63 | 164 |
| 165 + (void)setRequestFilterBlock:(RequestFilterBlock)block { |
| 166 if (gHttpProtocolHandlerDelegate.get()) |
| 167 gHttpProtocolHandlerDelegate.get()->SetRequestFilterBlock(block); |
| 168 else |
| 169 gRequestFilterBlock = block; |
| 170 } |
| 171 |
64 + (void)startInternal { | 172 + (void)startInternal { |
65 cronet::CronetEnvironment::Initialize(); | 173 cronet::CronetEnvironment::Initialize(); |
66 std::string partialUserAgent = base::SysNSStringToUTF8(gUserAgent); | 174 std::string user_agent = base::SysNSStringToUTF8(gUserAgent); |
67 gChromeNet.Get().reset(new cronet::CronetEnvironment(partialUserAgent)); | 175 gChromeNet.Get().reset( |
| 176 new cronet::CronetEnvironment(user_agent, gUserAgentPartial)); |
| 177 gChromeNet.Get()->set_accept_language( |
| 178 base::SysNSStringToUTF8([self getAcceptLanguages])); |
68 | 179 |
69 gChromeNet.Get()->set_http2_enabled(gHttp2Enabled); | 180 gChromeNet.Get()->set_http2_enabled(gHttp2Enabled); |
70 gChromeNet.Get()->set_quic_enabled(gQuicEnabled); | 181 gChromeNet.Get()->set_quic_enabled(gQuicEnabled); |
71 gChromeNet.Get()->set_ssl_key_log_file_name( | 182 gChromeNet.Get()->set_ssl_key_log_file_name( |
72 base::SysNSStringToUTF8(gSslKeyLogFileName)); | 183 base::SysNSStringToUTF8(gSslKeyLogFileName)); |
73 for (const auto* quicHint : gQuicHints) { | 184 for (const auto* quicHint : gQuicHints) { |
74 gChromeNet.Get()->AddQuicHint(quicHint->host, quicHint->port, | 185 gChromeNet.Get()->AddQuicHint(quicHint->host, quicHint->port, |
75 quicHint->alternate_port); | 186 quicHint->alternate_port); |
76 } | 187 } |
| 188 |
| 189 [self configureCronetEnvironmentForTesting:gChromeNet.Get().get()]; |
77 gChromeNet.Get()->Start(); | 190 gChromeNet.Get()->Start(); |
| 191 gHttpProtocolHandlerDelegate.reset(new CronetHttpProtocolHandlerDelegate( |
| 192 gChromeNet.Get()->GetURLRequestContextGetter(), gRequestFilterBlock)); |
| 193 net::HTTPProtocolHandlerDelegate::SetInstance( |
| 194 gHttpProtocolHandlerDelegate.get()); |
| 195 gRequestFilterBlock = nil; |
78 } | 196 } |
79 | 197 |
80 + (void)start { | 198 + (void)start { |
81 static dispatch_once_t onceToken; | 199 static dispatch_once_t onceToken; |
82 dispatch_once(&onceToken, ^{ | 200 dispatch_once(&onceToken, ^{ |
83 if (![NSThread isMainThread]) { | 201 if (![NSThread isMainThread]) { |
84 dispatch_sync(dispatch_get_main_queue(), ^(void) { | 202 dispatch_sync(dispatch_get_main_queue(), ^(void) { |
85 [self startInternal]; | 203 [self startInternal]; |
86 }); | 204 }); |
87 } else { | 205 } else { |
88 [self startInternal]; | 206 [self startInternal]; |
89 } | 207 } |
90 }); | 208 }); |
91 } | 209 } |
92 | 210 |
| 211 + (void)registerHttpProtocolHandler { |
| 212 if (gPreservedSharedURLCache == nil) { |
| 213 gPreservedSharedURLCache = [NSURLCache sharedURLCache]; |
| 214 } |
| 215 // Disable the default cache. |
| 216 [NSURLCache setSharedURLCache:[EmptyNSURLCache emptyNSURLCache]]; |
| 217 // Register the chrome http protocol handler to replace the default one. |
| 218 BOOL success = |
| 219 [NSURLProtocol registerClass:[CRNPauseableHTTPProtocolHandler class]]; |
| 220 DCHECK(success); |
| 221 } |
| 222 |
| 223 + (void)unregisterHttpProtocolHandler { |
| 224 // Set up SharedURLCache preserved in registerHttpProtocolHandler. |
| 225 if (gPreservedSharedURLCache != nil) { |
| 226 [NSURLCache setSharedURLCache:gPreservedSharedURLCache]; |
| 227 gPreservedSharedURLCache = nil; |
| 228 } |
| 229 [NSURLProtocol unregisterClass:[CRNPauseableHTTPProtocolHandler class]]; |
| 230 } |
| 231 |
| 232 + (void)installIntoSessionConfiguration:(NSURLSessionConfiguration*)config { |
| 233 config.protocolClasses = @[ [CRNPauseableHTTPProtocolHandler class] ]; |
| 234 } |
| 235 |
93 + (void)startNetLogToFile:(NSString*)fileName logBytes:(BOOL)logBytes { | 236 + (void)startNetLogToFile:(NSString*)fileName logBytes:(BOOL)logBytes { |
94 if (gChromeNet.Get().get() && [fileName length]) { | 237 if (gChromeNet.Get().get() && [fileName length]) { |
95 gChromeNet.Get()->StartNetLog([fileName UTF8String], logBytes); | 238 gChromeNet.Get()->StartNetLog([fileName UTF8String], logBytes); |
96 } | 239 } |
97 } | 240 } |
98 | 241 |
99 + (void)stopNetLog { | 242 + (void)stopNetLog { |
100 if (gChromeNet.Get().get()) { | 243 if (gChromeNet.Get().get()) { |
101 gChromeNet.Get()->StopNetLog(); | 244 gChromeNet.Get()->StopNetLog(); |
102 } | 245 } |
(...skipping 11 matching lines...) Expand all Loading... |
114 + (cronet_engine*)getGlobalEngine { | 257 + (cronet_engine*)getGlobalEngine { |
115 DCHECK(gChromeNet.Get().get()); | 258 DCHECK(gChromeNet.Get().get()); |
116 if (gChromeNet.Get().get()) { | 259 if (gChromeNet.Get().get()) { |
117 static cronet_engine engine; | 260 static cronet_engine engine; |
118 engine.obj = gChromeNet.Get().get(); | 261 engine.obj = gChromeNet.Get().get(); |
119 return &engine; | 262 return &engine; |
120 } | 263 } |
121 return nil; | 264 return nil; |
122 } | 265 } |
123 | 266 |
| 267 + (NSData*)getGlobalMetricsDeltas { |
| 268 if (!gChromeNet.Get().get()) { |
| 269 return nil; |
| 270 } |
| 271 std::vector<uint8_t> deltas(gChromeNet.Get()->GetHistogramDeltas()); |
| 272 return [NSData dataWithBytes:deltas.data() length:deltas.size()]; |
| 273 } |
| 274 |
| 275 + (void)enableTestCertVerifierForTesting { |
| 276 gEnableTestCertVerifierForTesting = YES; |
| 277 } |
| 278 |
| 279 + (void)setHostResolverRulesForTesting:(NSString*)hostResolverRulesForTesting { |
| 280 gHostResolverRulesForTesting = hostResolverRulesForTesting; |
| 281 } |
| 282 |
124 // This is a non-public dummy method that prevents the linker from stripping out | 283 // 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'. | 284 // the otherwise non-referenced methods from 'cronet_bidirectional_stream.cc'. |
126 + (void)preventStrippingCronetBidirectionalStream { | 285 + (void)preventStrippingCronetBidirectionalStream { |
127 cronet_bidirectional_stream_create(NULL, 0, 0); | 286 cronet_bidirectional_stream_create(NULL, 0, 0); |
128 } | 287 } |
129 | 288 |
130 @end | 289 @end |
OLD | NEW |