feat: migrate protocol module to NetworkService (Part 5) (#18170)

* fix: always have head.headers available

* fix: use StringDataPipeProducer to write string

It can handle large strings correctly.

* fix: override RegisterNonNetworkSubresourceURLLoaderFactories

* fix: add dummy uninterceptProtocol implementation

* fix: jquery error handler can pass empty string

For some errors jquery would pass empty string in the error handler,
which makes tests pass when they should fail.

* chore: fix cpplint warnings

* fix: guard RegisterNonNetworkSubresourceURLLoaderFactories call

It may be called even when NetworkService is not enabled.

* test: disable protocol.interceptHttpProtocol test
This commit is contained in:
Cheng Zhao 2019-05-07 11:33:05 +09:00 committed by GitHub
parent a96b6e2c96
commit 237f74a01f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 107 additions and 48 deletions

View file

@ -78,6 +78,11 @@ bool ProtocolNS::IsProtocolRegistered(const std::string& scheme) {
return base::ContainsKey(handlers_, scheme);
}
void ProtocolNS::UninterceptProtocol(const std::string& scheme,
mate::Arguments* args) {
HandleOptionalCallback(args, ProtocolError::NOT_INTERCEPTED);
}
v8::Local<v8::Promise> ProtocolNS::IsProtocolHandled(
const std::string& scheme) {
util::Promise promise(isolate());
@ -129,7 +134,7 @@ void ProtocolNS::BuildPrototype(v8::Isolate* isolate,
.SetMethod("interceptFileProtocol", &Noop)
.SetMethod("interceptHttpProtocol", &Noop)
.SetMethod("interceptStreamProtocol", &Noop)
.SetMethod("uninterceptProtocol", &Noop);
.SetMethod("uninterceptProtocol", &ProtocolNS::UninterceptProtocol);
}
} // namespace api

View file

@ -56,6 +56,7 @@ class ProtocolNS : public mate::TrackableObject<ProtocolNS> {
const ProtocolHandler& handler);
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
bool IsProtocolRegistered(const std::string& scheme);
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
// Old async version of IsProtocolRegistered.
v8::Local<v8::Promise> IsProtocolHandled(const std::string& scheme);

View file

@ -940,6 +940,24 @@ void AtomBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
protocol->RegisterURLLoaderFactories(factories);
}
void AtomBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
int render_process_id,
int render_frame_id,
NonNetworkURLLoaderFactoryMap* factories) {
// Chromium may call this even when NetworkService is not enabled.
if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
return;
content::RenderFrameHost* frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(frame_host);
api::ProtocolNS* protocol = api::ProtocolNS::FromWrappedClass(
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
if (protocol)
protocol->RegisterURLLoaderFactories(factories);
}
std::string AtomBrowserClient::GetApplicationLocale() {
if (BrowserThread::CurrentlyOn(BrowserThread::IO))
return g_io_thread_application_locale.Get();

View file

@ -163,6 +163,10 @@ class AtomBrowserClient : public content::ContentBrowserClient,
void RegisterNonNetworkNavigationURLLoaderFactories(
int frame_tree_node_id,
NonNetworkURLLoaderFactoryMap* factories) override;
void RegisterNonNetworkSubresourceURLLoaderFactories(
int render_process_id,
int render_frame_id,
NonNetworkURLLoaderFactoryMap* factories) override;
// content::RenderProcessHostObserver:
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;

View file

@ -4,6 +4,7 @@
#include "atom/browser/net/atom_url_loader_factory.h"
#include <memory>
#include <string>
#include <utility>
@ -19,6 +20,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/file_url_loader.h"
#include "content/public/browser/storage_partition.h"
#include "mojo/public/cpp/system/string_data_pipe_producer.h"
#include "net/base/filename_util.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
@ -87,8 +89,10 @@ network::ResourceResponseHead ToResponseHead(const mate::Dictionary& dict) {
network::ResourceResponseHead head;
head.mime_type = "text/html";
head.charset = "utf-8";
if (dict.IsEmpty())
if (dict.IsEmpty()) {
head.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
return head;
}
int status_code = 200;
dict.Get("statusCode", &status_code);
@ -98,8 +102,6 @@ network::ResourceResponseHead ToResponseHead(const mate::Dictionary& dict) {
base::DictionaryValue headers;
if (dict.Get("headers", &headers)) {
if (!head.headers)
head.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
for (const auto& iter : headers.DictItems()) {
head.headers->AddHeader(iter.first + ": " + iter.second.GetString());
// Some apps are passing content-type via headers, which is not accepted
@ -113,6 +115,26 @@ network::ResourceResponseHead ToResponseHead(const mate::Dictionary& dict) {
return head;
}
// Helper to write string to pipe.
struct WriteData {
network::mojom::URLLoaderClientPtr client;
std::string data;
std::unique_ptr<mojo::StringDataPipeProducer> producer;
};
void OnWrite(std::unique_ptr<WriteData> write_data, MojoResult result) {
if (result != MOJO_RESULT_OK) {
network::URLLoaderCompletionStatus status(net::ERR_FAILED);
return;
}
network::URLLoaderCompletionStatus status(net::OK);
status.encoded_data_length = write_data->data.size();
status.encoded_body_length = write_data->data.size();
status.decoded_body_length = write_data->data.size();
write_data->client->OnComplete(status);
}
} // namespace
AtomURLLoaderFactory::AtomURLLoaderFactory(ProtocolType type,
@ -215,8 +237,9 @@ void AtomURLLoaderFactory::StartLoadingBuffer(
return;
}
SendContents(std::move(client), ToResponseHead(dict),
node::Buffer::Data(buffer), node::Buffer::Length(buffer));
SendContents(
std::move(client), ToResponseHead(dict),
std::string(node::Buffer::Data(buffer), node::Buffer::Length(buffer)));
}
// static
@ -231,8 +254,7 @@ void AtomURLLoaderFactory::StartLoadingString(
else if (!dict.IsEmpty())
dict.Get("data", &contents);
SendContents(std::move(client), ToResponseHead(dict), contents.data(),
contents.size());
SendContents(std::move(client), ToResponseHead(dict), std::move(contents));
}
// static
@ -341,21 +363,32 @@ void AtomURLLoaderFactory::StartLoadingStream(
void AtomURLLoaderFactory::SendContents(
network::mojom::URLLoaderClientPtr client,
network::ResourceResponseHead head,
const char* data,
size_t ssize) {
uint32_t size = base::saturated_cast<uint32_t>(ssize);
mojo::DataPipe pipe(size);
MojoResult result =
pipe.producer_handle->WriteData(data, &size, MOJO_WRITE_DATA_FLAG_NONE);
if (result != MOJO_RESULT_OK || size < ssize) {
client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
std::string data) {
head.headers->AddHeader(kCORSHeader);
client->OnReceiveResponse(head);
// Code bellow follows the pattern of data_url_loader_factory.cc.
mojo::ScopedDataPipeProducerHandle producer;
mojo::ScopedDataPipeConsumerHandle consumer;
if (mojo::CreateDataPipe(nullptr, &producer, &consumer) != MOJO_RESULT_OK) {
client->OnComplete(
network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES));
return;
}
head.headers->AddHeader(kCORSHeader);
client->OnReceiveResponse(head);
client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
client->OnComplete(network::URLLoaderCompletionStatus(net::OK));
client->OnStartLoadingResponseBody(std::move(consumer));
auto write_data = std::make_unique<WriteData>();
write_data->client = std::move(client);
write_data->data = std::move(data);
write_data->producer =
std::make_unique<mojo::StringDataPipeProducer>(std::move(producer));
base::StringPiece string_piece(write_data->data);
write_data->producer->Write(string_piece,
mojo::StringDataPipeProducer::AsyncWritingMode::
STRING_STAYS_VALID_UNTIL_COMPLETION,
base::BindOnce(OnWrite, std::move(write_data)));
}
} // namespace atom

View file

@ -86,8 +86,7 @@ class AtomURLLoaderFactory : public network::mojom::URLLoaderFactory {
// Helper to send string as response.
static void SendContents(network::mojom::URLLoaderClientPtr client,
network::ResourceResponseHead head,
const char* data,
size_t size);
std::string data);
// TODO(zcbenz): This comes from extensions/browser/extension_protocols.cc
// but I don't know what it actually does, find out the meanings of |Clone|

View file

@ -86,7 +86,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -119,7 +119,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -146,7 +146,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -163,7 +163,7 @@ describe('protocol module', () => {
assert.strictEqual(request.getResponseHeader('Access-Control-Allow-Origin'), '*')
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -184,7 +184,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -219,7 +219,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -236,7 +236,7 @@ describe('protocol module', () => {
assert.strictEqual(request.getResponseHeader('Access-Control-Allow-Origin'), '*')
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -257,7 +257,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -296,7 +296,7 @@ describe('protocol module', () => {
assert.strictEqual(data, String(fileContent))
return done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -313,9 +313,7 @@ describe('protocol module', () => {
assert.strictEqual(request.getResponseHeader('Access-Control-Allow-Origin'), '*')
done()
},
error: (xhr, errorType, error) => {
done(error)
}
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -335,9 +333,7 @@ describe('protocol module', () => {
assert.strictEqual(request.getResponseHeader('X-Great-Header'), 'sogreat')
done()
},
error: (xhr, errorType, error) => {
done(error)
}
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -353,7 +349,7 @@ describe('protocol module', () => {
assert.strictEqual(data, String(fileContent))
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -369,7 +365,7 @@ describe('protocol module', () => {
assert.strictEqual(data, String(normalContent))
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -428,7 +424,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -757,7 +753,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -790,7 +786,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -812,7 +808,7 @@ describe('protocol module', () => {
assert.strictEqual(data.value, 1)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -833,7 +829,7 @@ describe('protocol module', () => {
assert.deepStrictEqual({ ...qs.parse(data) }, postData)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -851,7 +847,7 @@ describe('protocol module', () => {
assert.strictEqual(data, text)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
@ -872,14 +868,17 @@ describe('protocol module', () => {
assert.strictEqual(data, $.param(postData))
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})
})
describe('protocol.interceptHttpProtocol', () => {
it('can send POST request', (done) => {
// FIXME(zcbenz): This test was passing because the test itself was wrong,
// I don't know whether it ever passed before and we should take a look at
// it in future.
xit('can send POST request', (done) => {
const server = http.createServer((req, res) => {
let body = ''
req.on('data', (chunk) => {
@ -916,7 +915,7 @@ describe('protocol module', () => {
assert.deepStrictEqual({ ...qs.parse(data) }, postData)
done()
},
error: (xhr, errorType, error) => done(error)
error: (xhr, errorType, error) => done(new Error(error))
})
})
})