Remove five deleted header files from .gyp files
[chromium-blink-merge.git] / ios / crnet / crnet_environment.mm
blob234f389edfa2d2dc0dbdd6ea2351879d98988857
1 // Copyright 2014 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.
5 #include "ios/crnet/crnet_environment.h"
7 #import <Foundation/Foundation.h>
9 #include "base/at_exit.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_file.h"
14 #include "base/i18n/icu_util.h"
15 #include "base/json/json_writer.h"
16 #include "base/mac/bind_objc_block.h"
17 #include "base/mac/foundation_util.h"
18 #include "base/mac/scoped_block.h"
19 #include "base/path_service.h"
20 #include "base/threading/worker_pool.h"
21 #import "components/webp_transcode/webp_network_client_factory.h"
22 #include "crypto/nss_util.h"
23 #include "ios/net/cookies/cookie_store_ios.h"
24 #include "ios/net/crn_http_protocol_handler.h"
25 #include "ios/net/empty_nsurlcache.h"
26 #include "ios/net/request_tracker.h"
27 #include "ios/web/public/user_agent.h"
28 #include "net/base/net_errors.h"
29 #include "net/base/network_change_notifier.h"
30 #include "net/base/sdch_manager.h"
31 #include "net/cert/cert_verifier.h"
32 #include "net/cert_net/nss_ocsp.h"
33 #include "net/disk_cache/disk_cache.h"
34 #include "net/http/http_auth_handler_factory.h"
35 #include "net/http/http_cache.h"
36 #include "net/http/http_server_properties_impl.h"
37 #include "net/http/http_stream_factory.h"
38 #include "net/http/http_util.h"
39 #include "net/log/net_log.h"
40 #include "net/log/write_to_file_net_log_observer.h"
41 #include "net/proxy/proxy_service.h"
42 #include "net/socket/next_proto.h"
43 #include "net/ssl/channel_id_service.h"
44 #include "net/ssl/default_channel_id_store.h"
45 #include "net/ssl/ssl_config_service_defaults.h"
46 #include "net/url_request/data_protocol_handler.h"
47 #include "net/url_request/file_protocol_handler.h"
48 #include "net/url_request/sdch_dictionary_fetcher.h"
49 #include "net/url_request/static_http_user_agent_settings.h"
50 #include "net/url_request/url_request_context_getter.h"
51 #include "net/url_request/url_request_context_storage.h"
52 #include "net/url_request/url_request_job_factory_impl.h"
53 #include "url/url_util.h"
55 namespace {
57 base::AtExitManager* g_at_exit_ = nullptr;
59 // Request context getter for CrNet.
60 class CrNetURLRequestContextGetter : public net::URLRequestContextGetter {
61  public:
62   CrNetURLRequestContextGetter(
63       net::URLRequestContext* context,
64       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
65       : context_(context), task_runner_(task_runner) {}
67   net::URLRequestContext* GetURLRequestContext() override { return context_; }
69   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
70       const override {
71     return task_runner_;
72   }
73  private:
74   // Must be called on the IO thread.
75   ~CrNetURLRequestContextGetter() override {}
77   net::URLRequestContext* context_;
78   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
79   DISALLOW_COPY_AND_ASSIGN(CrNetURLRequestContextGetter);
82 }  // namespace
84 // net::HTTPProtocolHandlerDelegate for CrNet.
85 class CrNetHttpProtocolHandlerDelegate
86     : public net::HTTPProtocolHandlerDelegate {
87  public:
88   CrNetHttpProtocolHandlerDelegate(net::URLRequestContextGetter* getter,
89                                    RequestFilterBlock filter)
90       : getter_(getter), filter_(filter, base::scoped_policy::RETAIN) {}
92  private:
93   // net::HTTPProtocolHandlerDelegate implementation:
94   bool CanHandleRequest(NSURLRequest* request) override {
95     // Don't advertise support for file:// URLs for now.
96     // This broke some time ago but it's not clear how to fix it at the moment.
97     // http://crbug.com/480620
98     if ([[[request URL] scheme] caseInsensitiveCompare:@"file"] ==
99         NSOrderedSame) {
100       return false;
101     }
102     if (filter_) {
103       RequestFilterBlock block = filter_.get();
104       return block(request);
105     }
106     return true;
107   }
109   bool IsRequestSupported(NSURLRequest* request) override {
110     NSString* scheme = [[request URL] scheme];
111     if (!scheme)
112       return false;
113     return [scheme caseInsensitiveCompare:@"data"] == NSOrderedSame ||
114            [scheme caseInsensitiveCompare:@"http"] == NSOrderedSame ||
115            [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame;
116   }
118   net::URLRequestContextGetter* GetDefaultURLRequestContext() override {
119     return getter_.get();
120   }
122   scoped_refptr<net::URLRequestContextGetter> getter_;
123   base::mac::ScopedBlock<RequestFilterBlock> filter_;
126 void CrNetEnvironment::PostToNetworkThread(
127     const tracked_objects::Location& from_here,
128     const base::Closure& task) {
129   network_io_thread_->message_loop()->PostTask(from_here, task);
132 void CrNetEnvironment::PostToFileUserBlockingThread(
133     const tracked_objects::Location& from_here,
134     const base::Closure& task) {
135   file_user_blocking_thread_->message_loop()->PostTask(from_here, task);
138 // static
139 void CrNetEnvironment::Initialize() {
140   DCHECK_EQ([NSThread currentThread], [NSThread mainThread]);
141   if (!g_at_exit_)
142     g_at_exit_ = new base::AtExitManager;
144   CHECK(base::i18n::InitializeICU());
145   url::Initialize();
146   base::CommandLine::Init(0, nullptr);
147   // This needs to happen on the main thread. NSPR's initialization sets up its
148   // memory allocator; if this is not done before other threads are created,
149   // this initialization can race to cause accidental free/allocation
150   // mismatches.
151   crypto::EnsureNSPRInit();
153   // Create a message loop on the UI thread.
154   base::MessageLoop* main_message_loop =
155       new base::MessageLoop(base::MessageLoop::TYPE_UI);
156 #pragma unused(main_message_loop)
157   base::MessageLoopForUI::current()->Attach();
160 void CrNetEnvironment::StartNetLog(base::FilePath::StringType file_name,
161     bool log_bytes) {
162   DCHECK(file_name.length());
163   PostToFileUserBlockingThread(FROM_HERE,
164       base::Bind(&CrNetEnvironment::StartNetLogInternal,
165                  base::Unretained(this), file_name, log_bytes));
168 void CrNetEnvironment::StartNetLogInternal(
169     base::FilePath::StringType file_name, bool log_bytes) {
170   DCHECK(base::MessageLoop::current() ==
171          file_user_blocking_thread_->message_loop());
172   DCHECK(file_name.length());
173   DCHECK(net_log_);
175   if (net_log_observer_)
176     return;
178   base::FilePath temp_dir;
179   if (!base::GetTempDir(&temp_dir))
180     return;
182   base::FilePath full_path = temp_dir.Append(file_name);
183   base::ScopedFILE file(base::OpenFile(full_path, "w"));
184   if (!file)
185     return;
187   net::NetLogCaptureMode capture_mode = log_bytes ?
188       net::NetLogCaptureMode::IncludeSocketBytes() :
189       net::NetLogCaptureMode::Default();
191   net_log_observer_.reset(new net::WriteToFileNetLogObserver());
192   net_log_observer_->set_capture_mode(capture_mode);
193   net_log_observer_->StartObserving(net_log_.get(), file.Pass(), nullptr,
194                                     nullptr);
197 void CrNetEnvironment::StopNetLog() {
198   PostToFileUserBlockingThread(FROM_HERE,
199       base::Bind(&CrNetEnvironment::StopNetLogInternal,
200       base::Unretained(this)));
203 void CrNetEnvironment::StopNetLogInternal() {
204   DCHECK(base::MessageLoop::current() ==
205          file_user_blocking_thread_->message_loop());
206   if (net_log_observer_) {
207     net_log_observer_->StopObserving(nullptr);
208     net_log_observer_.reset();
209   }
212 void CrNetEnvironment::CloseAllSpdySessions() {
213   PostToNetworkThread(FROM_HERE,
214       base::Bind(&CrNetEnvironment::CloseAllSpdySessionsInternal,
215       base::Unretained(this)));
218 void CrNetEnvironment::SetRequestFilterBlock(RequestFilterBlock block) {
219   http_protocol_handler_delegate_.reset(
220       new CrNetHttpProtocolHandlerDelegate(main_context_getter_.get(), block));
221   net::HTTPProtocolHandlerDelegate::SetInstance(
222       http_protocol_handler_delegate_.get());
225 net::HttpNetworkSession* CrNetEnvironment::GetHttpNetworkSession(
226     net::URLRequestContext* context) {
227   DCHECK(context);
228   if (!context->http_transaction_factory())
229     return nullptr;
231   return context->http_transaction_factory()->GetSession();
234 void CrNetEnvironment::CloseAllSpdySessionsInternal() {
235   DCHECK(base::MessageLoop::current() ==
236          network_io_thread_->message_loop());
238   net::HttpNetworkSession* http_network_session =
239       GetHttpNetworkSession(GetMainContextGetter()->GetURLRequestContext());
241   if (http_network_session) {
242     net::SpdySessionPool *spdy_session_pool =
243         http_network_session->spdy_session_pool();
244     if (spdy_session_pool)
245       spdy_session_pool->CloseCurrentSessions(net::ERR_ABORTED);
246   }
249 CrNetEnvironment::CrNetEnvironment(std::string user_agent_product_name)
250     : main_context_(new net::URLRequestContext),
251       user_agent_product_name_(user_agent_product_name) {
255 void CrNetEnvironment::Install() {
256   // Threads setup.
257   network_cache_thread_.reset(new base::Thread("Chrome Network Cache Thread"));
258   network_cache_thread_->StartWithOptions(
259       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
260   network_io_thread_.reset(new base::Thread("Chrome Network IO Thread"));
261   network_io_thread_->StartWithOptions(
262       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
263   file_thread_.reset(new base::Thread("Chrome File Thread"));
264   file_thread_->StartWithOptions(
265       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
266   file_user_blocking_thread_.reset(
267       new base::Thread("Chrome File User Blocking Thread"));
268   file_user_blocking_thread_->StartWithOptions(
269       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
271   // The network change notifier must be initialized so that registered
272   // delegates will receive callbacks.
273   network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
274   proxy_config_service_.reset(net::ProxyService::CreateSystemProxyConfigService(
275       network_io_thread_->task_runner(), nullptr));
277   PostToNetworkThread(FROM_HERE,
278       base::Bind(&CrNetEnvironment::InitializeOnNetworkThread,
279                  base::Unretained(this)));
281   net::SetURLRequestContextForNSSHttpIO(main_context_.get());
282   main_context_getter_ = new CrNetURLRequestContextGetter(
283       main_context_.get(), network_io_thread_->task_runner());
284   SetRequestFilterBlock(nil);
287 void CrNetEnvironment::InstallIntoSessionConfiguration(
288     NSURLSessionConfiguration* config) {
289   config.protocolClasses = @[ [CRNPauseableHTTPProtocolHandler class] ];
292 CrNetEnvironment::~CrNetEnvironment() {
293   net::HTTPProtocolHandlerDelegate::SetInstance(nullptr);
294   net::SetURLRequestContextForNSSHttpIO(nullptr);
297 net::URLRequestContextGetter* CrNetEnvironment::GetMainContextGetter() {
298   return main_context_getter_.get();
301 void CrNetEnvironment::SetHTTPProtocolHandlerRegistered(bool registered) {
302   if (registered) {
303     // Disable the default cache.
304     [NSURLCache setSharedURLCache:[EmptyNSURLCache emptyNSURLCache]];
305     // Register the chrome http protocol handler to replace the default one.
306     BOOL success =
307         [NSURLProtocol registerClass:[CRNPauseableHTTPProtocolHandler class]];
308     DCHECK(success);
309   } else {
310     // Set up an empty default cache, with default size.
311     // TODO(droger): If the NSURLCache is to be used, its size should most
312     // likely be changed. On an iPod2 with iOS4, the default size is 512k.
313     [NSURLCache setSharedURLCache:[[[NSURLCache alloc] init] autorelease]];
314     [NSURLProtocol unregisterClass:[CRNPauseableHTTPProtocolHandler class]];
315   }
318 void CrNetEnvironment::InitializeOnNetworkThread() {
319   DCHECK(base::MessageLoop::current() == network_io_thread_->message_loop());
321   // Register network clients.
322   net::RequestTracker::AddGlobalNetworkClientFactory(
323       [[[WebPNetworkClientFactory alloc]
324           initWithTaskRunner:file_user_blocking_thread_
325                                  ->task_runner()] autorelease]);
327 #if 0
328   // TODO(huey): Re-enable this once SDCH supports SSL and dictionaries from
329   // previous sessions can be used on the first request after a fresh launch.
330   sdch_manager_.reset(new net::SdchManager());
331   sdch_manager_->set_sdch_fetcher(
332       new SdchDictionaryFetcher(main_context_getter_));
333 #else
334   // Otherwise, explicitly disable SDCH to avoid a crash.
335   net::SdchManager::EnableSdchSupport(false);
336 #endif
338   NSString* bundlePath =
339       [[NSBundle mainBundle] pathForResource:@"crnet_resources"
340                                       ofType:@"bundle"];
341   NSBundle* bundle = [NSBundle bundleWithPath:bundlePath];
342   NSString* acceptableLanguages = NSLocalizedStringWithDefaultValue(
343       @"IDS_ACCEPT_LANGUAGES",
344       @"Localizable",
345       bundle,
346       @"en-US,en",
347       @"These values are copied from Chrome's .xtb files, so the same "
348        "values are used in the |Accept-Language| header. Key name matches "
349        "Chrome's.");
350   DCHECK(acceptableLanguages);
351   std::string acceptable_languages =
352       [acceptableLanguages cStringUsingEncoding:NSUTF8StringEncoding];
353   std::string user_agent =
354       web::BuildUserAgentFromProduct(user_agent_product_name_);
355   // Set the user agent through NSUserDefaults. This sets it for both
356   // UIWebViews and WKWebViews, and javascript calls to navigator.userAgent
357   // return this value.
358   [[NSUserDefaults standardUserDefaults] registerDefaults:@{
359     @"UserAgent" : [NSString stringWithUTF8String:user_agent.c_str()]
360   }];
361   main_context_->set_http_user_agent_settings(
362       new net::StaticHttpUserAgentSettings(acceptable_languages, user_agent));
364   main_context_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
365   main_context_->set_transport_security_state(
366       new net::TransportSecurityState());
367   http_server_properties_.reset(new net::HttpServerPropertiesImpl());
368   main_context_->set_http_server_properties(
369       http_server_properties_->GetWeakPtr());
370   main_context_->set_host_resolver(
371       net::HostResolver::CreateDefaultResolver(nullptr).release());
372   main_context_->set_cert_verifier(net::CertVerifier::CreateDefault());
373   main_context_->set_http_auth_handler_factory(
374       net::HttpAuthHandlerRegistryFactory::CreateDefault(
375           main_context_->host_resolver()));
376   main_context_->set_proxy_service(
377       net::ProxyService::CreateUsingSystemProxyResolver(
378           proxy_config_service_.get(), 0, nullptr));
380   // Cache
381   NSArray* dirs = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
382                                                       NSUserDomainMask,
383                                                       YES);
384   base::FilePath cache_path =
385       base::mac::NSStringToFilePath([dirs objectAtIndex:0]);
386   cache_path = cache_path.Append(FILE_PATH_LITERAL("crnet"));
387   net::HttpCache::DefaultBackend* main_backend =
388       new net::HttpCache::DefaultBackend(net::DISK_CACHE,
389                                          net::CACHE_BACKEND_DEFAULT, cache_path,
390                                          0,  // Default cache size.
391                                          network_cache_thread_->task_runner());
393   net::HttpNetworkSession::Params params;
394   params.host_resolver = main_context_->host_resolver();
395   params.cert_verifier = main_context_->cert_verifier();
396   params.channel_id_service = main_context_->channel_id_service();
397   params.transport_security_state = main_context_->transport_security_state();
398   params.proxy_service = main_context_->proxy_service();
399   params.ssl_session_cache_shard = "";
400   params.ssl_config_service = main_context_->ssl_config_service();
401   params.http_auth_handler_factory = main_context_->http_auth_handler_factory();
402   params.network_delegate = main_context_->network_delegate();
403   params.http_server_properties = main_context_->http_server_properties();
404   params.net_log = main_context_->net_log();
405   params.next_protos =
406       net::NextProtosWithSpdyAndQuic(spdy_enabled(), quic_enabled());
407   params.use_alternate_protocols = true;
408   params.enable_quic = quic_enabled();
409   params.alternative_service_probability_threshold =
410       alternate_protocol_threshold_;
412   if (!params.channel_id_service) {
413     // The main context may not have a ChannelIDService, since it is lazily
414     // constructed. If not, build an ephemeral ChannelIDService with no backing
415     // disk store.
416     // TODO(ellyjones): support persisting ChannelID.
417     params.channel_id_service = new net::ChannelIDService(
418         new net::DefaultChannelIDStore(NULL),
419         base::WorkerPool::GetTaskRunner(true));
420   }
422   net::HttpCache* main_cache = new net::HttpCache(params, main_backend);
423   main_context_->set_http_transaction_factory(main_cache);
425   // Cookies
426   scoped_refptr<net::CookieStore> cookie_store =
427       net::CookieStoreIOS::CreateCookieStoreFromNSHTTPCookieStorage();
428   main_context_->set_cookie_store(cookie_store.get());
430   net::URLRequestJobFactoryImpl* job_factory =
431       new net::URLRequestJobFactoryImpl;
432   job_factory->SetProtocolHandler("data", new net::DataProtocolHandler);
433   job_factory->SetProtocolHandler(
434       "file", new net::FileProtocolHandler(file_thread_->task_runner()));
435   main_context_->set_job_factory(job_factory);
437   net_log_.reset(new net::NetLog());
438   main_context_->set_net_log(net_log_.get());
441 std::string CrNetEnvironment::user_agent() {
442   const net::HttpUserAgentSettings* user_agent_settings =
443       main_context_->http_user_agent_settings();
444   if (!user_agent_settings) {
445     return nullptr;
446   }
448   return user_agent_settings->GetUserAgent();
451 void CrNetEnvironment::ClearCache(ClearCacheCallback callback) {
452   PostToNetworkThread(FROM_HERE,
453       base::Bind(&CrNetEnvironment::ClearCacheOnNetworkThread,
454                  base::Unretained(this),
455                  callback));
458 void CrNetEnvironment::ClearCacheOnNetworkThread(ClearCacheCallback callback) {
459   DCHECK(base::MessageLoop::current() == network_io_thread_->message_loop());
460   __block disk_cache::Backend* backend = nullptr;
461   net::HttpCache* cache = main_context_->http_transaction_factory()->GetCache();
462   net::CompletionCallback client_callback = base::BindBlock(^(int error) {
463     if (callback != nil) {
464       callback(error);
465     }
466   });
467   net::CompletionCallback doom_callback = base::BindBlock(^(int error) {
468       if (backend)
469         backend->DoomAllEntries(client_callback);
470   });
471   int rc = cache->GetBackend(&backend, doom_callback);
472   if (rc != net::ERR_IO_PENDING) {
473     // GetBackend doesn't call the callback if it completes synchronously, so
474     // call it directly here.
475     doom_callback.Run(rc);
476   }