Index: content/browser/devtools/protocol/network_handler.cc |
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc |
index 62abd9ece33f18a6bb49276e8ef33653c28e7fee..3e44d0987a6a157023819ec86e324dff63103797 100644 |
--- a/content/browser/devtools/protocol/network_handler.cc |
+++ b/content/browser/devtools/protocol/network_handler.cc |
@@ -7,6 +7,7 @@ |
#include <stddef.h> |
#include "base/barrier_closure.h" |
+#include "base/base64.h" |
#include "base/command_line.h" |
#include "base/containers/hash_tables.h" |
#include "base/process/process_handle.h" |
@@ -14,6 +15,7 @@ |
#include "base/strings/stringprintf.h" |
#include "base/time/time.h" |
#include "content/browser/devtools/devtools_session.h" |
+#include "content/browser/devtools/devtools_url_interceptor_request_job.h" |
#include "content/browser/devtools/protocol/page.h" |
#include "content/browser/devtools/protocol/security.h" |
#include "content/browser/frame_host/frame_tree_node.h" |
@@ -35,6 +37,7 @@ |
#include "content/public/common/resource_devtools_info.h" |
#include "content/public/common/resource_response.h" |
#include "net/base/net_errors.h" |
+#include "net/base/upload_bytes_element_reader.h" |
#include "net/cookies/cookie_store.h" |
#include "net/http/http_response_headers.h" |
#include "net/url_request/url_request_context.h" |
@@ -337,6 +340,30 @@ String referrerPolicy(blink::WebReferrerPolicy referrer_policy) { |
return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade; |
} |
+String referrerPolicy(net::URLRequest::ReferrerPolicy referrer_policy) { |
+ switch (referrer_policy) { |
+ case net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: |
+ return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade; |
+ case net::URLRequest:: |
+ REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN: |
+ return Network::Request::ReferrerPolicyEnum:: |
+ NoReferrerWhenDowngradeOriginWhenCrossOrigin; |
+ case net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN: |
+ return Network::Request::ReferrerPolicyEnum:: |
+ NoReferrerWhenDowngradeOriginWhenCrossOrigin; |
+ case net::URLRequest::NEVER_CLEAR_REFERRER: |
+ return Network::Request::ReferrerPolicyEnum::Origin; |
+ case net::URLRequest::ORIGIN: |
+ return Network::Request::ReferrerPolicyEnum::Origin; |
+ case net::URLRequest::NO_REFERRER: |
+ return Network::Request::ReferrerPolicyEnum::NoReferrer; |
+ default: |
+ break; |
+ } |
+ NOTREACHED(); |
+ return Network::Request::ReferrerPolicyEnum::NoReferrerWhenDowngrade; |
+} |
+ |
String securityState(const GURL& url, const net::CertStatus& cert_status) { |
if (!url.SchemeIsCryptographic()) |
return Security::SecurityStateEnum::Neutral; |
@@ -347,6 +374,34 @@ String securityState(const GURL& url, const net::CertStatus& cert_status) { |
return Security::SecurityStateEnum::Secure; |
} |
+net::Error NetErrorFromString(const std::string& error) { |
+ if (error == Network::ErrorReasonEnum::Failed) |
+ return net::ERR_FAILED; |
+ if (error == Network::ErrorReasonEnum::Aborted) |
+ return net::ERR_ABORTED; |
+ if (error == Network::ErrorReasonEnum::TimedOut) |
+ return net::ERR_TIMED_OUT; |
+ if (error == Network::ErrorReasonEnum::AccessDenied) |
+ return net::ERR_ACCESS_DENIED; |
+ if (error == Network::ErrorReasonEnum::ConnectionClosed) |
+ return net::ERR_CONNECTION_CLOSED; |
+ if (error == Network::ErrorReasonEnum::ConnectionReset) |
+ return net::ERR_CONNECTION_RESET; |
+ if (error == Network::ErrorReasonEnum::ConnectionRefused) |
+ return net::ERR_CONNECTION_REFUSED; |
+ if (error == Network::ErrorReasonEnum::ConnectionAborted) |
+ return net::ERR_CONNECTION_ABORTED; |
+ if (error == Network::ErrorReasonEnum::ConnectionFailed) |
+ return net::ERR_CONNECTION_FAILED; |
+ if (error == Network::ErrorReasonEnum::NameNotResolved) |
+ return net::ERR_NAME_NOT_RESOLVED; |
+ if (error == Network::ErrorReasonEnum::InternetDisconnected) |
+ return net::ERR_INTERNET_DISCONNECTED; |
+ if (error == Network::ErrorReasonEnum::AddressUnreachable) |
+ return net::ERR_ADDRESS_UNREACHABLE; |
+ return net::ERR_FAILED; |
+} |
+ |
double timeDelta(base::TimeTicks time, |
base::TimeTicks start, |
double invalid_value = -1) { |
@@ -420,8 +475,9 @@ String getProtocol(const GURL& url, const ResourceResponseHead& head) { |
NetworkHandler::NetworkHandler() |
: DevToolsDomainHandler(Network::Metainfo::domainName), |
host_(nullptr), |
- enabled_(false) { |
-} |
+ enabled_(false), |
+ interception_enabled_(false), |
+ weak_factory_(this) {} |
NetworkHandler::~NetworkHandler() { |
} |
@@ -451,6 +507,7 @@ Response NetworkHandler::Enable(Maybe<int> max_total_size, |
Response NetworkHandler::Disable() { |
enabled_ = false; |
user_agent_ = std::string(); |
+ EnableRequestInterception(false); |
return Response::FallThrough(); |
} |
@@ -770,5 +827,116 @@ std::string NetworkHandler::UserAgentOverride() const { |
return enabled_ ? user_agent_ : std::string(); |
} |
+DispatchResponse NetworkHandler::EnableRequestInterception(bool enabled) { |
+ if (interception_enabled_ == enabled) |
+ return Response::OK(); // Nothing to do. |
+ |
+ WebContents* web_contents = WebContents::FromRenderFrameHost(host_); |
+ if (!web_contents) |
+ return Response::OK(); |
+ |
+ DevToolsURLRequestInterceptor* devtools_url_request_interceptor = |
+ DevToolsURLRequestInterceptor::FromBrowserContext( |
+ web_contents->GetBrowserContext()); |
+ if (!devtools_url_request_interceptor) |
+ return Response::OK(); |
+ |
+ if (enabled) { |
+ devtools_url_request_interceptor->state()->StartInterceptingRequests( |
+ web_contents, weak_factory_.GetWeakPtr()); |
+ } else { |
+ devtools_url_request_interceptor->state()->StopInterceptingRequests( |
+ web_contents); |
+ } |
+ interception_enabled_ = enabled; |
+ return Response::OK(); |
+} |
+ |
+namespace { |
+bool GetPostData(const net::URLRequest* request, std::string* post_data) { |
+ if (!request->has_upload()) |
+ return false; |
+ |
+ const net::UploadDataStream* stream = request->get_upload(); |
+ if (!stream->GetElementReaders()) |
+ return false; |
+ |
+ const auto* element_readers = stream->GetElementReaders(); |
+ if (element_readers->empty()) |
+ return false; |
+ |
+ *post_data = ""; |
+ for (const auto& element_reader : *element_readers) { |
+ const net::UploadBytesElementReader* reader = |
+ element_reader->AsBytesReader(); |
+ // TODO(alexclarke): This should really be base64 encoded. |
+ *post_data += std::string(reader->bytes(), reader->length()); |
+ } |
+ return true; |
+} |
+} // namespace |
+ |
+// TODO(alexclarke): Support structured data as well as |base64_raw_response|. |
+void NetworkHandler::ContinueInterceptedRequest( |
+ const std::string& interception_id, |
+ Maybe<std::string> error_reason, |
+ Maybe<std::string> base64_raw_response, |
+ Maybe<std::string> url, |
+ Maybe<std::string> method, |
+ Maybe<std::string> post_data, |
+ Maybe<protocol::Network::Headers> headers, |
+ std::unique_ptr<ContinueInterceptedRequestCallback> callback) { |
+ DevToolsURLRequestInterceptor* devtools_url_request_interceptor = |
+ DevToolsURLRequestInterceptor::FromBrowserContext( |
+ WebContents::FromRenderFrameHost(host_)->GetBrowserContext()); |
+ if (!devtools_url_request_interceptor) { |
+ callback->sendFailure(Response::InternalError()); |
+ return; |
+ } |
+ |
+ base::Optional<net::Error> error; |
+ if (error_reason.isJust()) |
+ error = NetErrorFromString(error_reason.fromJust()); |
+ |
+ base::Optional<std::string> raw_response; |
+ if (base64_raw_response.isJust()) { |
+ std::string decoded; |
+ if (!base::Base64Decode(base64_raw_response.fromJust(), &decoded)) { |
+ callback->sendFailure(Response::InvalidParams("Invalid rawResponse.")); |
+ return; |
+ } |
+ raw_response = decoded; |
+ } |
+ |
+ devtools_url_request_interceptor->state()->ContinueInterceptedRequest( |
+ interception_id, |
+ base::MakeUnique<DevToolsURLRequestInterceptor::Modifications>( |
+ std::move(error), std::move(raw_response), std::move(url), |
+ std::move(method), std::move(post_data), std::move(headers)), |
+ std::move(callback)); |
+} |
+ |
+// static |
+std::unique_ptr<Network::Request> NetworkHandler::CreateRequestFromURLRequest( |
+ const net::URLRequest* request) { |
+ std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create()); |
+ for (net::HttpRequestHeaders::Iterator it(request->extra_request_headers()); |
+ it.GetNext();) { |
+ headers_dict->setString(it.name(), it.value()); |
+ } |
+ std::unique_ptr<protocol::Network::Request> request_object = |
+ Network::Request::Create() |
+ .SetUrl(request->url().spec()) |
+ .SetMethod(request->method()) |
+ .SetHeaders(Object::fromValue(headers_dict.get(), nullptr)) |
+ .SetInitialPriority(resourcePriority(request->priority())) |
+ .SetReferrerPolicy(referrerPolicy(request->referrer_policy())) |
+ .Build(); |
+ std::string post_data; |
+ if (GetPostData(request, &post_data)) |
+ request_object->SetPostData(std::move(post_data)); |
+ return request_object; |
+} |
+ |
} // namespace protocol |
} // namespace content |