chore: bump chromium to 32e0bab929213da1019992bf31d29 (master) (#19488)
This commit is contained in:
parent
d0800aa200
commit
e959137a4b
112 changed files with 524 additions and 5639 deletions
|
@ -5,8 +5,8 @@
|
|||
#include "shell/browser/api/atom_api_net.h"
|
||||
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "services/network/public/cpp/features.h"
|
||||
#include "shell/browser/api/atom_api_url_request.h"
|
||||
#include "shell/browser/api/atom_api_url_request_ns.h"
|
||||
|
||||
#include "shell/common/node_includes.h"
|
||||
|
@ -36,10 +36,7 @@ void Net::BuildPrototype(v8::Isolate* isolate,
|
|||
|
||||
v8::Local<v8::Value> Net::URLRequest(v8::Isolate* isolate) {
|
||||
v8::Local<v8::FunctionTemplate> constructor;
|
||||
if (base::FeatureList::IsEnabled(network::features::kNetworkService))
|
||||
constructor = URLRequestNS::GetConstructor(isolate);
|
||||
else
|
||||
constructor = URLRequest::GetConstructor(isolate);
|
||||
constructor = URLRequestNS::GetConstructor(isolate);
|
||||
return constructor->GetFunction(isolate->GetCurrentContext())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
@ -51,7 +48,6 @@ v8::Local<v8::Value> Net::URLRequest(v8::Isolate* isolate) {
|
|||
namespace {
|
||||
|
||||
using electron::api::Net;
|
||||
using electron::api::URLRequest;
|
||||
using electron::api::URLRequestNS;
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
|
@ -60,11 +56,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
|
||||
if (base::FeatureList::IsEnabled(network::features::kNetworkService))
|
||||
URLRequestNS::SetConstructor(isolate,
|
||||
base::BindRepeating(URLRequestNS::New));
|
||||
else
|
||||
URLRequest::SetConstructor(isolate, base::BindRepeating(URLRequest::New));
|
||||
URLRequestNS::SetConstructor(isolate, base::BindRepeating(URLRequestNS::New));
|
||||
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("net", Net::Create(isolate));
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/atom_api_protocol.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "shell/browser/atom_browser_client.h"
|
||||
#include "shell/browser/atom_browser_main_parts.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/net/url_request_async_asar_job.h"
|
||||
#include "shell/browser/net/url_request_buffer_job.h"
|
||||
#include "shell/browser/net/url_request_fetch_job.h"
|
||||
#include "shell/browser/net/url_request_stream_job.h"
|
||||
#include "shell/browser/net/url_request_string_job.h"
|
||||
#include "shell/common/native_mate_converters/callback.h"
|
||||
#include "shell/common/native_mate_converters/value_converter.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "url/url_util.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace {
|
||||
|
||||
// List of registered custom standard schemes.
|
||||
std::vector<std::string> g_standard_schemes;
|
||||
|
||||
struct SchemeOptions {
|
||||
bool standard = false;
|
||||
bool secure = false;
|
||||
bool bypassCSP = false;
|
||||
bool allowServiceWorkers = false;
|
||||
bool supportFetchAPI = false;
|
||||
bool corsEnabled = false;
|
||||
};
|
||||
|
||||
struct CustomScheme {
|
||||
std::string scheme;
|
||||
SchemeOptions options;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<CustomScheme> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
CustomScheme* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!dict.Get("scheme", &(out->scheme)))
|
||||
return false;
|
||||
mate::Dictionary opt;
|
||||
// options are optional. Default values specified in SchemeOptions are used
|
||||
if (dict.Get("privileges", &opt)) {
|
||||
opt.Get("standard", &(out->options.standard));
|
||||
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
||||
opt.Get("secure", &(out->options.secure));
|
||||
opt.Get("bypassCSP", &(out->options.bypassCSP));
|
||||
opt.Get("allowServiceWorkers", &(out->options.allowServiceWorkers));
|
||||
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
||||
opt.Get("corsEnabled", &(out->options.corsEnabled));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
std::vector<std::string> GetStandardSchemes() {
|
||||
return g_standard_schemes;
|
||||
}
|
||||
|
||||
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args) {
|
||||
std::vector<CustomScheme> custom_schemes;
|
||||
if (!mate::ConvertFromV8(args->isolate(), val, &custom_schemes)) {
|
||||
args->ThrowError("Argument must be an array of custom schemes.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> secure_schemes, cspbypassing_schemes, fetch_schemes,
|
||||
service_worker_schemes, cors_schemes;
|
||||
for (const auto& custom_scheme : custom_schemes) {
|
||||
// Register scheme to privileged list (https, wss, data, chrome-extension)
|
||||
if (custom_scheme.options.standard) {
|
||||
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
|
||||
url::AddStandardScheme(custom_scheme.scheme.c_str(),
|
||||
url::SCHEME_WITH_HOST);
|
||||
g_standard_schemes.push_back(custom_scheme.scheme);
|
||||
policy->RegisterWebSafeScheme(custom_scheme.scheme);
|
||||
}
|
||||
if (custom_scheme.options.secure) {
|
||||
secure_schemes.push_back(custom_scheme.scheme);
|
||||
url::AddSecureScheme(custom_scheme.scheme.c_str());
|
||||
}
|
||||
if (custom_scheme.options.bypassCSP) {
|
||||
cspbypassing_schemes.push_back(custom_scheme.scheme);
|
||||
url::AddCSPBypassingScheme(custom_scheme.scheme.c_str());
|
||||
}
|
||||
if (custom_scheme.options.corsEnabled) {
|
||||
cors_schemes.push_back(custom_scheme.scheme);
|
||||
url::AddCorsEnabledScheme(custom_scheme.scheme.c_str());
|
||||
}
|
||||
if (custom_scheme.options.supportFetchAPI) {
|
||||
fetch_schemes.push_back(custom_scheme.scheme);
|
||||
}
|
||||
if (custom_scheme.options.allowServiceWorkers) {
|
||||
service_worker_schemes.push_back(custom_scheme.scheme);
|
||||
}
|
||||
}
|
||||
|
||||
const auto AppendSchemesToCmdLine = [](const char* switch_name,
|
||||
std::vector<std::string> schemes) {
|
||||
// Add the schemes to command line switches, so child processes can also
|
||||
// register them.
|
||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||
switch_name, base::JoinString(schemes, ","));
|
||||
};
|
||||
|
||||
AppendSchemesToCmdLine(electron::switches::kSecureSchemes, secure_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kBypassCSPSchemes,
|
||||
cspbypassing_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kCORSSchemes, cors_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kFetchSchemes, fetch_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kServiceWorkerSchemes,
|
||||
service_worker_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kStandardSchemes,
|
||||
g_standard_schemes);
|
||||
}
|
||||
|
||||
Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
||||
: browser_context_(browser_context), weak_factory_(this) {
|
||||
Init(isolate);
|
||||
}
|
||||
|
||||
Protocol::~Protocol() {}
|
||||
void Protocol::UnregisterProtocol(const std::string& scheme,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
auto* getter = static_cast<URLRequestContextGetter*>(
|
||||
browser_context_->GetRequestContext());
|
||||
base::PostTaskWithTraitsAndReplyWithResult(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&Protocol::UnregisterProtocolInIO,
|
||||
base::RetainedRef(getter), scheme),
|
||||
base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
|
||||
}
|
||||
|
||||
// static
|
||||
Protocol::ProtocolError Protocol::UnregisterProtocolInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
const std::string& scheme) {
|
||||
auto* job_factory = request_context_getter->job_factory();
|
||||
if (!job_factory->HasProtocolHandler(scheme))
|
||||
return ProtocolError::NOT_REGISTERED;
|
||||
job_factory->SetProtocolHandler(scheme, nullptr);
|
||||
return ProtocolError::OK;
|
||||
}
|
||||
|
||||
bool IsProtocolHandledInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
const std::string& scheme) {
|
||||
bool is_handled =
|
||||
request_context_getter->job_factory()->IsHandledProtocol(scheme);
|
||||
return is_handled;
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> Protocol::IsProtocolHandled(const std::string& scheme) {
|
||||
util::Promise promise(isolate());
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
auto* getter = static_cast<URLRequestContextGetter*>(
|
||||
browser_context_->GetRequestContext());
|
||||
|
||||
base::PostTaskWithTraitsAndReplyWithResult(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&IsProtocolHandledInIO, base::RetainedRef(getter), scheme),
|
||||
base::BindOnce(util::Promise::ResolvePromise<bool>, std::move(promise)));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Protocol::UninterceptProtocol(const std::string& scheme,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
auto* getter = static_cast<URLRequestContextGetter*>(
|
||||
browser_context_->GetRequestContext());
|
||||
base::PostTaskWithTraitsAndReplyWithResult(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&Protocol::UninterceptProtocolInIO,
|
||||
base::RetainedRef(getter), scheme),
|
||||
base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
|
||||
}
|
||||
|
||||
// static
|
||||
Protocol::ProtocolError Protocol::UninterceptProtocolInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
const std::string& scheme) {
|
||||
return request_context_getter->job_factory()->UninterceptProtocol(scheme)
|
||||
? ProtocolError::OK
|
||||
: ProtocolError::NOT_INTERCEPTED;
|
||||
}
|
||||
|
||||
void Protocol::OnIOCompleted(const CompletionCallback& callback,
|
||||
ProtocolError error) {
|
||||
// The completion callback is optional.
|
||||
if (callback.is_null())
|
||||
return;
|
||||
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
if (error == ProtocolError::OK) {
|
||||
callback.Run(v8::Null(isolate()));
|
||||
} else {
|
||||
std::string str = ErrorCodeToString(error);
|
||||
callback.Run(v8::Exception::Error(mate::StringToV8(isolate(), str)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string Protocol::ErrorCodeToString(ProtocolError error) {
|
||||
switch (error) {
|
||||
case ProtocolError::FAIL:
|
||||
return "Failed to manipulate protocol factory";
|
||||
case ProtocolError::REGISTERED:
|
||||
return "The scheme has been registered";
|
||||
case ProtocolError::NOT_REGISTERED:
|
||||
return "The scheme has not been registered";
|
||||
case ProtocolError::INTERCEPTED:
|
||||
return "The scheme has been intercepted";
|
||||
case ProtocolError::NOT_INTERCEPTED:
|
||||
return "The scheme has not been intercepted";
|
||||
default:
|
||||
return "Unexpected error";
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<Protocol> Protocol::Create(v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context) {
|
||||
return mate::CreateHandle(isolate, new Protocol(isolate, browser_context));
|
||||
}
|
||||
|
||||
// static
|
||||
void Protocol::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
prototype->SetClassName(mate::StringToV8(isolate, "Protocol"));
|
||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("registerStringProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestStringJob>)
|
||||
.SetMethod("registerBufferProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestBufferJob>)
|
||||
.SetMethod("registerFileProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestAsyncAsarJob>)
|
||||
.SetMethod("registerHttpProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("registerStreamProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestStreamJob>)
|
||||
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled)
|
||||
.SetMethod("interceptStringProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestStringJob>)
|
||||
.SetMethod("interceptBufferProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestBufferJob>)
|
||||
.SetMethod("interceptFileProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestAsyncAsarJob>)
|
||||
.SetMethod("interceptHttpProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("interceptStreamProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestStreamJob>)
|
||||
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
namespace {
|
||||
|
||||
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args) {
|
||||
if (electron::Browser::Get()->is_ready()) {
|
||||
args->ThrowError(
|
||||
"protocol.registerSchemesAsPrivileged should be called before "
|
||||
"app is ready");
|
||||
return;
|
||||
}
|
||||
|
||||
electron::api::RegisterSchemesAsPrivileged(val, args);
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
|
||||
dict.SetMethod("getStandardSchemes", &electron::api::GetStandardSchemes);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_protocol, Initialize)
|
|
@ -1,198 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_API_ATOM_API_PROTOCOL_H_
|
||||
#define SHELL_BROWSER_API_ATOM_API_PROTOCOL_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/arguments.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "shell/browser/api/trackable_object.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/net/atom_url_request_job_factory.h"
|
||||
#include "shell/common/promise_util.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
std::vector<std::string> GetStandardSchemes();
|
||||
|
||||
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args);
|
||||
|
||||
class Protocol : public mate::TrackableObject<Protocol> {
|
||||
public:
|
||||
using Handler = base::RepeatingCallback<void(const base::DictionaryValue&,
|
||||
v8::Local<v8::Value>)>;
|
||||
using CompletionCallback =
|
||||
base::RepeatingCallback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
static mate::Handle<Protocol> Create(v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
protected:
|
||||
Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
~Protocol() override;
|
||||
|
||||
private:
|
||||
// Possible errors.
|
||||
enum class ProtocolError {
|
||||
OK, // no error
|
||||
FAIL, // operation failed, should never occur
|
||||
REGISTERED,
|
||||
NOT_REGISTERED,
|
||||
INTERCEPTED,
|
||||
NOT_INTERCEPTED,
|
||||
};
|
||||
|
||||
// The protocol handler that will create a protocol handler for certain
|
||||
// request job.
|
||||
template <typename RequestJob>
|
||||
class CustomProtocolHandler
|
||||
: public net::URLRequestJobFactory::ProtocolHandler {
|
||||
public:
|
||||
CustomProtocolHandler(v8::Isolate* isolate,
|
||||
net::URLRequestContextGetter* request_context,
|
||||
const Handler& handler)
|
||||
: isolate_(isolate),
|
||||
request_context_(request_context),
|
||||
handler_(handler) {}
|
||||
~CustomProtocolHandler() override {}
|
||||
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override {
|
||||
RequestJob* request_job = new RequestJob(request, network_delegate);
|
||||
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
|
||||
return request_job;
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
net::URLRequestContextGetter* request_context_;
|
||||
Protocol::Handler handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
// Register the protocol with certain request job.
|
||||
template <typename RequestJob>
|
||||
void RegisterProtocol(const std::string& scheme,
|
||||
const Handler& handler,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
auto* getter = static_cast<URLRequestContextGetter*>(
|
||||
browser_context_->GetRequestContext());
|
||||
base::PostTaskWithTraitsAndReplyWithResult(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&Protocol::RegisterProtocolInIO<RequestJob>,
|
||||
base::RetainedRef(getter), isolate(), scheme, handler),
|
||||
base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
|
||||
}
|
||||
template <typename RequestJob>
|
||||
static ProtocolError RegisterProtocolInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const Handler& handler) {
|
||||
auto* job_factory = request_context_getter->job_factory();
|
||||
if (job_factory->IsHandledProtocol(scheme))
|
||||
return ProtocolError::REGISTERED;
|
||||
auto protocol_handler = std::make_unique<CustomProtocolHandler<RequestJob>>(
|
||||
isolate, request_context_getter.get(), handler);
|
||||
if (job_factory->SetProtocolHandler(scheme, std::move(protocol_handler)))
|
||||
return ProtocolError::OK;
|
||||
else
|
||||
return ProtocolError::FAIL;
|
||||
}
|
||||
|
||||
// Unregister the protocol handler that handles |scheme|.
|
||||
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
|
||||
static ProtocolError UnregisterProtocolInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
const std::string& scheme);
|
||||
|
||||
// Whether the protocol has handler registered.
|
||||
v8::Local<v8::Promise> IsProtocolHandled(const std::string& scheme);
|
||||
|
||||
// Replace the protocol handler with a new one.
|
||||
template <typename RequestJob>
|
||||
void InterceptProtocol(const std::string& scheme,
|
||||
const Handler& handler,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
auto* getter = static_cast<URLRequestContextGetter*>(
|
||||
browser_context_->GetRequestContext());
|
||||
base::PostTaskWithTraitsAndReplyWithResult(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&Protocol::InterceptProtocolInIO<RequestJob>,
|
||||
base::RetainedRef(getter), isolate(), scheme, handler),
|
||||
base::BindOnce(&Protocol::OnIOCompleted, GetWeakPtr(), callback));
|
||||
}
|
||||
template <typename RequestJob>
|
||||
static ProtocolError InterceptProtocolInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const Handler& handler) {
|
||||
auto* job_factory = request_context_getter->job_factory();
|
||||
if (!job_factory->IsHandledProtocol(scheme))
|
||||
return ProtocolError::NOT_REGISTERED;
|
||||
// It is possible a protocol is handled but can not be intercepted.
|
||||
if (!job_factory->HasProtocolHandler(scheme))
|
||||
return ProtocolError::FAIL;
|
||||
auto protocol_handler = std::make_unique<CustomProtocolHandler<RequestJob>>(
|
||||
isolate, request_context_getter.get(), handler);
|
||||
if (!job_factory->InterceptProtocol(scheme, std::move(protocol_handler)))
|
||||
return ProtocolError::INTERCEPTED;
|
||||
return ProtocolError::OK;
|
||||
}
|
||||
|
||||
// Restore the |scheme| to its original protocol handler.
|
||||
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
|
||||
static ProtocolError UninterceptProtocolInIO(
|
||||
scoped_refptr<URLRequestContextGetter> request_context_getter,
|
||||
const std::string& scheme);
|
||||
|
||||
// Convert error code to JS exception and call the callback.
|
||||
void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
|
||||
|
||||
// Convert error code to string.
|
||||
std::string ErrorCodeToString(ProtocolError error);
|
||||
|
||||
base::WeakPtr<Protocol> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
|
||||
|
||||
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||
base::WeakPtrFactory<Protocol> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Protocol);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_API_ATOM_API_PROTOCOL_H_
|
|
@ -6,17 +6,133 @@
|
|||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/common/deprecate_util.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/once_callback.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/promise_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// List of registered custom standard schemes.
|
||||
std::vector<std::string> g_standard_schemes;
|
||||
|
||||
struct SchemeOptions {
|
||||
bool standard = false;
|
||||
bool secure = false;
|
||||
bool bypassCSP = false;
|
||||
bool allowServiceWorkers = false;
|
||||
bool supportFetchAPI = false;
|
||||
bool corsEnabled = false;
|
||||
};
|
||||
|
||||
struct CustomScheme {
|
||||
std::string scheme;
|
||||
SchemeOptions options;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<CustomScheme> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
CustomScheme* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!dict.Get("scheme", &(out->scheme)))
|
||||
return false;
|
||||
mate::Dictionary opt;
|
||||
// options are optional. Default values specified in SchemeOptions are used
|
||||
if (dict.Get("privileges", &opt)) {
|
||||
opt.Get("standard", &(out->options.standard));
|
||||
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
||||
opt.Get("secure", &(out->options.secure));
|
||||
opt.Get("bypassCSP", &(out->options.bypassCSP));
|
||||
opt.Get("allowServiceWorkers", &(out->options.allowServiceWorkers));
|
||||
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
||||
opt.Get("corsEnabled", &(out->options.corsEnabled));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace electron {
|
||||
namespace api {
|
||||
|
||||
std::vector<std::string> GetStandardSchemes() {
|
||||
return g_standard_schemes;
|
||||
}
|
||||
|
||||
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args) {
|
||||
std::vector<CustomScheme> custom_schemes;
|
||||
if (!mate::ConvertFromV8(args->isolate(), val, &custom_schemes)) {
|
||||
args->ThrowError("Argument must be an array of custom schemes.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> secure_schemes, cspbypassing_schemes, fetch_schemes,
|
||||
service_worker_schemes, cors_schemes;
|
||||
for (const auto& custom_scheme : custom_schemes) {
|
||||
// Register scheme to privileged list (https, wss, data, chrome-extension)
|
||||
if (custom_scheme.options.standard) {
|
||||
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
|
||||
url::AddStandardScheme(custom_scheme.scheme.c_str(),
|
||||
url::SCHEME_WITH_HOST);
|
||||
g_standard_schemes.push_back(custom_scheme.scheme);
|
||||
policy->RegisterWebSafeScheme(custom_scheme.scheme);
|
||||
}
|
||||
if (custom_scheme.options.secure) {
|
||||
secure_schemes.push_back(custom_scheme.scheme);
|
||||
url::AddSecureScheme(custom_scheme.scheme.c_str());
|
||||
}
|
||||
if (custom_scheme.options.bypassCSP) {
|
||||
cspbypassing_schemes.push_back(custom_scheme.scheme);
|
||||
url::AddCSPBypassingScheme(custom_scheme.scheme.c_str());
|
||||
}
|
||||
if (custom_scheme.options.corsEnabled) {
|
||||
cors_schemes.push_back(custom_scheme.scheme);
|
||||
url::AddCorsEnabledScheme(custom_scheme.scheme.c_str());
|
||||
}
|
||||
if (custom_scheme.options.supportFetchAPI) {
|
||||
fetch_schemes.push_back(custom_scheme.scheme);
|
||||
}
|
||||
if (custom_scheme.options.allowServiceWorkers) {
|
||||
service_worker_schemes.push_back(custom_scheme.scheme);
|
||||
}
|
||||
}
|
||||
|
||||
const auto AppendSchemesToCmdLine = [](const char* switch_name,
|
||||
std::vector<std::string> schemes) {
|
||||
// Add the schemes to command line switches, so child processes can also
|
||||
// register them.
|
||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||
switch_name, base::JoinString(schemes, ","));
|
||||
};
|
||||
|
||||
AppendSchemesToCmdLine(electron::switches::kSecureSchemes, secure_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kBypassCSPSchemes,
|
||||
cspbypassing_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kCORSSchemes, cors_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kFetchSchemes, fetch_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kServiceWorkerSchemes,
|
||||
service_worker_schemes);
|
||||
AppendSchemesToCmdLine(electron::switches::kStandardSchemes,
|
||||
g_standard_schemes);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kBuiltinSchemes[] = {
|
||||
|
@ -192,3 +308,31 @@ void ProtocolNS::BuildPrototype(v8::Isolate* isolate,
|
|||
|
||||
} // namespace api
|
||||
} // namespace electron
|
||||
|
||||
namespace {
|
||||
|
||||
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args) {
|
||||
if (electron::Browser::Get()->is_ready()) {
|
||||
args->ThrowError(
|
||||
"protocol.registerSchemesAsPrivileged should be called before "
|
||||
"app is ready");
|
||||
return;
|
||||
}
|
||||
|
||||
electron::api::RegisterSchemesAsPrivileged(val, args);
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
|
||||
dict.SetMethod("getStandardSchemes", &electron::api::GetStandardSchemes);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_protocol, Initialize)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define SHELL_BROWSER_API_ATOM_API_PROTOCOL_NS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
@ -19,6 +20,11 @@ class AtomBrowserContext;
|
|||
|
||||
namespace api {
|
||||
|
||||
std::vector<std::string> GetStandardSchemes();
|
||||
|
||||
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||
mate::Arguments* args);
|
||||
|
||||
// Possible errors.
|
||||
enum class ProtocolError {
|
||||
OK, // no error
|
||||
|
|
|
@ -45,9 +45,7 @@
|
|||
#include "shell/browser/api/atom_api_cookies.h"
|
||||
#include "shell/browser/api/atom_api_download_item.h"
|
||||
#include "shell/browser/api/atom_api_net_log.h"
|
||||
#include "shell/browser/api/atom_api_protocol.h"
|
||||
#include "shell/browser/api/atom_api_protocol_ns.h"
|
||||
#include "shell/browser/api/atom_api_web_request.h"
|
||||
#include "shell/browser/api/atom_api_web_request_ns.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/atom_browser_main_parts.h"
|
||||
|
@ -122,15 +120,6 @@ uint32_t GetQuotaMask(const std::vector<std::string>& quota_types) {
|
|||
return quota_mask;
|
||||
}
|
||||
|
||||
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const std::string& accept_lang,
|
||||
const std::string& user_agent) {
|
||||
getter->GetURLRequestContext()->set_http_user_agent_settings(
|
||||
new net::StaticHttpUserAgentSettings(
|
||||
net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
|
||||
user_agent));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
@ -179,14 +168,6 @@ const char kPersistPrefix[] = "persist:";
|
|||
// Referenced session objects.
|
||||
std::map<uint32_t, v8::Global<v8::Object>> g_sessions;
|
||||
|
||||
void SetCertVerifyProcInIO(
|
||||
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
||||
const AtomCertVerifier::VerifyProc& proc) {
|
||||
auto* request_context = context_getter->GetURLRequestContext();
|
||||
static_cast<AtomCertVerifier*>(request_context->cert_verifier())
|
||||
->SetVerifyProc(proc);
|
||||
}
|
||||
|
||||
void DownloadIdCallback(content::DownloadManager* download_manager,
|
||||
const base::FilePath& path,
|
||||
const std::vector<GURL>& url_chain,
|
||||
|
@ -472,26 +453,17 @@ void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
|
|||
return;
|
||||
}
|
||||
|
||||
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
network::mojom::CertVerifierClientPtr cert_verifier_client;
|
||||
if (proc) {
|
||||
mojo::MakeStrongBinding(
|
||||
std::make_unique<ElectronCertVerifierClient>(proc),
|
||||
mojo::MakeRequest(&cert_verifier_client));
|
||||
}
|
||||
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
|
||||
->GetNetworkContext()
|
||||
->SetCertVerifierClient(std::move(cert_verifier_client));
|
||||
|
||||
// This causes the cert verifier cache to be cleared.
|
||||
content::GetNetworkService()->OnCertDBChanged();
|
||||
} else {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(&SetCertVerifyProcInIO,
|
||||
WrapRefCounted(browser_context_->GetRequestContext()),
|
||||
base::BindRepeating(&WrapVerifyProc, proc)));
|
||||
network::mojom::CertVerifierClientPtr cert_verifier_client;
|
||||
if (proc) {
|
||||
mojo::MakeStrongBinding(std::make_unique<ElectronCertVerifierClient>(proc),
|
||||
mojo::MakeRequest(&cert_verifier_client));
|
||||
}
|
||||
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
|
||||
->GetNetworkContext()
|
||||
->SetCertVerifierClient(std::move(cert_verifier_client));
|
||||
|
||||
// This causes the cert verifier cache to be cleared.
|
||||
content::GetNetworkService()->OnCertDBChanged();
|
||||
}
|
||||
|
||||
void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
|
||||
|
@ -563,22 +535,14 @@ v8::Local<v8::Promise> Session::ClearAuthCache() {
|
|||
|
||||
void Session::AllowNTLMCredentialsForDomains(const std::string& domains) {
|
||||
auto auth_params = CreateHttpAuthDynamicParams();
|
||||
auth_params->server_whitelist = domains;
|
||||
auth_params->server_allowlist = domains;
|
||||
content::GetNetworkService()->ConfigureHttpAuthPrefs(std::move(auth_params));
|
||||
}
|
||||
|
||||
void Session::SetUserAgent(const std::string& user_agent,
|
||||
mate::Arguments* args) {
|
||||
browser_context_->SetUserAgent(user_agent);
|
||||
|
||||
std::string accept_lang = g_browser_process->GetApplicationLocale();
|
||||
args->GetNext(&accept_lang);
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> getter(
|
||||
browser_context_->GetRequestContext());
|
||||
getter->GetNetworkTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&SetUserAgentInIO, getter, accept_lang, user_agent));
|
||||
CHECK(false)
|
||||
<< "TODO: This was disabled when the network service was turned on";
|
||||
}
|
||||
|
||||
std::string Session::GetUserAgent() {
|
||||
|
@ -661,10 +625,7 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
|||
v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
|
||||
if (protocol_.IsEmpty()) {
|
||||
v8::Local<v8::Value> handle;
|
||||
if (base::FeatureList::IsEnabled(network::features::kNetworkService))
|
||||
handle = ProtocolNS::Create(isolate, browser_context()).ToV8();
|
||||
else
|
||||
handle = Protocol::Create(isolate, browser_context()).ToV8();
|
||||
handle = ProtocolNS::Create(isolate, browser_context()).ToV8();
|
||||
protocol_.Reset(isolate, handle);
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, protocol_);
|
||||
|
@ -673,10 +634,7 @@ v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
|
|||
v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
|
||||
if (web_request_.IsEmpty()) {
|
||||
v8::Local<v8::Value> handle;
|
||||
if (base::FeatureList::IsEnabled(network::features::kNetworkService))
|
||||
handle = WebRequestNS::Create(isolate, browser_context()).ToV8();
|
||||
else
|
||||
handle = WebRequest::Create(isolate, browser_context()).ToV8();
|
||||
handle = WebRequestNS::Create(isolate, browser_context()).ToV8();
|
||||
web_request_.Reset(isolate, handle);
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, web_request_);
|
||||
|
@ -774,7 +732,7 @@ namespace {
|
|||
|
||||
using electron::api::Cookies;
|
||||
using electron::api::NetLog;
|
||||
using electron::api::Protocol;
|
||||
using electron::api::ProtocolNS;
|
||||
using electron::api::Session;
|
||||
|
||||
v8::Local<v8::Value> FromPartition(const std::string& partition,
|
||||
|
@ -803,9 +761,9 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
dict.Set(
|
||||
"NetLog",
|
||||
NetLog::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
|
||||
dict.Set(
|
||||
"Protocol",
|
||||
Protocol::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
|
||||
dict.Set("Protocol", ProtocolNS::GetConstructor(isolate)
|
||||
->GetFunction(context)
|
||||
.ToLocalChecked());
|
||||
dict.SetMethod("fromPartition", &FromPartition);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,496 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/atom_api_url_request.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "shell/browser/api/atom_api_session.h"
|
||||
#include "shell/browser/net/atom_url_request.h"
|
||||
#include "shell/common/api/event_emitter_caller.h"
|
||||
#include "shell/common/native_mate_converters/gurl_converter.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/once_callback.h"
|
||||
#include "shell/common/native_mate_converters/string16_converter.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template <>
|
||||
struct Converter<scoped_refptr<const net::IOBufferWithSize>> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
scoped_refptr<const net::IOBufferWithSize> buffer) {
|
||||
return node::Buffer::Copy(isolate, buffer->data(), buffer->size())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
scoped_refptr<const net::IOBufferWithSize>* out) {
|
||||
auto size = node::Buffer::Length(val);
|
||||
|
||||
if (size == 0) {
|
||||
// Support conversion from empty buffer. A use case is
|
||||
// a GET request without body.
|
||||
// Since zero-sized IOBuffer(s) are not supported, we set the
|
||||
// out pointer to null.
|
||||
*out = nullptr;
|
||||
return true;
|
||||
}
|
||||
auto* data = node::Buffer::Data(val);
|
||||
if (!data) {
|
||||
// This is an error as size is positive but data is null.
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = new net::IOBufferWithSize(size);
|
||||
// We do a deep copy. We could have used Buffer's internal memory
|
||||
// but that is much more complicated to be properly handled.
|
||||
memcpy((*out)->data(), data, size);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace electron {
|
||||
namespace api {
|
||||
|
||||
template <typename Flags>
|
||||
URLRequest::StateBase<Flags>::StateBase(Flags initialState)
|
||||
: state_(initialState) {}
|
||||
|
||||
template <typename Flags>
|
||||
void URLRequest::StateBase<Flags>::SetFlag(Flags flag) {
|
||||
state_ =
|
||||
static_cast<Flags>(static_cast<int>(state_) | static_cast<int>(flag));
|
||||
}
|
||||
|
||||
template <typename Flags>
|
||||
bool URLRequest::StateBase<Flags>::operator==(Flags flag) const {
|
||||
return state_ == flag;
|
||||
}
|
||||
|
||||
template <typename Flags>
|
||||
bool URLRequest::StateBase<Flags>::IsFlagSet(Flags flag) const {
|
||||
return static_cast<int>(state_) & static_cast<int>(flag);
|
||||
}
|
||||
|
||||
URLRequest::RequestState::RequestState()
|
||||
: StateBase(RequestStateFlags::kNotStarted) {}
|
||||
|
||||
bool URLRequest::RequestState::NotStarted() const {
|
||||
return *this == RequestStateFlags::kNotStarted;
|
||||
}
|
||||
|
||||
bool URLRequest::RequestState::Started() const {
|
||||
return IsFlagSet(RequestStateFlags::kStarted);
|
||||
}
|
||||
|
||||
bool URLRequest::RequestState::Finished() const {
|
||||
return IsFlagSet(RequestStateFlags::kFinished);
|
||||
}
|
||||
|
||||
bool URLRequest::RequestState::Canceled() const {
|
||||
return IsFlagSet(RequestStateFlags::kCanceled);
|
||||
}
|
||||
|
||||
bool URLRequest::RequestState::Failed() const {
|
||||
return IsFlagSet(RequestStateFlags::kFailed);
|
||||
}
|
||||
|
||||
bool URLRequest::RequestState::Closed() const {
|
||||
return IsFlagSet(RequestStateFlags::kClosed);
|
||||
}
|
||||
|
||||
URLRequest::ResponseState::ResponseState()
|
||||
: StateBase(ResponseStateFlags::kNotStarted) {}
|
||||
|
||||
bool URLRequest::ResponseState::NotStarted() const {
|
||||
return *this == ResponseStateFlags::kNotStarted;
|
||||
}
|
||||
|
||||
bool URLRequest::ResponseState::Started() const {
|
||||
return IsFlagSet(ResponseStateFlags::kStarted);
|
||||
}
|
||||
|
||||
bool URLRequest::ResponseState::Ended() const {
|
||||
return IsFlagSet(ResponseStateFlags::kEnded);
|
||||
}
|
||||
|
||||
bool URLRequest::ResponseState::Failed() const {
|
||||
return IsFlagSet(ResponseStateFlags::kFailed);
|
||||
}
|
||||
|
||||
mate::Dictionary URLRequest::GetUploadProgress(v8::Isolate* isolate) {
|
||||
mate::Dictionary progress = mate::Dictionary::CreateEmpty(isolate);
|
||||
|
||||
if (atom_request_) {
|
||||
progress.Set("active", true);
|
||||
atom_request_->GetUploadProgress(&progress);
|
||||
} else {
|
||||
progress.Set("active", false);
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
URLRequest::URLRequest(v8::Isolate* isolate, v8::Local<v8::Object> wrapper) {
|
||||
InitWith(isolate, wrapper);
|
||||
}
|
||||
|
||||
URLRequest::~URLRequest() {
|
||||
// A request has been created in JS, it was not used and then
|
||||
// it got collected, no close event to cleanup, only destructor
|
||||
// is called.
|
||||
if (atom_request_) {
|
||||
atom_request_->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
mate::WrappableBase* URLRequest::New(mate::Arguments* args) {
|
||||
auto* isolate = args->isolate();
|
||||
v8::Local<v8::Object> options;
|
||||
args->GetNext(&options);
|
||||
mate::Dictionary dict(isolate, options);
|
||||
std::string method;
|
||||
dict.Get("method", &method);
|
||||
std::string url;
|
||||
dict.Get("url", &url);
|
||||
std::string redirect_policy;
|
||||
dict.Get("redirect", &redirect_policy);
|
||||
std::string partition;
|
||||
mate::Handle<api::Session> session;
|
||||
if (dict.Get("session", &session)) {
|
||||
} else if (dict.Get("partition", &partition)) {
|
||||
session = Session::FromPartition(isolate, partition);
|
||||
} else {
|
||||
// Use the default session if not specified.
|
||||
session = Session::FromPartition(isolate, "");
|
||||
}
|
||||
auto* browser_context = session->browser_context();
|
||||
auto* api_url_request = new URLRequest(args->isolate(), args->GetThis());
|
||||
auto atom_url_request = AtomURLRequest::Create(
|
||||
browser_context, method, url, redirect_policy, api_url_request);
|
||||
|
||||
api_url_request->atom_request_ = atom_url_request;
|
||||
|
||||
return api_url_request;
|
||||
}
|
||||
|
||||
// static
|
||||
void URLRequest::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
prototype->SetClassName(mate::StringToV8(isolate, "URLRequest"));
|
||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
// Request API
|
||||
.MakeDestroyable()
|
||||
.SetMethod("write", &URLRequest::Write)
|
||||
.SetMethod("cancel", &URLRequest::Cancel)
|
||||
.SetMethod("setExtraHeader", &URLRequest::SetExtraHeader)
|
||||
.SetMethod("removeExtraHeader", &URLRequest::RemoveExtraHeader)
|
||||
.SetMethod("setChunkedUpload", &URLRequest::SetChunkedUpload)
|
||||
.SetMethod("followRedirect", &URLRequest::FollowRedirect)
|
||||
.SetMethod("_setLoadFlags", &URLRequest::SetLoadFlags)
|
||||
.SetMethod("getUploadProgress", &URLRequest::GetUploadProgress)
|
||||
.SetProperty("notStarted", &URLRequest::NotStarted)
|
||||
.SetProperty("finished", &URLRequest::Finished)
|
||||
// Response APi
|
||||
.SetProperty("statusCode", &URLRequest::StatusCode)
|
||||
.SetProperty("statusMessage", &URLRequest::StatusMessage)
|
||||
.SetProperty("rawResponseHeaders", &URLRequest::RawResponseHeaders)
|
||||
.SetProperty("httpVersionMajor", &URLRequest::ResponseHttpVersionMajor)
|
||||
.SetProperty("httpVersionMinor", &URLRequest::ResponseHttpVersionMinor);
|
||||
}
|
||||
|
||||
bool URLRequest::NotStarted() const {
|
||||
return request_state_.NotStarted();
|
||||
}
|
||||
|
||||
bool URLRequest::Finished() const {
|
||||
return request_state_.Finished();
|
||||
}
|
||||
|
||||
bool URLRequest::Canceled() const {
|
||||
return request_state_.Canceled();
|
||||
}
|
||||
|
||||
bool URLRequest::Write(scoped_refptr<const net::IOBufferWithSize> buffer,
|
||||
bool is_last) {
|
||||
if (request_state_.Canceled() || request_state_.Failed() ||
|
||||
request_state_.Finished() || request_state_.Closed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request_state_.NotStarted()) {
|
||||
request_state_.SetFlag(RequestStateFlags::kStarted);
|
||||
// Pin on first write.
|
||||
Pin();
|
||||
}
|
||||
|
||||
if (is_last) {
|
||||
request_state_.SetFlag(RequestStateFlags::kFinished);
|
||||
EmitRequestEvent(true, "finish");
|
||||
}
|
||||
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
return atom_request_->Write(buffer, is_last);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void URLRequest::Cancel() {
|
||||
if (request_state_.Canceled() || request_state_.Closed()) {
|
||||
// Cancel only once.
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as canceled.
|
||||
request_state_.SetFlag(RequestStateFlags::kCanceled);
|
||||
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_ && request_state_.Started()) {
|
||||
// Really cancel if it was started.
|
||||
atom_request_->Cancel();
|
||||
}
|
||||
EmitRequestEvent(true, "abort");
|
||||
|
||||
if (response_state_.Started() && !response_state_.Ended()) {
|
||||
EmitResponseEvent(true, "aborted");
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
void URLRequest::FollowRedirect() {
|
||||
if (request_state_.Canceled() || request_state_.Closed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
atom_request_->FollowRedirect();
|
||||
}
|
||||
}
|
||||
|
||||
bool URLRequest::SetExtraHeader(const std::string& name,
|
||||
const std::string& value) {
|
||||
// Request state must be in the initial non started state.
|
||||
if (!request_state_.NotStarted()) {
|
||||
// Cannot change headers after send.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!net::HttpUtil::IsValidHeaderName(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!net::HttpUtil::IsValidHeaderValue(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
atom_request_->SetExtraHeader(name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void URLRequest::RemoveExtraHeader(const std::string& name) {
|
||||
// State must be equal to not started.
|
||||
if (!request_state_.NotStarted()) {
|
||||
// Cannot change headers after send.
|
||||
return;
|
||||
}
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
atom_request_->RemoveExtraHeader(name);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequest::SetChunkedUpload(bool is_chunked_upload) {
|
||||
// State must be equal to not started.
|
||||
if (!request_state_.NotStarted()) {
|
||||
// Cannot change headers after send.
|
||||
return;
|
||||
}
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
atom_request_->SetChunkedUpload(is_chunked_upload);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequest::SetLoadFlags(int flags) {
|
||||
// State must be equal to not started.
|
||||
if (!request_state_.NotStarted()) {
|
||||
// Cannot change load flags after start.
|
||||
return;
|
||||
}
|
||||
DCHECK(atom_request_);
|
||||
if (atom_request_) {
|
||||
atom_request_->SetLoadFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequest::OnReceivedRedirect(
|
||||
int status_code,
|
||||
const std::string& method,
|
||||
const GURL& url,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers) {
|
||||
if (request_state_.Canceled() || request_state_.Closed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(atom_request_);
|
||||
if (!atom_request_) {
|
||||
return;
|
||||
}
|
||||
|
||||
EmitRequestEvent(false, "redirect", status_code, method, url,
|
||||
response_headers.get());
|
||||
}
|
||||
|
||||
void URLRequest::OnAuthenticationRequired(
|
||||
const net::AuthChallengeInfo& auth_info) {
|
||||
if (request_state_.Canceled() || request_state_.Closed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(atom_request_);
|
||||
if (!atom_request_) {
|
||||
return;
|
||||
}
|
||||
|
||||
Emit("login", auth_info,
|
||||
base::BindOnce(&AtomURLRequest::PassLoginInformation, atom_request_));
|
||||
}
|
||||
|
||||
void URLRequest::OnResponseStarted(
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers) {
|
||||
if (request_state_.Canceled() || request_state_.Failed() ||
|
||||
request_state_.Closed()) {
|
||||
// Don't emit any event after request cancel.
|
||||
return;
|
||||
}
|
||||
response_headers_ = response_headers;
|
||||
response_state_.SetFlag(ResponseStateFlags::kStarted);
|
||||
Emit("response");
|
||||
}
|
||||
|
||||
void URLRequest::OnResponseData(
|
||||
scoped_refptr<const net::IOBufferWithSize> buffer) {
|
||||
if (request_state_.Canceled() || request_state_.Closed() ||
|
||||
request_state_.Failed() || response_state_.Failed()) {
|
||||
// In case we received an unexpected event from Chromium net,
|
||||
// don't emit any data event after request cancel/error/close.
|
||||
return;
|
||||
}
|
||||
if (!buffer || !buffer->data() || !buffer->size()) {
|
||||
return;
|
||||
}
|
||||
Emit("data", buffer);
|
||||
}
|
||||
|
||||
void URLRequest::OnResponseCompleted() {
|
||||
if (request_state_.Canceled() || request_state_.Closed() ||
|
||||
request_state_.Failed() || response_state_.Failed()) {
|
||||
// In case we received an unexpected event from Chromium net,
|
||||
// don't emit any data event after request cancel/error/close.
|
||||
return;
|
||||
}
|
||||
response_state_.SetFlag(ResponseStateFlags::kEnded);
|
||||
Emit("end");
|
||||
Close();
|
||||
}
|
||||
|
||||
void URLRequest::OnError(const std::string& error, bool isRequestError) {
|
||||
auto error_object = v8::Exception::Error(mate::StringToV8(isolate(), error));
|
||||
if (isRequestError) {
|
||||
request_state_.SetFlag(RequestStateFlags::kFailed);
|
||||
EmitRequestEvent(false, "error", error_object);
|
||||
} else {
|
||||
response_state_.SetFlag(ResponseStateFlags::kFailed);
|
||||
EmitResponseEvent(false, "error", error_object);
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
int URLRequest::StatusCode() const {
|
||||
if (response_headers_) {
|
||||
return response_headers_->response_code();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string URLRequest::StatusMessage() const {
|
||||
std::string result;
|
||||
if (response_headers_) {
|
||||
result = response_headers_->GetStatusText();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
net::HttpResponseHeaders* URLRequest::RawResponseHeaders() const {
|
||||
return response_headers_.get();
|
||||
}
|
||||
|
||||
uint32_t URLRequest::ResponseHttpVersionMajor() const {
|
||||
if (response_headers_) {
|
||||
return response_headers_->GetHttpVersion().major_value();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t URLRequest::ResponseHttpVersionMinor() const {
|
||||
if (response_headers_) {
|
||||
return response_headers_->GetHttpVersion().minor_value();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void URLRequest::Close() {
|
||||
if (!request_state_.Closed()) {
|
||||
request_state_.SetFlag(RequestStateFlags::kClosed);
|
||||
if (response_state_.Started()) {
|
||||
// Emit a close event if we really have a response object.
|
||||
EmitResponseEvent(true, "close");
|
||||
}
|
||||
EmitRequestEvent(true, "close");
|
||||
}
|
||||
Unpin();
|
||||
if (atom_request_) {
|
||||
// A request has been created in JS, used and then it ended.
|
||||
// We release unneeded net resources.
|
||||
atom_request_->Terminate();
|
||||
}
|
||||
atom_request_ = nullptr;
|
||||
}
|
||||
|
||||
void URLRequest::Pin() {
|
||||
if (wrapper_.IsEmpty()) {
|
||||
wrapper_.Reset(isolate(), GetWrapper());
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequest::Unpin() {
|
||||
wrapper_.Reset();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void URLRequest::EmitRequestEvent(Args... args) {
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
mate::CustomEmit(isolate(), GetWrapper(), "_emitRequestEvent", args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void URLRequest::EmitResponseEvent(Args... args) {
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
mate::CustomEmit(isolate(), GetWrapper(), "_emitResponseEvent", args...);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
|
@ -1,213 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_API_ATOM_API_URL_REQUEST_H_
|
||||
#define SHELL_BROWSER_API_ATOM_API_URL_REQUEST_H_
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/wrappable_base.h"
|
||||
#include "net/base/auth.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "shell/browser/api/event_emitter.h"
|
||||
#include "shell/browser/api/trackable_object.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class AtomURLRequest;
|
||||
|
||||
namespace api {
|
||||
|
||||
// The URLRequest class implements the V8 binding between the JavaScript API
|
||||
// and Chromium native net library. It is responsible for handling HTTP/HTTPS
|
||||
// requests.
|
||||
//
|
||||
// The current class provides only the binding layer. Two other JavaScript
|
||||
// classes (ClientRequest and IncomingMessage) in the net module provide the
|
||||
// final API, including some state management and arguments validation.
|
||||
//
|
||||
// URLRequest's methods fall into two main categories: command and event
|
||||
// methods. They are always executed on the Browser's UI thread.
|
||||
// Command methods are called directly from JavaScript code via the API defined
|
||||
// in BuildPrototype. A command method is generally implemented by forwarding
|
||||
// the call to a corresponding method on AtomURLRequest which does the
|
||||
// synchronization on the Browser IO thread. The latter then calls into Chromium
|
||||
// net library. On the other hand, net library events originate on the IO
|
||||
// thread in AtomURLRequest and are synchronized back on the UI thread, then
|
||||
// forwarded to a corresponding event method in URLRequest and then to
|
||||
// JavaScript via the EmitRequestEvent/EmitResponseEvent helpers.
|
||||
//
|
||||
// URLRequest lifetime management: we followed the Wrapper/Wrappable pattern
|
||||
// defined in native_mate. However, we augment that pattern with a pin/unpin
|
||||
// mechanism. The main reason is that we want the JS API to provide a similar
|
||||
// lifetime guarantees as the XMLHttpRequest.
|
||||
// https://xhr.spec.whatwg.org/#garbage-collection
|
||||
//
|
||||
// The primary motivation is to not garbage collect a URLInstance as long as the
|
||||
// object is emitting network events. For instance, in the following JS code
|
||||
//
|
||||
// (function() {
|
||||
// let request = new URLRequest(...);
|
||||
// request.on('response', (response)=>{
|
||||
// response.on('data', (data) = > {
|
||||
// console.log(data.toString());
|
||||
// });
|
||||
// });
|
||||
// })();
|
||||
//
|
||||
// we still want data to be logged even if the response/request objects are n
|
||||
// more referenced in JavaScript.
|
||||
//
|
||||
// Binding by simply following the native_mate Wrapper/Wrappable pattern will
|
||||
// delete the URLRequest object when the corresponding JS object is collected.
|
||||
// The v8 handle is a private member in WrappableBase and it is always weak,
|
||||
// there is no way to make it strong without changing native_mate.
|
||||
// The solution we implement consists of maintaining some kind of state that
|
||||
// prevents collection of JS wrappers as long as the request is emitting network
|
||||
// events. At initialization, the object is unpinned. When the request starts,
|
||||
// it is pinned. When no more events would be emitted, the object is unpinned
|
||||
// and lifetime is again managed by the standard native mate Wrapper/Wrappable
|
||||
// pattern.
|
||||
//
|
||||
// pin/unpin: are implemented by constructing/reseting a V8 strong persistent
|
||||
// handle.
|
||||
//
|
||||
// The URLRequest/AtmURLRequest interaction could have been implemented in a
|
||||
// single class. However, it implies that the resulting class lifetime will be
|
||||
// managed by two conflicting mechanisms: JavaScript garbage collection and
|
||||
// Chromium reference counting. Reasoning about lifetime issues become much
|
||||
// more complex.
|
||||
//
|
||||
// We chose to split the implementation into two classes linked via a
|
||||
// reference counted/raw pointers. A URLRequest instance is deleted if it is
|
||||
// unpinned and the corresponding JS wrapper object is garbage collected. On the
|
||||
// other hand, an AtmURLRequest instance lifetime is totally governed by
|
||||
// reference counting.
|
||||
//
|
||||
class URLRequest : public mate::EventEmitter<URLRequest> {
|
||||
public:
|
||||
static mate::WrappableBase* New(mate::Arguments* args);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
// Methods for reporting events into JavaScript.
|
||||
void OnReceivedRedirect(
|
||||
int status_code,
|
||||
const std::string& method,
|
||||
const GURL& url,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers);
|
||||
void OnAuthenticationRequired(const net::AuthChallengeInfo& auth_info);
|
||||
void OnResponseStarted(
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers);
|
||||
void OnResponseData(scoped_refptr<const net::IOBufferWithSize> data);
|
||||
void OnResponseCompleted();
|
||||
void OnError(const std::string& error, bool isRequestError);
|
||||
mate::Dictionary GetUploadProgress(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
URLRequest(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
|
||||
~URLRequest() override;
|
||||
|
||||
private:
|
||||
template <typename Flags>
|
||||
class StateBase {
|
||||
public:
|
||||
void SetFlag(Flags flag);
|
||||
|
||||
protected:
|
||||
explicit StateBase(Flags initialState);
|
||||
bool operator==(Flags flag) const;
|
||||
bool IsFlagSet(Flags flag) const;
|
||||
|
||||
private:
|
||||
Flags state_;
|
||||
};
|
||||
|
||||
enum class RequestStateFlags {
|
||||
kNotStarted = 0x0,
|
||||
kStarted = 0x1,
|
||||
kFinished = 0x2,
|
||||
kCanceled = 0x4,
|
||||
kFailed = 0x8,
|
||||
kClosed = 0x10
|
||||
};
|
||||
|
||||
class RequestState : public StateBase<RequestStateFlags> {
|
||||
public:
|
||||
RequestState();
|
||||
bool NotStarted() const;
|
||||
bool Started() const;
|
||||
bool Finished() const;
|
||||
bool Canceled() const;
|
||||
bool Failed() const;
|
||||
bool Closed() const;
|
||||
};
|
||||
|
||||
enum class ResponseStateFlags {
|
||||
kNotStarted = 0x0,
|
||||
kStarted = 0x1,
|
||||
kEnded = 0x2,
|
||||
kFailed = 0x4
|
||||
};
|
||||
|
||||
class ResponseState : public StateBase<ResponseStateFlags> {
|
||||
public:
|
||||
ResponseState();
|
||||
bool NotStarted() const;
|
||||
bool Started() const;
|
||||
bool Ended() const;
|
||||
bool Canceled() const;
|
||||
bool Failed() const;
|
||||
bool Closed() const;
|
||||
};
|
||||
|
||||
bool NotStarted() const;
|
||||
bool Finished() const;
|
||||
bool Canceled() const;
|
||||
bool Failed() const;
|
||||
bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last);
|
||||
void Cancel();
|
||||
void FollowRedirect();
|
||||
bool SetExtraHeader(const std::string& name, const std::string& value);
|
||||
void RemoveExtraHeader(const std::string& name);
|
||||
void SetChunkedUpload(bool is_chunked_upload);
|
||||
void SetLoadFlags(int flags);
|
||||
|
||||
int StatusCode() const;
|
||||
std::string StatusMessage() const;
|
||||
net::HttpResponseHeaders* RawResponseHeaders() const;
|
||||
uint32_t ResponseHttpVersionMajor() const;
|
||||
uint32_t ResponseHttpVersionMinor() const;
|
||||
|
||||
void Close();
|
||||
void Pin();
|
||||
void Unpin();
|
||||
template <typename... Args>
|
||||
void EmitRequestEvent(Args... args);
|
||||
template <typename... Args>
|
||||
void EmitResponseEvent(Args... args);
|
||||
|
||||
scoped_refptr<AtomURLRequest> atom_request_;
|
||||
RequestState request_state_;
|
||||
ResponseState response_state_;
|
||||
|
||||
// Used to implement pin/unpin.
|
||||
v8::Global<v8::Object> wrapper_;
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequest);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_API_ATOM_API_URL_REQUEST_H_
|
|
@ -10,6 +10,8 @@
|
|||
#include "mojo/public/cpp/system/string_data_source.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/http/http_util.h"
|
||||
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
|
||||
#include "shell/browser/api/atom_api_session.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/common/native_mate_converters/gurl_converter.h"
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/atom_api_web_request.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/net/atom_network_delegate.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/once_callback.h"
|
||||
#include "shell/common/native_mate_converters/value_converter.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Method, typename Event, typename Listener>
|
||||
void CallNetworkDelegateMethod(
|
||||
URLRequestContextGetter* url_request_context_getter,
|
||||
Method method,
|
||||
Event type,
|
||||
URLPatterns patterns,
|
||||
Listener listener) {
|
||||
// Force creating network delegate.
|
||||
url_request_context_getter->GetURLRequestContext();
|
||||
// Then call the method.
|
||||
auto* network_delegate = url_request_context_getter->network_delegate();
|
||||
(network_delegate->*method)(type, std::move(patterns), std::move(listener));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WebRequest::WebRequest(v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context)
|
||||
: browser_context_(browser_context) {
|
||||
Init(isolate);
|
||||
}
|
||||
|
||||
WebRequest::~WebRequest() {}
|
||||
|
||||
template <AtomNetworkDelegate::SimpleEvent type>
|
||||
void WebRequest::SetSimpleListener(mate::Arguments* args) {
|
||||
SetListener<AtomNetworkDelegate::SimpleListener>(
|
||||
&AtomNetworkDelegate::SetSimpleListenerInIO, type, args);
|
||||
}
|
||||
|
||||
template <AtomNetworkDelegate::ResponseEvent type>
|
||||
void WebRequest::SetResponseListener(mate::Arguments* args) {
|
||||
SetListener<AtomNetworkDelegate::ResponseListener>(
|
||||
&AtomNetworkDelegate::SetResponseListenerInIO, type, args);
|
||||
}
|
||||
|
||||
template <typename Listener, typename Method, typename Event>
|
||||
void WebRequest::SetListener(Method method, Event type, mate::Arguments* args) {
|
||||
// { urls }.
|
||||
URLPatterns patterns;
|
||||
mate::Dictionary dict;
|
||||
std::set<std::string> filter_patterns;
|
||||
|
||||
if (args->GetNext(&dict) && !dict.Get("urls", &filter_patterns)) {
|
||||
args->ThrowError(
|
||||
"onBeforeRequest parameter 'filter' must have property 'urls'.");
|
||||
return;
|
||||
}
|
||||
|
||||
URLPattern pattern(URLPattern::SCHEME_ALL);
|
||||
for (const std::string& filter_pattern : filter_patterns) {
|
||||
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->ThrowError("Invalid url pattern " + filter_pattern + ": " +
|
||||
error_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Function or null.
|
||||
v8::Local<v8::Value> value;
|
||||
Listener listener;
|
||||
if (!args->GetNext(&listener) &&
|
||||
!(args->GetNext(&value) && value->IsNull())) {
|
||||
args->ThrowError("Must pass null or a Function");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* url_request_context_getter = static_cast<URLRequestContextGetter*>(
|
||||
browser_context_->GetRequestContext());
|
||||
if (!url_request_context_getter)
|
||||
return;
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(&CallNetworkDelegateMethod<Method, Event, Listener>,
|
||||
base::RetainedRef(url_request_context_getter), method,
|
||||
type, std::move(patterns), std::move(listener)));
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<WebRequest> WebRequest::Create(
|
||||
v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context) {
|
||||
return mate::CreateHandle(isolate, new WebRequest(isolate, browser_context));
|
||||
}
|
||||
|
||||
// static
|
||||
void WebRequest::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
prototype->SetClassName(mate::StringToV8(isolate, "WebRequest"));
|
||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("onBeforeRequest", &WebRequest::SetResponseListener<
|
||||
AtomNetworkDelegate::kOnBeforeRequest>)
|
||||
.SetMethod("onBeforeSendHeaders",
|
||||
&WebRequest::SetResponseListener<
|
||||
AtomNetworkDelegate::kOnBeforeSendHeaders>)
|
||||
.SetMethod("onHeadersReceived",
|
||||
&WebRequest::SetResponseListener<
|
||||
AtomNetworkDelegate::kOnHeadersReceived>)
|
||||
.SetMethod(
|
||||
"onSendHeaders",
|
||||
&WebRequest::SetSimpleListener<AtomNetworkDelegate::kOnSendHeaders>)
|
||||
.SetMethod("onBeforeRedirect",
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnBeforeRedirect>)
|
||||
.SetMethod("onResponseStarted",
|
||||
&WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnResponseStarted>)
|
||||
.SetMethod(
|
||||
"onCompleted",
|
||||
&WebRequest::SetSimpleListener<AtomNetworkDelegate::kOnCompleted>)
|
||||
.SetMethod("onErrorOccurred", &WebRequest::SetSimpleListener<
|
||||
AtomNetworkDelegate::kOnErrorOccurred>);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||
#define SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
||||
|
||||
#include "native_mate/arguments.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "shell/browser/api/trackable_object.h"
|
||||
#include "shell/browser/net/atom_network_delegate.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
namespace api {
|
||||
|
||||
class WebRequest : public mate::TrackableObject<WebRequest> {
|
||||
public:
|
||||
static mate::Handle<WebRequest> Create(v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
|
||||
protected:
|
||||
WebRequest(v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
~WebRequest() override;
|
||||
|
||||
// C++ can not distinguish overloaded member function.
|
||||
template <AtomNetworkDelegate::SimpleEvent type>
|
||||
void SetSimpleListener(mate::Arguments* args);
|
||||
template <AtomNetworkDelegate::ResponseEvent type>
|
||||
void SetResponseListener(mate::Arguments* args);
|
||||
template <typename Listener, typename Method, typename Event>
|
||||
void SetListener(Method method, Event type, mate::Arguments* args);
|
||||
|
||||
private:
|
||||
scoped_refptr<AtomBrowserContext> browser_context_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebRequest);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_H_
|
|
@ -1,119 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/stream_subscriber.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "shell/browser/net/url_request_stream_job.h"
|
||||
#include "shell/common/api/event_emitter_caller.h"
|
||||
#include "shell/common/native_mate_converters/callback.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
StreamSubscriber::StreamSubscriber(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> emitter,
|
||||
base::WeakPtr<electron::URLRequestStreamJob> url_job,
|
||||
scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
|
||||
: base::RefCountedDeleteOnSequence<StreamSubscriber>(ui_task_runner),
|
||||
isolate_(isolate),
|
||||
emitter_(isolate, emitter),
|
||||
url_job_(url_job),
|
||||
weak_factory_(this) {
|
||||
DCHECK(ui_task_runner->RunsTasksInCurrentSequence());
|
||||
|
||||
auto weak_self = weak_factory_.GetWeakPtr();
|
||||
On("data", base::BindRepeating(&StreamSubscriber::OnData, weak_self));
|
||||
On("end", base::BindRepeating(&StreamSubscriber::OnEnd, weak_self));
|
||||
On("error", base::BindRepeating(&StreamSubscriber::OnError, weak_self));
|
||||
}
|
||||
|
||||
StreamSubscriber::~StreamSubscriber() {
|
||||
RemoveAllListeners();
|
||||
}
|
||||
|
||||
void StreamSubscriber::On(const std::string& event,
|
||||
EventCallback&& callback) { // NOLINT
|
||||
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
DCHECK(js_handlers_.find(event) == js_handlers_.end());
|
||||
|
||||
v8::Locker locker(isolate_);
|
||||
v8::Isolate::Scope isolate_scope(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
// emitter.on(event, EventEmitted)
|
||||
auto fn = CallbackToV8(isolate_, callback);
|
||||
js_handlers_[event] = v8::Global<v8::Value>(isolate_, fn);
|
||||
internal::ValueVector args = {StringToV8(isolate_, event), fn};
|
||||
internal::CallMethodWithArgs(isolate_, emitter_.Get(isolate_), "on", &args);
|
||||
}
|
||||
|
||||
void StreamSubscriber::Off(const std::string& event) {
|
||||
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
DCHECK(js_handlers_.find(event) != js_handlers_.end());
|
||||
|
||||
v8::Locker locker(isolate_);
|
||||
v8::Isolate::Scope isolate_scope(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
auto js_handler = js_handlers_.find(event);
|
||||
DCHECK(js_handler != js_handlers_.end());
|
||||
RemoveListener(js_handler);
|
||||
}
|
||||
|
||||
void StreamSubscriber::OnData(mate::Arguments* args) {
|
||||
v8::Local<v8::Value> buf;
|
||||
args->GetNext(&buf);
|
||||
if (!node::Buffer::HasInstance(buf)) {
|
||||
args->ThrowError("data must be Buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
const char* data = node::Buffer::Data(buf);
|
||||
size_t length = node::Buffer::Length(buf);
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
// Pass the data to the URLJob in IO thread.
|
||||
std::vector<char> buffer(data, data + length);
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&electron::URLRequestStreamJob::OnData, url_job_,
|
||||
base::Passed(&buffer)));
|
||||
}
|
||||
|
||||
void StreamSubscriber::OnEnd(mate::Arguments* args) {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&electron::URLRequestStreamJob::OnEnd, url_job_));
|
||||
}
|
||||
|
||||
void StreamSubscriber::OnError(mate::Arguments* args) {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&electron::URLRequestStreamJob::OnError, url_job_,
|
||||
net::ERR_FAILED));
|
||||
}
|
||||
|
||||
void StreamSubscriber::RemoveAllListeners() {
|
||||
DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
v8::Locker locker(isolate_);
|
||||
v8::Isolate::Scope isolate_scope(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
while (!js_handlers_.empty()) {
|
||||
RemoveListener(js_handlers_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void StreamSubscriber::RemoveListener(JSHandlersMap::iterator it) {
|
||||
internal::ValueVector args = {StringToV8(isolate_, it->first),
|
||||
it->second.Get(isolate_)};
|
||||
internal::CallMethodWithArgs(isolate_, emitter_.Get(isolate_),
|
||||
"removeListener", &args);
|
||||
js_handlers_.erase(it);
|
||||
}
|
||||
|
||||
} // namespace mate
|
|
@ -1,68 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_API_STREAM_SUBSCRIBER_H_
|
||||
#define SHELL_BROWSER_API_STREAM_SUBSCRIBER_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/ref_counted_delete_on_sequence.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace electron {
|
||||
class URLRequestStreamJob;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
class Arguments;
|
||||
|
||||
class StreamSubscriber
|
||||
: public base::RefCountedDeleteOnSequence<StreamSubscriber> {
|
||||
public:
|
||||
REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
|
||||
|
||||
StreamSubscriber(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> emitter,
|
||||
base::WeakPtr<electron::URLRequestStreamJob> url_job,
|
||||
scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
|
||||
|
||||
private:
|
||||
friend class base::DeleteHelper<StreamSubscriber>;
|
||||
friend class base::RefCountedDeleteOnSequence<StreamSubscriber>;
|
||||
|
||||
using JSHandlersMap = std::map<std::string, v8::Global<v8::Value>>;
|
||||
using EventCallback = base::RepeatingCallback<void(mate::Arguments* args)>;
|
||||
|
||||
~StreamSubscriber();
|
||||
|
||||
void On(const std::string& event, EventCallback&& callback); // NOLINT
|
||||
void Off(const std::string& event);
|
||||
|
||||
void OnData(mate::Arguments* args);
|
||||
void OnEnd(mate::Arguments* args);
|
||||
void OnError(mate::Arguments* args);
|
||||
|
||||
void RemoveAllListeners();
|
||||
void RemoveListener(JSHandlersMap::iterator it);
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
v8::Global<v8::Object> emitter_;
|
||||
base::WeakPtr<electron::URLRequestStreamJob> url_job_;
|
||||
|
||||
JSHandlersMap js_handlers_;
|
||||
|
||||
base::WeakPtrFactory<StreamSubscriber> weak_factory_;
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // SHELL_BROWSER_API_STREAM_SUBSCRIBER_H_
|
|
@ -50,7 +50,6 @@
|
|||
#include "services/network/public/cpp/resource_request_body.h"
|
||||
#include "shell/app/manifests.h"
|
||||
#include "shell/browser/api/atom_api_app.h"
|
||||
#include "shell/browser/api/atom_api_protocol.h"
|
||||
#include "shell/browser/api/atom_api_protocol_ns.h"
|
||||
#include "shell/browser/api/atom_api_web_contents.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
|
@ -266,34 +265,28 @@ bool AtomBrowserClient::NavigationWasRedirectedCrossSite(
|
|||
void AtomBrowserClient::AddProcessPreferences(
|
||||
int process_id,
|
||||
AtomBrowserClient::ProcessPreferences prefs) {
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
process_preferences_[process_id] = prefs;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::RemoveProcessPreferences(int process_id) {
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
process_preferences_.erase(process_id);
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::IsProcessObserved(int process_id) const {
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
return process_preferences_.find(process_id) != process_preferences_.end();
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::IsRendererSandboxed(int process_id) const {
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
auto it = process_preferences_.find(process_id);
|
||||
return it != process_preferences_.end() && it->second.sandbox;
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::RendererUsesNativeWindowOpen(int process_id) const {
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
auto it = process_preferences_.find(process_id);
|
||||
return it != process_preferences_.end() && it->second.native_window_open;
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::RendererDisablesPopups(int process_id) const {
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
auto it = process_preferences_.find(process_id);
|
||||
return it != process_preferences_.end() && it->second.disable_popups;
|
||||
}
|
||||
|
@ -739,13 +732,8 @@ network::mojom::NetworkContextPtr AtomBrowserClient::CreateNetworkContext(
|
|||
if (!browser_context)
|
||||
return nullptr;
|
||||
|
||||
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
return NetworkContextServiceFactory::GetForContext(browser_context)
|
||||
->CreateNetworkContext();
|
||||
} else {
|
||||
return static_cast<AtomBrowserContext*>(browser_context)
|
||||
->GetNetworkContext();
|
||||
}
|
||||
return NetworkContextServiceFactory::GetForContext(browser_context)
|
||||
->CreateNetworkContext();
|
||||
}
|
||||
|
||||
network::mojom::NetworkContext* AtomBrowserClient::GetSystemNetworkContext() {
|
||||
|
@ -829,7 +817,7 @@ void OnOpenExternal(const GURL& escaped_url, bool allowed) {
|
|||
|
||||
void HandleExternalProtocolInUI(
|
||||
const GURL& url,
|
||||
const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
|
||||
const content::WebContents::Getter& web_contents_getter,
|
||||
bool has_user_gesture) {
|
||||
content::WebContents* web_contents = web_contents_getter.Run();
|
||||
if (!web_contents)
|
||||
|
@ -848,7 +836,7 @@ void HandleExternalProtocolInUI(
|
|||
|
||||
bool AtomBrowserClient::HandleExternalProtocol(
|
||||
const GURL& url,
|
||||
content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
|
||||
content::WebContents::Getter web_contents_getter,
|
||||
int child_id,
|
||||
content::NavigationUIData* navigation_data,
|
||||
bool is_main_frame,
|
||||
|
@ -913,8 +901,7 @@ AtomBrowserClient::GetSystemSharedURLLoaderFactory() {
|
|||
|
||||
void AtomBrowserClient::OnNetworkServiceCreated(
|
||||
network::mojom::NetworkService* network_service) {
|
||||
if (!g_browser_process ||
|
||||
!base::FeatureList::IsEnabled(network::features::kNetworkService))
|
||||
if (!g_browser_process)
|
||||
return;
|
||||
|
||||
g_browser_process->system_network_context_manager()->OnNetworkServiceCreated(
|
||||
|
@ -930,13 +917,6 @@ AtomBrowserClient::GetNetworkContextsParentDirectory() {
|
|||
return {user_data_dir};
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::ShouldBypassCORB(int render_process_id) const {
|
||||
// This is called on the network thread.
|
||||
base::AutoLock auto_lock(process_preferences_lock_);
|
||||
auto it = process_preferences_.find(render_process_id);
|
||||
return it != process_preferences_.end() && !it->second.web_security;
|
||||
}
|
||||
|
||||
std::string AtomBrowserClient::GetProduct() {
|
||||
return "Chrome/" CHROME_VERSION_STRING;
|
||||
}
|
||||
|
@ -967,17 +947,16 @@ void AtomBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
|||
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);
|
||||
if (web_contents) {
|
||||
api::ProtocolNS* protocol = api::ProtocolNS::FromWrappedClass(
|
||||
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
|
||||
if (protocol)
|
||||
protocol->RegisterURLLoaderFactories(factories);
|
||||
}
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::WillCreateURLLoaderFactory(
|
||||
|
@ -992,6 +971,9 @@ bool AtomBrowserClient::WillCreateURLLoaderFactory(
|
|||
bool* bypass_redirect_checks) {
|
||||
content::WebContents* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(frame_host);
|
||||
if (!web_contents) {
|
||||
return false;
|
||||
}
|
||||
api::ProtocolNS* protocol = api::ProtocolNS::FromWrappedClass(
|
||||
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
|
||||
if (!protocol)
|
||||
|
@ -1009,10 +991,38 @@ bool AtomBrowserClient::WillCreateURLLoaderFactory(
|
|||
protocol->intercept_handlers(), std::move(proxied_receiver),
|
||||
std::move(target_factory_info), std::move(header_client_request));
|
||||
|
||||
*bypass_redirect_checks = true;
|
||||
if (bypass_redirect_checks)
|
||||
*bypass_redirect_checks = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
network::mojom::URLLoaderFactoryPtrInfo
|
||||
AtomBrowserClient::CreateURLLoaderFactoryForNetworkRequests(
|
||||
content::RenderProcessHost* process,
|
||||
network::mojom::NetworkContext* network_context,
|
||||
network::mojom::TrustedURLLoaderHeaderClientPtrInfo* header_client,
|
||||
const url::Origin& request_initiator) {
|
||||
auto render_process_id = process->GetID();
|
||||
auto it = process_preferences_.find(render_process_id);
|
||||
if (it != process_preferences_.end() && !it->second.web_security) {
|
||||
// bypass CORB
|
||||
network::mojom::URLLoaderFactoryParamsPtr params =
|
||||
network::mojom::URLLoaderFactoryParams::New();
|
||||
|
||||
if (header_client)
|
||||
params->header_client = std::move(*header_client);
|
||||
params->process_id = render_process_id;
|
||||
params->is_corb_enabled = false;
|
||||
|
||||
// Create the URLLoaderFactory.
|
||||
network::mojom::URLLoaderFactoryPtrInfo factory_info;
|
||||
network_context->CreateURLLoaderFactory(mojo::MakeRequest(&factory_info),
|
||||
std::move(params));
|
||||
return factory_info;
|
||||
}
|
||||
return network::mojom::URLLoaderFactoryPtrInfo();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
bool AtomBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy* policy) {
|
||||
// Allow crashpad to communicate via named pipe.
|
||||
|
|
|
@ -158,7 +158,6 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
|||
void OnNetworkServiceCreated(
|
||||
network::mojom::NetworkService* network_service) override;
|
||||
std::vector<base::FilePath> GetNetworkContextsParentDirectory() override;
|
||||
bool ShouldBypassCORB(int render_process_id) const override;
|
||||
std::string GetProduct() override;
|
||||
void RegisterNonNetworkNavigationURLLoaderFactories(
|
||||
int frame_tree_node_id,
|
||||
|
@ -177,13 +176,19 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
|||
mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
|
||||
network::mojom::TrustedURLLoaderHeaderClientPtrInfo* header_client,
|
||||
bool* bypass_redirect_checks) override;
|
||||
network::mojom::URLLoaderFactoryPtrInfo
|
||||
CreateURLLoaderFactoryForNetworkRequests(
|
||||
content::RenderProcessHost* process,
|
||||
network::mojom::NetworkContext* network_context,
|
||||
network::mojom::TrustedURLLoaderHeaderClientPtrInfo* header_client,
|
||||
const url::Origin& request_initiator) override;
|
||||
#if defined(OS_WIN)
|
||||
bool PreSpawnRenderer(sandbox::TargetPolicy* policy) override;
|
||||
#endif
|
||||
|
||||
bool HandleExternalProtocol(
|
||||
const GURL& url,
|
||||
content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
|
||||
content::WebContents::Getter web_contents_getter,
|
||||
int child_id,
|
||||
content::NavigationUIData* navigation_data,
|
||||
bool is_main_frame,
|
||||
|
@ -248,7 +253,6 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
|||
|
||||
Delegate* delegate_ = nullptr;
|
||||
|
||||
mutable base::Lock process_preferences_lock_;
|
||||
std::map<int, ProcessPreferences> process_preferences_;
|
||||
|
||||
std::string user_agent_override_ = "";
|
||||
|
|
|
@ -113,12 +113,6 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition,
|
|||
// Initialize Pref Registry.
|
||||
InitPrefs();
|
||||
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
proxy_config_monitor_ = std::make_unique<ProxyConfigMonitor>(prefs_.get());
|
||||
io_handle_ =
|
||||
new URLRequestContextGetter::Handle(weak_factory_.GetWeakPtr());
|
||||
}
|
||||
|
||||
cookie_change_notifier_ = std::make_unique<CookieChangeNotifier>(this);
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
|
@ -137,12 +131,8 @@ AtomBrowserContext::~AtomBrowserContext() {
|
|||
NotifyWillBeDestroyed(this);
|
||||
ShutdownStoragePartitions();
|
||||
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
io_handle_->ShutdownOnUIThread();
|
||||
} else {
|
||||
BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
|
||||
std::move(resource_context_));
|
||||
}
|
||||
BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
|
||||
std::move(resource_context_));
|
||||
|
||||
// Notify any keyed services of browser context destruction.
|
||||
BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(
|
||||
|
@ -197,47 +187,6 @@ void AtomBrowserContext::SetUserAgent(const std::string& user_agent) {
|
|||
user_agent_ = user_agent;
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* AtomBrowserContext::CreateRequestContext(
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::URLRequestInterceptorScopedVector protocol_interceptors) {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
return io_handle_
|
||||
->CreateMainRequestContextGetter(protocol_handlers,
|
||||
std::move(protocol_interceptors))
|
||||
.get();
|
||||
} else {
|
||||
NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* AtomBrowserContext::CreateMediaRequestContext() {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
return io_handle_->GetMainRequestContextGetter().get();
|
||||
} else {
|
||||
NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* AtomBrowserContext::GetRequestContext() {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
return GetDefaultStoragePartition(this)->GetURLRequestContext();
|
||||
} else {
|
||||
NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
network::mojom::NetworkContextPtr AtomBrowserContext::GetNetworkContext() {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
return io_handle_->GetNetworkContext();
|
||||
} else {
|
||||
NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
base::FilePath AtomBrowserContext::GetPath() {
|
||||
return path_;
|
||||
}
|
||||
|
@ -255,13 +204,9 @@ int AtomBrowserContext::GetMaxCacheSize() const {
|
|||
}
|
||||
|
||||
content::ResourceContext* AtomBrowserContext::GetResourceContext() {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
return io_handle_->GetResourceContext();
|
||||
} else {
|
||||
if (!resource_context_)
|
||||
resource_context_.reset(new content::ResourceContext);
|
||||
return resource_context_.get();
|
||||
}
|
||||
if (!resource_context_)
|
||||
resource_context_.reset(new content::ResourceContext);
|
||||
return resource_context_.get();
|
||||
}
|
||||
|
||||
std::string AtomBrowserContext::GetMediaDeviceIDSalt() {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "content/public/browser/resource_context.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "shell/browser/media/media_device_id_salt.h"
|
||||
#include "shell/browser/net/url_request_context_getter.h"
|
||||
|
||||
class PrefRegistrySimple;
|
||||
class PrefService;
|
||||
|
@ -86,9 +85,6 @@ class AtomBrowserContext
|
|||
bool CanUseHttpCache() const;
|
||||
int GetMaxCacheSize() const;
|
||||
AtomBlobReader* GetBlobReader();
|
||||
network::mojom::NetworkContextPtr GetNetworkContext();
|
||||
// Get the request context, if there is none, create it.
|
||||
net::URLRequestContextGetter* GetRequestContext();
|
||||
ResolveProxyHelper* GetResolveProxyHelper();
|
||||
|
||||
// content::BrowserContext:
|
||||
|
@ -109,10 +105,6 @@ class AtomBrowserContext
|
|||
content::PermissionControllerDelegate* GetPermissionControllerDelegate()
|
||||
override;
|
||||
storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
|
||||
net::URLRequestContextGetter* CreateRequestContext(
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::URLRequestInterceptorScopedVector request_interceptors) override;
|
||||
net::URLRequestContextGetter* CreateMediaRequestContext() override;
|
||||
content::ClientHintsControllerDelegate* GetClientHintsControllerDelegate()
|
||||
override;
|
||||
|
||||
|
@ -155,9 +147,6 @@ class AtomBrowserContext
|
|||
|
||||
static BrowserContextMap browser_context_map_;
|
||||
|
||||
// Self-destructing class responsible for creating URLRequestContextGetter
|
||||
// on the UI thread and deletes itself on the IO thread.
|
||||
URLRequestContextGetter::Handle* io_handle_;
|
||||
ValueMapPrefStore* in_memory_pref_store_;
|
||||
|
||||
std::unique_ptr<content::ResourceContext> resource_context_;
|
||||
|
|
|
@ -249,11 +249,6 @@ BrowserProcessImpl::component_updater() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
component_updater::SupervisedUserWhitelistInstaller*
|
||||
BrowserProcessImpl::supervised_user_whitelist_installer() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MediaFileSystemRegistry* BrowserProcessImpl::media_file_system_registry() {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -84,8 +84,6 @@ class BrowserProcessImpl : public BrowserProcess {
|
|||
optimization_guide::OptimizationGuideService* optimization_guide_service()
|
||||
override;
|
||||
component_updater::ComponentUpdateService* component_updater() override;
|
||||
component_updater::SupervisedUserWhitelistInstaller*
|
||||
supervised_user_whitelist_installer() override;
|
||||
MediaFileSystemRegistry* media_file_system_registry() override;
|
||||
WebRtcLogUploader* webrtc_log_uploader() override;
|
||||
network_time::NetworkTimeTracker* network_time_tracker() override;
|
||||
|
|
|
@ -21,37 +21,9 @@
|
|||
#include "services/network/public/cpp/features.h"
|
||||
#include "services/network/public/cpp/network_switches.h"
|
||||
#include "services/network/public/mojom/net_log.mojom.h"
|
||||
#include "services/network/url_request_context_builder_mojo.h"
|
||||
#include "shell/browser/net/url_request_context_getter.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace {
|
||||
|
||||
// Parses the desired granularity of NetLog capturing specified by the command
|
||||
// line.
|
||||
net::NetLogCaptureMode GetNetCaptureModeFromCommandLine(
|
||||
const base::CommandLine& command_line) {
|
||||
base::StringPiece switch_name = network::switches::kNetLogCaptureMode;
|
||||
|
||||
if (command_line.HasSwitch(switch_name)) {
|
||||
std::string value = command_line.GetSwitchValueASCII(switch_name);
|
||||
|
||||
if (value == "Default")
|
||||
return net::NetLogCaptureMode::kDefault;
|
||||
if (value == "IncludeCookiesAndCredentials")
|
||||
return net::NetLogCaptureMode::kIncludeSensitive;
|
||||
if (value == "IncludeSocketBytes")
|
||||
return net::NetLogCaptureMode::kEverything;
|
||||
|
||||
LOG(ERROR) << "Unrecognized value for --" << switch_name;
|
||||
}
|
||||
|
||||
return net::NetLogCaptureMode::kDefault;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IOThread::IOThread(
|
||||
SystemNetworkContextManager* system_network_context_manager) {
|
||||
BrowserThread::SetIOThreadDelegate(this);
|
||||
|
@ -65,80 +37,6 @@ IOThread::~IOThread() {
|
|||
BrowserThread::SetIOThreadDelegate(nullptr);
|
||||
}
|
||||
|
||||
void IOThread::RegisterURLRequestContextGetter(
|
||||
electron::URLRequestContextGetter* getter) {
|
||||
base::AutoLock lock(lock_);
|
||||
void IOThread::Init() {}
|
||||
|
||||
DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
|
||||
DCHECK_EQ(0u, request_context_getters_.count(getter));
|
||||
request_context_getters_.insert(getter);
|
||||
}
|
||||
|
||||
void IOThread::DeregisterURLRequestContextGetter(
|
||||
electron::URLRequestContextGetter* getter) {
|
||||
base::AutoLock lock(lock_);
|
||||
|
||||
DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
|
||||
DCHECK_EQ(1u, request_context_getters_.count(getter));
|
||||
request_context_getters_.erase(getter);
|
||||
}
|
||||
|
||||
void IOThread::Init() {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
std::unique_ptr<network::URLRequestContextBuilderMojo> builder =
|
||||
std::make_unique<network::URLRequestContextBuilderMojo>();
|
||||
|
||||
// Enable file:// support.
|
||||
builder->set_file_enabled(true);
|
||||
|
||||
auto cert_verifier = std::make_unique<net::CachingCertVerifier>(
|
||||
std::make_unique<net::MultiThreadedCertVerifier>(
|
||||
net::CertVerifyProc::CreateDefault(nullptr)));
|
||||
builder->SetCertVerifier(std::move(cert_verifier));
|
||||
|
||||
// Create the network service, so that shared host resolver
|
||||
// gets created which is required to set the auth preferences below.
|
||||
network::NetworkService* network_service = content::GetNetworkServiceImpl();
|
||||
network_service->SetUpHttpAuth(std::move(http_auth_static_params_));
|
||||
network_service->ConfigureHttpAuthPrefs(
|
||||
std::move(http_auth_dynamic_params_));
|
||||
|
||||
const base::CommandLine* command_line =
|
||||
base::CommandLine::ForCurrentProcess();
|
||||
// start net log trace if --log-net-log is passed in the command line.
|
||||
if (command_line->HasSwitch(network::switches::kLogNetLog)) {
|
||||
base::FilePath log_file =
|
||||
command_line->GetSwitchValuePath(network::switches::kLogNetLog);
|
||||
base::File file(log_file,
|
||||
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
|
||||
if (log_file.empty() || !file.IsValid()) {
|
||||
LOG(ERROR) << "Failed opening NetLog: " << log_file.value();
|
||||
} else {
|
||||
auto platform_dict = net_log::GetPlatformConstantsForNetLog(
|
||||
base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
|
||||
std::string(ELECTRON_PRODUCT_NAME));
|
||||
network_service->StartNetLog(
|
||||
std::move(file), GetNetCaptureModeFromCommandLine(*command_line),
|
||||
platform_dict ? std::move(*platform_dict)
|
||||
: base::DictionaryValue());
|
||||
}
|
||||
}
|
||||
|
||||
system_network_context_ = network_service->CreateNetworkContextWithBuilder(
|
||||
std::move(network_context_request_), std::move(network_context_params_),
|
||||
std::move(builder), &system_request_context_);
|
||||
}
|
||||
}
|
||||
|
||||
void IOThread::CleanUp() {
|
||||
if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
|
||||
system_request_context_->proxy_resolution_service()->OnShutdown();
|
||||
|
||||
base::AutoLock lock(lock_);
|
||||
for (auto* getter : request_context_getters_) {
|
||||
getter->NotifyContextShuttingDown();
|
||||
}
|
||||
|
||||
system_network_context_.reset();
|
||||
}
|
||||
}
|
||||
void IOThread::CleanUp() {}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/loader/layered_resource_handler.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace electron {
|
||||
|
||||
LayeredResourceHandler::LayeredResourceHandler(
|
||||
net::URLRequest* request,
|
||||
std::unique_ptr<content::ResourceHandler> next_handler,
|
||||
Delegate* delegate)
|
||||
: content::LayeredResourceHandler(request, std::move(next_handler)),
|
||||
delegate_(delegate) {}
|
||||
|
||||
LayeredResourceHandler::~LayeredResourceHandler() {}
|
||||
|
||||
void LayeredResourceHandler::OnResponseStarted(
|
||||
network::ResourceResponse* response,
|
||||
std::unique_ptr<content::ResourceController> controller) {
|
||||
if (delegate_)
|
||||
delegate_->OnResponseStarted(response);
|
||||
next_handler_->OnResponseStarted(response, std::move(controller));
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
|
||||
#define SHELL_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "content/browser/loader/layered_resource_handler.h" // nogncheck
|
||||
#include "services/network/public/cpp/resource_response.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Resource handler that notifies on various stages of a resource request.
|
||||
class LayeredResourceHandler : public content::LayeredResourceHandler {
|
||||
public:
|
||||
class Delegate {
|
||||
public:
|
||||
Delegate() {}
|
||||
virtual ~Delegate() {}
|
||||
|
||||
virtual void OnResponseStarted(network::ResourceResponse* response) = 0;
|
||||
};
|
||||
|
||||
LayeredResourceHandler(net::URLRequest* request,
|
||||
std::unique_ptr<content::ResourceHandler> next_handler,
|
||||
Delegate* delegate);
|
||||
~LayeredResourceHandler() override;
|
||||
|
||||
// content::LayeredResourceHandler:
|
||||
void OnResponseStarted(
|
||||
network::ResourceResponse* response,
|
||||
std::unique_ptr<content::ResourceController> controller) override;
|
||||
|
||||
private:
|
||||
Delegate* delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LayeredResourceHandler);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_LOADER_LAYERED_RESOURCE_HANDLER_H_
|
|
@ -62,7 +62,7 @@ class LoginHandler : public base::RefCountedThreadSafe<LoginHandler> {
|
|||
std::unique_ptr<const net::AuthChallengeInfo> auth_info_;
|
||||
|
||||
// WebContents associated with the login request.
|
||||
content::ResourceRequestInfo::WebContentsGetter web_contents_getter_;
|
||||
content::WebContents::Getter web_contents_getter_;
|
||||
|
||||
// Called with preferred value of net::NetworkDelegate::AuthRequiredResponse.
|
||||
net::NetworkDelegate::AuthCallback auth_callback_;
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/about_protocol_handler.h"
|
||||
|
||||
#include "shell/browser/net/url_request_about_job.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
AboutProtocolHandler::AboutProtocolHandler() {}
|
||||
|
||||
AboutProtocolHandler::~AboutProtocolHandler() {}
|
||||
|
||||
net::URLRequestJob* AboutProtocolHandler::MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const {
|
||||
return new URLRequestAboutJob(request, network_delegate);
|
||||
}
|
||||
|
||||
bool AboutProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_ABOUT_PROTOCOL_HANDLER_H_
|
||||
#define SHELL_BROWSER_NET_ABOUT_PROTOCOL_HANDLER_H_
|
||||
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class AboutProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
|
||||
public:
|
||||
AboutProtocolHandler();
|
||||
~AboutProtocolHandler() override;
|
||||
|
||||
// net::URLRequestJobFactory::ProtocolHandler:
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override;
|
||||
bool IsSafeRedirectTarget(const GURL& location) const override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AboutProtocolHandler);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_ABOUT_PROTOCOL_HANDLER_H_
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/asar/asar_protocol_handler.h"
|
||||
|
||||
#include "base/task_runner.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "shell/browser/net/asar/url_request_asar_job.h"
|
||||
|
||||
namespace asar {
|
||||
|
||||
AsarProtocolHandler::AsarProtocolHandler(
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner)
|
||||
: file_task_runner_(file_task_runner) {}
|
||||
|
||||
AsarProtocolHandler::~AsarProtocolHandler() {}
|
||||
|
||||
net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const {
|
||||
base::FilePath full_path;
|
||||
net::FileURLToFilePath(request->url(), &full_path);
|
||||
auto* job = new URLRequestAsarJob(request, network_delegate);
|
||||
job->Initialize(file_task_runner_, full_path);
|
||||
return job;
|
||||
}
|
||||
|
||||
bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace asar
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_
|
||||
#define SHELL_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
namespace base {
|
||||
class TaskRunner;
|
||||
}
|
||||
|
||||
namespace asar {
|
||||
|
||||
class AsarProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
|
||||
public:
|
||||
explicit AsarProtocolHandler(
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner);
|
||||
~AsarProtocolHandler() override;
|
||||
|
||||
// net::URLRequestJobFactory::ProtocolHandler:
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override;
|
||||
bool IsSafeRedirectTarget(const GURL& location) const override;
|
||||
|
||||
private:
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AsarProtocolHandler);
|
||||
};
|
||||
|
||||
} // namespace asar
|
||||
|
||||
#endif // SHELL_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_
|
|
@ -27,6 +27,23 @@ namespace asar {
|
|||
|
||||
namespace {
|
||||
|
||||
net::Error ConvertMojoResultToNetError(MojoResult result) {
|
||||
switch (result) {
|
||||
case MOJO_RESULT_OK:
|
||||
return net::OK;
|
||||
case MOJO_RESULT_NOT_FOUND:
|
||||
return net::ERR_FILE_NOT_FOUND;
|
||||
case MOJO_RESULT_PERMISSION_DENIED:
|
||||
return net::ERR_ACCESS_DENIED;
|
||||
case MOJO_RESULT_RESOURCE_EXHAUSTED:
|
||||
return net::ERR_INSUFFICIENT_RESOURCES;
|
||||
case MOJO_RESULT_ABORTED:
|
||||
return net::ERR_ABORTED;
|
||||
default:
|
||||
return net::ERR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t kDefaultFileUrlPipeSize = 65536;
|
||||
|
||||
// Because this makes things simpler.
|
||||
|
@ -55,7 +72,6 @@ class AsarURLLoader : public network::mojom::URLLoader {
|
|||
void FollowRedirect(const std::vector<std::string>& removed_headers,
|
||||
const net::HttpRequestHeaders& modified_headers,
|
||||
const base::Optional<GURL>& new_url) override {}
|
||||
void ProceedWithResponse() override {}
|
||||
void SetPriority(net::RequestPriority priority,
|
||||
int32_t intra_priority_value) override {}
|
||||
void PauseReadingBodyFromNet() override {}
|
||||
|
@ -121,24 +137,17 @@ class AsarURLLoader : public network::mojom::URLLoader {
|
|||
// requests at the same time.
|
||||
base::File file(info.unpacked ? real_path : archive->path(),
|
||||
base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||
// Move cursor to sub-file.
|
||||
file.Seek(base::File::FROM_BEGIN, info.offset);
|
||||
auto file_data_source =
|
||||
std::make_unique<mojo::FileDataSource>(std::move(file));
|
||||
mojo::DataPipeProducer::DataSource* data_source = file_data_source.get();
|
||||
|
||||
// File reading logics are copied from FileURLLoader.
|
||||
if (!file.IsValid()) {
|
||||
OnClientComplete(net::FileErrorToNetError(file.error_details()));
|
||||
std::vector<char> initial_read_buffer(net::kMaxBytesToSniff);
|
||||
auto read_result =
|
||||
data_source->Read(info.offset, base::span<char>(initial_read_buffer));
|
||||
if (read_result.result != MOJO_RESULT_OK) {
|
||||
OnClientComplete(ConvertMojoResultToNetError(read_result.result));
|
||||
return;
|
||||
}
|
||||
char initial_read_buffer[net::kMaxBytesToSniff];
|
||||
int initial_read_result =
|
||||
file.ReadAtCurrentPos(initial_read_buffer, net::kMaxBytesToSniff);
|
||||
if (initial_read_result < 0) {
|
||||
base::File::Error read_error = base::File::GetLastFileError();
|
||||
DCHECK_NE(base::File::FILE_OK, read_error);
|
||||
OnClientComplete(net::FileErrorToNetError(read_error));
|
||||
return;
|
||||
}
|
||||
size_t initial_read_size = static_cast<size_t>(initial_read_result);
|
||||
|
||||
std::string range_header;
|
||||
net::HttpByteRange byte_range;
|
||||
|
@ -162,27 +171,25 @@ class AsarURLLoader : public network::mojom::URLLoader {
|
|||
}
|
||||
}
|
||||
|
||||
size_t first_byte_to_send = 0;
|
||||
size_t total_bytes_to_send = static_cast<size_t>(info.size);
|
||||
uint64_t first_byte_to_send = 0;
|
||||
uint64_t total_bytes_to_send = info.size;
|
||||
|
||||
if (byte_range.IsValid()) {
|
||||
first_byte_to_send =
|
||||
static_cast<size_t>(byte_range.first_byte_position());
|
||||
first_byte_to_send = byte_range.first_byte_position();
|
||||
total_bytes_to_send =
|
||||
static_cast<size_t>(byte_range.last_byte_position()) -
|
||||
first_byte_to_send + 1;
|
||||
byte_range.last_byte_position() - first_byte_to_send + 1;
|
||||
}
|
||||
|
||||
total_bytes_written_ = static_cast<size_t>(total_bytes_to_send);
|
||||
total_bytes_written_ = total_bytes_to_send;
|
||||
|
||||
head.content_length = base::saturated_cast<int64_t>(total_bytes_to_send);
|
||||
|
||||
if (first_byte_to_send < initial_read_size) {
|
||||
if (first_byte_to_send < read_result.bytes_read) {
|
||||
// Write any data we read for MIME sniffing, constraining by range where
|
||||
// applicable. This will always fit in the pipe (see assertion near
|
||||
// |kDefaultFileUrlPipeSize| definition).
|
||||
uint32_t write_size = std::min(
|
||||
static_cast<uint32_t>(initial_read_size - first_byte_to_send),
|
||||
static_cast<uint32_t>(read_result.bytes_read - first_byte_to_send),
|
||||
static_cast<uint32_t>(total_bytes_to_send));
|
||||
const uint32_t expected_write_size = write_size;
|
||||
MojoResult result = pipe.producer_handle->WriteData(
|
||||
|
@ -194,14 +201,14 @@ class AsarURLLoader : public network::mojom::URLLoader {
|
|||
}
|
||||
|
||||
// Discount the bytes we just sent from the total range.
|
||||
first_byte_to_send = initial_read_size;
|
||||
first_byte_to_send = read_result.bytes_read;
|
||||
total_bytes_to_send -= write_size;
|
||||
}
|
||||
|
||||
if (!net::GetMimeTypeFromFile(path, &head.mime_type)) {
|
||||
std::string new_type;
|
||||
net::SniffMimeType(initial_read_buffer, initial_read_result, request.url,
|
||||
head.mime_type,
|
||||
net::SniffMimeType(initial_read_buffer.data(), read_result.bytes_read,
|
||||
request.url, head.mime_type,
|
||||
net::ForceSniffFileUrlsForHtml::kDisabled, &new_type);
|
||||
head.mime_type.assign(new_type);
|
||||
head.did_mime_sniff = true;
|
||||
|
@ -225,14 +232,14 @@ class AsarURLLoader : public network::mojom::URLLoader {
|
|||
// (i.e., no range request) this Seek is effectively a no-op.
|
||||
//
|
||||
// Note that in Electron we also need to add file offset.
|
||||
file.Seek(base::File::FROM_BEGIN,
|
||||
static_cast<int64_t>(first_byte_to_send) + info.offset);
|
||||
file_data_source->SetRange(
|
||||
first_byte_to_send + info.offset,
|
||||
first_byte_to_send + info.offset + total_bytes_to_send);
|
||||
|
||||
data_producer_ = std::make_unique<mojo::DataPipeProducer>(
|
||||
std::move(pipe.producer_handle));
|
||||
data_producer_->Write(
|
||||
std::make_unique<mojo::FileDataSource>(std::move(file),
|
||||
total_bytes_to_send),
|
||||
std::move(file_data_source),
|
||||
base::BindOnce(&AsarURLLoader::OnFileWritten, base::Unretained(this)));
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ bool ResponseMustBeObject(ProtocolType type) {
|
|||
|
||||
// Helper to convert value to Dictionary.
|
||||
mate::Dictionary ToDict(v8::Isolate* isolate, v8::Local<v8::Value> value) {
|
||||
if (value->IsObject())
|
||||
if (!value->IsFunction() && value->IsObject())
|
||||
return mate::Dictionary(
|
||||
isolate,
|
||||
value->ToObject(isolate->GetCurrentContext()).ToLocalChecked());
|
||||
|
@ -322,10 +322,14 @@ void AtomURLLoaderFactory::StartLoadingString(
|
|||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> response) {
|
||||
std::string contents;
|
||||
if (response->IsString())
|
||||
if (response->IsString()) {
|
||||
contents = gin::V8ToString(isolate, response);
|
||||
else if (!dict.IsEmpty())
|
||||
} else if (!dict.IsEmpty()) {
|
||||
dict.Get("data", &contents);
|
||||
} else {
|
||||
client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
|
||||
return;
|
||||
}
|
||||
|
||||
SendContents(std::move(client), std::move(head), std::move(contents));
|
||||
}
|
||||
|
|
|
@ -1,522 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/atom_url_request.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/elements_upload_data_stream.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/upload_bytes_element_reader.h"
|
||||
#include "net/url_request/redirect_info.h"
|
||||
#include "shell/browser/api/atom_api_url_request.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/net/atom_url_request_job_factory.h"
|
||||
|
||||
namespace {
|
||||
const int kBufferSize = 4096;
|
||||
} // namespace
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace internal {
|
||||
|
||||
class UploadOwnedIOBufferElementReader : public net::UploadBytesElementReader {
|
||||
public:
|
||||
explicit UploadOwnedIOBufferElementReader(
|
||||
scoped_refptr<const net::IOBufferWithSize> buffer)
|
||||
: net::UploadBytesElementReader(buffer->data(), buffer->size()),
|
||||
buffer_(buffer) {}
|
||||
|
||||
~UploadOwnedIOBufferElementReader() override {}
|
||||
|
||||
static UploadOwnedIOBufferElementReader* CreateWithBuffer(
|
||||
scoped_refptr<const net::IOBufferWithSize> buffer) {
|
||||
return new UploadOwnedIOBufferElementReader(std::move(buffer));
|
||||
}
|
||||
|
||||
private:
|
||||
scoped_refptr<const net::IOBuffer> buffer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UploadOwnedIOBufferElementReader);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
AtomURLRequest::AtomURLRequest(api::URLRequest* delegate)
|
||||
: delegate_(delegate),
|
||||
response_read_buffer_(new net::IOBuffer(kBufferSize)) {}
|
||||
|
||||
AtomURLRequest::~AtomURLRequest() {
|
||||
DCHECK(!request_context_getter_);
|
||||
DCHECK(!request_);
|
||||
}
|
||||
|
||||
scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
|
||||
AtomBrowserContext* browser_context,
|
||||
const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy,
|
||||
api::URLRequest* delegate) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
DCHECK(browser_context);
|
||||
DCHECK(!url.empty());
|
||||
DCHECK(delegate);
|
||||
if (!browser_context || url.empty() || !delegate) {
|
||||
return nullptr;
|
||||
}
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter(
|
||||
browser_context->GetRequestContext());
|
||||
DCHECK(request_context_getter);
|
||||
scoped_refptr<AtomURLRequest> atom_url_request(new AtomURLRequest(delegate));
|
||||
if (base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoInitialize, atom_url_request,
|
||||
request_context_getter, method, url,
|
||||
redirect_policy))) {
|
||||
return atom_url_request;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AtomURLRequest::Terminate() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
delegate_ = nullptr;
|
||||
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoTerminate, this));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoInitialize(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
DCHECK(request_context_getter);
|
||||
|
||||
redirect_policy_ = redirect_policy;
|
||||
request_context_getter_ = request_context_getter;
|
||||
request_context_getter_->AddObserver(this);
|
||||
auto* context = request_context_getter_->GetURLRequestContext();
|
||||
if (!context) {
|
||||
// Called after shutdown.
|
||||
DoCancelWithError("Cannot start a request after shutdown.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(context);
|
||||
request_ =
|
||||
context->CreateRequest(GURL(url), net::RequestPriority::DEFAULT_PRIORITY,
|
||||
this, MISSING_TRAFFIC_ANNOTATION);
|
||||
if (!request_) {
|
||||
DoCancelWithError("Failed to create a net::URLRequest.", true);
|
||||
return;
|
||||
}
|
||||
request_->set_method(method);
|
||||
// Do not send cookies from the cookie store.
|
||||
DoSetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES);
|
||||
// Set a flag to stop custom protocol from intercepting this request.
|
||||
request_->SetUserData(DisableProtocolInterceptFlagKey(),
|
||||
base::WrapUnique(new base::SupportsUserData::Data()));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoTerminate() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
request_.reset();
|
||||
if (request_context_getter_) {
|
||||
request_context_getter_->RemoveObserver(this);
|
||||
request_context_getter_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool AtomURLRequest::Write(scoped_refptr<const net::IOBufferWithSize> buffer,
|
||||
bool is_last) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
return base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoWriteBuffer, this, buffer, is_last));
|
||||
}
|
||||
|
||||
void AtomURLRequest::SetChunkedUpload(bool is_chunked_upload) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
// The method can be called only before switching to multi-threaded mode,
|
||||
// i.e. before the first call to write.
|
||||
// So it is safe to change the object in the UI thread.
|
||||
is_chunked_upload_ = is_chunked_upload;
|
||||
}
|
||||
|
||||
void AtomURLRequest::Cancel() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoCancel, this));
|
||||
}
|
||||
|
||||
void AtomURLRequest::FollowRedirect() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoFollowRedirect, this));
|
||||
}
|
||||
|
||||
void AtomURLRequest::SetExtraHeader(const std::string& name,
|
||||
const std::string& value) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoSetExtraHeader, this, name, value));
|
||||
}
|
||||
|
||||
void AtomURLRequest::RemoveExtraHeader(const std::string& name) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoRemoveExtraHeader, this, name));
|
||||
}
|
||||
|
||||
void AtomURLRequest::PassLoginInformation(
|
||||
const base::string16& username,
|
||||
const base::string16& password) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
if (username.empty() || password.empty()) {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoCancelAuth, this));
|
||||
} else {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoSetAuth, this, username, password));
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::SetLoadFlags(int flags) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&AtomURLRequest::DoSetLoadFlags, this, flags));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoWriteBuffer(
|
||||
scoped_refptr<const net::IOBufferWithSize> buffer,
|
||||
bool is_last) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_chunked_upload_) {
|
||||
// Chunked encoding case.
|
||||
|
||||
bool first_call = false;
|
||||
if (!chunked_stream_writer_) {
|
||||
std::unique_ptr<net::ChunkedUploadDataStream> chunked_stream(
|
||||
new net::ChunkedUploadDataStream(0));
|
||||
chunked_stream_writer_ = chunked_stream->CreateWriter();
|
||||
request_->set_upload(std::move(chunked_stream));
|
||||
first_call = true;
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
// Non-empty buffer.
|
||||
chunked_stream_writer_->AppendData(buffer->data(), buffer->size(),
|
||||
is_last);
|
||||
else if (is_last)
|
||||
// Empty buffer and last chunk, i.e. request.end().
|
||||
chunked_stream_writer_->AppendData(nullptr, 0, true);
|
||||
|
||||
if (first_call) {
|
||||
request_->Start();
|
||||
}
|
||||
} else {
|
||||
if (buffer) {
|
||||
// Handling potential empty buffers.
|
||||
using internal::UploadOwnedIOBufferElementReader;
|
||||
auto* element_reader =
|
||||
UploadOwnedIOBufferElementReader::CreateWithBuffer(std::move(buffer));
|
||||
upload_element_readers_.push_back(
|
||||
std::unique_ptr<net::UploadElementReader>(element_reader));
|
||||
}
|
||||
|
||||
if (is_last) {
|
||||
auto* elements_upload_data_stream = new net::ElementsUploadDataStream(
|
||||
std::move(upload_element_readers_), 0);
|
||||
request_->set_upload(
|
||||
std::unique_ptr<net::UploadDataStream>(elements_upload_data_stream));
|
||||
request_->Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoCancel() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (request_) {
|
||||
request_->Cancel();
|
||||
}
|
||||
DoTerminate();
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoFollowRedirect() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (request_ && request_->is_redirecting() && redirect_policy_ == "manual") {
|
||||
request_->FollowDeferredRedirect(base::nullopt /* removed_headers */,
|
||||
base::nullopt /* modified_headers */);
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoSetExtraHeader(const std::string& name,
|
||||
const std::string& value) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
request_->SetExtraRequestHeaderByName(name, value, true);
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoRemoveExtraHeader(const std::string& name) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
request_->RemoveRequestHeaderByName(name);
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoSetAuth(const base::string16& username,
|
||||
const base::string16& password) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
request_->SetAuth(net::AuthCredentials(username, password));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoCancelAuth() const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
request_->CancelAuth();
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoCancelWithError(const std::string& error,
|
||||
bool isRequestError) {
|
||||
DoCancel();
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&AtomURLRequest::InformDelegateErrorOccured, this, error,
|
||||
isRequestError));
|
||||
}
|
||||
|
||||
void AtomURLRequest::DoSetLoadFlags(int flags) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
request_->SetLoadFlags(request_->load_flags() | flags);
|
||||
}
|
||||
|
||||
void AtomURLRequest::OnReceivedRedirect(net::URLRequest* request,
|
||||
const net::RedirectInfo& info,
|
||||
bool* defer_redirect) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_ || redirect_policy_ == "follow")
|
||||
return;
|
||||
|
||||
if (redirect_policy_ == "error") {
|
||||
request->Cancel();
|
||||
DoCancelWithError(
|
||||
"Request cannot follow redirect with the current redirect mode", true);
|
||||
} else if (redirect_policy_ == "manual") {
|
||||
*defer_redirect = true;
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers =
|
||||
request->response_headers();
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&AtomURLRequest::InformDelegateReceivedRedirect, this,
|
||||
info.status_code, info.new_method, info.new_url,
|
||||
response_headers));
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::OnAuthRequired(net::URLRequest* request,
|
||||
const net::AuthChallengeInfo& auth_info) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&AtomURLRequest::InformDelegateAuthenticationRequired,
|
||||
this, auth_info));
|
||||
}
|
||||
|
||||
void AtomURLRequest::OnResponseStarted(net::URLRequest* request,
|
||||
int net_error) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
DCHECK_EQ(request, request_.get());
|
||||
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers =
|
||||
request->response_headers();
|
||||
const auto& status = request_->status();
|
||||
if (status.is_success()) {
|
||||
// Success or pending trigger a Read.
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&AtomURLRequest::InformDelegateResponseStarted, this,
|
||||
response_headers));
|
||||
ReadResponse();
|
||||
} else if (status.status() == net::URLRequestStatus::Status::FAILED) {
|
||||
// Report error on Start.
|
||||
DoCancelWithError(net::ErrorToString(net_error), true);
|
||||
}
|
||||
// We don't report an error is the request is canceled.
|
||||
}
|
||||
|
||||
void AtomURLRequest::ReadResponse() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
int bytes_read = -1;
|
||||
if (request_->Read(response_read_buffer_.get(), kBufferSize, &bytes_read)) {
|
||||
OnReadCompleted(request_.get(), bytes_read);
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::OnReadCompleted(net::URLRequest* request, int bytes_read) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (!request_) {
|
||||
return;
|
||||
}
|
||||
DCHECK_EQ(request, request_.get());
|
||||
|
||||
const auto status = request_->status();
|
||||
if (status.error() == bytes_read &&
|
||||
bytes_read == net::ERR_CONTENT_DECODING_INIT_FAILED) {
|
||||
// When the request job is unable to create a source stream for the
|
||||
// content encoding, we fail the request.
|
||||
DoCancelWithError(net::ErrorToString(net::ERR_CONTENT_DECODING_INIT_FAILED),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
|
||||
bool response_error = false;
|
||||
bool data_ended = false;
|
||||
bool data_transfer_error = false;
|
||||
do {
|
||||
if (!status.is_success()) {
|
||||
response_error = true;
|
||||
break;
|
||||
}
|
||||
if (bytes_read == 0) {
|
||||
data_ended = true;
|
||||
break;
|
||||
}
|
||||
if (bytes_read < 0 || !CopyAndPostBuffer(bytes_read)) {
|
||||
data_transfer_error = true;
|
||||
break;
|
||||
}
|
||||
} while (
|
||||
request_->Read(response_read_buffer_.get(), kBufferSize, &bytes_read));
|
||||
if (response_error) {
|
||||
DoCancelWithError(net::ErrorToString(status.ToNetError()), false);
|
||||
} else if (data_ended) {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&AtomURLRequest::InformDelegateResponseCompleted, this));
|
||||
DoTerminate();
|
||||
} else if (data_transfer_error) {
|
||||
// We abort the request on corrupted data transfer.
|
||||
DoCancelWithError("Failed to transfer data from IO to UI thread.", false);
|
||||
}
|
||||
}
|
||||
|
||||
void AtomURLRequest::OnContextShuttingDown() {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
DoCancel();
|
||||
}
|
||||
|
||||
bool AtomURLRequest::CopyAndPostBuffer(int bytes_read) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
// data is only a wrapper for the asynchronous response_read_buffer_.
|
||||
// Make a deep copy of payload and transfer ownership to the UI thread.
|
||||
auto buffer_copy = WrapRefCounted(new net::IOBufferWithSize(bytes_read));
|
||||
memcpy(buffer_copy->data(), response_read_buffer_->data(), bytes_read);
|
||||
|
||||
return base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(&AtomURLRequest::InformDelegateResponseData, this,
|
||||
buffer_copy));
|
||||
}
|
||||
|
||||
void AtomURLRequest::InformDelegateReceivedRedirect(
|
||||
int status_code,
|
||||
const std::string& method,
|
||||
const GURL& url,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
if (delegate_)
|
||||
delegate_->OnReceivedRedirect(status_code, method, url, response_headers);
|
||||
}
|
||||
|
||||
void AtomURLRequest::InformDelegateAuthenticationRequired(
|
||||
const net::AuthChallengeInfo& auth_info) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
if (delegate_)
|
||||
delegate_->OnAuthenticationRequired(auth_info);
|
||||
}
|
||||
|
||||
void AtomURLRequest::InformDelegateResponseStarted(
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
if (delegate_)
|
||||
delegate_->OnResponseStarted(response_headers);
|
||||
}
|
||||
|
||||
void AtomURLRequest::InformDelegateResponseData(
|
||||
scoped_refptr<net::IOBufferWithSize> data) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
// Transfer ownership of the data buffer, data will be released
|
||||
// by the delegate's OnResponseData.
|
||||
if (delegate_)
|
||||
delegate_->OnResponseData(data);
|
||||
}
|
||||
|
||||
void AtomURLRequest::InformDelegateResponseCompleted() const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
if (delegate_)
|
||||
delegate_->OnResponseCompleted();
|
||||
}
|
||||
|
||||
void AtomURLRequest::InformDelegateErrorOccured(const std::string& error,
|
||||
bool isRequestError) const {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
if (delegate_)
|
||||
delegate_->OnError(error, isRequestError);
|
||||
}
|
||||
|
||||
void AtomURLRequest::GetUploadProgress(mate::Dictionary* progress) const {
|
||||
net::UploadProgress upload_progress;
|
||||
if (request_) {
|
||||
progress->Set("started", true);
|
||||
upload_progress = request_->GetUploadProgress();
|
||||
} else {
|
||||
progress->Set("started", false);
|
||||
}
|
||||
progress->Set("current", upload_progress.position());
|
||||
progress->Set("total", upload_progress.size());
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,122 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_ATOM_URL_REQUEST_H_
|
||||
#define SHELL_BROWSER_NET_ATOM_URL_REQUEST_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/base/auth.h"
|
||||
#include "net/base/chunked_upload_data_stream.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/upload_element_reader.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
#include "net/url_request/url_request_context_getter_observer.h"
|
||||
#include "shell/browser/api/atom_api_url_request.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class AtomURLRequest : public base::RefCountedThreadSafe<AtomURLRequest>,
|
||||
public net::URLRequest::Delegate,
|
||||
public net::URLRequestContextGetterObserver {
|
||||
public:
|
||||
static scoped_refptr<AtomURLRequest> Create(
|
||||
AtomBrowserContext* browser_context,
|
||||
const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy,
|
||||
api::URLRequest* delegate);
|
||||
void Terminate();
|
||||
|
||||
bool Write(scoped_refptr<const net::IOBufferWithSize> buffer, bool is_last);
|
||||
void SetChunkedUpload(bool is_chunked_upload);
|
||||
void Cancel();
|
||||
void FollowRedirect();
|
||||
void SetExtraHeader(const std::string& name, const std::string& value) const;
|
||||
void RemoveExtraHeader(const std::string& name) const;
|
||||
void PassLoginInformation(const base::string16& username,
|
||||
const base::string16& password) const;
|
||||
void SetLoadFlags(int flags) const;
|
||||
void GetUploadProgress(mate::Dictionary* progress) const;
|
||||
|
||||
protected:
|
||||
// Overrides of net::URLRequest::Delegate
|
||||
void OnReceivedRedirect(net::URLRequest* request,
|
||||
const net::RedirectInfo& info,
|
||||
bool* defer_redirect) override;
|
||||
void OnAuthRequired(net::URLRequest* request,
|
||||
const net::AuthChallengeInfo& auth_info) override;
|
||||
void OnResponseStarted(net::URLRequest* request, int net_error) override;
|
||||
void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
|
||||
|
||||
// Overrides of net::URLRequestContextGetterObserver
|
||||
void OnContextShuttingDown() override;
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<AtomURLRequest>;
|
||||
|
||||
explicit AtomURLRequest(api::URLRequest* delegate);
|
||||
~AtomURLRequest() override;
|
||||
|
||||
void DoInitialize(scoped_refptr<net::URLRequestContextGetter>,
|
||||
const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& redirect_policy);
|
||||
void DoTerminate();
|
||||
void DoWriteBuffer(scoped_refptr<const net::IOBufferWithSize> buffer,
|
||||
bool is_last);
|
||||
void DoCancel();
|
||||
void DoFollowRedirect();
|
||||
void DoSetExtraHeader(const std::string& name,
|
||||
const std::string& value) const;
|
||||
void DoRemoveExtraHeader(const std::string& name) const;
|
||||
void DoSetAuth(const base::string16& username,
|
||||
const base::string16& password) const;
|
||||
void DoCancelAuth() const;
|
||||
void DoCancelWithError(const std::string& error, bool isRequestError);
|
||||
void DoSetLoadFlags(int flags) const;
|
||||
|
||||
void ReadResponse();
|
||||
bool CopyAndPostBuffer(int bytes_read);
|
||||
|
||||
void InformDelegateReceivedRedirect(
|
||||
int status_code,
|
||||
const std::string& method,
|
||||
const GURL& url,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers) const;
|
||||
void InformDelegateAuthenticationRequired(
|
||||
const net::AuthChallengeInfo& auth_info) const;
|
||||
void InformDelegateResponseStarted(
|
||||
scoped_refptr<net::HttpResponseHeaders>) const;
|
||||
void InformDelegateResponseData(
|
||||
scoped_refptr<net::IOBufferWithSize> data) const;
|
||||
void InformDelegateResponseCompleted() const;
|
||||
void InformDelegateErrorOccured(const std::string& error,
|
||||
bool isRequestError) const;
|
||||
|
||||
api::URLRequest* delegate_;
|
||||
std::unique_ptr<net::URLRequest> request_;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
|
||||
bool is_chunked_upload_ = false;
|
||||
std::string redirect_policy_;
|
||||
std::unique_ptr<net::ChunkedUploadDataStream> chunked_stream_;
|
||||
std::unique_ptr<net::ChunkedUploadDataStream::Writer> chunked_stream_writer_;
|
||||
std::vector<std::unique_ptr<net::UploadElementReader>>
|
||||
upload_element_readers_;
|
||||
scoped_refptr<net::IOBuffer> response_read_buffer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomURLRequest);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_ATOM_URL_REQUEST_H_
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/http_protocol_handler.h"
|
||||
|
||||
#include "net/url_request/url_request_http_job.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
HttpProtocolHandler::HttpProtocolHandler(const std::string& scheme)
|
||||
: scheme_(scheme) {}
|
||||
|
||||
HttpProtocolHandler::~HttpProtocolHandler() {}
|
||||
|
||||
net::URLRequestJob* HttpProtocolHandler::MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const {
|
||||
return net::URLRequestHttpJob::Factory(request, network_delegate, scheme_);
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_HTTP_PROTOCOL_HANDLER_H_
|
||||
#define SHELL_BROWSER_NET_HTTP_PROTOCOL_HANDLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class HttpProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
|
||||
public:
|
||||
explicit HttpProtocolHandler(const std::string&);
|
||||
~HttpProtocolHandler() override;
|
||||
|
||||
// net::URLRequestJobFactory::ProtocolHandler:
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override;
|
||||
|
||||
private:
|
||||
std::string scheme_;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_HTTP_PROTOCOL_HANDLER_H_
|
|
@ -50,7 +50,6 @@ class NodeStreamLoader : public network::mojom::URLLoader {
|
|||
void FollowRedirect(const std::vector<std::string>& removed_headers,
|
||||
const net::HttpRequestHeaders& modified_headers,
|
||||
const base::Optional<GURL>& new_url) override {}
|
||||
void ProceedWithResponse() override {}
|
||||
void SetPriority(net::RequestPriority priority,
|
||||
int32_t intra_priority_value) override {}
|
||||
void PauseReadingBodyFromNet() override {}
|
||||
|
|
|
@ -145,11 +145,6 @@ void ProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
|
|||
RestartInternal();
|
||||
}
|
||||
|
||||
void ProxyingURLLoaderFactory::InProgressRequest::ProceedWithResponse() {
|
||||
if (target_loader_.is_bound())
|
||||
target_loader_->ProceedWithResponse();
|
||||
}
|
||||
|
||||
void ProxyingURLLoaderFactory::InProgressRequest::SetPriority(
|
||||
net::RequestPriority priority,
|
||||
int32_t intra_priority_value) {
|
||||
|
|
|
@ -50,7 +50,6 @@ class ProxyingURLLoaderFactory
|
|||
void FollowRedirect(const std::vector<std::string>& removed_headers,
|
||||
const net::HttpRequestHeaders& modified_headers,
|
||||
const base::Optional<GURL>& new_url) override;
|
||||
void ProceedWithResponse() override;
|
||||
void SetPriority(net::RequestPriority priority,
|
||||
int32_t intra_priority_value) override;
|
||||
void PauseReadingBodyFromNet() override;
|
||||
|
|
|
@ -50,9 +50,9 @@ network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams() {
|
|||
network::mojom::HttpAuthDynamicParamsPtr auth_dynamic_params =
|
||||
network::mojom::HttpAuthDynamicParams::New();
|
||||
|
||||
auth_dynamic_params->server_whitelist = command_line->GetSwitchValueASCII(
|
||||
auth_dynamic_params->server_allowlist = command_line->GetSwitchValueASCII(
|
||||
electron::switches::kAuthServerWhitelist);
|
||||
auth_dynamic_params->delegate_whitelist = command_line->GetSwitchValueASCII(
|
||||
auth_dynamic_params->delegate_allowlist = command_line->GetSwitchValueASCII(
|
||||
electron::switches::kAuthNegotiateDelegateWhitelist);
|
||||
auth_dynamic_params->enable_negotiate_port =
|
||||
command_line->HasSwitch(electron::switches::kEnableAuthNegotiatePort);
|
||||
|
|
|
@ -60,7 +60,6 @@ class URLPipeLoader : public network::mojom::URLLoader,
|
|||
void FollowRedirect(const std::vector<std::string>& removed_headers,
|
||||
const net::HttpRequestHeaders& modified_headers,
|
||||
const base::Optional<GURL>& new_url) override {}
|
||||
void ProceedWithResponse() override {}
|
||||
void SetPriority(net::RequestPriority priority,
|
||||
int32_t intra_priority_value) override {}
|
||||
void PauseReadingBodyFromNet() override {}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_about_job.h"
|
||||
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
URLRequestAboutJob::URLRequestAboutJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestJob(request, network_delegate), weak_ptr_factory_(this) {}
|
||||
|
||||
void URLRequestAboutJob::Start() {
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&URLRequestAboutJob::StartAsync,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void URLRequestAboutJob::Kill() {
|
||||
weak_ptr_factory_.InvalidateWeakPtrs();
|
||||
URLRequestJob::Kill();
|
||||
}
|
||||
|
||||
bool URLRequestAboutJob::GetMimeType(std::string* mime_type) const {
|
||||
*mime_type = "text/html";
|
||||
return true;
|
||||
}
|
||||
|
||||
URLRequestAboutJob::~URLRequestAboutJob() {}
|
||||
|
||||
void URLRequestAboutJob::StartAsync() {
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_ABOUT_JOB_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_ABOUT_JOB_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class URLRequestAboutJob : public net::URLRequestJob {
|
||||
public:
|
||||
URLRequestAboutJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// URLRequestJob:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
|
||||
private:
|
||||
~URLRequestAboutJob() override;
|
||||
void StartAsync();
|
||||
|
||||
base::WeakPtrFactory<URLRequestAboutJob> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestAboutJob);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_ABOUT_JOB_H_
|
|
@ -1,138 +0,0 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_async_asar_job.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/v8_value_converter.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
void BeforeStartInUI(base::WeakPtr<URLRequestAsyncAsarJob> job,
|
||||
mate::Arguments* args) {
|
||||
v8::Local<v8::Value> value;
|
||||
int error = net::OK;
|
||||
std::unique_ptr<base::Value> request_options = nullptr;
|
||||
|
||||
if (args->GetNext(&value)) {
|
||||
V8ValueConverter converter;
|
||||
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
|
||||
request_options = converter.FromV8Value(value, context);
|
||||
}
|
||||
|
||||
if (request_options) {
|
||||
JsAsker::IsErrorOptions(request_options.get(), &error);
|
||||
} else {
|
||||
error = net::ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// sanitize custom headers
|
||||
if (request_options && request_options->is_dict()) {
|
||||
const base::Value* headersDict = request_options->FindDictKey("headers");
|
||||
if (headersDict) {
|
||||
for (const auto& iter : headersDict->DictItems()) {
|
||||
if (!iter.second.is_string()) {
|
||||
args->ThrowError("Value of '" + iter.first +
|
||||
"' header has to be a string");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestAsyncAsarJob::StartAsync, job,
|
||||
std::move(request_options), error));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestAsyncAsarJob::URLRequestAsyncAsarJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: asar::URLRequestAsarJob(request, network_delegate), weak_factory_(this) {}
|
||||
|
||||
URLRequestAsyncAsarJob::~URLRequestAsyncAsarJob() = default;
|
||||
|
||||
void URLRequestAsyncAsarJob::Start() {
|
||||
auto request_details = std::make_unique<base::DictionaryValue>();
|
||||
FillRequestDetails(request_details.get(), request());
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
&JsAsker::AskForOptions, base::Unretained(isolate()), handler(),
|
||||
std::move(request_details),
|
||||
base::BindOnce(&BeforeStartInUI, weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
|
||||
void URLRequestAsyncAsarJob::StartAsync(std::unique_ptr<base::Value> options,
|
||||
int error) {
|
||||
if (error != net::OK) {
|
||||
NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string file_path;
|
||||
response_headers_ = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
|
||||
if (options->is_dict()) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
base::Value* pathValue =
|
||||
dict->FindKeyOfType("path", base::Value::Type::STRING);
|
||||
if (pathValue) {
|
||||
file_path = pathValue->GetString();
|
||||
}
|
||||
base::Value* headersValue =
|
||||
dict->FindKeyOfType("headers", base::Value::Type::DICTIONARY);
|
||||
if (headersValue) {
|
||||
for (const auto& iter : headersValue->DictItems()) {
|
||||
response_headers_->AddHeader(iter.first + ": " +
|
||||
iter.second.GetString());
|
||||
}
|
||||
}
|
||||
} else if (options->is_string()) {
|
||||
file_path = options->GetString();
|
||||
}
|
||||
response_headers_->AddHeader(kCORSHeader);
|
||||
|
||||
if (file_path.empty()) {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_NOT_IMPLEMENTED));
|
||||
} else {
|
||||
asar::URLRequestAsarJob::Initialize(
|
||||
base::CreateSequencedTaskRunnerWithTraits(
|
||||
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}),
|
||||
#if defined(OS_WIN)
|
||||
base::FilePath(base::UTF8ToWide(file_path)));
|
||||
#else
|
||||
base::FilePath(file_path));
|
||||
#endif
|
||||
asar::URLRequestAsarJob::Start();
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsyncAsarJob::Kill() {
|
||||
weak_factory_.InvalidateWeakPtrs();
|
||||
URLRequestAsarJob::Kill();
|
||||
}
|
||||
|
||||
void URLRequestAsyncAsarJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
info->headers = response_headers_;
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "shell/browser/net/asar/url_request_asar_job.h"
|
||||
#include "shell/browser/net/js_asker.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Like URLRequestAsarJob, but asks the JavaScript handler for file path.
|
||||
class URLRequestAsyncAsarJob : public asar::URLRequestAsarJob, public JsAsker {
|
||||
public:
|
||||
URLRequestAsyncAsarJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
~URLRequestAsyncAsarJob() override;
|
||||
|
||||
void StartAsync(std::unique_ptr<base::Value> options, int error);
|
||||
|
||||
// URLRequestJob:
|
||||
void Start() override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
void Kill() override;
|
||||
|
||||
private:
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers_;
|
||||
base::WeakPtrFactory<URLRequestAsyncAsarJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestAsyncAsarJob);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
|
@ -1,155 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_buffer_job.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/v8_value_converter.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GetExtFromURL(const GURL& url) {
|
||||
std::string spec = url.spec();
|
||||
size_t index = spec.find_last_of('.');
|
||||
if (index == std::string::npos || index == spec.size())
|
||||
return std::string();
|
||||
return spec.substr(index + 1, spec.size() - index - 1);
|
||||
}
|
||||
|
||||
void BeforeStartInUI(base::WeakPtr<URLRequestBufferJob> job,
|
||||
mate::Arguments* args) {
|
||||
v8::Local<v8::Value> value;
|
||||
int error = net::OK;
|
||||
std::unique_ptr<base::Value> request_options = nullptr;
|
||||
|
||||
if (args->GetNext(&value)) {
|
||||
V8ValueConverter converter;
|
||||
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
|
||||
request_options = converter.FromV8Value(value, context);
|
||||
}
|
||||
|
||||
if (request_options) {
|
||||
JsAsker::IsErrorOptions(request_options.get(), &error);
|
||||
} else {
|
||||
error = net::ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestBufferJob::StartAsync, job,
|
||||
std::move(request_options), error));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestBufferJob::URLRequestBufferJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestSimpleJob(request, network_delegate),
|
||||
status_code_(net::HTTP_NOT_IMPLEMENTED),
|
||||
weak_factory_(this) {}
|
||||
|
||||
URLRequestBufferJob::~URLRequestBufferJob() = default;
|
||||
|
||||
void URLRequestBufferJob::Start() {
|
||||
auto request_details = std::make_unique<base::DictionaryValue>();
|
||||
FillRequestDetails(request_details.get(), request());
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
&JsAsker::AskForOptions, base::Unretained(isolate()), handler(),
|
||||
std::move(request_details),
|
||||
base::BindOnce(&BeforeStartInUI, weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
|
||||
void URLRequestBufferJob::StartAsync(std::unique_ptr<base::Value> options,
|
||||
int error) {
|
||||
if (error != net::OK) {
|
||||
NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
return;
|
||||
}
|
||||
|
||||
const base::Value* binary = nullptr;
|
||||
if (options->is_dict()) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("mimeType", &mime_type_);
|
||||
dict->GetString("charset", &charset_);
|
||||
dict->GetBinary("data", &binary);
|
||||
} else if (options->is_blob()) {
|
||||
binary = options.get();
|
||||
}
|
||||
|
||||
if (mime_type_.empty()) {
|
||||
std::string ext = GetExtFromURL(request()->url());
|
||||
#if defined(OS_WIN)
|
||||
net::GetWellKnownMimeTypeFromExtension(base::UTF8ToUTF16(ext), &mime_type_);
|
||||
#else
|
||||
net::GetWellKnownMimeTypeFromExtension(ext, &mime_type_);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!binary) {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_NOT_IMPLEMENTED));
|
||||
return;
|
||||
}
|
||||
|
||||
data_ = new base::RefCountedBytes(
|
||||
reinterpret_cast<const unsigned char*>(binary->GetBlob().data()),
|
||||
binary->GetBlob().size());
|
||||
status_code_ = net::HTTP_OK;
|
||||
net::URLRequestSimpleJob::Start();
|
||||
}
|
||||
|
||||
void URLRequestBufferJob::Kill() {
|
||||
weak_factory_.InvalidateWeakPtrs();
|
||||
net::URLRequestSimpleJob::Kill();
|
||||
}
|
||||
|
||||
void URLRequestBufferJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
std::string status("HTTP/1.1 ");
|
||||
status.append(base::NumberToString(status_code_));
|
||||
status.append(" ");
|
||||
status.append(net::GetHttpReasonPhrase(status_code_));
|
||||
status.append("\0\0", 2);
|
||||
auto* headers = new net::HttpResponseHeaders(status);
|
||||
|
||||
headers->AddHeader(kCORSHeader);
|
||||
|
||||
if (!mime_type_.empty()) {
|
||||
std::string content_type_header(net::HttpRequestHeaders::kContentType);
|
||||
content_type_header.append(": ");
|
||||
content_type_header.append(mime_type_);
|
||||
headers->AddHeader(content_type_header);
|
||||
}
|
||||
|
||||
info->headers = headers;
|
||||
}
|
||||
|
||||
int URLRequestBufferJob::GetRefCountedData(
|
||||
std::string* mime_type,
|
||||
std::string* charset,
|
||||
scoped_refptr<base::RefCountedMemory>* data,
|
||||
net::CompletionOnceCallback callback) const {
|
||||
*mime_type = mime_type_;
|
||||
*charset = charset_;
|
||||
*data = data_;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_BUFFER_JOB_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_BUFFER_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
#include "shell/browser/net/js_asker.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class URLRequestBufferJob : public JsAsker, public net::URLRequestSimpleJob {
|
||||
public:
|
||||
URLRequestBufferJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
~URLRequestBufferJob() override;
|
||||
|
||||
void StartAsync(std::unique_ptr<base::Value> options, int error);
|
||||
|
||||
// URLRequestJob:
|
||||
void Start() override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
void Kill() override;
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
int GetRefCountedData(std::string* mime_type,
|
||||
std::string* charset,
|
||||
scoped_refptr<base::RefCountedMemory>* data,
|
||||
net::CompletionOnceCallback callback) const override;
|
||||
|
||||
private:
|
||||
std::string mime_type_;
|
||||
std::string charset_;
|
||||
scoped_refptr<base::RefCountedBytes> data_;
|
||||
net::HttpStatusCode status_code_;
|
||||
|
||||
base::WeakPtrFactory<URLRequestBufferJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestBufferJob);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_BUFFER_JOB_H_
|
|
@ -1,365 +0,0 @@
|
|||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_context_getter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "chrome/common/chrome_constants.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "components/network_session_configurator/common/network_switches.h"
|
||||
#include "components/prefs/value_map_pref_store.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/devtools_network_transaction_factory.h"
|
||||
#include "content/public/browser/network_service_instance.h"
|
||||
#include "net/base/host_mapping_rules.h"
|
||||
#include "net/cert/multi_log_ct_verifier.h"
|
||||
#include "net/cookies/cookie_monster.h"
|
||||
#include "net/dns/mapped_host_resolver.h" // nogncheck
|
||||
#include "net/http/http_auth_handler_factory.h"
|
||||
#include "net/http/http_auth_preferences.h"
|
||||
#include "net/http/http_auth_scheme.h"
|
||||
#include "net/http/http_transaction_factory.h"
|
||||
#include "net/log/net_log.h"
|
||||
#include "net/traffic_annotation/network_traffic_annotation.h"
|
||||
#include "net/url_request/data_protocol_handler.h"
|
||||
#include "net/url_request/static_http_user_agent_settings.h"
|
||||
#include "net/url_request/url_request_intercepting_job_factory.h"
|
||||
#include "net/url_request/url_request_job_factory_impl.h"
|
||||
#include "services/network/ignore_errors_cert_verifier.h"
|
||||
#include "services/network/network_service.h"
|
||||
#include "services/network/public/cpp/features.h"
|
||||
#include "services/network/public/cpp/network_switches.h"
|
||||
#include "services/network/url_request_context_builder_mojo.h"
|
||||
#include "shell/browser/api/atom_api_protocol.h"
|
||||
#include "shell/browser/atom_browser_client.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/atom_browser_main_parts.h"
|
||||
#include "shell/browser/browser_process_impl.h"
|
||||
#include "shell/browser/net/about_protocol_handler.h"
|
||||
#include "shell/browser/net/asar/asar_protocol_handler.h"
|
||||
#include "shell/browser/net/atom_cert_verifier.h"
|
||||
#include "shell/browser/net/atom_network_delegate.h"
|
||||
#include "shell/browser/net/atom_url_request_job_factory.h"
|
||||
#include "shell/browser/net/http_protocol_handler.h"
|
||||
#include "shell/browser/net/require_ct_delegate.h"
|
||||
#include "shell/browser/net/system_network_context_manager.h"
|
||||
#include "url/url_constants.h"
|
||||
|
||||
#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
|
||||
#include "net/url_request/ftp_protocol_handler.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_REPORTING)
|
||||
#include "net/reporting/reporting_policy.h"
|
||||
#include "net/reporting/reporting_service.h"
|
||||
#endif // BUILDFLAG(ENABLE_REPORTING)
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetupAtomURLRequestJobFactory(
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
net::URLRequestContext* url_request_context,
|
||||
AtomURLRequestJobFactory* job_factory) {
|
||||
for (auto& protocol_handler : *protocol_handlers) {
|
||||
job_factory->SetProtocolHandler(protocol_handler.first,
|
||||
std::move(protocol_handler.second));
|
||||
}
|
||||
protocol_handlers->clear();
|
||||
|
||||
job_factory->SetProtocolHandler(url::kAboutScheme,
|
||||
std::make_unique<AboutProtocolHandler>());
|
||||
job_factory->SetProtocolHandler(url::kDataScheme,
|
||||
std::make_unique<net::DataProtocolHandler>());
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kFileScheme,
|
||||
std::make_unique<asar::AsarProtocolHandler>(
|
||||
base::CreateTaskRunnerWithTraits(
|
||||
{base::MayBlock(), base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kHttpScheme,
|
||||
std::make_unique<HttpProtocolHandler>(url::kHttpScheme));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kHttpsScheme,
|
||||
std::make_unique<HttpProtocolHandler>(url::kHttpsScheme));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kWsScheme, std::make_unique<HttpProtocolHandler>(url::kWsScheme));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kWssScheme, std::make_unique<HttpProtocolHandler>(url::kWssScheme));
|
||||
|
||||
#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
|
||||
auto* host_resolver = url_request_context->host_resolver();
|
||||
auto* ftp_auth_cache = url_request_context->ftp_auth_cache();
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kFtpScheme,
|
||||
net::FtpProtocolHandler::Create(host_resolver, ftp_auth_cache));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestContextGetter::Handle::Handle(
|
||||
base::WeakPtr<AtomBrowserContext> browser_context)
|
||||
: resource_context_(new content::ResourceContext),
|
||||
browser_context_(browser_context),
|
||||
initialized_(false) {}
|
||||
|
||||
URLRequestContextGetter::Handle::~Handle() {}
|
||||
|
||||
content::ResourceContext*
|
||||
URLRequestContextGetter::Handle::GetResourceContext() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
LazyInitialize();
|
||||
return resource_context_.get();
|
||||
}
|
||||
|
||||
scoped_refptr<URLRequestContextGetter>
|
||||
URLRequestContextGetter::Handle::CreateMainRequestContextGetter(
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::URLRequestInterceptorScopedVector protocol_interceptors) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
DCHECK(!main_request_context_getter_.get());
|
||||
DCHECK(AtomBrowserMainParts::Get()->browser_process()->io_thread());
|
||||
|
||||
LazyInitialize();
|
||||
main_request_context_getter_ = new URLRequestContextGetter(
|
||||
this, protocol_handlers, std::move(protocol_interceptors));
|
||||
AtomBrowserMainParts::Get()
|
||||
->browser_process()
|
||||
->io_thread()
|
||||
->RegisterURLRequestContextGetter(main_request_context_getter_.get());
|
||||
return main_request_context_getter_;
|
||||
}
|
||||
|
||||
scoped_refptr<URLRequestContextGetter>
|
||||
URLRequestContextGetter::Handle::GetMainRequestContextGetter() {
|
||||
return main_request_context_getter_;
|
||||
}
|
||||
|
||||
network::mojom::NetworkContextPtr
|
||||
URLRequestContextGetter::Handle::GetNetworkContext() {
|
||||
if (!main_network_context_) {
|
||||
main_network_context_request_ = mojo::MakeRequest(&main_network_context_);
|
||||
}
|
||||
return std::move(main_network_context_);
|
||||
}
|
||||
|
||||
network::mojom::NetworkContextParamsPtr
|
||||
URLRequestContextGetter::Handle::CreateNetworkContextParams() {
|
||||
network::mojom::NetworkContextParamsPtr network_context_params =
|
||||
SystemNetworkContextManager::GetInstance()
|
||||
->CreateDefaultNetworkContextParams();
|
||||
|
||||
network_context_params->user_agent = browser_context_->GetUserAgent();
|
||||
|
||||
network_context_params->http_cache_enabled =
|
||||
browser_context_->CanUseHttpCache();
|
||||
|
||||
network_context_params->accept_language =
|
||||
net::HttpUtil::GenerateAcceptLanguageHeader(
|
||||
AtomBrowserClient::Get()->GetApplicationLocale());
|
||||
|
||||
if (!browser_context_->IsOffTheRecord()) {
|
||||
auto base_path = browser_context_->GetPath();
|
||||
network_context_params->http_cache_path =
|
||||
base_path.Append(chrome::kCacheDirname);
|
||||
network_context_params->http_cache_max_size =
|
||||
browser_context_->GetMaxCacheSize();
|
||||
network_context_params->http_server_properties_path =
|
||||
base_path.Append(chrome::kNetworkPersistentStateFilename);
|
||||
network_context_params->cookie_path =
|
||||
base_path.Append(chrome::kCookieFilename);
|
||||
network_context_params->restore_old_session_cookies = false;
|
||||
network_context_params->persist_session_cookies = false;
|
||||
// TODO(deepak1556): Matches the existing behavior https://git.io/fxHMl,
|
||||
// enable encryption as a followup.
|
||||
network_context_params->enable_encrypted_cookies = false;
|
||||
}
|
||||
|
||||
// TODO(deepak1556): Decide the stand on chrome ct policy and
|
||||
// enable it.
|
||||
// See //net/docs/certificate-transparency.md
|
||||
// network_context_params->enforce_chrome_ct_policy = true;
|
||||
return network_context_params;
|
||||
}
|
||||
|
||||
void URLRequestContextGetter::Handle::LazyInitialize() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
if (initialized_)
|
||||
return;
|
||||
|
||||
initialized_ = true;
|
||||
main_network_context_params_ = CreateNetworkContextParams();
|
||||
|
||||
browser_context_->proxy_config_monitor()->AddToNetworkContextParams(
|
||||
main_network_context_params_.get());
|
||||
|
||||
BrowserProcessImpl::ApplyProxyModeFromCommandLine(
|
||||
browser_context_->in_memory_pref_store());
|
||||
|
||||
if (!main_network_context_request_.is_pending()) {
|
||||
main_network_context_request_ = mojo::MakeRequest(&main_network_context_);
|
||||
}
|
||||
content::BrowserContext::EnsureResourceContextInitialized(
|
||||
browser_context_.get());
|
||||
}
|
||||
|
||||
void URLRequestContextGetter::Handle::ShutdownOnUIThread() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
if (main_request_context_getter_) {
|
||||
if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestContextGetter::NotifyContextShuttingDown,
|
||||
base::RetainedRef(main_request_context_getter_)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, this))
|
||||
delete this;
|
||||
}
|
||||
|
||||
URLRequestContextGetter::URLRequestContextGetter(
|
||||
URLRequestContextGetter::Handle* context_handle,
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::URLRequestInterceptorScopedVector protocol_interceptors)
|
||||
: context_handle_(context_handle),
|
||||
url_request_context_(nullptr),
|
||||
protocol_interceptors_(std::move(protocol_interceptors)),
|
||||
context_shutting_down_(false) {
|
||||
// Must first be created on the UI thread.
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
if (protocol_handlers)
|
||||
std::swap(protocol_handlers_, *protocol_handlers);
|
||||
}
|
||||
|
||||
URLRequestContextGetter::~URLRequestContextGetter() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
// NotifyContextShuttingDown should have been called.
|
||||
DCHECK(context_shutting_down_);
|
||||
}
|
||||
|
||||
void URLRequestContextGetter::NotifyContextShuttingDown() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
DCHECK(AtomBrowserMainParts::Get()->browser_process()->io_thread());
|
||||
DCHECK(context_handle_);
|
||||
|
||||
if (context_shutting_down_)
|
||||
return;
|
||||
|
||||
AtomBrowserMainParts::Get()
|
||||
->browser_process()
|
||||
->io_thread()
|
||||
->DeregisterURLRequestContextGetter(this);
|
||||
|
||||
context_shutting_down_ = true;
|
||||
context_handle_->resource_context_.reset();
|
||||
net::URLRequestContextGetter::NotifyContextShuttingDown();
|
||||
network_context_.reset();
|
||||
}
|
||||
|
||||
net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
if (context_shutting_down_)
|
||||
return nullptr;
|
||||
|
||||
if (!url_request_context_) {
|
||||
std::unique_ptr<network::URLRequestContextBuilderMojo> builder =
|
||||
std::make_unique<network::URLRequestContextBuilderMojo>();
|
||||
|
||||
// Enable file:// support.
|
||||
builder->set_file_enabled(true);
|
||||
|
||||
#if BUILDFLAG(ENABLE_REPORTING)
|
||||
if (base::FeatureList::IsEnabled(network::features::kReporting)) {
|
||||
auto reporting_policy = net::ReportingPolicy::Create();
|
||||
builder->set_reporting_policy(std::move(reporting_policy));
|
||||
} else {
|
||||
builder->set_reporting_policy(nullptr);
|
||||
}
|
||||
|
||||
builder->set_network_error_logging_enabled(
|
||||
base::FeatureList::IsEnabled(network::features::kNetworkErrorLogging));
|
||||
#endif // BUILDFLAG(ENABLE_REPORTING)
|
||||
|
||||
auto network_delegate = std::make_unique<AtomNetworkDelegate>();
|
||||
network_delegate_ = network_delegate.get();
|
||||
builder->set_network_delegate(std::move(network_delegate));
|
||||
|
||||
ct_delegate_.reset(new RequireCTDelegate);
|
||||
auto cert_verifier = std::make_unique<AtomCertVerifier>(ct_delegate_.get());
|
||||
builder->SetCertVerifier(std::move(cert_verifier));
|
||||
|
||||
builder->SetCreateHttpTransactionFactoryCallback(
|
||||
base::BindOnce(&content::CreateDevToolsNetworkTransactionFactory));
|
||||
|
||||
builder->set_ct_verifier(std::make_unique<net::MultiLogCTVerifier>());
|
||||
|
||||
// Enable FTP, we override it later in SetupAtomURLRequestJobFactory
|
||||
#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
|
||||
builder->set_ftp_enabled(true);
|
||||
#endif
|
||||
|
||||
auto* network_service = content::GetNetworkServiceImpl();
|
||||
network_context_ = network_service->CreateNetworkContextWithBuilder(
|
||||
std::move(context_handle_->main_network_context_request_),
|
||||
std::move(context_handle_->main_network_context_params_),
|
||||
std::move(builder), &url_request_context_);
|
||||
|
||||
net::TransportSecurityState* transport_security_state =
|
||||
url_request_context_->transport_security_state();
|
||||
transport_security_state->SetRequireCTDelegate(ct_delegate_.get());
|
||||
|
||||
// Add custom standard schemes to cookie schemes.
|
||||
auto* cookie_monster =
|
||||
static_cast<net::CookieMonster*>(url_request_context_->cookie_store());
|
||||
std::vector<std::string> cookie_schemes(
|
||||
{url::kHttpScheme, url::kHttpsScheme, url::kWsScheme, url::kWssScheme});
|
||||
const auto& custom_standard_schemes = electron::api::GetStandardSchemes();
|
||||
cookie_schemes.insert(cookie_schemes.end(), custom_standard_schemes.begin(),
|
||||
custom_standard_schemes.end());
|
||||
cookie_monster->SetCookieableSchemes(cookie_schemes, base::NullCallback());
|
||||
|
||||
// Setup handlers for custom job factory.
|
||||
top_job_factory_.reset(new AtomURLRequestJobFactory);
|
||||
SetupAtomURLRequestJobFactory(&protocol_handlers_, url_request_context_,
|
||||
top_job_factory_.get());
|
||||
std::unique_ptr<net::URLRequestJobFactory> inner_job_factory(
|
||||
new net::URLRequestJobFactoryImpl);
|
||||
if (!protocol_interceptors_.empty()) {
|
||||
// Set up interceptors in the reverse order.
|
||||
for (auto it = protocol_interceptors_.rbegin();
|
||||
it != protocol_interceptors_.rend(); ++it) {
|
||||
inner_job_factory.reset(new net::URLRequestInterceptingJobFactory(
|
||||
std::move(inner_job_factory), std::move(*it)));
|
||||
}
|
||||
protocol_interceptors_.clear();
|
||||
}
|
||||
top_job_factory_->Chain(std::move(inner_job_factory));
|
||||
url_request_context_->set_job_factory(top_job_factory_.get());
|
||||
}
|
||||
|
||||
return url_request_context_;
|
||||
}
|
||||
|
||||
scoped_refptr<base::SingleThreadTaskRunner>
|
||||
URLRequestContextGetter::GetNetworkTaskRunner() const {
|
||||
return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO});
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,114 +0,0 @@
|
|||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "services/network/public/mojom/network_service.mojom.h"
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
#include "base/debug/leak_tracker.h"
|
||||
#endif
|
||||
|
||||
namespace electron {
|
||||
|
||||
class AtomBrowserContext;
|
||||
class AtomNetworkDelegate;
|
||||
class AtomURLRequestJobFactory;
|
||||
class RequireCTDelegate;
|
||||
class ResourceContext;
|
||||
|
||||
class URLRequestContextGetter : public net::URLRequestContextGetter {
|
||||
public:
|
||||
// net::URLRequestContextGetter:
|
||||
net::URLRequestContext* GetURLRequestContext() override;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
|
||||
const override;
|
||||
|
||||
// Discard reference to URLRequestContext and inform observers to
|
||||
// shutdown. Must be called only on IO thread.
|
||||
void NotifyContextShuttingDown();
|
||||
|
||||
AtomURLRequestJobFactory* job_factory() const {
|
||||
return top_job_factory_.get();
|
||||
}
|
||||
|
||||
AtomNetworkDelegate* network_delegate() const { return network_delegate_; }
|
||||
|
||||
private:
|
||||
friend class AtomBrowserContext;
|
||||
|
||||
// Responsible for destroying URLRequestContextGetter
|
||||
// on the IO thread.
|
||||
class Handle {
|
||||
public:
|
||||
explicit Handle(base::WeakPtr<AtomBrowserContext> browser_context);
|
||||
~Handle();
|
||||
|
||||
scoped_refptr<URLRequestContextGetter> CreateMainRequestContextGetter(
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::URLRequestInterceptorScopedVector protocol_interceptors);
|
||||
content::ResourceContext* GetResourceContext();
|
||||
scoped_refptr<URLRequestContextGetter> GetMainRequestContextGetter();
|
||||
network::mojom::NetworkContextPtr GetNetworkContext();
|
||||
network::mojom::NetworkContextParamsPtr CreateNetworkContextParams();
|
||||
|
||||
void ShutdownOnUIThread();
|
||||
|
||||
private:
|
||||
friend class URLRequestContextGetter;
|
||||
void LazyInitialize();
|
||||
|
||||
scoped_refptr<URLRequestContextGetter> main_request_context_getter_;
|
||||
std::unique_ptr<content::ResourceContext> resource_context_;
|
||||
base::WeakPtr<AtomBrowserContext> browser_context_;
|
||||
// This is a NetworkContext interface that uses URLRequestContextGetter
|
||||
// NetworkContext, ownership is passed to StoragePartition when
|
||||
// CreateMainNetworkContext is called.
|
||||
network::mojom::NetworkContextPtr main_network_context_;
|
||||
// Request corresponding to |main_network_context_|. Ownership
|
||||
// is passed to network service.
|
||||
network::mojom::NetworkContextRequest main_network_context_request_;
|
||||
network::mojom::NetworkContextParamsPtr main_network_context_params_;
|
||||
bool initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Handle);
|
||||
};
|
||||
|
||||
URLRequestContextGetter(
|
||||
URLRequestContextGetter::Handle* context_handle,
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::URLRequestInterceptorScopedVector protocol_interceptors);
|
||||
~URLRequestContextGetter() override;
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
base::debug::LeakTracker<URLRequestContextGetter> leak_tracker_;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<RequireCTDelegate> ct_delegate_;
|
||||
std::unique_ptr<AtomURLRequestJobFactory> top_job_factory_;
|
||||
std::unique_ptr<network::mojom::NetworkContext> network_context_;
|
||||
|
||||
URLRequestContextGetter::Handle* context_handle_;
|
||||
net::URLRequestContext* url_request_context_;
|
||||
AtomNetworkDelegate* network_delegate_;
|
||||
content::ProtocolHandlerMap protocol_handlers_;
|
||||
content::URLRequestInterceptorScopedVector protocol_interceptors_;
|
||||
bool context_shutting_down_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_CONTEXT_GETTER_H_
|
|
@ -1,344 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_fetch_job.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/guid.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_fetcher.h"
|
||||
#include "net/url_request/url_fetcher_response_writer.h"
|
||||
#include "shell/browser/api/atom_api_session.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/v8_value_converter.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert string to RequestType.
|
||||
net::URLFetcher::RequestType GetRequestType(const std::string& raw) {
|
||||
std::string method = base::ToUpperASCII(raw);
|
||||
if (method.empty() || method == "GET")
|
||||
return net::URLFetcher::GET;
|
||||
else if (method == "POST")
|
||||
return net::URLFetcher::POST;
|
||||
else if (method == "HEAD")
|
||||
return net::URLFetcher::HEAD;
|
||||
else if (method == "DELETE")
|
||||
return net::URLFetcher::DELETE_REQUEST;
|
||||
else if (method == "PUT")
|
||||
return net::URLFetcher::PUT;
|
||||
else if (method == "PATCH")
|
||||
return net::URLFetcher::PATCH;
|
||||
else // Use "GET" as fallback.
|
||||
return net::URLFetcher::GET;
|
||||
}
|
||||
|
||||
// Pipe the response writer back to URLRequestFetchJob.
|
||||
class ResponsePiper : public net::URLFetcherResponseWriter {
|
||||
public:
|
||||
explicit ResponsePiper(URLRequestFetchJob* job) : job_(job) {}
|
||||
|
||||
// net::URLFetcherResponseWriter:
|
||||
int Initialize(net::CompletionOnceCallback callback) override {
|
||||
return net::OK;
|
||||
}
|
||||
int Write(net::IOBuffer* buffer,
|
||||
int num_bytes,
|
||||
net::CompletionOnceCallback callback) override {
|
||||
if (first_write_) {
|
||||
// The URLFetcherResponseWriter doesn't have an event when headers have
|
||||
// been read, so we have to emulate by hooking to first write event.
|
||||
job_->HeadersCompleted();
|
||||
first_write_ = false;
|
||||
}
|
||||
return job_->DataAvailable(buffer, num_bytes, std::move(callback));
|
||||
}
|
||||
int Finish(int net_error, net::CompletionOnceCallback callback) override {
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
private:
|
||||
bool first_write_ = true;
|
||||
URLRequestFetchJob* job_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResponsePiper);
|
||||
};
|
||||
|
||||
void BeforeStartInUI(base::WeakPtr<URLRequestFetchJob> job,
|
||||
mate::Arguments* args) {
|
||||
// Pass whatever user passed to the actaul request job.
|
||||
v8::Local<v8::Value> value;
|
||||
mate::Dictionary options;
|
||||
if (!args->GetNext(&value) ||
|
||||
!mate::ConvertFromV8(args->isolate(), value, &options)) {
|
||||
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestFetchJob::OnError, job,
|
||||
net::ERR_NOT_IMPLEMENTED));
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter;
|
||||
scoped_refptr<AtomBrowserContext> custom_browser_context;
|
||||
// When |session| is set to |null| we use a new request context for fetch
|
||||
// job.
|
||||
if (options.Get("session", &value)) {
|
||||
if (value->IsNull()) {
|
||||
// We have to create the URLRequestContextGetter on UI thread.
|
||||
custom_browser_context =
|
||||
AtomBrowserContext::From(base::GenerateGUID(), true);
|
||||
url_request_context_getter = custom_browser_context->GetRequestContext();
|
||||
} else {
|
||||
mate::Handle<api::Session> session;
|
||||
if (mate::ConvertFromV8(args->isolate(), value, &session) &&
|
||||
!session.IsEmpty()) {
|
||||
AtomBrowserContext* browser_context = session->browser_context();
|
||||
url_request_context_getter = browser_context->GetRequestContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
V8ValueConverter converter;
|
||||
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
|
||||
std::unique_ptr<base::Value> request_options(
|
||||
converter.FromV8Value(value, context));
|
||||
|
||||
int error = net::OK;
|
||||
if (!request_options || !request_options->is_dict())
|
||||
error = net::ERR_NOT_IMPLEMENTED;
|
||||
|
||||
JsAsker::IsErrorOptions(request_options.get(), &error);
|
||||
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestFetchJob::StartAsync, job,
|
||||
base::RetainedRef(url_request_context_getter),
|
||||
base::RetainedRef(custom_browser_context),
|
||||
std::move(request_options), error));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestFetchJob::URLRequestFetchJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestJob(request, network_delegate), weak_factory_(this) {}
|
||||
|
||||
URLRequestFetchJob::~URLRequestFetchJob() = default;
|
||||
|
||||
void URLRequestFetchJob::Start() {
|
||||
auto request_details = std::make_unique<base::DictionaryValue>();
|
||||
FillRequestDetails(request_details.get(), request());
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
&JsAsker::AskForOptions, base::Unretained(isolate()), handler(),
|
||||
std::move(request_details),
|
||||
base::BindOnce(&BeforeStartInUI, weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::StartAsync(
|
||||
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
|
||||
scoped_refptr<AtomBrowserContext> browser_context,
|
||||
std::unique_ptr<base::Value> options,
|
||||
int error) {
|
||||
if (error != net::OK) {
|
||||
NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url, method, referrer;
|
||||
base::DictionaryValue* upload_data = nullptr;
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("url", &url);
|
||||
dict->GetString("method", &method);
|
||||
dict->GetString("referrer", &referrer);
|
||||
dict->GetDictionary("uploadData", &upload_data);
|
||||
|
||||
// Check if URL is valid.
|
||||
GURL formated_url(url);
|
||||
if (!formated_url.is_valid()) {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_INVALID_URL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use |request|'s method if |method| is not specified.
|
||||
net::URLFetcher::RequestType request_type;
|
||||
if (method.empty())
|
||||
request_type = GetRequestType(request()->method());
|
||||
else
|
||||
request_type = GetRequestType(method);
|
||||
|
||||
fetcher_ = net::URLFetcher::Create(formated_url, request_type, this,
|
||||
MISSING_TRAFFIC_ANNOTATION);
|
||||
fetcher_->SaveResponseWithWriter(base::WrapUnique(new ResponsePiper(this)));
|
||||
|
||||
// A request context getter is passed by the user.
|
||||
if (url_request_context_getter)
|
||||
fetcher_->SetRequestContext(url_request_context_getter.get());
|
||||
else
|
||||
fetcher_->SetRequestContext(request_context_getter());
|
||||
|
||||
// Use |request|'s referrer if |referrer| is not specified.
|
||||
if (referrer.empty())
|
||||
fetcher_->SetReferrer(request()->referrer());
|
||||
else
|
||||
fetcher_->SetReferrer(referrer);
|
||||
|
||||
// Set the data needed for POSTs.
|
||||
if (upload_data && request_type == net::URLFetcher::POST) {
|
||||
std::string content_type, data;
|
||||
upload_data->GetString("contentType", &content_type);
|
||||
upload_data->GetString("data", &data);
|
||||
fetcher_->SetUploadData(content_type, data);
|
||||
}
|
||||
|
||||
// Use |request|'s headers.
|
||||
fetcher_->SetExtraRequestHeaders(
|
||||
request()->extra_request_headers().ToString());
|
||||
|
||||
fetcher_->Start();
|
||||
|
||||
if (browser_context)
|
||||
custom_browser_context_ = browser_context;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::OnError(int error) {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::HeadersCompleted() {
|
||||
response_info_.reset(new net::HttpResponseInfo);
|
||||
response_info_->headers = fetcher_->GetResponseHeaders();
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
||||
int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer,
|
||||
int num_bytes,
|
||||
net::CompletionOnceCallback callback) {
|
||||
// When pending_buffer_ is empty, there's no ReadRawData() operation waiting
|
||||
// for IO completion, we have to save the parameters until the request is
|
||||
// ready to read data.
|
||||
if (!pending_buffer_.get()) {
|
||||
write_buffer_ = buffer;
|
||||
write_num_bytes_ = num_bytes;
|
||||
write_callback_ = std::move(callback);
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
// Write data to the pending buffer and clear them after the writing.
|
||||
int bytes_read = BufferCopy(buffer, num_bytes, pending_buffer_.get(),
|
||||
pending_buffer_size_);
|
||||
ClearPendingBuffer();
|
||||
ReadRawDataComplete(bytes_read);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Kill() {
|
||||
weak_factory_.InvalidateWeakPtrs();
|
||||
net::URLRequestJob::Kill();
|
||||
fetcher_.reset();
|
||||
custom_browser_context_ = nullptr;
|
||||
}
|
||||
|
||||
int URLRequestFetchJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
|
||||
if (GetResponseCode() == 204) {
|
||||
request()->set_received_response_content_length(prefilter_bytes_read());
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
// When write_buffer_ is empty, there is no data valable yet, we have to save
|
||||
// the dest buffer util DataAvailable.
|
||||
if (!write_buffer_.get()) {
|
||||
pending_buffer_ = dest;
|
||||
pending_buffer_size_ = dest_size;
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
// Read from the write buffer and clear them after reading.
|
||||
int bytes_read =
|
||||
BufferCopy(write_buffer_.get(), write_num_bytes_, dest, dest_size);
|
||||
ClearWriteBuffer();
|
||||
if (!write_callback_.is_null())
|
||||
std::move(write_callback_).Run(bytes_read);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
bool URLRequestFetchJob::GetMimeType(std::string* mime_type) const {
|
||||
if (!response_info_ || !response_info_->headers)
|
||||
return false;
|
||||
|
||||
return response_info_->headers->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
if (response_info_)
|
||||
*info = *response_info_;
|
||||
}
|
||||
|
||||
int URLRequestFetchJob::GetResponseCode() const {
|
||||
if (!response_info_ || !response_info_->headers)
|
||||
return -1;
|
||||
|
||||
return response_info_->headers->response_code();
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::OnURLFetchComplete(const net::URLFetcher* source) {
|
||||
ClearPendingBuffer();
|
||||
ClearWriteBuffer();
|
||||
|
||||
if (fetcher_->GetStatus().is_success()) {
|
||||
if (!response_info_) {
|
||||
// Since we notify header completion only after first write there will be
|
||||
// no response object constructed for http respones with no content 204.
|
||||
// We notify header completion here.
|
||||
HeadersCompleted();
|
||||
return;
|
||||
}
|
||||
if (request_->status().is_io_pending()) {
|
||||
ReadRawDataComplete(0);
|
||||
}
|
||||
} else {
|
||||
NotifyStartError(fetcher_->GetStatus());
|
||||
}
|
||||
}
|
||||
|
||||
int URLRequestFetchJob::BufferCopy(net::IOBuffer* source,
|
||||
int num_bytes,
|
||||
net::IOBuffer* target,
|
||||
int target_size) {
|
||||
int bytes_written = std::min(num_bytes, target_size);
|
||||
memcpy(target->data(), source->data(), bytes_written);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::ClearPendingBuffer() {
|
||||
pending_buffer_ = nullptr;
|
||||
pending_buffer_size_ = 0;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::ClearWriteBuffer() {
|
||||
write_buffer_ = nullptr;
|
||||
write_num_bytes_ = 0;
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,81 +0,0 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/url_request/url_fetcher_delegate.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "shell/browser/net/js_asker.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
class URLRequestFetchJob : public JsAsker,
|
||||
public net::URLRequestJob,
|
||||
public net::URLFetcherDelegate {
|
||||
public:
|
||||
URLRequestFetchJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
~URLRequestFetchJob() override;
|
||||
|
||||
void StartAsync(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
scoped_refptr<AtomBrowserContext> browser_context,
|
||||
std::unique_ptr<base::Value> options,
|
||||
int error);
|
||||
void OnError(int error);
|
||||
|
||||
// Called by response writer.
|
||||
void HeadersCompleted();
|
||||
int DataAvailable(net::IOBuffer* buffer,
|
||||
int num_bytes,
|
||||
net::CompletionOnceCallback callback);
|
||||
|
||||
protected:
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
int ReadRawData(net::IOBuffer* buf, int buf_size) override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
int GetResponseCode() const override;
|
||||
|
||||
// net::URLFetcherDelegate:
|
||||
void OnURLFetchComplete(const net::URLFetcher* source) override;
|
||||
|
||||
private:
|
||||
int BufferCopy(net::IOBuffer* source,
|
||||
int num_bytes,
|
||||
net::IOBuffer* target,
|
||||
int target_size);
|
||||
void ClearPendingBuffer();
|
||||
void ClearWriteBuffer();
|
||||
|
||||
scoped_refptr<AtomBrowserContext> custom_browser_context_;
|
||||
std::unique_ptr<net::URLFetcher> fetcher_;
|
||||
std::unique_ptr<net::HttpResponseInfo> response_info_;
|
||||
|
||||
// Saved arguments passed to ReadRawData.
|
||||
scoped_refptr<net::IOBuffer> pending_buffer_;
|
||||
int pending_buffer_size_ = 0;
|
||||
|
||||
// Saved arguments passed to DataAvailable.
|
||||
scoped_refptr<net::IOBuffer> write_buffer_;
|
||||
int write_num_bytes_ = 0;
|
||||
net::CompletionOnceCallback write_callback_;
|
||||
|
||||
base::WeakPtrFactory<URLRequestFetchJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestFetchJob);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
|
|
@ -1,258 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_stream_job.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/filter/gzip_source_stream.h"
|
||||
#include "shell/common/api/event_emitter_caller.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
void BeforeStartInUI(base::WeakPtr<URLRequestStreamJob> job,
|
||||
mate::Arguments* args) {
|
||||
v8::Local<v8::Value> value;
|
||||
int error = net::OK;
|
||||
bool ended = false;
|
||||
if (!args->GetNext(&value) || !value->IsObject()) {
|
||||
// Invalid opts.
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestStreamJob::OnError, job, net::ERR_FAILED));
|
||||
return;
|
||||
}
|
||||
|
||||
mate::Dictionary opts(args->isolate(), v8::Local<v8::Object>::Cast(value));
|
||||
int status_code;
|
||||
if (!opts.Get("statusCode", &status_code)) {
|
||||
// assume HTTP OK if statusCode is not passed.
|
||||
status_code = 200;
|
||||
}
|
||||
std::string status("HTTP/1.1 ");
|
||||
status.append(base::NumberToString(status_code));
|
||||
status.append(" ");
|
||||
status.append(
|
||||
net::GetHttpReasonPhrase(static_cast<net::HttpStatusCode>(status_code)));
|
||||
status.append("\0\0", 2);
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers(
|
||||
new net::HttpResponseHeaders(status));
|
||||
|
||||
if (opts.Get("headers", &value)) {
|
||||
mate::Converter<net::HttpResponseHeaders*>::FromV8(args->isolate(), value,
|
||||
response_headers.get());
|
||||
}
|
||||
|
||||
if (!opts.Get("data", &value)) {
|
||||
// Assume the opts is already a stream
|
||||
value = opts.GetHandle();
|
||||
} else if (value->IsNullOrUndefined()) {
|
||||
// "data" was explicitly passed as null or undefined, assume the user wants
|
||||
// to send an empty body.
|
||||
ended = true;
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestStreamJob::StartAsync, job, nullptr,
|
||||
base::RetainedRef(response_headers), ended, error));
|
||||
return;
|
||||
}
|
||||
|
||||
mate::Dictionary data(args->isolate(), v8::Local<v8::Object>::Cast(value));
|
||||
if (!data.Get("on", &value) || !value->IsFunction() ||
|
||||
!data.Get("removeListener", &value) || !value->IsFunction()) {
|
||||
// If data is passed but it is not a stream, signal an error.
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestStreamJob::OnError, job, net::ERR_FAILED));
|
||||
return;
|
||||
}
|
||||
|
||||
auto subscriber = base::MakeRefCounted<mate::StreamSubscriber>(
|
||||
args->isolate(), data.GetHandle(), job,
|
||||
base::ThreadTaskRunnerHandle::Get());
|
||||
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestStreamJob::StartAsync, job, subscriber,
|
||||
base::RetainedRef(response_headers), ended, error));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestStreamJob::URLRequestStreamJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestJob(request, network_delegate),
|
||||
pending_buf_(nullptr),
|
||||
pending_buf_size_(0),
|
||||
ended_(false),
|
||||
response_headers_(nullptr),
|
||||
weak_factory_(this) {}
|
||||
|
||||
URLRequestStreamJob::~URLRequestStreamJob() {
|
||||
DCHECK(!subscriber_ || subscriber_->HasOneRef());
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::Start() {
|
||||
auto request_details = std::make_unique<base::DictionaryValue>();
|
||||
FillRequestDetails(request_details.get(), request());
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
&JsAsker::AskForOptions, base::Unretained(isolate()), handler(),
|
||||
std::move(request_details),
|
||||
base::BindOnce(&BeforeStartInUI, weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::StartAsync(
|
||||
scoped_refptr<mate::StreamSubscriber> subscriber,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers,
|
||||
bool ended,
|
||||
int error) {
|
||||
if (error != net::OK) {
|
||||
NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
return;
|
||||
}
|
||||
|
||||
ended_ = ended;
|
||||
response_headers_ = response_headers;
|
||||
subscriber_ = subscriber;
|
||||
request_start_time_ = base::TimeTicks::Now();
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnData(std::vector<char>&& buffer) { // NOLINT
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (write_buffer_.empty()) {
|
||||
// Quick branch without copying.
|
||||
write_buffer_ = std::move(buffer);
|
||||
} else {
|
||||
// write_buffer_ += buffer
|
||||
size_t len = write_buffer_.size();
|
||||
write_buffer_.resize(len + buffer.size());
|
||||
std::copy(buffer.begin(), buffer.end(), write_buffer_.begin() + len);
|
||||
}
|
||||
|
||||
// Copy to output.
|
||||
if (pending_buf_) {
|
||||
int len = BufferCopy(&write_buffer_, pending_buf_.get(), pending_buf_size_);
|
||||
write_buffer_.erase(write_buffer_.begin(), write_buffer_.begin() + len);
|
||||
pending_buf_ = nullptr;
|
||||
pending_buf_size_ = 0;
|
||||
ReadRawDataComplete(len);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnEnd() {
|
||||
ended_ = true;
|
||||
if (pending_buf_) {
|
||||
ReadRawDataComplete(0);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnError(int error) {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
}
|
||||
|
||||
int URLRequestStreamJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
|
||||
response_start_time_ = base::TimeTicks::Now();
|
||||
|
||||
if (ended_ && write_buffer_.empty())
|
||||
return 0;
|
||||
|
||||
// When write_buffer_ is empty, there is no data valable yet, we have to save
|
||||
// the dest buffer util DataAvailable.
|
||||
if (write_buffer_.empty()) {
|
||||
pending_buf_ = dest;
|
||||
pending_buf_size_ = dest_size;
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
// Read from the write buffer and clear them after reading.
|
||||
int len = BufferCopy(&write_buffer_, dest, dest_size);
|
||||
write_buffer_.erase(write_buffer_.begin(), write_buffer_.begin() + len);
|
||||
return len;
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::DoneReading() {
|
||||
write_buffer_.clear();
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::DoneReadingRedirectResponse() {
|
||||
if (subscriber_) {
|
||||
DCHECK(subscriber_->HasAtLeastOneRef());
|
||||
subscriber_ = nullptr;
|
||||
}
|
||||
DoneReading();
|
||||
}
|
||||
|
||||
std::unique_ptr<net::SourceStream> URLRequestStreamJob::SetUpSourceStream() {
|
||||
std::unique_ptr<net::SourceStream> source =
|
||||
net::URLRequestJob::SetUpSourceStream();
|
||||
size_t i = 0;
|
||||
std::string type;
|
||||
while (response_headers_->EnumerateHeader(&i, "Content-Encoding", &type)) {
|
||||
if (base::LowerCaseEqualsASCII(type, "gzip") ||
|
||||
base::LowerCaseEqualsASCII(type, "x-gzip")) {
|
||||
return net::GzipSourceStream::Create(std::move(source),
|
||||
net::SourceStream::TYPE_GZIP);
|
||||
} else if (base::LowerCaseEqualsASCII(type, "deflate")) {
|
||||
return net::GzipSourceStream::Create(std::move(source),
|
||||
net::SourceStream::TYPE_DEFLATE);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
bool URLRequestStreamJob::GetMimeType(std::string* mime_type) const {
|
||||
return response_headers_->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
int URLRequestStreamJob::GetResponseCode() const {
|
||||
return response_headers_->response_code();
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
info->headers = response_headers_;
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const {
|
||||
load_timing_info->send_start = request_start_time_;
|
||||
load_timing_info->send_end = request_start_time_;
|
||||
load_timing_info->request_start = request_start_time_;
|
||||
load_timing_info->receive_headers_end = response_start_time_;
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::Kill() {
|
||||
weak_factory_.InvalidateWeakPtrs();
|
||||
net::URLRequestJob::Kill();
|
||||
}
|
||||
|
||||
int URLRequestStreamJob::BufferCopy(std::vector<char>* source,
|
||||
net::IOBuffer* target,
|
||||
int target_size) {
|
||||
int bytes_written = std::min(static_cast<int>(source->size()), target_size);
|
||||
memcpy(target->data(), source->data(), bytes_written);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_STREAM_JOB_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_STREAM_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "shell/browser/api/stream_subscriber.h"
|
||||
#include "shell/browser/net/js_asker.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class URLRequestStreamJob : public JsAsker, public net::URLRequestJob {
|
||||
public:
|
||||
URLRequestStreamJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate);
|
||||
~URLRequestStreamJob() override;
|
||||
|
||||
void StartAsync(scoped_refptr<mate::StreamSubscriber> subscriber,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers,
|
||||
bool ended,
|
||||
int error);
|
||||
|
||||
void OnData(std::vector<char>&& buffer); // NOLINT
|
||||
void OnEnd();
|
||||
void OnError(int error);
|
||||
|
||||
protected:
|
||||
// URLRequestJob
|
||||
void Start() override;
|
||||
int ReadRawData(net::IOBuffer* buf, int buf_size) override;
|
||||
void DoneReading() override;
|
||||
void DoneReadingRedirectResponse() override;
|
||||
std::unique_ptr<net::SourceStream> SetUpSourceStream() override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
int GetResponseCode() const override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
|
||||
void Kill() override;
|
||||
|
||||
private:
|
||||
int BufferCopy(std::vector<char>* source,
|
||||
net::IOBuffer* target,
|
||||
int target_size);
|
||||
|
||||
// Saved arguments passed to ReadRawData.
|
||||
scoped_refptr<net::IOBuffer> pending_buf_;
|
||||
int pending_buf_size_;
|
||||
|
||||
// Saved arguments passed to OnData.
|
||||
std::vector<char> write_buffer_;
|
||||
|
||||
bool ended_;
|
||||
base::TimeTicks request_start_time_;
|
||||
base::TimeTicks response_start_time_;
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers_;
|
||||
scoped_refptr<mate::StreamSubscriber> subscriber_;
|
||||
|
||||
base::WeakPtrFactory<URLRequestStreamJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestStreamJob);
|
||||
};
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_STREAM_JOB_H_
|
|
@ -1,117 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/net/url_request_string_job.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "shell/common/native_mate_converters/net_converter.h"
|
||||
#include "shell/common/native_mate_converters/v8_value_converter.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
void BeforeStartInUI(base::WeakPtr<URLRequestStringJob> job,
|
||||
mate::Arguments* args) {
|
||||
v8::Local<v8::Value> value;
|
||||
int error = net::OK;
|
||||
std::unique_ptr<base::Value> request_options = nullptr;
|
||||
|
||||
if (args->GetNext(&value)) {
|
||||
V8ValueConverter converter;
|
||||
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
|
||||
request_options = converter.FromV8Value(value, context);
|
||||
}
|
||||
|
||||
if (request_options) {
|
||||
JsAsker::IsErrorOptions(request_options.get(), &error);
|
||||
} else {
|
||||
error = net::ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
|
||||
base::BindOnce(&URLRequestStringJob::StartAsync, job,
|
||||
std::move(request_options), error));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestSimpleJob(request, network_delegate),
|
||||
weak_factory_(this) {}
|
||||
|
||||
URLRequestStringJob::~URLRequestStringJob() = default;
|
||||
|
||||
void URLRequestStringJob::Start() {
|
||||
auto request_details = std::make_unique<base::DictionaryValue>();
|
||||
FillRequestDetails(request_details.get(), request());
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
&JsAsker::AskForOptions, base::Unretained(isolate()), handler(),
|
||||
std::move(request_details),
|
||||
base::BindOnce(&BeforeStartInUI, weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
|
||||
void URLRequestStringJob::StartAsync(std::unique_ptr<base::Value> options,
|
||||
int error) {
|
||||
if (error != net::OK) {
|
||||
NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (options->is_dict()) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("mimeType", &mime_type_);
|
||||
dict->GetString("charset", &charset_);
|
||||
dict->GetString("data", &data_);
|
||||
} else if (options->is_string()) {
|
||||
data_ = options->GetString();
|
||||
}
|
||||
net::URLRequestSimpleJob::Start();
|
||||
}
|
||||
|
||||
void URLRequestStringJob::Kill() {
|
||||
weak_factory_.InvalidateWeakPtrs();
|
||||
net::URLRequestSimpleJob::Kill();
|
||||
}
|
||||
|
||||
void URLRequestStringJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
std::string status("HTTP/1.1 200 OK");
|
||||
auto* headers = new net::HttpResponseHeaders(status);
|
||||
|
||||
headers->AddHeader(kCORSHeader);
|
||||
|
||||
if (!mime_type_.empty()) {
|
||||
std::string content_type_header(net::HttpRequestHeaders::kContentType);
|
||||
content_type_header.append(": ");
|
||||
content_type_header.append(mime_type_);
|
||||
headers->AddHeader(content_type_header);
|
||||
}
|
||||
|
||||
info->headers = headers;
|
||||
}
|
||||
|
||||
int URLRequestStringJob::GetData(std::string* mime_type,
|
||||
std::string* charset,
|
||||
std::string* data,
|
||||
net::CompletionOnceCallback callback) const {
|
||||
*mime_type = mime_type_;
|
||||
*charset = charset_;
|
||||
*data = data_;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||
#define SHELL_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
#include "shell/browser/net/js_asker.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class URLRequestStringJob : public JsAsker, public net::URLRequestSimpleJob {
|
||||
public:
|
||||
URLRequestStringJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
~URLRequestStringJob() override;
|
||||
|
||||
void StartAsync(std::unique_ptr<base::Value> options, int error);
|
||||
|
||||
// URLRequestJob:
|
||||
void Start() override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
void Kill() override;
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
int GetData(std::string* mime_type,
|
||||
std::string* charset,
|
||||
std::string* data,
|
||||
net::CompletionOnceCallback callback) const override;
|
||||
|
||||
private:
|
||||
std::string mime_type_;
|
||||
std::string charset_;
|
||||
std::string data_;
|
||||
|
||||
base::WeakPtrFactory<URLRequestStringJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestStringJob);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
|
@ -10,7 +10,7 @@
|
|||
#include "base/callback.h"
|
||||
#include "base/memory/shared_memory_mapping.h"
|
||||
#include "components/viz/host/host_display_client.h"
|
||||
#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h"
|
||||
#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
|
|
@ -60,10 +60,9 @@ class BundledDataSource : public content::URLDataSource {
|
|||
// content::URLDataSource implementation.
|
||||
std::string GetSource() override { return kChromeUIDevToolsHost; }
|
||||
|
||||
void StartDataRequest(
|
||||
const std::string& path,
|
||||
const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
|
||||
const GotDataCallback& callback) override {
|
||||
void StartDataRequest(const std::string& path,
|
||||
const content::WebContents::Getter& wc_getter,
|
||||
const GotDataCallback& callback) override {
|
||||
// Serve request from local bundle.
|
||||
std::string bundled_path_prefix(kChromeUIDevToolsBundledPath);
|
||||
bundled_path_prefix += "/";
|
||||
|
|
|
@ -1,231 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/ui/webui/pdf_viewer_handler.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "content/public/browser/stream_handle.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_ui.h"
|
||||
#include "content/public/common/page_zoom.h"
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/webui/web_ui_util.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers,
|
||||
base::DictionaryValue* result) {
|
||||
if (!headers)
|
||||
return;
|
||||
|
||||
size_t iter = 0;
|
||||
std::string header_name;
|
||||
std::string header_value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
|
||||
base::Value* existing_value = nullptr;
|
||||
if (result->Get(header_name, &existing_value)) {
|
||||
std::string src = existing_value->GetString();
|
||||
result->SetString(header_name, src + ", " + header_value);
|
||||
} else {
|
||||
result->SetString(header_name, header_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateStreamInfo(base::DictionaryValue* stream_info,
|
||||
content::StreamInfo* stream,
|
||||
const std::string& original_url) {
|
||||
auto headers_dict = std::make_unique<base::DictionaryValue>();
|
||||
auto stream_url = stream->handle->GetURL().spec();
|
||||
CreateResponseHeadersDictionary(stream->response_headers.get(),
|
||||
headers_dict.get());
|
||||
stream_info->SetString("streamURL", stream_url);
|
||||
stream_info->SetString("originalURL", original_url);
|
||||
stream_info->Set("responseHeaders", std::move(headers_dict));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PdfViewerHandler::PdfViewerHandler(const std::string& src)
|
||||
: original_url_(src) {}
|
||||
|
||||
PdfViewerHandler::~PdfViewerHandler() {
|
||||
RemoveObserver();
|
||||
}
|
||||
|
||||
void PdfViewerHandler::SetPdfResourceStream(content::StreamInfo* stream) {
|
||||
stream_ = stream;
|
||||
if (!!initialize_callback_id_.get()) {
|
||||
auto list = std::make_unique<base::ListValue>();
|
||||
list->Set(0, std::move(initialize_callback_id_));
|
||||
Initialize(list.get());
|
||||
}
|
||||
}
|
||||
|
||||
void PdfViewerHandler::RegisterMessages() {
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"initialize", base::BindRepeating(&PdfViewerHandler::Initialize,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"getDefaultZoom", base::BindRepeating(&PdfViewerHandler::GetInitialZoom,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"getInitialZoom", base::BindRepeating(&PdfViewerHandler::GetInitialZoom,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"setZoom",
|
||||
base::BindRepeating(&PdfViewerHandler::SetZoom, base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"getStrings", base::BindRepeating(&PdfViewerHandler::GetStrings,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"reload",
|
||||
base::BindRepeating(&PdfViewerHandler::Reload, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::OnJavascriptAllowed() {
|
||||
AddObserver();
|
||||
}
|
||||
|
||||
void PdfViewerHandler::OnJavascriptDisallowed() {
|
||||
RemoveObserver();
|
||||
}
|
||||
|
||||
void PdfViewerHandler::Initialize(const base::ListValue* args) {
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
if (stream_) {
|
||||
CHECK(!initialize_callback_id_.get());
|
||||
AllowJavascript();
|
||||
|
||||
auto stream_info = std::make_unique<base::DictionaryValue>();
|
||||
PopulateStreamInfo(stream_info.get(), stream_, original_url_);
|
||||
ResolveJavascriptCallback(*callback_id, *stream_info);
|
||||
} else {
|
||||
initialize_callback_id_ =
|
||||
base::Value::ToUniquePtrValue(callback_id.Clone());
|
||||
}
|
||||
|
||||
auto zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(web_ui()->GetWebContents());
|
||||
zoom_controller->SetZoomMode(WebContentsZoomController::ZoomMode::MANUAL);
|
||||
zoom_controller->SetZoomLevel(0);
|
||||
}
|
||||
|
||||
void PdfViewerHandler::GetDefaultZoom(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
auto zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(web_ui()->GetWebContents());
|
||||
double zoom_level = zoom_controller->GetDefaultZoomLevel();
|
||||
ResolveJavascriptCallback(
|
||||
*callback_id, base::Value(content::ZoomLevelToZoomFactor(zoom_level)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::GetInitialZoom(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
auto zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(web_ui()->GetWebContents());
|
||||
double zoom_level = zoom_controller->GetZoomLevel();
|
||||
ResolveJavascriptCallback(
|
||||
*callback_id, base::Value(content::ZoomLevelToZoomFactor(zoom_level)));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::SetZoom(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(2U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
double zoom_level = 0.0;
|
||||
CHECK(args->GetDouble(1, &zoom_level));
|
||||
|
||||
auto zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(web_ui()->GetWebContents());
|
||||
zoom_controller->SetZoomLevel(zoom_level);
|
||||
ResolveJavascriptCallback(*callback_id, base::Value(zoom_level));
|
||||
}
|
||||
|
||||
void PdfViewerHandler::GetStrings(const base::ListValue* args) {
|
||||
if (!IsJavascriptAllowed())
|
||||
return;
|
||||
CHECK_EQ(1U, args->GetSize());
|
||||
const base::Value* callback_id;
|
||||
CHECK(args->Get(0, &callback_id));
|
||||
|
||||
auto result = std::make_unique<base::DictionaryValue>();
|
||||
// TODO(deepak1556): Generate strings from components/pdf_strings.grdp.
|
||||
#define SET_STRING(id, resource) result->SetString(id, resource)
|
||||
SET_STRING("passwordPrompt",
|
||||
"This document is password protected. Please enter a password.");
|
||||
SET_STRING("passwordSubmit", "Submit");
|
||||
SET_STRING("passwordInvalid", "Incorrect password");
|
||||
SET_STRING("pageLoading", "Loading...");
|
||||
SET_STRING("pageLoadFailed", "Failed to load PDF document");
|
||||
SET_STRING("pageReload", "Reload");
|
||||
SET_STRING("bookmarks", "Bookmarks");
|
||||
SET_STRING("labelPageNumber", "Page number");
|
||||
SET_STRING("tooltipRotateCW", "Rotate clockwise");
|
||||
SET_STRING("tooltipDownload", "Download");
|
||||
SET_STRING("tooltipFitToPage", "Fit to page");
|
||||
SET_STRING("tooltipFitToWidth", "Fit to width");
|
||||
SET_STRING("tooltipZoomIn", "Zoom in");
|
||||
SET_STRING("tooltipZoomOut", "Zoom out");
|
||||
#undef SET_STRING
|
||||
|
||||
webui::SetLoadTimeDataDefaults(g_browser_process->GetApplicationLocale(),
|
||||
result.get());
|
||||
ResolveJavascriptCallback(*callback_id, *result);
|
||||
}
|
||||
|
||||
void PdfViewerHandler::Reload(const base::ListValue* args) {
|
||||
CHECK_EQ(0U, args->GetSize());
|
||||
web_ui()->GetWebContents()->ReloadFocusedFrame(false);
|
||||
}
|
||||
|
||||
void PdfViewerHandler::OnZoomLevelChanged(content::WebContents* web_contents,
|
||||
double level,
|
||||
bool is_temporary) {
|
||||
if (web_ui()->GetWebContents() == web_contents) {
|
||||
CallJavascriptFunction("cr.webUIListenerCallback",
|
||||
base::Value("onZoomLevelChanged"),
|
||||
base::Value(content::ZoomLevelToZoomFactor(level)));
|
||||
}
|
||||
}
|
||||
|
||||
void PdfViewerHandler::AddObserver() {
|
||||
auto zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(web_ui()->GetWebContents());
|
||||
zoom_controller->AddObserver(this);
|
||||
}
|
||||
|
||||
void PdfViewerHandler::RemoveObserver() {
|
||||
auto zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(web_ui()->GetWebContents());
|
||||
zoom_controller->RemoveObserver(this);
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_UI_WEBUI_PDF_VIEWER_HANDLER_H_
|
||||
#define SHELL_BROWSER_UI_WEBUI_PDF_VIEWER_HANDLER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "content/public/browser/host_zoom_map.h"
|
||||
#include "content/public/browser/web_ui_message_handler.h"
|
||||
#include "shell/browser/web_contents_zoom_controller.h"
|
||||
|
||||
namespace base {
|
||||
class ListValue;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
struct StreamInfo;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
class PdfViewerHandler : public content::WebUIMessageHandler,
|
||||
public WebContentsZoomController::Observer {
|
||||
public:
|
||||
explicit PdfViewerHandler(const std::string& original_url);
|
||||
~PdfViewerHandler() override;
|
||||
|
||||
void SetPdfResourceStream(content::StreamInfo* stream);
|
||||
|
||||
protected:
|
||||
// WebUIMessageHandler implementation.
|
||||
void RegisterMessages() override;
|
||||
void OnJavascriptAllowed() override;
|
||||
void OnJavascriptDisallowed() override;
|
||||
|
||||
private:
|
||||
void Initialize(const base::ListValue* args);
|
||||
void GetDefaultZoom(const base::ListValue* args);
|
||||
void GetInitialZoom(const base::ListValue* args);
|
||||
void SetZoom(const base::ListValue* args);
|
||||
void GetStrings(const base::ListValue* args);
|
||||
void Reload(const base::ListValue* args);
|
||||
void OnZoomLevelChanged(content::WebContents* web_contents,
|
||||
double level,
|
||||
bool is_temporary);
|
||||
void AddObserver();
|
||||
void RemoveObserver();
|
||||
std::unique_ptr<base::Value> initialize_callback_id_;
|
||||
content::StreamInfo* stream_ = nullptr;
|
||||
std::string original_url_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PdfViewerHandler);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_UI_WEBUI_PDF_VIEWER_HANDLER_H_
|
|
@ -1,258 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/ui/webui/pdf_viewer_ui.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "base/sequenced_task_runner_helpers.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/browser/loader/resource_dispatcher_host_impl.h"
|
||||
#include "content/browser/loader/resource_request_info_impl.h"
|
||||
#include "content/browser/loader/stream_resource_handler.h"
|
||||
#include "content/browser/resource_context_impl.h"
|
||||
#include "content/browser/streams/stream.h"
|
||||
#include "content/browser/streams/stream_context.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "content/public/browser/stream_handle.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "content/public/browser/url_data_source.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "grit/pdf_viewer_resources_map.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "services/network/public/cpp/resource_response.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/loader/layered_resource_handler.h"
|
||||
#include "shell/browser/ui/webui/pdf_viewer_handler.h"
|
||||
#include "shell/common/atom_constants.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
||||
// Extracts the path value from the URL without the leading '/',
|
||||
// which follows the mapping of names in pdf_viewer_resources_map.
|
||||
std::string PathWithoutParams(const std::string& path) {
|
||||
return GURL(kPdfViewerUIOrigin + path).path().substr(1);
|
||||
}
|
||||
|
||||
class BundledDataSource : public content::URLDataSource {
|
||||
public:
|
||||
BundledDataSource() {
|
||||
for (size_t i = 0; i < kPdfViewerResourcesSize; ++i) {
|
||||
std::string resource_path = kPdfViewerResources[i].name;
|
||||
DCHECK(path_to_resource_id_.find(resource_path) ==
|
||||
path_to_resource_id_.end());
|
||||
path_to_resource_id_[resource_path] = kPdfViewerResources[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
// content::URLDataSource implementation.
|
||||
std::string GetSource() const override { return kPdfViewerUIHost; }
|
||||
|
||||
void StartDataRequest(
|
||||
const std::string& path,
|
||||
const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
|
||||
const GotDataCallback& callback) override {
|
||||
std::string filename = PathWithoutParams(path);
|
||||
auto entry = path_to_resource_id_.find(filename);
|
||||
|
||||
if (entry != path_to_resource_id_.end()) {
|
||||
int resource_id = entry->second;
|
||||
const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
||||
callback.Run(rb.LoadDataResourceBytes(resource_id));
|
||||
} else {
|
||||
LOG(ERROR) << "Unable to find: " << path;
|
||||
callback.Run(new base::RefCountedString());
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetMimeType(const std::string& path) const override {
|
||||
base::FilePath::StringType ext =
|
||||
base::FilePath::FromUTF8Unsafe(PathWithoutParams(path)).Extension();
|
||||
std::string mime_type;
|
||||
if (!ext.empty() &&
|
||||
net::GetWellKnownMimeTypeFromExtension(ext.substr(1), &mime_type))
|
||||
return mime_type;
|
||||
return "text/html";
|
||||
}
|
||||
|
||||
bool ShouldAddContentSecurityPolicy() const override { return false; }
|
||||
|
||||
bool ShouldDenyXFrameOptions() const override { return false; }
|
||||
|
||||
bool ShouldServeMimeTypeAsContentTypeHeader() const override { return true; }
|
||||
|
||||
private:
|
||||
~BundledDataSource() override {}
|
||||
|
||||
// A map from a resource path to the resource ID.
|
||||
std::map<std::string, int> path_to_resource_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BundledDataSource);
|
||||
};
|
||||
|
||||
// Helper to convert from OnceCallback to Callback.
|
||||
template <typename T>
|
||||
void CallMigrationCallback(T callback,
|
||||
std::unique_ptr<content::StreamInfo> stream_info) {
|
||||
std::move(callback).Run(std::move(stream_info));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class PdfViewerUI::ResourceRequester
|
||||
: public base::RefCountedThreadSafe<ResourceRequester,
|
||||
BrowserThread::DeleteOnIOThread>,
|
||||
public electron::LayeredResourceHandler::Delegate {
|
||||
public:
|
||||
explicit ResourceRequester(StreamResponseCallback cb)
|
||||
: stream_response_cb_(std::move(cb)) {}
|
||||
|
||||
void StartRequest(const GURL& url,
|
||||
const GURL& origin,
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
int render_frame_id,
|
||||
content::ResourceContext* resource_context) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
const net::URLRequestContext* request_context =
|
||||
resource_context->GetRequestContext();
|
||||
std::unique_ptr<net::URLRequest> request(request_context->CreateRequest(
|
||||
url, net::DEFAULT_PRIORITY, nullptr, MISSING_TRAFFIC_ANNOTATION));
|
||||
request->set_method("GET");
|
||||
|
||||
content::ResourceDispatcherHostImpl::Get()->InitializeURLRequest(
|
||||
request.get(), content::Referrer(url, blink::kWebReferrerPolicyDefault),
|
||||
false, // download.
|
||||
render_process_id, render_view_id, render_frame_id,
|
||||
content::PREVIEWS_OFF, resource_context);
|
||||
|
||||
content::ResourceRequestInfoImpl* info =
|
||||
content::ResourceRequestInfoImpl::ForRequest(request.get());
|
||||
content::StreamContext* stream_context =
|
||||
content::GetStreamContextForResourceContext(resource_context);
|
||||
|
||||
std::unique_ptr<content::ResourceHandler> handler =
|
||||
std::make_unique<content::StreamResourceHandler>(
|
||||
request.get(), stream_context->registry(), origin, false);
|
||||
info->set_is_stream(true);
|
||||
stream_info_.reset(new content::StreamInfo);
|
||||
stream_info_->handle =
|
||||
static_cast<content::StreamResourceHandler*>(handler.get())
|
||||
->stream()
|
||||
->CreateHandle();
|
||||
stream_info_->original_url = request->url();
|
||||
|
||||
// Helper to fill stream response details.
|
||||
handler.reset(new electron::LayeredResourceHandler(
|
||||
request.get(), std::move(handler), this));
|
||||
|
||||
content::ResourceDispatcherHostImpl::Get()->BeginURLRequest(
|
||||
std::move(request), std::move(handler),
|
||||
false, // download
|
||||
false, // content_initiated (download specific)
|
||||
false, // do_not_prompt_for_login (download specific)
|
||||
resource_context);
|
||||
}
|
||||
|
||||
protected:
|
||||
// electron::LayeredResourceHandler::Delegate:
|
||||
void OnResponseStarted(network::ResourceResponse* response) override {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
auto resource_response_head = response->head;
|
||||
auto headers = resource_response_head.headers;
|
||||
auto mime_type = resource_response_head.mime_type;
|
||||
if (headers.get())
|
||||
stream_info_->response_headers =
|
||||
new net::HttpResponseHeaders(headers->raw_headers());
|
||||
stream_info_->mime_type = mime_type;
|
||||
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::UI},
|
||||
base::BindOnce(&CallMigrationCallback<StreamResponseCallback>,
|
||||
base::Passed(&stream_response_cb_),
|
||||
base::Passed(&stream_info_)));
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
|
||||
friend class base::DeleteHelper<ResourceRequester>;
|
||||
~ResourceRequester() override {}
|
||||
|
||||
StreamResponseCallback stream_response_cb_;
|
||||
std::unique_ptr<content::StreamInfo> stream_info_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResourceRequester);
|
||||
};
|
||||
|
||||
PdfViewerUI::PdfViewerUI(content::BrowserContext* browser_context,
|
||||
content::WebUI* web_ui,
|
||||
const std::string& src)
|
||||
: content::WebUIController(web_ui),
|
||||
content::WebContentsObserver(web_ui->GetWebContents()),
|
||||
src_(src) {
|
||||
pdf_handler_ = new PdfViewerHandler(src);
|
||||
web_ui->AddMessageHandler(
|
||||
std::unique_ptr<content::WebUIMessageHandler>(pdf_handler_));
|
||||
content::URLDataSource::Add(browser_context, new BundledDataSource);
|
||||
}
|
||||
|
||||
PdfViewerUI::~PdfViewerUI() {}
|
||||
|
||||
bool PdfViewerUI::OnMessageReceived(
|
||||
const IPC::Message& message,
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(PdfViewerUI, message)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
return handled;
|
||||
}
|
||||
|
||||
void PdfViewerUI::OnPdfStreamCreated(
|
||||
std::unique_ptr<content::StreamInfo> stream) {
|
||||
stream_ = std::move(stream);
|
||||
if (pdf_handler_)
|
||||
pdf_handler_->SetPdfResourceStream(stream_.get());
|
||||
resource_requester_ = nullptr;
|
||||
}
|
||||
|
||||
void PdfViewerUI::RenderFrameCreated(content::RenderFrameHost* rfh) {
|
||||
int render_process_id = rfh->GetProcess()->GetID();
|
||||
int render_frame_id = rfh->GetRoutingID();
|
||||
int render_view_id = rfh->GetRenderViewHost()->GetRoutingID();
|
||||
auto resource_context =
|
||||
web_contents()->GetBrowserContext()->GetResourceContext();
|
||||
auto callback =
|
||||
base::BindOnce(&PdfViewerUI::OnPdfStreamCreated, base::Unretained(this));
|
||||
resource_requester_ = new ResourceRequester(std::move(callback));
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(&ResourceRequester::StartRequest, resource_requester_,
|
||||
GURL(src_), GURL(kPdfViewerUIOrigin), render_process_id,
|
||||
render_view_id, render_frame_id, resource_context));
|
||||
}
|
||||
|
||||
void PdfViewerUI::OnSaveURLAs(const GURL& url,
|
||||
const content::Referrer& referrer) {
|
||||
web_contents()->SaveFrame(url, referrer);
|
||||
}
|
||||
|
||||
} // namespace electron
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_UI_WEBUI_PDF_VIEWER_UI_H_
|
||||
#define SHELL_BROWSER_UI_WEBUI_PDF_VIEWER_UI_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_ui_controller.h"
|
||||
#include "ipc/ipc_message.h"
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
struct StreamInfo;
|
||||
} // namespace content
|
||||
|
||||
namespace electron {
|
||||
|
||||
class PdfViewerHandler;
|
||||
|
||||
class PdfViewerUI : public content::WebUIController,
|
||||
public content::WebContentsObserver {
|
||||
public:
|
||||
PdfViewerUI(content::BrowserContext* browser_context,
|
||||
content::WebUI* web_ui,
|
||||
const std::string& src);
|
||||
~PdfViewerUI() override;
|
||||
|
||||
// content::WebContentsObserver:
|
||||
bool OnMessageReceived(const IPC::Message& message,
|
||||
content::RenderFrameHost* render_frame_host) override;
|
||||
void RenderFrameCreated(content::RenderFrameHost* rfh) override;
|
||||
|
||||
private:
|
||||
using StreamResponseCallback =
|
||||
base::OnceCallback<void(std::unique_ptr<content::StreamInfo>)>;
|
||||
class ResourceRequester;
|
||||
|
||||
void OnPdfStreamCreated(std::unique_ptr<content::StreamInfo> stream_info);
|
||||
void OnSaveURLAs(const GURL& url, const content::Referrer& referrer);
|
||||
|
||||
// Source URL from where the PDF originates.
|
||||
std::string src_;
|
||||
|
||||
PdfViewerHandler* pdf_handler_;
|
||||
|
||||
scoped_refptr<ResourceRequester> resource_requester_;
|
||||
|
||||
// Pdf Resource stream.
|
||||
std::unique_ptr<content::StreamInfo> stream_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PdfViewerUI);
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_UI_WEBUI_PDF_VIEWER_UI_H_
|
Loading…
Add table
Add a link
Reference in a new issue