Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: content/browser/devtools/protocol/network_handler.cc

Issue 2739323003: DevTools protocol interception, blocking & modification of requests (Closed)
Patch Set: Address remaining TODOs Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/devtools/protocol/network_handler.h" 5 #include "content/browser/devtools/protocol/network_handler.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/barrier_closure.h" 9 #include "base/barrier_closure.h"
10 #include "base/base64.h"
10 #include "base/command_line.h" 11 #include "base/command_line.h"
11 #include "base/containers/hash_tables.h" 12 #include "base/containers/hash_tables.h"
12 #include "base/process/process_handle.h" 13 #include "base/process/process_handle.h"
13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h" 16 #include "base/time/time.h"
16 #include "content/browser/devtools/devtools_session.h" 17 #include "content/browser/devtools/devtools_session.h"
18 #include "content/browser/devtools/devtools_url_interceptor_request_job.h"
17 #include "content/browser/devtools/protocol/page.h" 19 #include "content/browser/devtools/protocol/page.h"
18 #include "content/browser/devtools/protocol/security.h" 20 #include "content/browser/devtools/protocol/security.h"
19 #include "content/browser/frame_host/frame_tree_node.h" 21 #include "content/browser/frame_host/frame_tree_node.h"
20 #include "content/browser/frame_host/render_frame_host_impl.h" 22 #include "content/browser/frame_host/render_frame_host_impl.h"
21 #include "content/common/navigation_params.h" 23 #include "content/common/navigation_params.h"
22 #include "content/common/resource_request.h" 24 #include "content/common/resource_request.h"
23 #include "content/common/resource_request_completion_status.h" 25 #include "content/common/resource_request_completion_status.h"
24 #include "content/public/browser/browser_context.h" 26 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/browsing_data_remover.h" 28 #include "content/public/browser/browsing_data_remover.h"
27 #include "content/public/browser/content_browser_client.h" 29 #include "content/public/browser/content_browser_client.h"
28 #include "content/public/browser/render_process_host.h" 30 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/resource_context.h" 31 #include "content/public/browser/resource_context.h"
30 #include "content/public/browser/site_instance.h" 32 #include "content/public/browser/site_instance.h"
31 #include "content/public/browser/storage_partition.h" 33 #include "content/public/browser/storage_partition.h"
32 #include "content/public/browser/web_contents.h" 34 #include "content/public/browser/web_contents.h"
33 #include "content/public/common/content_client.h" 35 #include "content/public/common/content_client.h"
34 #include "content/public/common/content_switches.h" 36 #include "content/public/common/content_switches.h"
35 #include "content/public/common/resource_devtools_info.h" 37 #include "content/public/common/resource_devtools_info.h"
36 #include "content/public/common/resource_response.h" 38 #include "content/public/common/resource_response.h"
37 #include "net/base/net_errors.h" 39 #include "net/base/net_errors.h"
40 #include "net/base/upload_bytes_element_reader.h"
38 #include "net/cookies/cookie_store.h" 41 #include "net/cookies/cookie_store.h"
39 #include "net/http/http_response_headers.h" 42 #include "net/http/http_response_headers.h"
40 #include "net/url_request/url_request_context.h" 43 #include "net/url_request/url_request_context.h"
41 #include "net/url_request/url_request_context_getter.h" 44 #include "net/url_request/url_request_context_getter.h"
42 45
43 namespace content { 46 namespace content {
44 namespace protocol { 47 namespace protocol {
45 namespace { 48 namespace {
46 49
47 using ProtocolCookieArray = Array<Network::Cookie>; 50 using ProtocolCookieArray = Array<Network::Cookie>;
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 case blink::kWebReferrerPolicyOriginWhenCrossOrigin: 333 case blink::kWebReferrerPolicyOriginWhenCrossOrigin:
331 return Network::Request::ReferrerPolicyEnum::OriginWhenCrossOrigin; 334 return Network::Request::ReferrerPolicyEnum::OriginWhenCrossOrigin;
332 case blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin: 335 case blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin:
333 return Network::Request::ReferrerPolicyEnum:: 336 return Network::Request::ReferrerPolicyEnum::
334 NoReferrerWhenDowngradeOriginWhenCrossOrigin; 337 NoReferrerWhenDowngradeOriginWhenCrossOrigin;
335 } 338 }
336 NOTREACHED(); 339 NOTREACHED();
337 return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade; 340 return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade;
338 } 341 }
339 342
343 String referrerPolicy(net::URLRequest::ReferrerPolicy referrer_policy) {
344 switch (referrer_policy) {
345 case net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
346 return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade;
347 case net::URLRequest::
348 REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
349 return Network::Request::ReferrerPolicyEnum::
350 NoReferrerWhenDowngradeOriginWhenCrossOrigin;
351 case net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
352 return Network::Request::ReferrerPolicyEnum::
353 NoReferrerWhenDowngradeOriginWhenCrossOrigin;
354 case net::URLRequest::NEVER_CLEAR_REFERRER:
355 return Network::Request::ReferrerPolicyEnum::Origin;
356 case net::URLRequest::ORIGIN:
357 return Network::Request::ReferrerPolicyEnum::Origin;
358 case net::URLRequest::NO_REFERRER:
359 return Network::Request::ReferrerPolicyEnum::NoReferrer;
360 default:
361 break;
362 }
363 NOTREACHED();
364 return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade;
365 }
366
340 String securityState(const GURL& url, const net::CertStatus& cert_status) { 367 String securityState(const GURL& url, const net::CertStatus& cert_status) {
341 if (!url.SchemeIsCryptographic()) 368 if (!url.SchemeIsCryptographic())
342 return Security::SecurityStateEnum::Neutral; 369 return Security::SecurityStateEnum::Neutral;
343 if (net::IsCertStatusError(cert_status) && 370 if (net::IsCertStatusError(cert_status) &&
344 !net::IsCertStatusMinorError(cert_status)) { 371 !net::IsCertStatusMinorError(cert_status)) {
345 return Security::SecurityStateEnum::Insecure; 372 return Security::SecurityStateEnum::Insecure;
346 } 373 }
347 return Security::SecurityStateEnum::Secure; 374 return Security::SecurityStateEnum::Secure;
348 } 375 }
349 376
377 net::Error NetErrorFromString(const std::string& error) {
378 if (error == Network::ErrorReasonEnum::Failed)
379 return net::ERR_FAILED;
380 if (error == Network::ErrorReasonEnum::Aborted)
381 return net::ERR_ABORTED;
382 if (error == Network::ErrorReasonEnum::TimedOut)
383 return net::ERR_TIMED_OUT;
384 if (error == Network::ErrorReasonEnum::AccessDenied)
385 return net::ERR_ACCESS_DENIED;
386 if (error == Network::ErrorReasonEnum::ConnectionClosed)
387 return net::ERR_CONNECTION_CLOSED;
388 if (error == Network::ErrorReasonEnum::ConnectionReset)
389 return net::ERR_CONNECTION_RESET;
390 if (error == Network::ErrorReasonEnum::ConnectionRefused)
391 return net::ERR_CONNECTION_REFUSED;
392 if (error == Network::ErrorReasonEnum::ConnectionAborted)
393 return net::ERR_CONNECTION_ABORTED;
394 if (error == Network::ErrorReasonEnum::ConnectionFailed)
395 return net::ERR_CONNECTION_FAILED;
396 if (error == Network::ErrorReasonEnum::NameNotResolved)
397 return net::ERR_NAME_NOT_RESOLVED;
398 if (error == Network::ErrorReasonEnum::InternetDisconnected)
399 return net::ERR_INTERNET_DISCONNECTED;
400 if (error == Network::ErrorReasonEnum::AddressUnreachable)
401 return net::ERR_ADDRESS_UNREACHABLE;
402 return net::ERR_FAILED;
403 }
404
350 double timeDelta(base::TimeTicks time, 405 double timeDelta(base::TimeTicks time,
351 base::TimeTicks start, 406 base::TimeTicks start,
352 double invalid_value = -1) { 407 double invalid_value = -1) {
353 return time.is_null() ? invalid_value : (time - start).InMillisecondsF(); 408 return time.is_null() ? invalid_value : (time - start).InMillisecondsF();
354 } 409 }
355 410
356 std::unique_ptr<Network::ResourceTiming> getTiming( 411 std::unique_ptr<Network::ResourceTiming> getTiming(
357 const net::LoadTimingInfo& load_timing) { 412 const net::LoadTimingInfo& load_timing) {
358 const base::TimeTicks kNullTicks; 413 const base::TimeTicks kNullTicks;
359 return Network::ResourceTiming::Create() 414 return Network::ResourceTiming::Create()
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 } 468 }
414 } 469 }
415 return protocol; 470 return protocol;
416 } 471 }
417 472
418 } // namespace 473 } // namespace
419 474
420 NetworkHandler::NetworkHandler() 475 NetworkHandler::NetworkHandler()
421 : DevToolsDomainHandler(Network::Metainfo::domainName), 476 : DevToolsDomainHandler(Network::Metainfo::domainName),
422 host_(nullptr), 477 host_(nullptr),
423 enabled_(false) { 478 enabled_(false),
424 } 479 interception_enabled_(false),
480 weak_factory_(this) {}
425 481
426 NetworkHandler::~NetworkHandler() { 482 NetworkHandler::~NetworkHandler() {
427 } 483 }
428 484
429 // static 485 // static
430 std::vector<NetworkHandler*> NetworkHandler::ForAgentHost( 486 std::vector<NetworkHandler*> NetworkHandler::ForAgentHost(
431 DevToolsAgentHostImpl* host) { 487 DevToolsAgentHostImpl* host) {
432 return DevToolsSession::HandlersForAgentHost<NetworkHandler>( 488 return DevToolsSession::HandlersForAgentHost<NetworkHandler>(
433 host, Network::Metainfo::domainName); 489 host, Network::Metainfo::domainName);
434 } 490 }
435 491
436 void NetworkHandler::Wire(UberDispatcher* dispatcher) { 492 void NetworkHandler::Wire(UberDispatcher* dispatcher) {
437 frontend_.reset(new Network::Frontend(dispatcher->channel())); 493 frontend_.reset(new Network::Frontend(dispatcher->channel()));
438 Network::Dispatcher::wire(dispatcher, this); 494 Network::Dispatcher::wire(dispatcher, this);
439 } 495 }
440 496
441 void NetworkHandler::SetRenderFrameHost(RenderFrameHostImpl* host) { 497 void NetworkHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
442 host_ = host; 498 host_ = host;
443 } 499 }
444 500
445 Response NetworkHandler::Enable(Maybe<int> max_total_size, 501 Response NetworkHandler::Enable(Maybe<int> max_total_size,
446 Maybe<int> max_resource_size) { 502 Maybe<int> max_resource_size) {
447 enabled_ = true; 503 enabled_ = true;
448 return Response::FallThrough(); 504 return Response::FallThrough();
449 } 505 }
450 506
451 Response NetworkHandler::Disable() { 507 Response NetworkHandler::Disable() {
452 enabled_ = false; 508 enabled_ = false;
453 user_agent_ = std::string(); 509 user_agent_ = std::string();
510 EnableFetchInterception(false);
454 return Response::FallThrough(); 511 return Response::FallThrough();
455 } 512 }
456 513
457 Response NetworkHandler::ClearBrowserCache() { 514 Response NetworkHandler::ClearBrowserCache() {
458 if (host_) { 515 if (host_) {
459 content::BrowsingDataRemover* remover = 516 content::BrowsingDataRemover* remover =
460 content::BrowserContext::GetBrowsingDataRemover( 517 content::BrowserContext::GetBrowsingDataRemover(
461 host_->GetSiteInstance()->GetProcess()->GetBrowserContext()); 518 host_->GetSiteInstance()->GetProcess()->GetBrowserContext());
462 remover->Remove(base::Time(), base::Time::Max(), 519 remover->Remove(base::Time(), base::Time::Max(),
463 content::BrowsingDataRemover::DATA_TYPE_CACHE, 520 content::BrowsingDataRemover::DATA_TYPE_CACHE,
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 request_id, 820 request_id,
764 base::TimeTicks::Now().ToInternalValue() / 821 base::TimeTicks::Now().ToInternalValue() /
765 static_cast<double>(base::Time::kMicrosecondsPerSecond), 822 static_cast<double>(base::Time::kMicrosecondsPerSecond),
766 Page::ResourceTypeEnum::Document, error_string, cancelled); 823 Page::ResourceTypeEnum::Document, error_string, cancelled);
767 } 824 }
768 825
769 std::string NetworkHandler::UserAgentOverride() const { 826 std::string NetworkHandler::UserAgentOverride() const {
770 return enabled_ ? user_agent_ : std::string(); 827 return enabled_ ? user_agent_ : std::string();
771 } 828 }
772 829
830 DispatchResponse NetworkHandler::EnableFetchInterception(bool enabled) {
831 if (interception_enabled_ == enabled)
832 return Response::OK(); // Nothing to do.
833
834 WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
835 if (!web_contents)
836 return Response::OK();
837
838 DevToolsURLRequestInterceptor* devtools_url_request_interceptor =
839 DevToolsURLRequestInterceptor::FromBrowserContext(
840 web_contents->GetBrowserContext());
841 if (!devtools_url_request_interceptor)
842 return Response::OK();
843
844 if (enabled) {
845 BrowserThread::PostTask(
846 BrowserThread::IO, FROM_HERE,
847 base::BindOnce(
848 &DevToolsURLRequestInterceptor::State::StartInterceptingRequests,
849 devtools_url_request_interceptor->state().GetWeakPtr(),
dgozman 2017/05/25 21:29:36 It's prohibited to dereference weak pointer on the
alex clarke (OOO till 29th) 2017/05/26 19:37:03 An alternative is we can make the state ref counte
850 web_contents, weak_factory_.GetWeakPtr()));
851 } else {
852 BrowserThread::PostTask(
853 BrowserThread::IO, FROM_HERE,
854 base::BindOnce(
855 &DevToolsURLRequestInterceptor::State::StopInterceptingRequests,
856 devtools_url_request_interceptor->state().GetWeakPtr(),
857 web_contents));
858 }
859 interception_enabled_ = enabled;
860 return Response::OK();
861 }
862
863 namespace {
864 void ProcessContinueRequestResultOnIoThread(
865 std::unique_ptr<NetworkHandler::ContinueRequestCallback> callback,
866 const DevToolsURLRequestInterceptor::CommandStatus& result) {
867 switch (result) {
868 case DevToolsURLRequestInterceptor::CommandStatus::OK:
869 BrowserThread::PostTask(
870 BrowserThread::UI, FROM_HERE,
871 base::BindOnce(&NetworkHandler::ContinueRequestCallback::sendSuccess,
872 base::Owned(callback.release())));
873 break;
874 case DevToolsURLRequestInterceptor::CommandStatus::UnknownInterceptionId:
875 BrowserThread::PostTask(
876 BrowserThread::UI, FROM_HERE,
877 base::BindOnce(&NetworkHandler::ContinueRequestCallback::sendFailure,
878 base::Owned(callback.release()),
879 Response::InvalidParams("Invalid InterceptionId.")));
880 break;
881 case DevToolsURLRequestInterceptor::CommandStatus::CommandAlreadyProcessed:
882 BrowserThread::PostTask(
883 BrowserThread::UI, FROM_HERE,
884 base::BindOnce(
885 &NetworkHandler::ContinueRequestCallback::sendFailure,
886 base::Owned(callback.release()),
887 Response::InvalidParams("Response already processed.")));
888 break;
889 }
890 }
891
892 bool GetPostData(const net::URLRequest* request, std::string* post_data) {
893 if (!request->has_upload())
894 return false;
895
896 const net::UploadDataStream* stream = request->get_upload();
897 if (!stream->GetElementReaders())
898 return false;
899
900 if (stream->GetElementReaders()->size() == 0)
901 return false;
902
903 DCHECK_EQ(1u, stream->GetElementReaders()->size());
dgozman 2017/05/25 21:29:36 Is this guaranteed by net?
alex clarke (OOO till 29th) 2017/05/26 19:37:03 Looks like no although this is the common case. I
dgozman 2017/05/30 21:44:27 IIUC, std::string += operator is smart since it us
alex clarke (OOO till 29th) 2017/05/31 15:52:02 Mmm OK that should help. I'm just worried about p
904 const net::UploadBytesElementReader* reader =
905 (*stream->GetElementReaders())[0]->AsBytesReader();
906 if (!reader)
907 return false;
908 *post_data = std::string(reader->bytes(), reader->length());
dgozman 2017/05/25 21:29:36 I think we'll need to base64-encode this? Let's ha
alex clarke (OOO till 29th) 2017/05/26 19:37:03 For reference it's simple to base 64 encode that h
909 return true;
910 }
911 } // namespace
912
913 void NetworkHandler::ContinueRequest(
914 const std::string& interception_id,
915 Maybe<std::string> error_reason,
916 Maybe<std::string> base64_raw_response,
917 Maybe<std::string> url,
918 Maybe<std::string> method,
919 Maybe<std::string> post_data,
920 Maybe<protocol::Network::Headers> headers,
921 std::unique_ptr<ContinueRequestCallback> callback) {
922 DevToolsURLRequestInterceptor* devtools_url_request_interceptor =
923 DevToolsURLRequestInterceptor::FromBrowserContext(
924 WebContents::FromRenderFrameHost(host_)->GetBrowserContext());
925 if (!devtools_url_request_interceptor) {
926 callback->sendFailure(Response::InternalError());
927 return;
928 }
929
930 base::Optional<net::Error> error;
931 if (error_reason.isJust())
932 error = NetErrorFromString(error_reason.fromJust());
933
934 base::Optional<std::string> raw_response;
935 if (base64_raw_response.isJust()) {
936 std::string decoded;
937 if (!base::Base64Decode(base64_raw_response.fromJust(), &decoded)) {
938 callback->sendFailure(Response::InvalidParams("Invalid rawResponse."));
939 return;
940 }
941 raw_response = decoded;
942 }
943
944 BrowserThread::PostTask(
945 BrowserThread::IO, FROM_HERE,
946 base::BindOnce(
947 &DevToolsURLRequestInterceptor::State::ContinueRequest,
948 devtools_url_request_interceptor->state().GetWeakPtr(),
dgozman 2017/05/25 21:29:36 Similar thing here.
alex clarke (OOO till 29th) 2017/05/26 19:37:03 Done.
949 interception_id,
950 base::MakeUnique<DevToolsURLRequestInterceptor::Modifications>(
951 std::move(error), std::move(raw_response), std::move(url),
952 std::move(method), std::move(post_data), std::move(headers)),
953 base::BindOnce(ProcessContinueRequestResultOnIoThread,
954 base::Passed(std::move(callback)))));
955 }
956
957 // static
958 std::unique_ptr<Network::Request> NetworkHandler::CreateRequestFromURLRequest(
959 const net::URLRequest* request) {
960 std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create());
961 for (net::HttpRequestHeaders::Iterator it(request->extra_request_headers());
962 it.GetNext();) {
963 headers_dict->setString(it.name(), it.value());
964 }
965 std::unique_ptr<protocol::Network::Request> request_object =
966 Network::Request::Create()
967 .SetUrl(request->url().spec())
968 .SetMethod(request->method())
969 .SetHeaders(Object::fromValue(headers_dict.get(), nullptr))
970 .SetInitialPriority(resourcePriority(request->priority()))
971 .SetReferrerPolicy(referrerPolicy(request->referrer_policy()))
972 .Build();
973 std::string post_data;
974 if (GetPostData(request, &post_data))
975 request_object->SetPostData(std::move(post_data));
976 return request_object;
977 }
978
773 } // namespace protocol 979 } // namespace protocol
774 } // namespace content 980 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698