blob: 2c65be638488e795da5754ef3d53f77efb63b0a6 [file] [log] [blame]
[email protected]9045b8822012-01-13 20:35:351// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ac039522010-06-15 16:39:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/net/chrome_network_delegate.h"
6
7#include "base/logging.h"
[email protected]6baff0b52012-03-06 01:30:188#include "chrome/browser/browser_process.h"
[email protected]9c8ae8c2012-03-09 13:13:359#include "chrome/browser/content_settings/cookie_settings.h"
10#include "chrome/browser/content_settings/tab_specific_content_settings.h"
[email protected]8523ba52011-05-22 19:00:5811#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
[email protected]aa84a7e2012-03-15 21:29:0612#include "chrome/browser/extensions/api/proxy/proxy_api.h"
[email protected]2b33dcd02012-03-18 01:34:1613#include "chrome/browser/extensions/api/web_request/web_request_api.h"
[email protected]3ce02412011-03-01 12:01:1514#include "chrome/browser/extensions/extension_event_router_forwarder.h"
[email protected]c357acb42011-06-09 20:52:4215#include "chrome/browser/extensions/extension_info_map.h"
[email protected]6baff0b52012-03-06 01:30:1816#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]0a8db0d2011-04-13 15:15:4017#include "chrome/browser/prefs/pref_member.h"
[email protected]6baff0b52012-03-06 01:30:1818#include "chrome/browser/profiles/profile_manager.h"
[email protected]8523ba52011-05-22 19:00:5819#include "chrome/browser/task_manager/task_manager.h"
[email protected]0a8db0d2011-04-13 15:15:4020#include "chrome/common/pref_names.h"
[email protected]c38831a12011-10-28 12:44:4921#include "content/public/browser/browser_thread.h"
[email protected]9c1662b2012-03-06 15:44:3322#include "content/public/browser/render_view_host.h"
[email protected]9c8ae8c2012-03-09 13:13:3523#include "content/public/browser/resource_request_info.h"
[email protected]82b42302011-04-20 16:28:1624#include "net/base/host_port_pair.h"
[email protected]8202d0c2011-02-23 08:31:1425#include "net/base/net_errors.h"
[email protected]6a5f77c32011-09-04 19:19:5926#include "net/base/net_log.h"
[email protected]aa84a7e2012-03-15 21:29:0627#include "net/cookies/cookie_monster.h"
[email protected]ac039522010-06-15 16:39:4428#include "net/http/http_request_headers.h"
[email protected]48944382011-04-23 13:28:1629#include "net/http/http_response_headers.h"
[email protected]d05ef99c2011-02-01 21:38:1630#include "net/url_request/url_request.h"
31
[email protected]4c219e22012-05-05 19:41:0432#if defined(OS_CHROMEOS)
33#include "base/chromeos/chromeos_version.h"
34#endif
35
[email protected]3e598ff12011-09-06 11:22:3436#if defined(ENABLE_CONFIGURATION_POLICY)
37#include "chrome/browser/policy/url_blacklist_manager.h"
38#endif
39
[email protected]631bb742011-11-02 11:29:3940using content::BrowserThread;
[email protected]eaabba22012-03-07 15:02:1141using content::RenderViewHost;
[email protected]ea114722012-03-12 01:11:2542using content::ResourceRequestInfo;
[email protected]631bb742011-11-02 11:29:3943
[email protected]4c219e22012-05-05 19:41:0444// By default we don't allow access to all file:// urls on ChromeOS but we do on
45// other platforms.
46#if defined(OS_CHROMEOS)
47bool ChromeNetworkDelegate::g_allow_file_access_ = false;
48#else
49bool ChromeNetworkDelegate::g_allow_file_access_ = true;
50#endif
51
[email protected]d05ef99c2011-02-01 21:38:1652namespace {
53
[email protected]8202d0c2011-02-23 08:31:1454// If the |request| failed due to problems with a proxy, forward the error to
55// the proxy extension API.
[email protected]0651b812011-02-24 00:22:5056void ForwardProxyErrors(net::URLRequest* request,
[email protected]3ce02412011-03-01 12:01:1557 ExtensionEventRouterForwarder* event_router,
[email protected]673514522011-07-13 18:17:1858 void* profile) {
[email protected]8202d0c2011-02-23 08:31:1459 if (request->status().status() == net::URLRequestStatus::FAILED) {
[email protected]d0cc35b2011-09-08 12:02:0560 switch (request->status().error()) {
[email protected]8202d0c2011-02-23 08:31:1461 case net::ERR_PROXY_AUTH_UNSUPPORTED:
62 case net::ERR_PROXY_CONNECTION_FAILED:
63 case net::ERR_TUNNEL_CONNECTION_FAILED:
[email protected]c454fe672012-03-12 21:18:0164 extensions::ProxyEventRouter::GetInstance()->OnProxyError(
[email protected]d0cc35b2011-09-08 12:02:0565 event_router, profile, request->status().error());
[email protected]8202d0c2011-02-23 08:31:1466 }
67 }
68}
69
[email protected]6baff0b52012-03-06 01:30:1870enum RequestStatus { REQUEST_STARTED, REQUEST_DONE };
71
72// Notifies the ExtensionProcessManager that a request has started or stopped
73// for a particular RenderView.
74void NotifyEPMRequestStatus(RequestStatus status,
75 void* profile_id,
76 int process_id,
77 int render_view_id) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79 Profile* profile = reinterpret_cast<Profile*>(profile_id);
80 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
81 return;
82
[email protected]e5775a52012-03-17 04:59:5783 ExtensionProcessManager* extension_process_manager =
84 profile->GetExtensionProcessManager();
85 // This may be NULL in unit tests.
86 if (!extension_process_manager)
87 return;
88
[email protected]6baff0b52012-03-06 01:30:1889 // Will be NULL if the request was not issued on behalf of a renderer (e.g. a
90 // system-level request).
[email protected]d3e898e2012-03-14 03:45:0891 RenderViewHost* render_view_host =
92 RenderViewHost::FromID(process_id, render_view_id);
[email protected]e5775a52012-03-17 04:59:5793 if (render_view_host) {
[email protected]6baff0b52012-03-06 01:30:1894 if (status == REQUEST_STARTED) {
[email protected]d3e898e2012-03-14 03:45:0895 extension_process_manager->OnNetworkRequestStarted(render_view_host);
[email protected]6baff0b52012-03-06 01:30:1896 } else if (status == REQUEST_DONE) {
[email protected]d3e898e2012-03-14 03:45:0897 extension_process_manager->OnNetworkRequestDone(render_view_host);
[email protected]6baff0b52012-03-06 01:30:1898 } else {
99 NOTREACHED();
100 }
101 }
102}
103
104void ForwardRequestStatus(
105 RequestStatus status, net::URLRequest* request, void* profile_id) {
[email protected]ea114722012-03-12 01:11:25106 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
107 if (!info)
108 return;
109
[email protected]6baff0b52012-03-06 01:30:18110 int process_id, render_view_id;
[email protected]ea114722012-03-12 01:11:25111 if (info->GetAssociatedRenderView(&process_id, &render_view_id)) {
[email protected]6baff0b52012-03-06 01:30:18112 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
113 base::Bind(&NotifyEPMRequestStatus,
114 status, profile_id, process_id, render_view_id));
115 }
116}
117
[email protected]d05ef99c2011-02-01 21:38:16118} // namespace
[email protected]ac039522010-06-15 16:39:44119
[email protected]0651b812011-02-24 00:22:50120ChromeNetworkDelegate::ChromeNetworkDelegate(
[email protected]3ce02412011-03-01 12:01:15121 ExtensionEventRouterForwarder* event_router,
[email protected]c357acb42011-06-09 20:52:42122 ExtensionInfoMap* extension_info_map,
[email protected]6a5f77c32011-09-04 19:19:59123 const policy::URLBlacklistManager* url_blacklist_manager,
[email protected]673514522011-07-13 18:17:18124 void* profile,
[email protected]9c8ae8c2012-03-09 13:13:35125 CookieSettings* cookie_settings,
[email protected]a8c1e7452011-05-14 06:17:07126 BooleanPrefMember* enable_referrers)
[email protected]3ce02412011-03-01 12:01:15127 : event_router_(event_router),
[email protected]673514522011-07-13 18:17:18128 profile_(profile),
[email protected]9c8ae8c2012-03-09 13:13:35129 cookie_settings_(cookie_settings),
[email protected]c357acb42011-06-09 20:52:42130 extension_info_map_(extension_info_map),
[email protected]6a5f77c32011-09-04 19:19:59131 enable_referrers_(enable_referrers),
132 url_blacklist_manager_(url_blacklist_manager) {
[email protected]4b50cb52011-03-10 00:29:37133 DCHECK(event_router);
[email protected]0a8db0d2011-04-13 15:15:40134 DCHECK(enable_referrers);
[email protected]9c8ae8c2012-03-09 13:13:35135 DCHECK(!profile || cookie_settings);
[email protected]0651b812011-02-24 00:22:50136}
137
[email protected]ac039522010-06-15 16:39:44138ChromeNetworkDelegate::~ChromeNetworkDelegate() {}
139
[email protected]0a8db0d2011-04-13 15:15:40140// static
141void ChromeNetworkDelegate::InitializeReferrersEnabled(
142 BooleanPrefMember* enable_referrers,
143 PrefService* pref_service) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 enable_referrers->Init(prefs::kEnableReferrers, pref_service, NULL);
146 enable_referrers->MoveToThread(BrowserThread::IO);
147}
148
[email protected]4c219e22012-05-05 19:41:04149// static
150void ChromeNetworkDelegate::AllowAccessToAllFiles() {
151 g_allow_file_access_ = true;
152}
153
[email protected]4875ba12011-03-30 22:31:51154int ChromeNetworkDelegate::OnBeforeURLRequest(
[email protected]4c76d7c2011-04-15 19:14:12155 net::URLRequest* request,
[email protected]084262c2011-12-01 21:12:47156 const net::CompletionCallback& callback,
[email protected]4c76d7c2011-04-15 19:14:12157 GURL* new_url) {
[email protected]3e598ff12011-09-06 11:22:34158#if defined(ENABLE_CONFIGURATION_POLICY)
[email protected]6a5f77c32011-09-04 19:19:59159 // TODO(joaodasilva): This prevents extensions from seeing URLs that are
160 // blocked. However, an extension might redirect the request to another URL,
161 // which is not blocked.
162 if (url_blacklist_manager_ &&
163 url_blacklist_manager_->IsURLBlocked(request->url())) {
164 // URL access blocked by policy.
165 scoped_refptr<net::NetLog::EventParameters> params;
166 params = new net::NetLogStringParameter("url", request->url().spec());
167 request->net_log().AddEvent(
168 net::NetLog::TYPE_CHROME_POLICY_ABORTED_REQUEST, params);
169 return net::ERR_NETWORK_ACCESS_DENIED;
170 }
[email protected]3e598ff12011-09-06 11:22:34171#endif
[email protected]6a5f77c32011-09-04 19:19:59172
[email protected]6baff0b52012-03-06 01:30:18173 ForwardRequestStatus(REQUEST_STARTED, request, profile_);
174
[email protected]0a8db0d2011-04-13 15:15:40175 if (!enable_referrers_->GetValue())
176 request->set_referrer(std::string());
[email protected]05cc4e72011-03-08 21:29:48177 return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
[email protected]673514522011-07-13 18:17:18178 profile_, extension_info_map_.get(), request, callback, new_url);
[email protected]d05ef99c2011-02-01 21:38:16179}
180
[email protected]4875ba12011-03-30 22:31:51181int ChromeNetworkDelegate::OnBeforeSendHeaders(
[email protected]636eccd2011-06-28 12:28:01182 net::URLRequest* request,
[email protected]084262c2011-12-01 21:12:47183 const net::CompletionCallback& callback,
[email protected]4c76d7c2011-04-15 19:14:12184 net::HttpRequestHeaders* headers) {
[email protected]4875ba12011-03-30 22:31:51185 return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
[email protected]673514522011-07-13 18:17:18186 profile_, extension_info_map_.get(), request, callback, headers);
[email protected]ac039522010-06-15 16:39:44187}
[email protected]8202d0c2011-02-23 08:31:14188
[email protected]5796dc942011-07-14 19:26:10189void ChromeNetworkDelegate::OnSendHeaders(
190 net::URLRequest* request,
[email protected]783573b2011-05-13 11:05:15191 const net::HttpRequestHeaders& headers) {
[email protected]5796dc942011-07-14 19:26:10192 ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
193 profile_, extension_info_map_.get(), request, headers);
[email protected]82b42302011-04-20 16:28:16194}
195
[email protected]ea8141e2011-10-05 13:12:51196int ChromeNetworkDelegate::OnHeadersReceived(
197 net::URLRequest* request,
[email protected]084262c2011-12-01 21:12:47198 const net::CompletionCallback& callback,
[email protected]ea8141e2011-10-05 13:12:51199 net::HttpResponseHeaders* original_response_headers,
200 scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
201 return ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
202 profile_, extension_info_map_.get(), request, callback,
203 original_response_headers, override_response_headers);
204}
205
[email protected]31b2e5f2011-04-20 16:58:32206void ChromeNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
207 const GURL& new_location) {
208 ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
[email protected]673514522011-07-13 18:17:18209 profile_, extension_info_map_.get(), request, new_location);
[email protected]31b2e5f2011-04-20 16:58:32210}
211
212
[email protected]8202d0c2011-02-23 08:31:14213void ChromeNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
[email protected]62fecae2011-04-21 11:08:24214 ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
[email protected]673514522011-07-13 18:17:18215 profile_, extension_info_map_.get(), request);
216 ForwardProxyErrors(request, event_router_.get(), profile_);
[email protected]8202d0c2011-02-23 08:31:14217}
218
[email protected]8523ba52011-05-22 19:00:58219void ChromeNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
220 int bytes_read) {
[email protected]44879ed2012-04-06 01:11:02221#if defined(ENABLE_TASK_MANAGER)
[email protected]8523ba52011-05-22 19:00:58222 TaskManager::GetInstance()->model()->NotifyBytesRead(request, bytes_read);
[email protected]44879ed2012-04-06 01:11:02223#endif // defined(ENABLE_TASK_MANAGER)
[email protected]8523ba52011-05-22 19:00:58224}
225
[email protected]9045b8822012-01-13 20:35:35226void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
227 bool started) {
[email protected]a83dd332011-07-13 10:41:01228 if (request->status().status() == net::URLRequestStatus::SUCCESS ||
229 request->status().status() == net::URLRequestStatus::HANDLED_EXTERNALLY) {
[email protected]48944382011-04-23 13:28:16230 bool is_redirect = request->response_headers() &&
231 net::HttpResponseHeaders::IsRedirectResponseCode(
232 request->response_headers()->response_code());
233 if (!is_redirect) {
234 ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
[email protected]673514522011-07-13 18:17:18235 profile_, extension_info_map_.get(), request);
[email protected]48944382011-04-23 13:28:16236 }
[email protected]a83dd332011-07-13 10:41:01237 } else if (request->status().status() == net::URLRequestStatus::FAILED ||
238 request->status().status() == net::URLRequestStatus::CANCELED) {
[email protected]05b6ab42011-04-23 13:46:04239 ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
[email protected]9045b8822012-01-13 20:35:35240 profile_, extension_info_map_.get(), request, started);
[email protected]a83dd332011-07-13 10:41:01241 } else {
242 NOTREACHED();
[email protected]48944382011-04-23 13:28:16243 }
[email protected]673514522011-07-13 18:17:18244 ForwardProxyErrors(request, event_router_.get(), profile_);
[email protected]6baff0b52012-03-06 01:30:18245
246 ForwardRequestStatus(REQUEST_DONE, request, profile_);
[email protected]8202d0c2011-02-23 08:31:14247}
[email protected]4b50cb52011-03-10 00:29:37248
[email protected]4875ba12011-03-30 22:31:51249void ChromeNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
250 ExtensionWebRequestEventRouter::GetInstance()->OnURLRequestDestroyed(
[email protected]673514522011-07-13 18:17:18251 profile_, request);
[email protected]4875ba12011-03-30 22:31:51252}
253
[email protected]82a37672011-05-03 12:02:41254void ChromeNetworkDelegate::OnPACScriptError(int line_number,
255 const string16& error) {
[email protected]c454fe672012-03-12 21:18:01256 extensions::ProxyEventRouter::GetInstance()->OnPACScriptError(
[email protected]673514522011-07-13 18:17:18257 event_router_.get(), profile_, line_number, error);
[email protected]82a37672011-05-03 12:02:41258}
[email protected]7efc582d2011-08-03 20:46:35259
[email protected]c2911d72011-10-03 22:16:36260net::NetworkDelegate::AuthRequiredResponse
261ChromeNetworkDelegate::OnAuthRequired(
[email protected]7efc582d2011-08-03 20:46:35262 net::URLRequest* request,
[email protected]c2911d72011-10-03 22:16:36263 const net::AuthChallengeInfo& auth_info,
264 const AuthCallback& callback,
265 net::AuthCredentials* credentials) {
[email protected]90449ab2011-10-11 15:36:45266 return ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired(
267 profile_, extension_info_map_.get(), request, auth_info,
268 callback, credentials);
[email protected]7efc582d2011-08-03 20:46:35269}
[email protected]9c8ae8c2012-03-09 13:13:35270
[email protected]4c219e22012-05-05 19:41:04271bool ChromeNetworkDelegate::OnCanGetCookies(
272 const net::URLRequest& request,
[email protected]9c8ae8c2012-03-09 13:13:35273 const net::CookieList& cookie_list) {
274 // NULL during tests, or when we're running in the system context.
275 if (!cookie_settings_)
276 return true;
277
278 bool allow = cookie_settings_->IsReadingCookieAllowed(
[email protected]4c219e22012-05-05 19:41:04279 request.url(), request.first_party_for_cookies());
[email protected]9c8ae8c2012-03-09 13:13:35280
281 int render_process_id = -1;
282 int render_view_id = -1;
283 if (content::ResourceRequestInfo::GetRenderViewForRequest(
[email protected]4c219e22012-05-05 19:41:04284 &request, &render_process_id, &render_view_id)) {
[email protected]9c8ae8c2012-03-09 13:13:35285 BrowserThread::PostTask(
286 BrowserThread::UI, FROM_HERE,
287 base::Bind(&TabSpecificContentSettings::CookiesRead,
288 render_process_id, render_view_id,
[email protected]4c219e22012-05-05 19:41:04289 request.url(), request.first_party_for_cookies(),
[email protected]fd473d12012-04-05 11:38:43290 cookie_list, !allow));
[email protected]9c8ae8c2012-03-09 13:13:35291 }
292
293 return allow;
294}
295
[email protected]4c219e22012-05-05 19:41:04296bool ChromeNetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
297 const std::string& cookie_line,
298 net::CookieOptions* options) {
[email protected]9c8ae8c2012-03-09 13:13:35299 // NULL during tests, or when we're running in the system context.
300 if (!cookie_settings_)
301 return true;
302
303 bool allow = cookie_settings_->IsSettingCookieAllowed(
[email protected]4c219e22012-05-05 19:41:04304 request.url(), request.first_party_for_cookies());
[email protected]9c8ae8c2012-03-09 13:13:35305
[email protected]4c219e22012-05-05 19:41:04306 if (cookie_settings_->IsCookieSessionOnly(request.url()))
[email protected]9c8ae8c2012-03-09 13:13:35307 options->set_force_session();
308
309 int render_process_id = -1;
310 int render_view_id = -1;
311 if (content::ResourceRequestInfo::GetRenderViewForRequest(
[email protected]4c219e22012-05-05 19:41:04312 &request, &render_process_id, &render_view_id)) {
[email protected]9c8ae8c2012-03-09 13:13:35313 BrowserThread::PostTask(
314 BrowserThread::UI, FROM_HERE,
315 base::Bind(&TabSpecificContentSettings::CookieChanged,
316 render_process_id, render_view_id,
[email protected]4c219e22012-05-05 19:41:04317 request.url(), request.first_party_for_cookies(),
[email protected]fd473d12012-04-05 11:38:43318 cookie_line, *options, !allow));
[email protected]9c8ae8c2012-03-09 13:13:35319 }
320
321 return allow;
322}
[email protected]4c219e22012-05-05 19:41:04323
324bool ChromeNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
325 const FilePath& path) const {
326 if (g_allow_file_access_)
327 return true;
328
329#if defined(OS_CHROMEOS)
330 // ChromeOS uses a whitelist to only allow access to files residing in the
331 // list of directories below.
332 static const char* const kLocalAccessWhiteList[] = {
333 "/home/chronos/user/Downloads",
334 "/home/chronos/user/log",
335 "/media",
336 "/opt/oem",
337 "/usr/share/chromeos-assets",
338 "/tmp",
339 "/var/log",
340 };
341
342 // If we're running Chrome for ChromeOS on Linux, we want to allow file
343 // access.
344 if (!base::chromeos::IsRunningOnChromeOS())
345 return true;
346
347 for (size_t i = 0; i < arraysize(kLocalAccessWhiteList); ++i) {
348 const FilePath white_listed_path(kLocalAccessWhiteList[i]);
349 // FilePath::operator== should probably handle trailing separators.
350 if (white_listed_path == path.StripTrailingSeparators() ||
351 white_listed_path.IsParent(path)) {
352 return true;
353 }
354 }
355 return false;
356#else
357 return true;
358#endif // defined(OS_CHROMEOS)
359}