feat: migrate webRequest module to NetworkService (Part 8) (#19841)

* fix: fill uploadData property

* fix: requestHeaders in onBeforeSendHeaders

* fix: responseHeaders in onHeadersReceived

* fix: header keys should not be lowercased

* fix: gin::Dictionary::Get succeeds even though key does not exist...

* fix: throw for invalid filters

* test: re-enable api-web-request-spec

* chore: do not use deprecated base::Value API
This commit is contained in:
Cheng Zhao 2019-08-21 11:14:21 +09:00 committed by GitHub
parent f10f44acf5
commit b7defaaf6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 43 deletions

View file

@ -9,6 +9,7 @@
#include <utility> #include <utility>
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/values.h"
#include "gin/converter.h" #include "gin/converter.h"
#include "gin/dictionary.h" #include "gin/dictionary.h"
#include "gin/object_template_builder.h" #include "gin/object_template_builder.h"
@ -99,6 +100,28 @@ bool MatchesFilterCondition(extensions::WebRequestInfo* info,
return false; return false;
} }
// Convert HttpResponseHeaders to V8.
//
// Note that while we already have converters for HttpResponseHeaders, we can
// not use it because it lowercases the header keys, while the webRequest has
// to pass the original keys.
v8::Local<v8::Value> HttpResponseHeadersToV8(
net::HttpResponseHeaders* headers) {
base::DictionaryValue response_headers;
if (headers) {
size_t iter = 0;
std::string key;
std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
base::Value* values = response_headers.FindListKey(key);
if (!values)
values = response_headers.SetKey(key, base::ListValue());
values->GetList().emplace_back(value);
}
}
return gin::ConvertToV8(v8::Isolate::GetCurrent(), response_headers);
}
// Overloaded by multiple types to fill the |details| object. // Overloaded by multiple types to fill the |details| object.
void ToDictionary(gin::Dictionary* details, extensions::WebRequestInfo* info) { void ToDictionary(gin::Dictionary* details, extensions::WebRequestInfo* info) {
details->Set("id", info->id); details->Set("id", info->id);
@ -110,9 +133,10 @@ void ToDictionary(gin::Dictionary* details, extensions::WebRequestInfo* info) {
details->Set("ip", info->response_ip); details->Set("ip", info->response_ip);
if (info->response_headers) { if (info->response_headers) {
details->Set("fromCache", info->response_from_cache); details->Set("fromCache", info->response_from_cache);
details->Set("responseHeaders", info->response_headers.get());
details->Set("statusLine", info->response_headers->GetStatusLine()); details->Set("statusLine", info->response_headers->GetStatusLine());
details->Set("statusCode", info->response_headers->response_code()); details->Set("statusCode", info->response_headers->response_code());
details->Set("responseHeaders",
HttpResponseHeadersToV8(info->response_headers.get()));
} }
auto* web_contents = content::WebContents::FromRenderFrameHost( auto* web_contents = content::WebContents::FromRenderFrameHost(
@ -127,6 +151,8 @@ void ToDictionary(gin::Dictionary* details, extensions::WebRequestInfo* info) {
void ToDictionary(gin::Dictionary* details, void ToDictionary(gin::Dictionary* details,
const network::ResourceRequest& request) { const network::ResourceRequest& request) {
details->Set("referrer", request.referrer); details->Set("referrer", request.referrer);
if (request.request_body)
details->Set("uploadData", *request.request_body);
} }
void ToDictionary(gin::Dictionary* details, void ToDictionary(gin::Dictionary* details,
@ -165,7 +191,7 @@ void ReadFromResponse(v8::Isolate* isolate,
gin::Dictionary* response, gin::Dictionary* response,
net::HttpRequestHeaders* headers) { net::HttpRequestHeaders* headers) {
headers->Clear(); headers->Clear();
gin::ConvertFromV8(isolate, gin::ConvertToV8(isolate, *response), headers); response->Get("requestHeaders", headers);
} }
void ReadFromResponse(v8::Isolate* isolate, void ReadFromResponse(v8::Isolate* isolate,
@ -176,7 +202,7 @@ void ReadFromResponse(v8::Isolate* isolate,
if (!response->Get("statusLine", &status_line)) if (!response->Get("statusLine", &status_line))
status_line = headers.second; status_line = headers.second;
v8::Local<v8::Value> value; v8::Local<v8::Value> value;
if (response->Get("responseHeaders", &value)) { if (response->Get("responseHeaders", &value) && value->IsObject()) {
*headers.first = new net::HttpResponseHeaders(""); *headers.first = new net::HttpResponseHeaders("");
(*headers.first)->ReplaceStatusLine(status_line); (*headers.first)->ReplaceStatusLine(status_line);
gin::Converter<net::HttpResponseHeaders*>::FromV8(isolate, value, gin::Converter<net::HttpResponseHeaders*>::FromV8(isolate, value,
@ -256,7 +282,7 @@ int WebRequestNS::OnBeforeSendHeaders(extensions::WebRequestInfo* info,
kOnBeforeSendHeaders, info, kOnBeforeSendHeaders, info,
base::BindOnce(std::move(callback), std::set<std::string>(), base::BindOnce(std::move(callback), std::set<std::string>(),
std::set<std::string>()), std::set<std::string>()),
headers, request); headers, request, *headers);
} }
int WebRequestNS::OnHeadersReceived( int WebRequestNS::OnHeadersReceived(
@ -323,18 +349,35 @@ void WebRequestNS::SetListener(Event event,
v8::Local<v8::Value> arg; v8::Local<v8::Value> arg;
// { urls }. // { urls }.
std::set<URLPattern> patterns; std::set<std::string> filter_patterns;
gin::Dictionary dict(args->isolate()); gin::Dictionary dict(args->isolate());
if (args->GetNext(&arg) && !arg->IsFunction()) { if (args->GetNext(&arg) && !arg->IsFunction()) {
// Note that gin treats Function as Dictionary when doing convertions, so we // Note that gin treats Function as Dictionary when doing convertions, so we
// have to explicitly check if the argument is Function before trying to // have to explicitly check if the argument is Function before trying to
// convert it to Dictionary. // convert it to Dictionary.
if (gin::ConvertFromV8(args->isolate(), arg, &dict)) { if (gin::ConvertFromV8(args->isolate(), arg, &dict)) {
dict.Get("urls", &patterns); if (!dict.Get("urls", &filter_patterns)) {
args->ThrowTypeError("Parameter 'filter' must have property 'urls'.");
return;
}
args->GetNext(&arg); args->GetNext(&arg);
} }
} }
std::set<URLPattern> patterns;
for (const std::string& filter_pattern : filter_patterns) {
URLPattern pattern(URLPattern::SCHEME_ALL);
const URLPattern::ParseResult result = pattern.Parse(filter_pattern);
if (result == URLPattern::ParseResult::kSuccess) {
patterns.insert(pattern);
} else {
const char* error_type = URLPattern::GetParseResultString(result);
args->ThrowTypeError("Invalid url pattern " + filter_pattern + ": " +
error_type);
return;
}
}
// Function or null. // Function or null.
Listener listener; Listener listener;
if (arg.IsEmpty() || if (arg.IsEmpty() ||

View file

@ -608,6 +608,8 @@ void ProxyingURLLoaderFactory::InProgressRequest::
override_headers_ = nullptr; override_headers_ = nullptr;
redirect_url_ = GURL(); redirect_url_ = GURL();
info_->AddResponseInfoFromResourceResponse(current_response_);
net::CompletionRepeatingCallback copyable_callback = net::CompletionRepeatingCallback copyable_callback =
base::AdaptCallbackForRepeating(std::move(continuation)); base::AdaptCallbackForRepeating(std::move(continuation));
DCHECK(info_.has_value()); DCHECK(info_.has_value());

View file

@ -160,15 +160,10 @@ v8::Local<v8::Value> Converter<net::HttpResponseHeaders*>::ToV8(
std::string value; std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) { while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
key = base::ToLowerASCII(key); key = base::ToLowerASCII(key);
if (response_headers.FindKey(key)) { base::Value* values = response_headers.FindListKey(key);
base::ListValue* values = nullptr; if (!values)
if (response_headers.GetList(key, &values)) values = response_headers.SetKey(key, base::ListValue());
values->AppendString(value); values->GetList().emplace_back(value);
} else {
auto values = std::make_unique<base::ListValue>();
values->AppendString(value);
response_headers.Set(key, std::move(values));
}
} }
} }
return ConvertToV8(isolate, response_headers); return ConvertToV8(isolate, response_headers);
@ -252,16 +247,10 @@ bool Converter<net::HttpRequestHeaders>::FromV8(v8::Isolate* isolate,
} }
// static // static
v8::Local<v8::Value> Converter<network::ResourceRequest>::ToV8( v8::Local<v8::Value> Converter<network::ResourceRequestBody>::ToV8(
v8::Isolate* isolate, v8::Isolate* isolate,
const network::ResourceRequest& val) { const network::ResourceRequestBody& val) {
gin::Dictionary dict(isolate, v8::Object::New(isolate)); const auto& elements = *val.elements();
dict.Set("method", val.method);
dict.Set("url", val.url.spec());
dict.Set("referrer", val.referrer.spec());
dict.Set("headers", val.headers);
if (val.request_body) {
const auto& elements = *val.request_body->elements();
v8::Local<v8::Array> arr = v8::Array::New(isolate, elements.size()); v8::Local<v8::Array> arr = v8::Array::New(isolate, elements.size());
for (size_t i = 0; i < elements.size(); ++i) { for (size_t i = 0; i < elements.size(); ++i) {
const auto& element = elements[i]; const auto& element = elements[i];
@ -285,8 +274,20 @@ v8::Local<v8::Value> Converter<network::ResourceRequest>::ToV8(
ConvertToV8(isolate, upload_data)) ConvertToV8(isolate, upload_data))
.Check(); .Check();
} }
dict.Set("uploadData", arr); return arr;
} }
// static
v8::Local<v8::Value> Converter<network::ResourceRequest>::ToV8(
v8::Isolate* isolate,
const network::ResourceRequest& val) {
gin::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("method", val.method);
dict.Set("url", val.url.spec());
dict.Set("referrer", val.referrer.spec());
dict.Set("headers", val.headers);
if (val.request_body)
dict.Set("uploadData", ConvertToV8(isolate, *val.request_body));
return ConvertToV8(isolate, dict); return ConvertToV8(isolate, dict);
} }

View file

@ -69,6 +69,12 @@ struct Converter<net::HttpRequestHeaders> {
net::HttpRequestHeaders* out); net::HttpRequestHeaders* out);
}; };
template <>
struct Converter<network::ResourceRequestBody> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const network::ResourceRequestBody& val);
};
template <> template <>
struct Converter<network::ResourceRequest> { struct Converter<network::ResourceRequest> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,

View file

@ -12,7 +12,7 @@ chai.use(dirtyChai)
/* The whole webRequest API doesn't use standard callbacks */ /* The whole webRequest API doesn't use standard callbacks */
/* eslint-disable standard/no-callback-literal */ /* eslint-disable standard/no-callback-literal */
describe.skip('webRequest module', () => { describe('webRequest module', () => {
const ses = session.defaultSession const ses = session.defaultSession
const server = http.createServer((req, res) => { const server = http.createServer((req, res) => {
if (req.url === '/serverRedirect') { if (req.url === '/serverRedirect') {