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 "mojo/services/network/network_context.h"
10 #include "base/base_paths.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "mojo/common/user_agent.h"
17 #include "mojo/services/network/mojo_persistent_cookie_store.h"
18 #include "mojo/services/network/url_loader_impl.h"
19 #include "net/cookies/cookie_monster.h"
20 #include "net/dns/host_resolver.h"
21 #include "net/dns/mapped_host_resolver.h"
22 #include "net/log/net_log_util.h"
23 #include "net/log/write_to_file_net_log_observer.h"
24 #include "net/proxy/proxy_service.h"
25 #include "net/ssl/channel_id_service.h"
26 #include "net/url_request/url_request_context.h"
27 #include "net/url_request/url_request_context_builder.h"
32 // Applies the specified mapping rules when resolving hosts. Please see the
33 // comment of net::MappedHostResolver::AddRulesFromString() for rule format.
34 const char kHostResolverRules
[] = "host-resolver-rules";
36 // Ignores certificate-related errors.
37 const char kIgnoreCertificateErrors
[] = "ignore-certificate-errors";
39 // Logs network information to the specified file.
40 const char kLogNetLog
[] = "log-net-log";
42 // Allows for forcing socket connections to HTTP/HTTPS to use fixed ports.
43 const char kTestingFixedHttpPort
[] = "testing-fixed-http-port";
44 const char kTestingFixedHttpsPort
[] = "testing-fixed-https-port";
46 uint16
GetPortNumber(const base::CommandLine
& command_line
,
47 const base::StringPiece
& switch_name
) {
48 std::string port_str
= command_line
.GetSwitchValueASCII(switch_name
);
50 if (!base::StringToUint(port_str
, &port
) || port
> 65535) {
51 LOG(ERROR
) << "Invalid value for switch " << switch_name
<< ": '"
52 << port_str
<< "' is not a valid port number.";
55 return static_cast<uint16
>(port
);
60 class NetworkContext::MojoNetLog
: public net::NetLog
{
63 const base::CommandLine
* command_line
=
64 base::CommandLine::ForCurrentProcess();
65 if (!command_line
->HasSwitch(kLogNetLog
))
68 base::FilePath log_path
= command_line
->GetSwitchValuePath(kLogNetLog
);
69 base::ScopedFILE file
;
71 file
.reset(_wfopen(log_path
.value().c_str(), L
"w"));
72 #elif defined(OS_POSIX)
73 file
.reset(fopen(log_path
.value().c_str(), "w"));
76 LOG(ERROR
) << "Could not open file " << log_path
.value()
77 << " for net logging";
79 write_to_file_observer_
.reset(new net::WriteToFileNetLogObserver());
80 write_to_file_observer_
->set_capture_mode(
81 net::NetLogCaptureMode::IncludeCookiesAndCredentials());
82 write_to_file_observer_
->StartObserving(this, file
.Pass(), nullptr,
87 ~MojoNetLog() override
{
88 if (write_to_file_observer_
)
89 write_to_file_observer_
->StopObserving(nullptr);
93 scoped_ptr
<net::WriteToFileNetLogObserver
> write_to_file_observer_
;
95 DISALLOW_COPY_AND_ASSIGN(MojoNetLog
);
98 NetworkContext::NetworkContext(
99 scoped_ptr
<net::URLRequestContext
> url_request_context
)
100 : net_log_(new MojoNetLog
),
101 url_request_context_(url_request_context
.Pass()),
102 in_shutdown_(false) {
103 url_request_context_
->set_net_log(net_log_
.get());
106 NetworkContext::NetworkContext(
107 const base::FilePath
& base_path
,
108 const scoped_refptr
<base::SequencedTaskRunner
>& background_task_runner
,
109 NetworkServiceDelegate
* delegate
)
110 : NetworkContext(MakeURLRequestContext(base_path
, background_task_runner
,
114 NetworkContext::~NetworkContext() {
116 // TODO(darin): Be careful about destruction order of member variables?
118 // Call each URLLoaderImpl and ask it to release its net::URLRequest, as the
119 // corresponding net::URLRequestContext is going away with this
120 // NetworkContext. The loaders can be deregistering themselves in Cleanup(),
121 // so iterate over a copy.
122 for (auto& url_loader
: url_loaders_
) {
123 url_loader
->Cleanup();
127 void NetworkContext::RegisterURLLoader(URLLoaderImpl
* url_loader
) {
128 DCHECK(url_loaders_
.count(url_loader
) == 0);
129 url_loaders_
.insert(url_loader
);
132 void NetworkContext::DeregisterURLLoader(URLLoaderImpl
* url_loader
) {
134 size_t removed_count
= url_loaders_
.erase(url_loader
);
135 DCHECK(removed_count
);
139 size_t NetworkContext::GetURLLoaderCountForTesting() {
140 return url_loaders_
.size();
144 scoped_ptr
<net::URLRequestContext
> NetworkContext::MakeURLRequestContext(
145 const base::FilePath
& base_path
,
146 const scoped_refptr
<base::SequencedTaskRunner
>& background_task_runner
,
147 NetworkServiceDelegate
* delegate
) {
148 net::URLRequestContextBuilder builder
;
149 net::URLRequestContextBuilder::HttpNetworkSessionParams params
;
150 const base::CommandLine
* command_line
=
151 base::CommandLine::ForCurrentProcess();
152 if (command_line
->HasSwitch(kIgnoreCertificateErrors
))
153 params
.ignore_certificate_errors
= true;
154 if (command_line
->HasSwitch(kTestingFixedHttpPort
)) {
155 params
.testing_fixed_http_port
=
156 GetPortNumber(*command_line
, kTestingFixedHttpPort
);
158 if (command_line
->HasSwitch(kTestingFixedHttpsPort
)) {
159 params
.testing_fixed_https_port
=
160 GetPortNumber(*command_line
, kTestingFixedHttpsPort
);
162 builder
.set_http_network_session_params(params
);
164 if (command_line
->HasSwitch(kHostResolverRules
)) {
165 scoped_ptr
<net::HostResolver
> host_resolver(
166 net::HostResolver::CreateDefaultResolver(nullptr));
167 scoped_ptr
<net::MappedHostResolver
> remapped_host_resolver(
168 new net::MappedHostResolver(host_resolver
.Pass()));
169 remapped_host_resolver
->SetRulesFromString(
170 command_line
->GetSwitchValueASCII(kHostResolverRules
));
171 builder
.set_host_resolver(remapped_host_resolver
.Pass());
174 builder
.set_accept_language("en-us,en");
175 builder
.set_user_agent(mojo::common::GetUserAgent());
176 builder
.set_proxy_service(make_scoped_ptr(net::ProxyService::CreateDirect()));
177 builder
.set_transport_security_persister_path(base_path
);
179 net::URLRequestContextBuilder::HttpCacheParams cache_params
;
180 #if defined(OS_ANDROID)
181 // On Android, we store the cache on disk becase we can run only a single
182 // instance of the shell at a time.
183 cache_params
.type
= net::URLRequestContextBuilder::HttpCacheParams::DISK
;
184 cache_params
.path
= base_path
.Append(FILE_PATH_LITERAL("Cache"));
186 // On desktop, we store the cache in memory so we can run many shells
187 // in parallel when running tests, otherwise the network services in each
188 // shell will corrupt the disk cache.
189 cache_params
.type
= net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY
;
192 builder
.EnableHttpCache(cache_params
);
193 builder
.set_file_enabled(true);
195 if (background_task_runner
) {
196 // TODO(erg): This only gets run on non-android system. Currently, any
197 // attempts from the network_service trying to access the filesystem break
198 // the apptests on android. (And only the apptests on android. Mandoline
199 // shell works fine on android, as does apptests on desktop.)
200 MojoPersistentCookieStore
* cookie_store
=
201 new MojoPersistentCookieStore(
203 base::FilePath(FILE_PATH_LITERAL("Cookies")),
204 base::MessageLoop::current()->task_runner(),
205 background_task_runner
,
206 false, // TODO(erg): Make RESTORED_SESSION_COOKIES configurable.
208 builder
.SetCookieAndChannelIdStores(
209 new net::CookieMonster(cookie_store
, nullptr), nullptr);
212 return builder
.Build().Pass();