mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "components/cronet/ios/cronet_environment.h" |
| 6 | |
| 7 | #include <utility> |
| 8 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 9 | #include "base/atomicops.h" |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 10 | #include "base/bind.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 11 | #include "base/command_line.h" |
kapishnikov | f7b51309 | 2016-07-08 23:42:55 | [diff] [blame] | 12 | #include "base/feature_list.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 13 | #include "base/files/file_path.h" |
| 14 | #include "base/files/file_util.h" |
Eric Roman | 8470292 | 2017-07-11 19:07:37 | [diff] [blame] | 15 | #include "base/files/scoped_file.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 16 | #include "base/mac/foundation_util.h" |
| 17 | #include "base/macros.h" |
Alexander Timin | 4f9c35c | 2018-11-01 20:15:20 | [diff] [blame] | 18 | #include "base/message_loop/message_loop.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 19 | #include "base/path_service.h" |
fdoray | 6ef45cf | 2016-08-25 15:36:37 | [diff] [blame] | 20 | #include "base/single_thread_task_runner.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 21 | #include "base/synchronization/waitable_event.h" |
kapishnikov | 46532f3 | 2017-10-23 08:54:46 | [diff] [blame] | 22 | #include "base/threading/thread_restrictions.h" |
Misha Efimov | a0b0fe61 | 2018-10-02 14:23:44 | [diff] [blame] | 23 | #include "components/cronet/cronet_buildflags.h" |
Paul Jensen | 6a1ea3a | 2018-08-24 14:46:41 | [diff] [blame] | 24 | #include "components/cronet/cronet_global_state.h" |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 25 | #include "components/cronet/cronet_prefs_manager.h" |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 26 | #include "components/cronet/histogram_manager.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 27 | #include "components/prefs/pref_filter.h" |
mef | 3c84be9 | 2016-11-19 00:06:56 | [diff] [blame] | 28 | #include "ios/net/cookies/cookie_store_ios.h" |
Mohammad Refaat | 4103280 | 2017-10-06 04:15:57 | [diff] [blame] | 29 | #include "ios/net/cookies/cookie_store_ios_client.h" |
Mike Dougherty | e10717185 | 2017-07-12 17:56:25 | [diff] [blame] | 30 | #include "ios/web/public/global_state/ios_global_state.h" |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 31 | #include "ios/web/public/global_state/ios_global_state_configuration.h" |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 32 | #include "ios/web/public/user_agent.h" |
Matt Menke | d732ea4 | 2019-03-08 12:05:00 | [diff] [blame] | 33 | #include "net/base/http_user_agent_settings.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 34 | #include "net/base/network_change_notifier.h" |
Lily Houghton | 5a1a911 | 2017-08-10 17:21:55 | [diff] [blame] | 35 | #include "net/base/url_util.h" |
mef | 4c515e14 | 2016-09-06 18:16:30 | [diff] [blame] | 36 | #include "net/cert/cert_verifier.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 37 | #include "net/dns/host_resolver.h" |
| 38 | #include "net/dns/mapped_host_resolver.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 39 | #include "net/http/http_server_properties_impl.h" |
| 40 | #include "net/http/http_stream_factory.h" |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 41 | #include "net/http/http_transaction_factory.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 42 | #include "net/http/http_util.h" |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 43 | #include "net/log/file_net_log_observer.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 44 | #include "net/log/net_log.h" |
mikecirone | f22f981 | 2016-10-04 03:40:19 | [diff] [blame] | 45 | #include "net/log/net_log_capture_mode.h" |
kapishnikov | d0c6860 | 2017-08-31 02:50:50 | [diff] [blame] | 46 | #include "net/log/net_log_util.h" |
Lily Houghton | ffe89daa0 | 2018-03-09 18:30:03 | [diff] [blame] | 47 | #include "net/proxy_resolution/proxy_resolution_service.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 48 | #include "net/socket/ssl_client_socket.h" |
mef | 2989c37 | 2017-01-06 18:35:59 | [diff] [blame] | 49 | #include "net/ssl/channel_id_service.h" |
David Benjamin | bd37c17 | 2018-07-11 17:24:57 | [diff] [blame] | 50 | #include "net/ssl/ssl_key_logger_impl.h" |
Victor Vasiliev | 6bb59d2 | 2019-03-08 21:34:51 | [diff] [blame] | 51 | #include "net/third_party/quiche/src/quic/core/quic_versions.h" |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 52 | #include "net/url_request/url_request_context.h" |
| 53 | #include "net/url_request/url_request_context_builder.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 54 | #include "net/url_request/url_request_context_storage.h" |
| 55 | #include "net/url_request/url_request_job_factory_impl.h" |
zhongyi | 3d4a55e7 | 2016-04-22 20:36:46 | [diff] [blame] | 56 | #include "url/scheme_host_port.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 57 | #include "url/url_util.h" |
| 58 | |
kapishnikov | bd67093 | 2017-10-13 16:57:38 | [diff] [blame] | 59 | #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 60 | #error "This file requires ARC support." |
| 61 | #endif |
| 62 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 63 | namespace { |
| 64 | |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 65 | // Request context getter for Cronet. |
| 66 | class CronetURLRequestContextGetter : public net::URLRequestContextGetter { |
| 67 | public: |
| 68 | CronetURLRequestContextGetter( |
| 69 | cronet::CronetEnvironment* environment, |
| 70 | const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
| 71 | : environment_(environment), task_runner_(task_runner) {} |
| 72 | |
| 73 | net::URLRequestContext* GetURLRequestContext() override { |
| 74 | DCHECK(environment_); |
| 75 | return environment_->GetURLRequestContext(); |
| 76 | } |
| 77 | |
| 78 | scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() |
| 79 | const override { |
| 80 | return task_runner_; |
| 81 | } |
| 82 | |
| 83 | private: |
| 84 | // Must be called on the IO thread. |
| 85 | ~CronetURLRequestContextGetter() override {} |
| 86 | |
| 87 | cronet::CronetEnvironment* environment_; |
| 88 | scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 89 | DISALLOW_COPY_AND_ASSIGN(CronetURLRequestContextGetter); |
| 90 | }; |
| 91 | |
Mohammad Refaat | 4103280 | 2017-10-06 04:15:57 | [diff] [blame] | 92 | // Cronet implementation of net::CookieStoreIOSClient. |
| 93 | // Used to provide Cronet Network IO TaskRunner. |
| 94 | class CronetCookieStoreIOSClient : public net::CookieStoreIOSClient { |
| 95 | public: |
| 96 | CronetCookieStoreIOSClient( |
| 97 | const scoped_refptr<base::SequencedTaskRunner>& task_runner) |
| 98 | : task_runner_(task_runner) {} |
| 99 | |
| 100 | scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override { |
| 101 | return task_runner_; |
| 102 | } |
| 103 | |
| 104 | private: |
| 105 | ~CronetCookieStoreIOSClient() override {} |
| 106 | |
| 107 | scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 108 | DISALLOW_COPY_AND_ASSIGN(CronetCookieStoreIOSClient); |
| 109 | }; |
| 110 | |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 111 | void SignalEvent(base::WaitableEvent* event) { |
| 112 | event->Signal(); |
| 113 | } |
| 114 | |
| 115 | // TODO(eroman): Creating the file(s) for a netlog is an internal detail for |
| 116 | // FileNetLogObsever. This code assumes that the unbounded format is being used, |
| 117 | // which writes a single file at |path| (creating or overwriting it). |
| 118 | bool IsNetLogPathValid(const base::FilePath& path) { |
| 119 | base::ScopedFILE file(base::OpenFile(path, "w")); |
| 120 | return !!file; |
| 121 | } |
| 122 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 123 | } // namespace |
| 124 | |
| 125 | namespace cronet { |
| 126 | |
kapishnikov | 9f98c43 | 2018-01-12 23:24:08 | [diff] [blame] | 127 | const double CronetEnvironment::kKeepDefaultThreadPriority = -1; |
| 128 | |
| 129 | base::SingleThreadTaskRunner* CronetEnvironment::GetNetworkThreadTaskRunner() |
| 130 | const { |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 131 | if (network_io_thread_) { |
| 132 | return network_io_thread_->task_runner().get(); |
| 133 | } |
| 134 | return ios_global_state::GetSharedNetworkIOThreadTaskRunner().get(); |
| 135 | } |
| 136 | |
Brett Wilson | 190fd2ac | 2017-09-12 05:04:30 | [diff] [blame] | 137 | void CronetEnvironment::PostToNetworkThread(const base::Location& from_here, |
| 138 | const base::Closure& task) { |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 139 | GetNetworkThreadTaskRunner()->PostTask(from_here, task); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 140 | } |
| 141 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 142 | net::URLRequestContext* CronetEnvironment::GetURLRequestContext() const { |
| 143 | return main_context_.get(); |
| 144 | } |
| 145 | |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 146 | net::URLRequestContextGetter* CronetEnvironment::GetURLRequestContextGetter() |
| 147 | const { |
| 148 | return main_context_getter_.get(); |
| 149 | } |
| 150 | |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 151 | bool CronetEnvironment::StartNetLog(base::FilePath::StringType file_name, |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 152 | bool log_bytes) { |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 153 | if (file_name.empty()) |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 154 | return false; |
| 155 | |
| 156 | base::FilePath path(file_name); |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 157 | if (!IsNetLogPathValid(path)) { |
Eric Roman | 8470292 | 2017-07-11 19:07:37 | [diff] [blame] | 158 | LOG(ERROR) << "Can not start NetLog to " << path.value() << ": " |
| 159 | << strerror(errno); |
| 160 | return false; |
| 161 | } |
| 162 | |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 163 | LOG(WARNING) << "Starting NetLog to " << path.value(); |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 164 | PostToNetworkThread(FROM_HERE, |
| 165 | base::Bind(&CronetEnvironment::StartNetLogOnNetworkThread, |
| 166 | base::Unretained(this), path, log_bytes)); |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 167 | |
| 168 | return true; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 169 | } |
| 170 | |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 171 | void CronetEnvironment::StartNetLogOnNetworkThread(const base::FilePath& path, |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 172 | bool log_bytes) { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 173 | DCHECK(net_log_); |
| 174 | |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 175 | if (file_net_log_observer_) |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 176 | return; |
| 177 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 178 | net::NetLogCaptureMode capture_mode = |
| 179 | log_bytes ? net::NetLogCaptureMode::IncludeSocketBytes() |
| 180 | : net::NetLogCaptureMode::Default(); |
| 181 | |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 182 | file_net_log_observer_ = |
| 183 | net::FileNetLogObserver::CreateUnbounded(path, nullptr); |
| 184 | file_net_log_observer_->StartObserving(main_context_->net_log(), |
| 185 | capture_mode); |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 186 | LOG(WARNING) << "Started NetLog"; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | void CronetEnvironment::StopNetLog() { |
gab | 5600d5b | 2016-06-08 21:44:41 | [diff] [blame] | 190 | base::WaitableEvent log_stopped_event( |
| 191 | base::WaitableEvent::ResetPolicy::MANUAL, |
| 192 | base::WaitableEvent::InitialState::NOT_SIGNALED); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 193 | PostToNetworkThread(FROM_HERE, |
| 194 | base::Bind(&CronetEnvironment::StopNetLogOnNetworkThread, |
| 195 | base::Unretained(this), &log_stopped_event)); |
| 196 | log_stopped_event.Wait(); |
| 197 | } |
| 198 | |
| 199 | void CronetEnvironment::StopNetLogOnNetworkThread( |
| 200 | base::WaitableEvent* log_stopped_event) { |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 201 | if (file_net_log_observer_) { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 202 | DLOG(WARNING) << "Stopped NetLog."; |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 203 | file_net_log_observer_->StopObserving( |
kapishnikov | d0c6860 | 2017-08-31 02:50:50 | [diff] [blame] | 204 | GetNetLogInfo(), base::BindOnce(&SignalEvent, log_stopped_event)); |
Misha Efimov | a33615a | 2017-07-12 19:47:15 | [diff] [blame] | 205 | file_net_log_observer_.reset(); |
| 206 | } else { |
| 207 | log_stopped_event->Signal(); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 208 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 209 | } |
| 210 | |
kapishnikov | d0c6860 | 2017-08-31 02:50:50 | [diff] [blame] | 211 | std::unique_ptr<base::DictionaryValue> CronetEnvironment::GetNetLogInfo() |
| 212 | const { |
| 213 | std::unique_ptr<base::DictionaryValue> net_info = |
| 214 | net::GetNetInfo(main_context_.get(), net::NET_INFO_ALL_SOURCES); |
| 215 | if (effective_experimental_options_) { |
| 216 | net_info->Set("cronetExperimentalParams", |
| 217 | effective_experimental_options_->CreateDeepCopy()); |
| 218 | } |
| 219 | return net_info; |
| 220 | } |
| 221 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 222 | net::HttpNetworkSession* CronetEnvironment::GetHttpNetworkSession( |
| 223 | net::URLRequestContext* context) { |
| 224 | DCHECK(context); |
| 225 | if (!context->http_transaction_factory()) |
| 226 | return nullptr; |
| 227 | |
| 228 | return context->http_transaction_factory()->GetSession(); |
| 229 | } |
| 230 | |
| 231 | void CronetEnvironment::AddQuicHint(const std::string& host, |
| 232 | int port, |
| 233 | int alternate_port) { |
| 234 | DCHECK(port == alternate_port); |
| 235 | quic_hints_.push_back(net::HostPortPair(host, port)); |
| 236 | } |
| 237 | |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 238 | CronetEnvironment::CronetEnvironment(const std::string& user_agent, |
| 239 | bool user_agent_partial) |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 240 | : http2_enabled_(false), |
| 241 | quic_enabled_(false), |
Brad Lassey | 250b624 | 2017-07-10 14:19:57 | [diff] [blame] | 242 | brotli_enabled_(false), |
lilyhoughton | 5ed6b50f | 2017-01-19 22:04:04 | [diff] [blame] | 243 | http_cache_(URLRequestContextConfig::HttpCacheType::DISK), |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 244 | user_agent_(user_agent), |
| 245 | user_agent_partial_(user_agent_partial), |
lilyhoughton | 41c31a68 | 2017-06-28 16:54:09 | [diff] [blame] | 246 | net_log_(new net::NetLog), |
kapishnikov | 9f98c43 | 2018-01-12 23:24:08 | [diff] [blame] | 247 | enable_pkp_bypass_for_local_trust_anchors_(true), |
| 248 | network_thread_priority_(kKeepDefaultThreadPriority) {} |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 249 | |
| 250 | void CronetEnvironment::Start() { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 251 | // Threads setup. |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 252 | file_thread_.reset(new base::Thread("Chrome File Thread")); |
| 253 | file_thread_->StartWithOptions( |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 254 | base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 255 | // Fetching the task_runner will create the shared thread if necessary. |
| 256 | scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| 257 | ios_global_state::GetSharedNetworkIOThreadTaskRunner(); |
| 258 | if (!task_runner) { |
kapishnikov | 2633388 | 2017-09-08 14:25:56 | [diff] [blame] | 259 | network_io_thread_.reset( |
| 260 | new CronetNetworkThread("Chrome Network IO Thread", this)); |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 261 | network_io_thread_->StartWithOptions( |
| 262 | base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| 263 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 264 | |
Mohammad Refaat | 4103280 | 2017-10-06 04:15:57 | [diff] [blame] | 265 | net::SetCookieStoreIOSClient(new CronetCookieStoreIOSClient( |
| 266 | CronetEnvironment::GetNetworkThreadTaskRunner())); |
| 267 | |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 268 | main_context_getter_ = new CronetURLRequestContextGetter( |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 269 | this, CronetEnvironment::GetNetworkThreadTaskRunner()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 270 | base::subtle::MemoryBarrier(); |
| 271 | PostToNetworkThread(FROM_HERE, |
| 272 | base::Bind(&CronetEnvironment::InitializeOnNetworkThread, |
| 273 | base::Unretained(this))); |
| 274 | } |
| 275 | |
kapishnikov | 2633388 | 2017-09-08 14:25:56 | [diff] [blame] | 276 | void CronetEnvironment::CleanUpOnNetworkThread() { |
lilyhoughton | 94bde17 | 2017-05-08 17:25:16 | [diff] [blame] | 277 | // TODO(lilyhoughton) make unregistering of this work. |
mef | 3c84be9 | 2016-11-19 00:06:56 | [diff] [blame] | 278 | // net::HTTPProtocolHandlerDelegate::SetInstance(nullptr); |
lilyhoughton | 8c4ab79 | 2017-01-18 15:34:15 | [diff] [blame] | 279 | |
lilyhoughton | 94bde17 | 2017-05-08 17:25:16 | [diff] [blame] | 280 | // TODO(lilyhoughton) this can only be run once, so right now leaking it. |
| 281 | // Should be be called when the _last_ CronetEnvironment is destroyed. |
| 282 | // base::TaskScheduler* ts = base::TaskScheduler::GetInstance(); |
| 283 | // if (ts) |
| 284 | // ts->Shutdown(); |
| 285 | |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 286 | if (cronet_prefs_manager_) { |
| 287 | cronet_prefs_manager_->PrepareForShutdown(); |
| 288 | } |
| 289 | |
Matt Menke | 258cfcb | 2017-10-05 22:54:32 | [diff] [blame] | 290 | // TODO(lilyhoughton) this should be smarter about making sure there are no |
| 291 | // pending requests, etc. |
| 292 | main_context_.reset(); |
| 293 | |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 294 | // cronet_prefs_manager_ should be deleted on the network thread. |
kapishnikov | 2633388 | 2017-09-08 14:25:56 | [diff] [blame] | 295 | cronet_prefs_manager_.reset(); |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 296 | } |
lilyhoughton | 94bde17 | 2017-05-08 17:25:16 | [diff] [blame] | 297 | |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 298 | CronetEnvironment::~CronetEnvironment() { |
kapishnikov | 2633388 | 2017-09-08 14:25:56 | [diff] [blame] | 299 | // Deleting a thread blocks the current thread and waits until all pending |
| 300 | // tasks are completed. |
| 301 | network_io_thread_.reset(); |
kapishnikov | 46532f3 | 2017-10-23 08:54:46 | [diff] [blame] | 302 | file_thread_.reset(); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 303 | } |
| 304 | |
| 305 | void CronetEnvironment::InitializeOnNetworkThread() { |
Mike Dougherty | fc4bf31 | 2017-08-18 17:06:59 | [diff] [blame] | 306 | DCHECK(GetNetworkThreadTaskRunner()->BelongsToCurrentThread()); |
kapishnikov | 46532f3 | 2017-10-23 08:54:46 | [diff] [blame] | 307 | base::DisallowBlocking(); |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 308 | |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 309 | static bool ssl_key_log_file_set = false; |
| 310 | if (!ssl_key_log_file_set && !ssl_key_log_file_name_.empty()) { |
| 311 | ssl_key_log_file_set = true; |
lilyhoughton | 3c82bec | 2017-04-26 18:53:15 | [diff] [blame] | 312 | base::FilePath ssl_key_log_file(ssl_key_log_file_name_); |
David Benjamin | bd37c17 | 2018-07-11 17:24:57 | [diff] [blame] | 313 | net::SSLClientSocket::SetSSLKeyLogger( |
| 314 | std::make_unique<net::SSLKeyLoggerImpl>(ssl_key_log_file)); |
lilyhoughton | 214b3a2 | 2017-01-09 19:42:02 | [diff] [blame] | 315 | } |
| 316 | |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 317 | if (user_agent_partial_) |
| 318 | user_agent_ = web::BuildUserAgentFromProduct(user_agent_); |
| 319 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 320 | // Cache |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 321 | base::FilePath storage_path; |
Avi Drissman | f617d01 | 2018-05-02 18:48:53 | [diff] [blame] | 322 | if (!base::PathService::Get(base::DIR_CACHE, &storage_path)) |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 323 | return; |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 324 | storage_path = storage_path.Append(FILE_PATH_LITERAL("cronet")); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 325 | |
lilyhoughton | 14e2a1f1 | 2017-01-11 14:50:27 | [diff] [blame] | 326 | URLRequestContextConfigBuilder context_config_builder; |
| 327 | context_config_builder.enable_quic = quic_enabled_; // Enable QUIC. |
Lily Houghton | 2d8a8ff | 2017-12-20 16:00:26 | [diff] [blame] | 328 | context_config_builder.quic_user_agent_id = |
| 329 | getDefaultQuicUserAgentId(); // QUIC User Agent ID. |
lilyhoughton | 14e2a1f1 | 2017-01-11 14:50:27 | [diff] [blame] | 330 | context_config_builder.enable_spdy = http2_enabled_; // Enable HTTP/2. |
Lily Houghton | 2d8a8ff | 2017-12-20 16:00:26 | [diff] [blame] | 331 | context_config_builder.http_cache = http_cache_; // Set HTTP cache. |
lilyhoughton | 14e2a1f1 | 2017-01-11 14:50:27 | [diff] [blame] | 332 | context_config_builder.storage_path = |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 333 | storage_path.value(); // Storage path for http cache and prefs storage. |
Misha Efimov | d4ab3830 | 2018-01-30 23:56:42 | [diff] [blame] | 334 | context_config_builder.accept_language = |
| 335 | accept_language_; // Accept-Language request header field. |
lilyhoughton | 14e2a1f1 | 2017-01-11 14:50:27 | [diff] [blame] | 336 | context_config_builder.user_agent = |
| 337 | user_agent_; // User-Agent request header field. |
lilyhoughton | 3c82bec | 2017-04-26 18:53:15 | [diff] [blame] | 338 | context_config_builder.experimental_options = |
| 339 | experimental_options_; // Set experimental Cronet options. |
lilyhoughton | 14e2a1f1 | 2017-01-11 14:50:27 | [diff] [blame] | 340 | context_config_builder.mock_cert_verifier = std::move( |
| 341 | mock_cert_verifier_); // MockCertVerifier to use for testing purposes. |
Paul Jensen | 6a1ea3a | 2018-08-24 14:46:41 | [diff] [blame] | 342 | if (network_thread_priority_ != kKeepDefaultThreadPriority) |
| 343 | context_config_builder.network_thread_priority = network_thread_priority_; |
lilyhoughton | 14e2a1f1 | 2017-01-11 14:50:27 | [diff] [blame] | 344 | std::unique_ptr<URLRequestContextConfig> config = |
| 345 | context_config_builder.Build(); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 346 | |
kapishnikov | eac2ab0 | 2017-06-19 22:20:29 | [diff] [blame] | 347 | config->pkp_list = std::move(pkp_list_); |
| 348 | |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 349 | net::URLRequestContextBuilder context_builder; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 350 | |
kapishnikov | eac2ab0 | 2017-06-19 22:20:29 | [diff] [blame] | 351 | // Explicitly disable the persister for Cronet to avoid persistence of dynamic |
| 352 | // HPKP. This is a safety measure ensuring that nobody enables the |
| 353 | // persistence of HPKP by specifying transport_security_persister_path in the |
| 354 | // future. |
| 355 | context_builder.set_transport_security_persister_path(base::FilePath()); |
| 356 | |
David Benjamin | dc2f4b0 | 2017-07-27 23:59:02 | [diff] [blame] | 357 | config->ConfigureURLRequestContextBuilder(&context_builder, net_log_.get()); |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 358 | |
kapishnikov | d0c6860 | 2017-08-31 02:50:50 | [diff] [blame] | 359 | effective_experimental_options_ = |
| 360 | std::move(config->effective_experimental_options); |
| 361 | |
Eric Orth | 9ded7fe | 2019-03-22 16:32:38 | [diff] [blame] | 362 | // TODO(crbug.com/934402): Use a shared HostResolverManager instead of a |
| 363 | // global HostResolver. |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 364 | std::unique_ptr<net::MappedHostResolver> mapped_host_resolver( |
| 365 | new net::MappedHostResolver( |
Eric Orth | 9ded7fe | 2019-03-22 16:32:38 | [diff] [blame] | 366 | net::HostResolver::CreateStandaloneResolver(nullptr))); |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 367 | |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 368 | if (!config->storage_path.empty()) { |
| 369 | cronet_prefs_manager_ = std::make_unique<CronetPrefsManager>( |
| 370 | config->storage_path, GetNetworkThreadTaskRunner(), |
| 371 | file_thread_->task_runner(), false /* nqe */, false /* host_cache */, |
| 372 | net_log_.get(), &context_builder); |
| 373 | } |
| 374 | |
lilyhoughton | 4e23c36 | 2016-12-09 19:04:34 | [diff] [blame] | 375 | context_builder.set_host_resolver(std::move(mapped_host_resolver)); |
| 376 | |
mef | 67456516 | 2017-02-10 18:44:24 | [diff] [blame] | 377 | // TODO(690969): This behavior matches previous behavior of CookieStoreIOS in |
| 378 | // CrNet, but should change to adhere to App's Cookie Accept Policy instead |
| 379 | // of changing it. |
| 380 | [[NSHTTPCookieStorage sharedHTTPCookieStorage] |
| 381 | setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways]; |
Helen Li | 8c7c8be | 2018-08-24 13:59:40 | [diff] [blame] | 382 | auto cookie_store = std::make_unique<net::CookieStoreIOS>( |
| 383 | [NSHTTPCookieStorage sharedHTTPCookieStorage], nullptr /* net_log */); |
Nick Harper | b7f127d | 2018-12-04 19:54:05 | [diff] [blame] | 384 | context_builder.SetCookieStore(std::move(cookie_store)); |
mef | 2989c37 | 2017-01-06 18:35:59 | [diff] [blame] | 385 | |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 386 | context_builder.set_enable_brotli(brotli_enabled_); |
| 387 | main_context_ = context_builder.Build(); |
zhongyi | e537a00 | 2017-06-27 16:48:21 | [diff] [blame] | 388 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 389 | for (const auto& quic_hint : quic_hints_) { |
Lily Houghton | 5a1a911 | 2017-08-10 17:21:55 | [diff] [blame] | 390 | url::CanonHostInfo host_info; |
| 391 | std::string canon_host(net::CanonicalizeHost(quic_hint.host(), &host_info)); |
| 392 | if (!host_info.IsIPAddress() && |
| 393 | !net::IsCanonicalizedHostCompliant(canon_host)) { |
| 394 | LOG(ERROR) << "Invalid QUIC hint host: " << quic_hint.host(); |
| 395 | continue; |
| 396 | } |
| 397 | |
gcasto | 899886f | 2016-11-18 13:54:03 | [diff] [blame] | 398 | net::AlternativeService alternative_service(net::kProtoQUIC, "", |
| 399 | quic_hint.port()); |
Lily Houghton | 5a1a911 | 2017-08-10 17:21:55 | [diff] [blame] | 400 | |
zhongyi | 3d4a55e7 | 2016-04-22 20:36:46 | [diff] [blame] | 401 | url::SchemeHostPort quic_hint_server("https", quic_hint.host(), |
| 402 | quic_hint.port()); |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 403 | main_context_->http_server_properties()->SetQuicAlternativeService( |
zhongyi | e537a00 | 2017-06-27 16:48:21 | [diff] [blame] | 404 | quic_hint_server, alternative_service, base::Time::Max(), |
Ryan Hamilton | 8d9ee76e | 2018-05-29 23:52:52 | [diff] [blame] | 405 | quic::QuicTransportVersionVector()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 406 | } |
| 407 | |
lilyhoughton | 41c31a68 | 2017-06-28 16:54:09 | [diff] [blame] | 408 | main_context_->transport_security_state() |
| 409 | ->SetEnablePublicKeyPinningBypassForLocalTrustAnchors( |
| 410 | enable_pkp_bypass_for_local_trust_anchors_); |
| 411 | |
| 412 | // Iterate trhough PKP configuration for every host. |
Donna Wu | 7ea51c2 | 2017-06-20 08:34:52 | [diff] [blame] | 413 | for (const auto& pkp : config->pkp_list) { |
kapishnikov | eac2ab0 | 2017-06-19 22:20:29 | [diff] [blame] | 414 | // Add the host pinning. |
| 415 | main_context_->transport_security_state()->AddHPKP( |
| 416 | pkp->host, pkp->expiration_date, pkp->include_subdomains, |
| 417 | pkp->pin_hashes, GURL::EmptyGURL()); |
| 418 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 419 | } |
| 420 | |
kapishnikov | 9f98c43 | 2018-01-12 23:24:08 | [diff] [blame] | 421 | void CronetEnvironment::SetNetworkThreadPriority(double priority) { |
| 422 | DCHECK_LE(priority, 1.0); |
| 423 | DCHECK_GE(priority, 0.0); |
| 424 | network_thread_priority_ = priority; |
| 425 | if (network_io_thread_) { |
| 426 | PostToNetworkThread( |
| 427 | FROM_HERE, |
| 428 | base::BindRepeating( |
| 429 | &CronetEnvironment::SetNetworkThreadPriorityOnNetworkThread, |
| 430 | base::Unretained(this), priority)); |
| 431 | } |
| 432 | } |
| 433 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 434 | std::string CronetEnvironment::user_agent() { |
| 435 | const net::HttpUserAgentSettings* user_agent_settings = |
| 436 | main_context_->http_user_agent_settings(); |
| 437 | if (!user_agent_settings) { |
| 438 | return nullptr; |
| 439 | } |
| 440 | |
| 441 | return user_agent_settings->GetUserAgent(); |
| 442 | } |
| 443 | |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 444 | std::vector<uint8_t> CronetEnvironment::GetHistogramDeltas() { |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 445 | std::vector<uint8_t> data; |
Misha Efimov | a0b0fe61 | 2018-10-02 14:23:44 | [diff] [blame] | 446 | #if BUILDFLAG(DISABLE_HISTOGRAM_SUPPORT) |
| 447 | NOTREACHED() << "Histogram support is disabled"; |
| 448 | #else // BUILDFLAG(DISABLE_HISTOGRAM_SUPPORT) |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 449 | if (!HistogramManager::GetInstance()->GetDeltas(&data)) |
| 450 | return std::vector<uint8_t>(); |
Misha Efimov | a0b0fe61 | 2018-10-02 14:23:44 | [diff] [blame] | 451 | #endif // BUILDFLAG(DISABLE_HISTOGRAM_SUPPORT) |
mef | 254963db | 2016-10-20 21:48:07 | [diff] [blame] | 452 | return data; |
| 453 | } |
| 454 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 455 | void CronetEnvironment::SetHostResolverRules(const std::string& rules) { |
| 456 | base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 457 | base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 458 | PostToNetworkThread( |
| 459 | FROM_HERE, |
| 460 | base::Bind(&CronetEnvironment::SetHostResolverRulesOnNetworkThread, |
| 461 | base::Unretained(this), rules, &event)); |
| 462 | event.Wait(); |
| 463 | } |
| 464 | |
| 465 | void CronetEnvironment::SetHostResolverRulesOnNetworkThread( |
| 466 | const std::string& rules, |
| 467 | base::WaitableEvent* event) { |
| 468 | static_cast<net::MappedHostResolver*>(main_context_->host_resolver()) |
| 469 | ->SetRulesFromString(rules); |
| 470 | event->Signal(); |
| 471 | } |
| 472 | |
kapishnikov | 9f98c43 | 2018-01-12 23:24:08 | [diff] [blame] | 473 | void CronetEnvironment::SetNetworkThreadPriorityOnNetworkThread( |
| 474 | double priority) { |
| 475 | DCHECK(GetNetworkThreadTaskRunner()->BelongsToCurrentThread()); |
Paul Jensen | 6a1ea3a | 2018-08-24 14:46:41 | [diff] [blame] | 476 | cronet::SetNetworkThreadPriorityOnNetworkThread(priority); |
kapishnikov | 9f98c43 | 2018-01-12 23:24:08 | [diff] [blame] | 477 | } |
| 478 | |
lilyhoughton | 52f8be3 | 2016-12-15 20:33:48 | [diff] [blame] | 479 | std::string CronetEnvironment::getDefaultQuicUserAgentId() const { |
| 480 | return base::SysNSStringToUTF8([[NSBundle mainBundle] |
| 481 | objectForInfoDictionaryKey:@"CFBundleDisplayName"]) + |
| 482 | " Cronet/" + CRONET_VERSION; |
| 483 | } |
| 484 | |
kapishnikov | 8de9436 | 2017-08-30 14:40:59 | [diff] [blame] | 485 | base::SingleThreadTaskRunner* CronetEnvironment::GetFileThreadRunnerForTesting() |
| 486 | const { |
| 487 | return file_thread_->task_runner().get(); |
| 488 | } |
| 489 | |
kapishnikov | 9f98c43 | 2018-01-12 23:24:08 | [diff] [blame] | 490 | base::SingleThreadTaskRunner* |
| 491 | CronetEnvironment::GetNetworkThreadRunnerForTesting() const { |
| 492 | return GetNetworkThreadTaskRunner(); |
| 493 | } |
| 494 | |
kapishnikov | 2633388 | 2017-09-08 14:25:56 | [diff] [blame] | 495 | CronetEnvironment::CronetNetworkThread::CronetNetworkThread( |
| 496 | const std::string& name, |
| 497 | cronet::CronetEnvironment* cronet_environment) |
| 498 | : base::Thread(name), cronet_environment_(cronet_environment) {} |
| 499 | |
| 500 | CronetEnvironment::CronetNetworkThread::~CronetNetworkThread() { |
| 501 | Stop(); |
| 502 | } |
| 503 | |
| 504 | void CronetEnvironment::CronetNetworkThread::CleanUp() { |
| 505 | cronet_environment_->CleanUpOnNetworkThread(); |
| 506 | } |
| 507 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 508 | } // namespace cronet |