Make api::Protocol thread safe

This commit is contained in:
Cheng Zhao 2016-06-15 21:11:42 +09:00
parent 659384383e
commit fe0e17d1c3
4 changed files with 94 additions and 62 deletions

View file

@ -13,7 +13,6 @@
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/arguments.h"
@ -45,17 +44,6 @@ class Protocol : public mate::TrackableObject<Protocol> {
protected:
Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context);
AtomURLRequestJobFactory* job_factory() const {
request_context_getter_->GetURLRequestContext(); // Force init.
return static_cast<AtomURLRequestJobFactory*>(
static_cast<brightray::URLRequestContextGetter*>(
request_context_getter_.get())->job_factory());
}
base::WeakPtr<Protocol> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
// Possible errors.
enum ProtocolError {
@ -86,13 +74,13 @@ class Protocol : public mate::TrackableObject<Protocol> {
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override {
RequestJob* request_job = new RequestJob(request, network_delegate);
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
request_job->SetHandlerInfo(isolate_, request_context_.get(), handler_);
return request_job;
}
private:
v8::Isolate* isolate_;
net::URLRequestContextGetter* request_context_;
scoped_refptr<net::URLRequestContextGetter> request_context_;
Protocol::Handler handler_;
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
@ -111,19 +99,24 @@ class Protocol : public mate::TrackableObject<Protocol> {
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::RegisterProtocolInIO<RequestJob>,
base::Unretained(this), scheme, handler),
request_context_getter_, isolate(), scheme, handler),
base::Bind(&Protocol::OnIOCompleted,
GetWeakPtr(), callback));
}
template<typename RequestJob>
ProtocolError RegisterProtocolInIO(const std::string& scheme,
const Handler& handler) {
if (job_factory()->IsHandledProtocol(scheme))
static ProtocolError RegisterProtocolInIO(
scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
v8::Isolate* isolate,
const std::string& scheme,
const Handler& handler) {
auto job_factory = static_cast<AtomURLRequestJobFactory*>(
request_context_getter->job_factory());
if (job_factory->IsHandledProtocol(scheme))
return PROTOCOL_REGISTERED;
std::unique_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
new CustomProtocolHandler<RequestJob>(
isolate(), request_context_getter_.get(), handler));
if (job_factory()->SetProtocolHandler(scheme, std::move(protocol_handler)))
isolate, request_context_getter.get(), handler));
if (job_factory->SetProtocolHandler(scheme, std::move(protocol_handler)))
return PROTOCOL_OK;
else
return PROTOCOL_FAIL;
@ -131,12 +124,16 @@ class Protocol : public mate::TrackableObject<Protocol> {
// Unregister the protocol handler that handles |scheme|.
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
ProtocolError UnregisterProtocolInIO(const std::string& scheme);
static ProtocolError UnregisterProtocolInIO(
scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
const std::string& scheme);
// Whether the protocol has handler registered.
void IsProtocolHandled(const std::string& scheme,
const BooleanCallback& callback);
bool IsProtocolHandledInIO(const std::string& scheme);
static bool IsProtocolHandledInIO(
scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
const std::string& scheme);
// Replace the protocol handler with a new one.
template<typename RequestJob>
@ -148,32 +145,36 @@ class Protocol : public mate::TrackableObject<Protocol> {
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::InterceptProtocolInIO<RequestJob>,
base::Unretained(this), scheme, handler),
request_context_getter_, isolate(), scheme, handler),
base::Bind(&Protocol::OnIOCompleted,
GetWeakPtr(), callback));
}
template<typename RequestJob>
ProtocolError InterceptProtocolInIO(const std::string& scheme,
const Handler& handler) {
if (!job_factory()->IsHandledProtocol(scheme))
static ProtocolError InterceptProtocolInIO(
scoped_refptr<brightray::URLRequestContextGetter> request_context_getter,
v8::Isolate* isolate,
const std::string& scheme,
const Handler& handler) {
auto job_factory = static_cast<AtomURLRequestJobFactory*>(
request_context_getter->job_factory());
if (!job_factory->IsHandledProtocol(scheme))
return PROTOCOL_NOT_REGISTERED;
// It is possible a protocol is handled but can not be intercepted.
if (!job_factory()->HasProtocolHandler(scheme))
if (!job_factory->HasProtocolHandler(scheme))
return PROTOCOL_FAIL;
if (ContainsKey(original_protocols_, scheme))
return PROTOCOL_INTERCEPTED;
std::unique_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
new CustomProtocolHandler<RequestJob>(
isolate(), request_context_getter_.get(), handler));
original_protocols_.set(
scheme,
job_factory()->ReplaceProtocol(scheme, std::move(protocol_handler)));
isolate, request_context_getter.get(), handler));
if (!job_factory->InterceptProtocol(scheme, std::move(protocol_handler)))
return PROTOCOL_INTERCEPTED;
return PROTOCOL_OK;
}
// Restore the |scheme| to its original protocol handler.
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
ProtocolError UninterceptProtocolInIO(const std::string& scheme);
static ProtocolError UninterceptProtocolInIO(
scoped_refptr<brightray::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);
@ -181,14 +182,13 @@ class Protocol : public mate::TrackableObject<Protocol> {
// Convert error code to string.
std::string ErrorCodeToString(ProtocolError error);
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
AtomURLRequestJobFactory* GetJobFactoryInIO() const;
// Map that stores the original protocols of schemes.
using OriginalProtocolsMap = base::ScopedPtrHashMap<
std::string,
std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>>;
OriginalProtocolsMap original_protocols_;
base::WeakPtr<Protocol> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
scoped_refptr<brightray::URLRequestContextGetter> request_context_getter_;
base::WeakPtrFactory<Protocol> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Protocol);