blob: 60f39a1b4df8dc770a8977f69f55ce7ecad54ae7 [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
[email protected]8b12ebe2012-03-21 17:42:057#include "base/base64.h"
[email protected]ac039522010-06-15 16:39:448#include "base/logging.h"
[email protected]8b12ebe2012-03-21 17:42:059#include "base/metrics/histogram.h"
[email protected]6baff0b52012-03-06 01:30:1810#include "chrome/browser/browser_process.h"
[email protected]9c8ae8c2012-03-09 13:13:3511#include "chrome/browser/content_settings/cookie_settings.h"
12#include "chrome/browser/content_settings/tab_specific_content_settings.h"
[email protected]8523ba52011-05-22 19:00:5813#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
[email protected]aa84a7e2012-03-15 21:29:0614#include "chrome/browser/extensions/api/proxy/proxy_api.h"
[email protected]2b33dcd02012-03-18 01:34:1615#include "chrome/browser/extensions/api/web_request/web_request_api.h"
[email protected]3ce02412011-03-01 12:01:1516#include "chrome/browser/extensions/extension_event_router_forwarder.h"
[email protected]c357acb42011-06-09 20:52:4217#include "chrome/browser/extensions/extension_info_map.h"
[email protected]6baff0b52012-03-06 01:30:1818#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]0a8db0d2011-04-13 15:15:4019#include "chrome/browser/prefs/pref_member.h"
[email protected]6baff0b52012-03-06 01:30:1820#include "chrome/browser/profiles/profile_manager.h"
[email protected]8523ba52011-05-22 19:00:5821#include "chrome/browser/task_manager/task_manager.h"
[email protected]0a8db0d2011-04-13 15:15:4022#include "chrome/common/pref_names.h"
[email protected]c38831a12011-10-28 12:44:4923#include "content/public/browser/browser_thread.h"
[email protected]9c1662b2012-03-06 15:44:3324#include "content/public/browser/render_view_host.h"
[email protected]9c8ae8c2012-03-09 13:13:3525#include "content/public/browser/resource_request_info.h"
[email protected]82b42302011-04-20 16:28:1626#include "net/base/host_port_pair.h"
[email protected]8b12ebe2012-03-21 17:42:0527#include "net/base/dns_util.h"
28#include "net/base/dnsrr_resolver.h"
[email protected]8202d0c2011-02-23 08:31:1429#include "net/base/net_errors.h"
[email protected]6a5f77c32011-09-04 19:19:5930#include "net/base/net_log.h"
[email protected]8b12ebe2012-03-21 17:42:0531#include "net/base/public_key_hashes.h"
[email protected]aa84a7e2012-03-15 21:29:0632#include "net/cookies/cookie_monster.h"
[email protected]ac039522010-06-15 16:39:4433#include "net/http/http_request_headers.h"
[email protected]48944382011-04-23 13:28:1634#include "net/http/http_response_headers.h"
[email protected]d05ef99c2011-02-01 21:38:1635#include "net/url_request/url_request.h"
36
[email protected]3e598ff12011-09-06 11:22:3437#if defined(ENABLE_CONFIGURATION_POLICY)
38#include "chrome/browser/policy/url_blacklist_manager.h"
39#endif
40
[email protected]631bb742011-11-02 11:29:3941using content::BrowserThread;
[email protected]eaabba22012-03-07 15:02:1142using content::RenderViewHost;
[email protected]ea114722012-03-12 01:11:2543using content::ResourceRequestInfo;
[email protected]631bb742011-11-02 11:29:3944
[email protected]d05ef99c2011-02-01 21:38:1645namespace {
46
[email protected]8202d0c2011-02-23 08:31:1447// If the |request| failed due to problems with a proxy, forward the error to
48// the proxy extension API.
[email protected]0651b812011-02-24 00:22:5049void ForwardProxyErrors(net::URLRequest* request,
[email protected]3ce02412011-03-01 12:01:1550 ExtensionEventRouterForwarder* event_router,
[email protected]673514522011-07-13 18:17:1851 void* profile) {
[email protected]8202d0c2011-02-23 08:31:1452 if (request->status().status() == net::URLRequestStatus::FAILED) {
[email protected]d0cc35b2011-09-08 12:02:0553 switch (request->status().error()) {
[email protected]8202d0c2011-02-23 08:31:1454 case net::ERR_PROXY_AUTH_UNSUPPORTED:
55 case net::ERR_PROXY_CONNECTION_FAILED:
56 case net::ERR_TUNNEL_CONNECTION_FAILED:
[email protected]c454fe672012-03-12 21:18:0157 extensions::ProxyEventRouter::GetInstance()->OnProxyError(
[email protected]d0cc35b2011-09-08 12:02:0558 event_router, profile, request->status().error());
[email protected]8202d0c2011-02-23 08:31:1459 }
60 }
61}
62
[email protected]6baff0b52012-03-06 01:30:1863enum RequestStatus { REQUEST_STARTED, REQUEST_DONE };
64
65// Notifies the ExtensionProcessManager that a request has started or stopped
66// for a particular RenderView.
67void NotifyEPMRequestStatus(RequestStatus status,
68 void* profile_id,
69 int process_id,
70 int render_view_id) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
72 Profile* profile = reinterpret_cast<Profile*>(profile_id);
73 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
74 return;
75
[email protected]e5775a52012-03-17 04:59:5776 ExtensionProcessManager* extension_process_manager =
77 profile->GetExtensionProcessManager();
78 // This may be NULL in unit tests.
79 if (!extension_process_manager)
80 return;
81
[email protected]6baff0b52012-03-06 01:30:1882 // Will be NULL if the request was not issued on behalf of a renderer (e.g. a
83 // system-level request).
[email protected]d3e898e2012-03-14 03:45:0884 RenderViewHost* render_view_host =
85 RenderViewHost::FromID(process_id, render_view_id);
[email protected]e5775a52012-03-17 04:59:5786 if (render_view_host) {
[email protected]6baff0b52012-03-06 01:30:1887 if (status == REQUEST_STARTED) {
[email protected]d3e898e2012-03-14 03:45:0888 extension_process_manager->OnNetworkRequestStarted(render_view_host);
[email protected]6baff0b52012-03-06 01:30:1889 } else if (status == REQUEST_DONE) {
[email protected]d3e898e2012-03-14 03:45:0890 extension_process_manager->OnNetworkRequestDone(render_view_host);
[email protected]6baff0b52012-03-06 01:30:1891 } else {
92 NOTREACHED();
93 }
94 }
95}
96
97void ForwardRequestStatus(
98 RequestStatus status, net::URLRequest* request, void* profile_id) {
[email protected]ea114722012-03-12 01:11:2599 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
100 if (!info)
101 return;
102
[email protected]6baff0b52012-03-06 01:30:18103 int process_id, render_view_id;
[email protected]ea114722012-03-12 01:11:25104 if (info->GetAssociatedRenderView(&process_id, &render_view_id)) {
[email protected]6baff0b52012-03-06 01:30:18105 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
106 base::Bind(&NotifyEPMRequestStatus,
107 status, profile_id, process_id, render_view_id));
108 }
109}
110
[email protected]8b12ebe2012-03-21 17:42:05111const char* const kComodoCerts[] = {
112 kSPKIHash_AAACertificateServices,
113 kSPKIHash_AddTrustClass1CARoot,
114 kSPKIHash_AddTrustExternalCARoot,
115 kSPKIHash_AddTrustPublicCARoot,
116 kSPKIHash_AddTrustQualifiedCARoot,
117 kSPKIHash_COMODOCertificationAuthority,
118 kSPKIHash_SecureCertificateServices,
119 kSPKIHash_TrustedCertificateServices,
120 kSPKIHash_UTNDATACorpSGC,
121 kSPKIHash_UTNUSERFirstClientAuthenticationandEmail,
122 kSPKIHash_UTNUSERFirstHardware,
123 kSPKIHash_UTNUSERFirstObject,
124};
125
126// IsComodoCertificate returns true if a known Comodo public key appears in
127// |public_key_hashes|.
128// TODO(agl): remove once experiment is complete, by July 2012.
129static bool IsComodoCertificate(
130 const std::vector<net::SHA1Fingerprint>& public_key_hashes) {
131 for (std::vector<net::SHA1Fingerprint>::const_iterator
132 i = public_key_hashes.begin(); i != public_key_hashes.end(); ++i) {
133 std::string base64_hash;
134 base::Base64Encode(
135 base::StringPiece(reinterpret_cast<const char*>(i->data),
136 arraysize(i->data)),
137 &base64_hash);
138 base64_hash = "sha1/" + base64_hash;
139
140 for (size_t j = 0; j < arraysize(kComodoCerts); j++) {
141 if (base64_hash == kComodoCerts[j])
142 return true;
143 }
144 }
145
146 return false;
147}
148
149// RecordComodoDNSResult is a callback from a DNS resolution. It records the
150// elapsed time in a histogram.
151// TODO(agl): remove once experiment is complete, by July 2012.
152static void RecordComodoDNSResult(net::RRResponse* response,
153 base::TimeTicks start_time,
154 int result) {
155 base::TimeDelta total_time = base::TimeTicks::Now() - start_time;
156 if (total_time.InMilliseconds() > 10) {
157 // If the reply took > 10 ms there's a good chance that it didn't come from
158 // a local DNS cache.
159 if (result == net::OK &&
160 response->rrdatas.size() &&
161 response->rrdatas[0].find("wibble") != std::string::npos) {
162 UMA_HISTOGRAM_TIMES("Net.ComodoDNSExperimentSuccessTime", total_time);
163 } else {
164 UMA_HISTOGRAM_TIMES("Net.ComodoDNSExperimentFailureTime", total_time);
165 }
166 }
167}
168
169bool g_comodo_dns_experiment_enabled = false;
170
[email protected]d05ef99c2011-02-01 21:38:16171} // namespace
[email protected]ac039522010-06-15 16:39:44172
[email protected]0651b812011-02-24 00:22:50173ChromeNetworkDelegate::ChromeNetworkDelegate(
[email protected]3ce02412011-03-01 12:01:15174 ExtensionEventRouterForwarder* event_router,
[email protected]c357acb42011-06-09 20:52:42175 ExtensionInfoMap* extension_info_map,
[email protected]6a5f77c32011-09-04 19:19:59176 const policy::URLBlacklistManager* url_blacklist_manager,
[email protected]673514522011-07-13 18:17:18177 void* profile,
[email protected]9c8ae8c2012-03-09 13:13:35178 CookieSettings* cookie_settings,
[email protected]a8c1e7452011-05-14 06:17:07179 BooleanPrefMember* enable_referrers)
[email protected]3ce02412011-03-01 12:01:15180 : event_router_(event_router),
[email protected]673514522011-07-13 18:17:18181 profile_(profile),
[email protected]9c8ae8c2012-03-09 13:13:35182 cookie_settings_(cookie_settings),
[email protected]c357acb42011-06-09 20:52:42183 extension_info_map_(extension_info_map),
[email protected]6a5f77c32011-09-04 19:19:59184 enable_referrers_(enable_referrers),
185 url_blacklist_manager_(url_blacklist_manager) {
[email protected]4b50cb52011-03-10 00:29:37186 DCHECK(event_router);
[email protected]0a8db0d2011-04-13 15:15:40187 DCHECK(enable_referrers);
[email protected]9c8ae8c2012-03-09 13:13:35188 DCHECK(!profile || cookie_settings);
[email protected]0651b812011-02-24 00:22:50189}
190
[email protected]ac039522010-06-15 16:39:44191ChromeNetworkDelegate::~ChromeNetworkDelegate() {}
192
[email protected]0a8db0d2011-04-13 15:15:40193// static
194void ChromeNetworkDelegate::InitializeReferrersEnabled(
195 BooleanPrefMember* enable_referrers,
196 PrefService* pref_service) {
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
198 enable_referrers->Init(prefs::kEnableReferrers, pref_service, NULL);
199 enable_referrers->MoveToThread(BrowserThread::IO);
200}
201
[email protected]8b12ebe2012-03-21 17:42:05202// static
203void ChromeNetworkDelegate::EnableComodoDNSExperiment() {
204 g_comodo_dns_experiment_enabled = true;
205}
206
[email protected]4875ba12011-03-30 22:31:51207int ChromeNetworkDelegate::OnBeforeURLRequest(
[email protected]4c76d7c2011-04-15 19:14:12208 net::URLRequest* request,
[email protected]084262c2011-12-01 21:12:47209 const net::CompletionCallback& callback,
[email protected]4c76d7c2011-04-15 19:14:12210 GURL* new_url) {
[email protected]3e598ff12011-09-06 11:22:34211#if defined(ENABLE_CONFIGURATION_POLICY)
[email protected]6a5f77c32011-09-04 19:19:59212 // TODO(joaodasilva): This prevents extensions from seeing URLs that are
213 // blocked. However, an extension might redirect the request to another URL,
214 // which is not blocked.
215 if (url_blacklist_manager_ &&
216 url_blacklist_manager_->IsURLBlocked(request->url())) {
217 // URL access blocked by policy.
218 scoped_refptr<net::NetLog::EventParameters> params;
219 params = new net::NetLogStringParameter("url", request->url().spec());
220 request->net_log().AddEvent(
221 net::NetLog::TYPE_CHROME_POLICY_ABORTED_REQUEST, params);
222 return net::ERR_NETWORK_ACCESS_DENIED;
223 }
[email protected]3e598ff12011-09-06 11:22:34224#endif
[email protected]6a5f77c32011-09-04 19:19:59225
[email protected]6baff0b52012-03-06 01:30:18226 ForwardRequestStatus(REQUEST_STARTED, request, profile_);
227
[email protected]0a8db0d2011-04-13 15:15:40228 if (!enable_referrers_->GetValue())
229 request->set_referrer(std::string());
[email protected]05cc4e72011-03-08 21:29:48230 return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
[email protected]673514522011-07-13 18:17:18231 profile_, extension_info_map_.get(), request, callback, new_url);
[email protected]d05ef99c2011-02-01 21:38:16232}
233
[email protected]4875ba12011-03-30 22:31:51234int ChromeNetworkDelegate::OnBeforeSendHeaders(
[email protected]636eccd2011-06-28 12:28:01235 net::URLRequest* request,
[email protected]084262c2011-12-01 21:12:47236 const net::CompletionCallback& callback,
[email protected]4c76d7c2011-04-15 19:14:12237 net::HttpRequestHeaders* headers) {
[email protected]4875ba12011-03-30 22:31:51238 return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
[email protected]673514522011-07-13 18:17:18239 profile_, extension_info_map_.get(), request, callback, headers);
[email protected]ac039522010-06-15 16:39:44240}
[email protected]8202d0c2011-02-23 08:31:14241
[email protected]5796dc942011-07-14 19:26:10242void ChromeNetworkDelegate::OnSendHeaders(
243 net::URLRequest* request,
[email protected]783573b2011-05-13 11:05:15244 const net::HttpRequestHeaders& headers) {
[email protected]5796dc942011-07-14 19:26:10245 ExtensionWebRequestEventRouter::GetInstance()->OnSendHeaders(
246 profile_, extension_info_map_.get(), request, headers);
[email protected]82b42302011-04-20 16:28:16247}
248
[email protected]ea8141e2011-10-05 13:12:51249int ChromeNetworkDelegate::OnHeadersReceived(
250 net::URLRequest* request,
[email protected]084262c2011-12-01 21:12:47251 const net::CompletionCallback& callback,
[email protected]ea8141e2011-10-05 13:12:51252 net::HttpResponseHeaders* original_response_headers,
253 scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
254 return ExtensionWebRequestEventRouter::GetInstance()->OnHeadersReceived(
255 profile_, extension_info_map_.get(), request, callback,
256 original_response_headers, override_response_headers);
257}
258
[email protected]31b2e5f2011-04-20 16:58:32259void ChromeNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
260 const GURL& new_location) {
261 ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
[email protected]673514522011-07-13 18:17:18262 profile_, extension_info_map_.get(), request, new_location);
[email protected]31b2e5f2011-04-20 16:58:32263}
264
265
[email protected]8202d0c2011-02-23 08:31:14266void ChromeNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
[email protected]62fecae2011-04-21 11:08:24267 ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
[email protected]673514522011-07-13 18:17:18268 profile_, extension_info_map_.get(), request);
269 ForwardProxyErrors(request, event_router_.get(), profile_);
[email protected]8b12ebe2012-03-21 17:42:05270
271 if (g_comodo_dns_experiment_enabled) {
272 // This is a temporary experiment, in conjuction with Comodo, to measure the
273 // effectiveness of a possible DNS-based revocation mechanism.
274 // TODO(agl): remove once experiment is complete, by July 2012.
275 const net::SSLInfo& ssl_info = request->response_info().ssl_info;
276 if (request->response_info().was_cached == false &&
277 ssl_info.is_valid() &&
278 ssl_info.is_issued_by_known_root &&
279 IsComodoCertificate(ssl_info.public_key_hashes)) {
280 if (dnsrr_resolver_.get() == NULL)
281 dnsrr_resolver_.reset(new net::DnsRRResolver);
282
283 // The Comodo DNS record has a 20 minute TTL, so we won't actually
284 // request it more than three times an hour because it'll be in the
285 // DnsRRResolver's cache. However, just in case something goes wrong we
286 // also implement a hard stop to prevent resolutions more than once
287 // every ten minutes.
288 const base::TimeTicks now(base::TimeTicks::Now());
289 if (!last_comodo_resolution_time_.is_null() &&
290 (now - last_comodo_resolution_time_).InMinutes() < 10) {
291 return;
292 }
293 last_comodo_resolution_time_ = now;
294
295 net::RRResponse* response = new net::RRResponse;
296 base::TimeTicks start_time(now);
297 dnsrr_resolver_->Resolve(
298 "wibble.comodoca.com", net::kDNS_TXT, 0 /* flags */,
299 Bind(RecordComodoDNSResult, base::Owned(response), start_time),
300 response, 0 /* priority */,
301 request->net_log());
302 }
303 }
[email protected]8202d0c2011-02-23 08:31:14304}
305
[email protected]8523ba52011-05-22 19:00:58306void ChromeNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
307 int bytes_read) {
308 TaskManager::GetInstance()->model()->NotifyBytesRead(request, bytes_read);
309}
310
[email protected]9045b8822012-01-13 20:35:35311void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
312 bool started) {
[email protected]a83dd332011-07-13 10:41:01313 if (request->status().status() == net::URLRequestStatus::SUCCESS ||
314 request->status().status() == net::URLRequestStatus::HANDLED_EXTERNALLY) {
[email protected]48944382011-04-23 13:28:16315 bool is_redirect = request->response_headers() &&
316 net::HttpResponseHeaders::IsRedirectResponseCode(
317 request->response_headers()->response_code());
318 if (!is_redirect) {
319 ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
[email protected]673514522011-07-13 18:17:18320 profile_, extension_info_map_.get(), request);
[email protected]48944382011-04-23 13:28:16321 }
[email protected]a83dd332011-07-13 10:41:01322 } else if (request->status().status() == net::URLRequestStatus::FAILED ||
323 request->status().status() == net::URLRequestStatus::CANCELED) {
[email protected]05b6ab42011-04-23 13:46:04324 ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
[email protected]9045b8822012-01-13 20:35:35325 profile_, extension_info_map_.get(), request, started);
[email protected]a83dd332011-07-13 10:41:01326 } else {
327 NOTREACHED();
[email protected]48944382011-04-23 13:28:16328 }
[email protected]673514522011-07-13 18:17:18329 ForwardProxyErrors(request, event_router_.get(), profile_);
[email protected]6baff0b52012-03-06 01:30:18330
331 ForwardRequestStatus(REQUEST_DONE, request, profile_);
[email protected]8202d0c2011-02-23 08:31:14332}
[email protected]4b50cb52011-03-10 00:29:37333
[email protected]4875ba12011-03-30 22:31:51334void ChromeNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
335 ExtensionWebRequestEventRouter::GetInstance()->OnURLRequestDestroyed(
[email protected]673514522011-07-13 18:17:18336 profile_, request);
[email protected]4875ba12011-03-30 22:31:51337}
338
[email protected]82a37672011-05-03 12:02:41339void ChromeNetworkDelegate::OnPACScriptError(int line_number,
340 const string16& error) {
[email protected]c454fe672012-03-12 21:18:01341 extensions::ProxyEventRouter::GetInstance()->OnPACScriptError(
[email protected]673514522011-07-13 18:17:18342 event_router_.get(), profile_, line_number, error);
[email protected]82a37672011-05-03 12:02:41343}
[email protected]7efc582d2011-08-03 20:46:35344
[email protected]c2911d72011-10-03 22:16:36345net::NetworkDelegate::AuthRequiredResponse
346ChromeNetworkDelegate::OnAuthRequired(
[email protected]7efc582d2011-08-03 20:46:35347 net::URLRequest* request,
[email protected]c2911d72011-10-03 22:16:36348 const net::AuthChallengeInfo& auth_info,
349 const AuthCallback& callback,
350 net::AuthCredentials* credentials) {
[email protected]90449ab2011-10-11 15:36:45351 return ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired(
352 profile_, extension_info_map_.get(), request, auth_info,
353 callback, credentials);
[email protected]7efc582d2011-08-03 20:46:35354}
[email protected]9c8ae8c2012-03-09 13:13:35355
356bool ChromeNetworkDelegate::CanGetCookies(
357 const net::URLRequest* request,
358 const net::CookieList& cookie_list) {
359 // NULL during tests, or when we're running in the system context.
360 if (!cookie_settings_)
361 return true;
362
363 bool allow = cookie_settings_->IsReadingCookieAllowed(
364 request->url(), request->first_party_for_cookies());
365
366 int render_process_id = -1;
367 int render_view_id = -1;
368 if (content::ResourceRequestInfo::GetRenderViewForRequest(
369 request, &render_process_id, &render_view_id)) {
370 BrowserThread::PostTask(
371 BrowserThread::UI, FROM_HERE,
372 base::Bind(&TabSpecificContentSettings::CookiesRead,
373 render_process_id, render_view_id,
[email protected]fd473d12012-04-05 11:38:43374 request->url(), request->first_party_for_cookies(),
375 cookie_list, !allow));
[email protected]9c8ae8c2012-03-09 13:13:35376 }
377
378 return allow;
379}
380
381bool ChromeNetworkDelegate::CanSetCookie(
382 const net::URLRequest* request,
383 const std::string& cookie_line,
384 net::CookieOptions* options) {
385 // NULL during tests, or when we're running in the system context.
386 if (!cookie_settings_)
387 return true;
388
389 bool allow = cookie_settings_->IsSettingCookieAllowed(
390 request->url(), request->first_party_for_cookies());
391
392 if (cookie_settings_->IsCookieSessionOnly(request->url()))
393 options->set_force_session();
394
395 int render_process_id = -1;
396 int render_view_id = -1;
397 if (content::ResourceRequestInfo::GetRenderViewForRequest(
398 request, &render_process_id, &render_view_id)) {
399 BrowserThread::PostTask(
400 BrowserThread::UI, FROM_HERE,
401 base::Bind(&TabSpecificContentSettings::CookieChanged,
402 render_process_id, render_view_id,
[email protected]fd473d12012-04-05 11:38:43403 request->url(), request->first_party_for_cookies(),
404 cookie_line, *options, !allow));
[email protected]9c8ae8c2012-03-09 13:13:35405 }
406
407 return allow;
408}