Commit 1d68ca31 authored by Pavel Feldman's avatar Pavel Feldman Committed by Commit Bot

CDP: report binary post data in Network and Fetch domains

This change introduces a binary post data field in the Network.Request
type. New field contains entries that correspond to the http body data
entries. New PostDataEntry type supports text/bytes data only, but
allows progressive enhancement for other types such as files and blobs.

Bug: 1107728
Change-Id: I205dd7fc93d627a14c111cc2a05a63ce962bc449
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2309660Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Commit-Queue: Pavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790513}
parent 5290366e
...@@ -494,8 +494,10 @@ String GetProtocol(const GURL& url, ...@@ -494,8 +494,10 @@ String GetProtocol(const GURL& url,
return protocol; return protocol;
} }
bool GetPostData(const network::ResourceRequestBody& request_body, bool GetPostData(
std::string* result) { const network::ResourceRequestBody& request_body,
protocol::Array<protocol::Network::PostDataEntry>* data_entries,
std::string* result) {
const std::vector<network::DataElement>* elements = request_body.elements(); const std::vector<network::DataElement>* elements = request_body.elements();
if (elements->empty()) if (elements->empty())
return false; return false;
...@@ -503,7 +505,11 @@ bool GetPostData(const network::ResourceRequestBody& request_body, ...@@ -503,7 +505,11 @@ bool GetPostData(const network::ResourceRequestBody& request_body,
// TODO(caseq): Also support blobs. // TODO(caseq): Also support blobs.
if (element.type() != network::mojom::DataElementType::kBytes) if (element.type() != network::mojom::DataElementType::kBytes)
return false; return false;
// TODO(caseq): This should rather be sent as Binary. auto bytes = protocol::Binary::fromSpan(
reinterpret_cast<const uint8_t*>(element.bytes()), element.length());
auto data_entry = protocol::Network::PostDataEntry::Create().Build();
data_entry->SetBytes(std::move(bytes));
data_entries->push_back(std::move(data_entry));
result->append(element.bytes(), element.length()); result->append(element.bytes(), element.length());
} }
return true; return true;
...@@ -1630,10 +1636,17 @@ void NetworkHandler::NavigationRequestWillBeSent( ...@@ -1630,10 +1636,17 @@ void NetworkHandler::NavigationRequestWillBeSent(
if (!url_fragment.empty()) if (!url_fragment.empty())
request->SetUrlFragment(url_fragment); request->SetUrlFragment(url_fragment);
std::string post_data; if (common_params.post_data) {
if (common_params.post_data && std::string post_data;
GetPostData(*common_params.post_data, &post_data)) { auto data_entries =
request->SetPostData(post_data); std::make_unique<protocol::Array<protocol::Network::PostDataEntry>>();
if (GetPostData(*common_params.post_data, data_entries.get(), &post_data)) {
if (!post_data.empty())
request->SetPostData(post_data);
if (data_entries->size())
request->SetPostDataEntries(std::move(data_entries));
request->SetHasPostData(true);
}
} }
// TODO(caseq): report potentially blockable types // TODO(caseq): report potentially blockable types
request->SetMixedContentType(Security::MixedContentTypeEnum::None); request->SetMixedContentType(Security::MixedContentTypeEnum::None);
...@@ -2040,9 +2053,18 @@ NetworkHandler::CreateRequestFromResourceRequest( ...@@ -2040,9 +2053,18 @@ NetworkHandler::CreateRequestFromResourceRequest(
.Build(); .Build();
if (!url_fragment.empty()) if (!url_fragment.empty())
request_object->SetUrlFragment(url_fragment); request_object->SetUrlFragment(url_fragment);
std::string post_data; if (request.request_body) {
if (request.request_body && GetPostData(*request.request_body, &post_data)) std::string post_data;
request_object->SetPostData(std::move(post_data)); auto data_entries =
std::make_unique<protocol::Array<protocol::Network::PostDataEntry>>();
if (GetPostData(*request.request_body, data_entries.get(), &post_data)) {
if (!post_data.empty())
request_object->SetPostData(std::move(post_data));
if (data_entries->size())
request_object->SetPostDataEntries(std::move(data_entries));
request_object->SetHasPostData(true);
}
}
return request_object; return request_object;
} }
......
...@@ -4260,6 +4260,11 @@ domain Network ...@@ -4260,6 +4260,11 @@ domain Network
High High
VeryHigh VeryHigh
# Post data entry for HTTP request
type PostDataEntry extends object
properties
optional binary bytes
# HTTP request data. # HTTP request data.
type Request extends object type Request extends object
properties properties
...@@ -4275,6 +4280,8 @@ domain Network ...@@ -4275,6 +4280,8 @@ domain Network
optional string postData optional string postData
# True when the request has POST data. Note that postData might still be omitted when this flag is true when the data is too long. # True when the request has POST data. Note that postData might still be omitted when this flag is true when the data is too long.
optional boolean hasPostData optional boolean hasPostData
# Request body elements. This will be converted from base64 to binary
experimental optional array of PostDataEntry postDataEntries
# The mixed content type of the request. # The mixed content type of the request.
optional Security.MixedContentType mixedContentType optional Security.MixedContentType mixedContentType
# Priority of the resource request at the time request is sent. # Priority of the resource request at the time request is sent.
......
...@@ -523,9 +523,11 @@ static std::unique_ptr<protocol::Network::ResourceTiming> BuildObjectForTiming( ...@@ -523,9 +523,11 @@ static std::unique_ptr<protocol::Network::ResourceTiming> BuildObjectForTiming(
.build(); .build();
} }
static bool FormDataToString(scoped_refptr<EncodedFormData> body, static bool FormDataToString(
size_t max_body_size, scoped_refptr<EncodedFormData> body,
String* content) { size_t max_body_size,
protocol::Array<protocol::Network::PostDataEntry>* data_entries,
String* content) {
*content = ""; *content = "";
if (!body || body->IsEmpty()) if (!body || body->IsEmpty())
return false; return false;
...@@ -540,6 +542,15 @@ static bool FormDataToString(scoped_refptr<EncodedFormData> body, ...@@ -540,6 +542,15 @@ static bool FormDataToString(scoped_refptr<EncodedFormData> body,
if (max_body_size != 0 && body->SizeInBytes() > max_body_size) if (max_body_size != 0 && body->SizeInBytes() > max_body_size)
return true; return true;
for (const auto& element : body->Elements()) {
auto data_entry = protocol::Network::PostDataEntry::create().build();
auto bytes = protocol::Binary::fromSpan(
reinterpret_cast<const uint8_t*>(element.data_.data()),
element.data_.size());
data_entry->setBytes(std::move(bytes));
data_entries->push_back(std::move(data_entry));
}
Vector<char> bytes; Vector<char> bytes;
body->Flatten(bytes); body->Flatten(bytes);
*content = String::FromUTF8WithLatin1Fallback(bytes.data(), bytes.size()); *content = String::FromUTF8WithLatin1Fallback(bytes.data(), bytes.size());
...@@ -550,8 +561,11 @@ static std::unique_ptr<protocol::Network::Request> ...@@ -550,8 +561,11 @@ static std::unique_ptr<protocol::Network::Request>
BuildObjectForResourceRequest(const ResourceRequest& request, BuildObjectForResourceRequest(const ResourceRequest& request,
scoped_refptr<EncodedFormData> post_data, scoped_refptr<EncodedFormData> post_data,
size_t max_body_size) { size_t max_body_size) {
String postData; String data_string;
bool hasPostData = FormDataToString(post_data, max_body_size, &postData); auto data_entries =
std::make_unique<protocol::Array<protocol::Network::PostDataEntry>>();
bool has_post_data = FormDataToString(post_data, max_body_size,
data_entries.get(), &data_string);
KURL url = request.Url(); KURL url = request.Url();
// protocol::Network::Request doesn't have a separate referrer string member // protocol::Network::Request doesn't have a separate referrer string member
// like blink::ResourceRequest, so here we add ResourceRequest's referrer // like blink::ResourceRequest, so here we add ResourceRequest's referrer
...@@ -572,9 +586,11 @@ BuildObjectForResourceRequest(const ResourceRequest& request, ...@@ -572,9 +586,11 @@ BuildObjectForResourceRequest(const ResourceRequest& request,
.build(); .build();
if (url.FragmentIdentifier()) if (url.FragmentIdentifier())
result->setUrlFragment("#" + url.FragmentIdentifier()); result->setUrlFragment("#" + url.FragmentIdentifier());
if (!postData.IsEmpty()) if (!data_string.IsEmpty())
result->setPostData(postData); result->setPostData(data_string);
if (hasPostData) if (data_entries->size())
result->setPostDataEntries(std::move(data_entries));
if (has_post_data)
result->setHasPostData(true); result->setHasPostData(true);
return result; return result;
} }
......
Test post data interception
[
[0] : {
bytes : AQIDBAU=
}
]
[
[0] : {
bytes : AQIDBAU=
}
]
(async function(testRunner) {
const {page, session, dp} = await testRunner.startBlank(
`Test post data interception`);
await dp.Network.enable();
await dp.Fetch.enable();
const [requestWillBeSent, requestPaused] = await Promise.all([
dp.Network.onceRequestWillBeSent(),
dp.Fetch.onceRequestPaused(),
session.evaluate(`fetch('${testRunner.url('./resources/hello-world.txt')}', {
method: 'post',
body: new Uint8Array([1, 2, 3, 4, 5])
})`)
]);
testRunner.log(requestWillBeSent.params.request.postDataEntries);
testRunner.log(requestPaused.params.request.postDataEntries);
testRunner.completeTest();
})
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment