Simplify protocol api.
This commit is contained in:
parent
dd6caba082
commit
a13c29f0e6
4 changed files with 243 additions and 265 deletions
|
@ -9,142 +9,111 @@
|
||||||
#include "atom/browser/net/adapter_request_job.h"
|
#include "atom/browser/net/adapter_request_job.h"
|
||||||
#include "atom/browser/net/atom_url_request_context_getter.h"
|
#include "atom/browser/net/atom_url_request_context_getter.h"
|
||||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||||
#include "atom/common/v8/native_type_conversions.h"
|
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||||
|
#include "atom/common/native_mate_converters/function_converter.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "native_mate/dictionary.h"
|
||||||
#include "net/url_request/url_request_context.h"
|
#include "net/url_request/url_request_context.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
|
||||||
|
using content::BrowserThread;
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<const net::URLRequest*> {
|
||||||
|
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
const net::URLRequest* val) {
|
||||||
|
return mate::ObjectTemplateBuilder(isolate)
|
||||||
|
.SetValue("method", val->method())
|
||||||
|
.SetValue("url", val->url().spec())
|
||||||
|
.SetValue("referrer", val->referrer())
|
||||||
|
.Build()->NewInstance();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// The protocol module object.
|
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||||
ScopedPersistent<v8::Object> g_protocol_object;
|
|
||||||
|
|
||||||
// Registered protocol handlers.
|
|
||||||
typedef std::map<std::string, RefCountedV8Function> HandlersMap;
|
|
||||||
static HandlersMap g_handlers;
|
|
||||||
|
|
||||||
static const char* kEarlyUseProtocolError = "This method can only be used"
|
|
||||||
"after the application has finished launching.";
|
|
||||||
|
|
||||||
// Emit an event for the protocol module.
|
|
||||||
void EmitEventInUI(const std::string& event, const std::string& parameter) {
|
|
||||||
v8::Locker locker(node_isolate);
|
|
||||||
v8::HandleScope handle_scope(node_isolate);
|
|
||||||
|
|
||||||
v8::Handle<v8::Value> argv[] = {
|
|
||||||
ToV8Value(event),
|
|
||||||
ToV8Value(parameter),
|
|
||||||
};
|
|
||||||
node::MakeCallback(g_protocol_object.NewHandle(node_isolate),
|
|
||||||
"emit", 2, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the URLRequest object to V8 object.
|
|
||||||
v8::Handle<v8::Object> ConvertURLRequestToV8Object(
|
|
||||||
const net::URLRequest* request) {
|
|
||||||
v8::Local<v8::Object> obj = v8::Object::New();
|
|
||||||
obj->Set(ToV8Value("method"), ToV8Value(request->method()));
|
|
||||||
obj->Set(ToV8Value("url"), ToV8Value(request->url().spec()));
|
|
||||||
obj->Set(ToV8Value("referrer"), ToV8Value(request->referrer()));
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the job factory.
|
|
||||||
AtomURLRequestJobFactory* GetRequestJobFactory() {
|
|
||||||
return AtomBrowserContext::Get()->url_request_context_getter()->job_factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomProtocolRequestJob : public AdapterRequestJob {
|
class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||||
public:
|
public:
|
||||||
CustomProtocolRequestJob(ProtocolHandler* protocol_handler,
|
CustomProtocolRequestJob(Protocol* registry,
|
||||||
|
ProtocolHandler* protocol_handler,
|
||||||
net::URLRequest* request,
|
net::URLRequest* request,
|
||||||
net::NetworkDelegate* network_delegate)
|
net::NetworkDelegate* network_delegate)
|
||||||
: AdapterRequestJob(protocol_handler, request, network_delegate) {
|
: AdapterRequestJob(protocol_handler, request, network_delegate),
|
||||||
|
registry_(registry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdapterRequestJob:
|
// AdapterRequestJob:
|
||||||
virtual void GetJobTypeInUI() OVERRIDE {
|
virtual void GetJobTypeInUI() OVERRIDE {
|
||||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||||
|
|
||||||
v8::Locker locker(node_isolate);
|
v8::Locker locker(node_isolate);
|
||||||
v8::HandleScope handle_scope(node_isolate);
|
v8::HandleScope handle_scope(node_isolate);
|
||||||
|
|
||||||
// Call the JS handler.
|
// Call the JS handler.
|
||||||
v8::Handle<v8::Value> argv[] = {
|
Protocol::JsProtocolHandler callback =
|
||||||
ConvertURLRequestToV8Object(request()),
|
registry_->GetProtocolHandler(request()->url().scheme());
|
||||||
};
|
v8::Handle<v8::Value> result = callback.Run(request());
|
||||||
RefCountedV8Function callback = g_handlers[request()->url().scheme()];
|
|
||||||
v8::Handle<v8::Value> result = callback->NewHandle(node_isolate)->Call(
|
|
||||||
v8::Context::GetCurrent()->Global(), 1, argv);
|
|
||||||
|
|
||||||
// Determine the type of the job we are going to create.
|
// Determine the type of the job we are going to create.
|
||||||
if (result->IsString()) {
|
if (result->IsString()) {
|
||||||
std::string data = FromV8Value(result);
|
std::string data = mate::V8ToString(result);
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||||
GetWeakPtr(),
|
GetWeakPtr(), "text/plain", "UTF-8", data));
|
||||||
"text/plain",
|
|
||||||
"UTF-8",
|
|
||||||
data));
|
|
||||||
return;
|
return;
|
||||||
} else if (result->IsObject()) {
|
} else if (result->IsObject()) {
|
||||||
v8::Handle<v8::Object> obj = result->ToObject();
|
v8::Handle<v8::Object> obj = result->ToObject();
|
||||||
std::string name = FromV8Value(obj->GetConstructorName());
|
mate::Dictionary dict(node_isolate, obj);
|
||||||
|
std::string name = mate::V8ToString(obj->GetConstructorName());
|
||||||
if (name == "RequestStringJob") {
|
if (name == "RequestStringJob") {
|
||||||
std::string mime_type = FromV8Value(obj->Get(
|
std::string mime_type, charset, data;
|
||||||
v8::String::New("mimeType")));
|
dict.Get("mimeType", &mime_type);
|
||||||
std::string charset = FromV8Value(obj->Get(v8::String::New("charset")));
|
dict.Get("charset", &charset);
|
||||||
std::string data = FromV8Value(obj->Get(v8::String::New("data")));
|
dict.Get("data", &data);
|
||||||
|
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||||
GetWeakPtr(),
|
GetWeakPtr(), mime_type, charset, data));
|
||||||
mime_type,
|
|
||||||
charset,
|
|
||||||
data));
|
|
||||||
return;
|
return;
|
||||||
} else if (name == "RequestFileJob") {
|
} else if (name == "RequestFileJob") {
|
||||||
base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
|
base::FilePath path;
|
||||||
|
dict.Get("path", &path);
|
||||||
|
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
||||||
GetWeakPtr(),
|
GetWeakPtr(), path));
|
||||||
path));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try the default protocol handler if we have.
|
// Try the default protocol handler if we have.
|
||||||
if (default_protocol_handler()) {
|
if (default_protocol_handler()) {
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
||||||
GetWeakPtr()));
|
GetWeakPtr()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to the not implemented error.
|
// Fallback to the not implemented error.
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||||
content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||||
GetWeakPtr(),
|
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
|
||||||
net::ERR_NOT_IMPLEMENTED));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Always return the same CustomProtocolRequestJob for all requests, because
|
// Always return the same CustomProtocolRequestJob for all requests, because
|
||||||
|
@ -155,16 +124,16 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||||
// registered handler doesn't want to deal with the request.
|
// registered handler doesn't want to deal with the request.
|
||||||
class CustomProtocolHandler : public ProtocolHandler {
|
class CustomProtocolHandler : public ProtocolHandler {
|
||||||
public:
|
public:
|
||||||
explicit CustomProtocolHandler(ProtocolHandler* protocol_handler = NULL)
|
CustomProtocolHandler(api::Protocol* registry,
|
||||||
: protocol_handler_(protocol_handler) {
|
ProtocolHandler* protocol_handler = NULL)
|
||||||
|
: registry_(registry), protocol_handler_(protocol_handler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual net::URLRequestJob* MaybeCreateJob(
|
virtual net::URLRequestJob* MaybeCreateJob(
|
||||||
net::URLRequest* request,
|
net::URLRequest* request,
|
||||||
net::NetworkDelegate* network_delegate) const OVERRIDE {
|
net::NetworkDelegate* network_delegate) const OVERRIDE {
|
||||||
return new CustomProtocolRequestJob(protocol_handler_.get(),
|
return new CustomProtocolRequestJob(registry_, protocol_handler_.get(),
|
||||||
request,
|
request, network_delegate);
|
||||||
network_delegate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
||||||
|
@ -174,6 +143,7 @@ class CustomProtocolHandler : public ProtocolHandler {
|
||||||
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||||
scoped_ptr<ProtocolHandler> protocol_handler_;
|
scoped_ptr<ProtocolHandler> protocol_handler_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||||
|
@ -181,206 +151,182 @@ class CustomProtocolHandler : public ProtocolHandler {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// static
|
Protocol::Protocol() : job_factory_(
|
||||||
void Protocol::RegisterProtocol(
|
AtomBrowserContext::Get()->url_request_context_getter()->job_factory()) {
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
}
|
||||||
std::string scheme;
|
|
||||||
RefCountedV8Function callback;
|
|
||||||
if (!FromV8Arguments(args, &scheme, &callback))
|
|
||||||
return node::ThrowTypeError("Bad argument");
|
|
||||||
|
|
||||||
if (g_handlers.find(scheme) != g_handlers.end() ||
|
Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
|
||||||
GetRequestJobFactory()->IsHandledProtocol(scheme))
|
const std::string& scheme) {
|
||||||
|
return protocol_handlers_[scheme];
|
||||||
|
}
|
||||||
|
|
||||||
|
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
||||||
|
v8::Isolate* isolate) {
|
||||||
|
return mate::ObjectTemplateBuilder(isolate)
|
||||||
|
.SetMethod("registerProtocol",
|
||||||
|
base::Bind(&Protocol::RegisterProtocol,
|
||||||
|
base::Unretained(this)))
|
||||||
|
.SetMethod("unregisterProtocol",
|
||||||
|
base::Bind(&Protocol::UnregisterProtocol,
|
||||||
|
base::Unretained(this)))
|
||||||
|
.SetMethod("isHandledProtocol",
|
||||||
|
base::Bind(&Protocol::IsHandledProtocol,
|
||||||
|
base::Unretained(this)))
|
||||||
|
.SetMethod("interceptProtocol",
|
||||||
|
base::Bind(&Protocol::InterceptProtocol,
|
||||||
|
base::Unretained(this)))
|
||||||
|
.SetMethod("uninterceptProtocol",
|
||||||
|
base::Bind(&Protocol::UninterceptProtocol,
|
||||||
|
base::Unretained(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Protocol::RegisterProtocol(const std::string& scheme,
|
||||||
|
const JsProtocolHandler& callback) {
|
||||||
|
if (ContainsKey(protocol_handlers_, scheme) ||
|
||||||
|
job_factory_->IsHandledProtocol(scheme))
|
||||||
return node::ThrowError("The scheme is already registered");
|
return node::ThrowError("The scheme is already registered");
|
||||||
|
|
||||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
protocol_handlers_[scheme] = callback;
|
||||||
return node::ThrowError(kEarlyUseProtocolError);
|
BrowserThread::PostTask(BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
// Store the handler in a map.
|
base::Bind(&Protocol::RegisterProtocolInIO,
|
||||||
g_handlers[scheme] = callback;
|
base::Unretained(this), scheme));
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&RegisterProtocolInIO, scheme));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
void Protocol::UnregisterProtocol(const std::string& scheme) {
|
||||||
void Protocol::UnregisterProtocol(
|
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
if (it == protocol_handlers_.end())
|
||||||
std::string scheme;
|
|
||||||
if (!FromV8Arguments(args, &scheme))
|
|
||||||
return node::ThrowTypeError("Bad argument");
|
|
||||||
|
|
||||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
|
||||||
return node::ThrowError(kEarlyUseProtocolError);
|
|
||||||
|
|
||||||
// Erase the handler from map.
|
|
||||||
HandlersMap::iterator it(g_handlers.find(scheme));
|
|
||||||
if (it == g_handlers.end())
|
|
||||||
return node::ThrowError("The scheme has not been registered");
|
return node::ThrowError("The scheme has not been registered");
|
||||||
g_handlers.erase(it);
|
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
protocol_handlers_.erase(it);
|
||||||
FROM_HERE,
|
BrowserThread::PostTask(BrowserThread::IO,
|
||||||
base::Bind(&UnregisterProtocolInIO, scheme));
|
FROM_HERE,
|
||||||
|
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||||
|
base::Unretained(this), scheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
bool Protocol::IsHandledProtocol(const std::string& scheme) {
|
||||||
void Protocol::IsHandledProtocol(
|
return job_factory_->IsHandledProtocol(scheme);
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
||||||
std::string scheme;
|
|
||||||
if (!FromV8Arguments(args, &scheme))
|
|
||||||
return node::ThrowTypeError("Bad argument");
|
|
||||||
|
|
||||||
args.GetReturnValue().Set(GetRequestJobFactory()->IsHandledProtocol(scheme));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
void Protocol::InterceptProtocol(const std::string& scheme,
|
||||||
void Protocol::InterceptProtocol(
|
const JsProtocolHandler& callback) {
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
if (!job_factory_->HasProtocolHandler(scheme))
|
||||||
std::string scheme;
|
return node::ThrowError("Scheme does not exist.");
|
||||||
RefCountedV8Function callback;
|
|
||||||
if (!FromV8Arguments(args, &scheme, &callback))
|
|
||||||
return node::ThrowTypeError("Bad argument");
|
|
||||||
|
|
||||||
if (!GetRequestJobFactory()->HasProtocolHandler(scheme))
|
if (ContainsKey(protocol_handlers_, scheme))
|
||||||
return node::ThrowError("Cannot intercept procotol");
|
|
||||||
|
|
||||||
if (ContainsKey(g_handlers, scheme))
|
|
||||||
return node::ThrowError("Cannot intercept custom procotols");
|
return node::ThrowError("Cannot intercept custom procotols");
|
||||||
|
|
||||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
protocol_handlers_[scheme] = callback;
|
||||||
return node::ThrowError(kEarlyUseProtocolError);
|
BrowserThread::PostTask(BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
// Store the handler in a map.
|
base::Bind(&Protocol::InterceptProtocolInIO,
|
||||||
g_handlers[scheme] = callback;
|
base::Unretained(this), scheme));
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
|
||||||
FROM_HERE,
|
|
||||||
base::Bind(&InterceptProtocolInIO, scheme));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
void Protocol::UninterceptProtocol(const std::string& scheme) {
|
||||||
void Protocol::UninterceptProtocol(
|
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
if (it == protocol_handlers_.end())
|
||||||
std::string scheme;
|
|
||||||
if (!FromV8Arguments(args, &scheme))
|
|
||||||
return node::ThrowTypeError("Bad argument");
|
|
||||||
|
|
||||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
|
||||||
return node::ThrowError(kEarlyUseProtocolError);
|
|
||||||
|
|
||||||
// Erase the handler from map.
|
|
||||||
HandlersMap::iterator it(g_handlers.find(scheme));
|
|
||||||
if (it == g_handlers.end())
|
|
||||||
return node::ThrowError("The scheme has not been registered");
|
return node::ThrowError("The scheme has not been registered");
|
||||||
g_handlers.erase(it);
|
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
protocol_handlers_.erase(it);
|
||||||
FROM_HERE,
|
BrowserThread::PostTask(BrowserThread::IO,
|
||||||
base::Bind(&UninterceptProtocolInIO,
|
FROM_HERE,
|
||||||
scheme));
|
base::Bind(&Protocol::UninterceptProtocolInIO,
|
||||||
|
base::Unretained(this), scheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
|
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
|
||||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
|
||||||
job_factory->SetProtocolHandler(scheme, new CustomProtocolHandler);
|
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
|
||||||
FROM_HERE,
|
BrowserThread::PostTask(BrowserThread::UI,
|
||||||
base::Bind(&EmitEventInUI,
|
FROM_HERE,
|
||||||
"registered",
|
base::Bind(&Protocol::EmitEventInUI,
|
||||||
scheme));
|
base::Unretained(this),
|
||||||
|
"registered", scheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
|
||||||
job_factory->SetProtocolHandler(scheme, NULL);
|
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
job_factory_->SetProtocolHandler(scheme, NULL);
|
||||||
FROM_HERE,
|
BrowserThread::PostTask(BrowserThread::UI,
|
||||||
base::Bind(&EmitEventInUI,
|
FROM_HERE,
|
||||||
"unregistered",
|
base::Bind(&Protocol::EmitEventInUI,
|
||||||
scheme));
|
base::Unretained(this),
|
||||||
|
"unregistered", scheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
|
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
|
||||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
|
||||||
ProtocolHandler* original_handler = job_factory->GetProtocolHandler(scheme);
|
ProtocolHandler* original_handler = job_factory_->GetProtocolHandler(scheme);
|
||||||
if (original_handler == NULL) {
|
if (original_handler == NULL) {
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
||||||
content::BrowserThread::UI,
|
&Protocol::EmitEventInUI,
|
||||||
FROM_HERE,
|
base::Unretained(this),
|
||||||
base::Bind(&EmitEventInUI,
|
"error", "There is no protocol handler to intercpet"));
|
||||||
"error",
|
|
||||||
"There is no protocol handler to intercpet"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
job_factory->ReplaceProtocol(scheme,
|
job_factory_->ReplaceProtocol(
|
||||||
new CustomProtocolHandler(original_handler));
|
scheme, new CustomProtocolHandler(this, original_handler));
|
||||||
|
BrowserThread::PostTask(BrowserThread::UI,
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
FROM_HERE,
|
||||||
FROM_HERE,
|
base::Bind(&Protocol::EmitEventInUI,
|
||||||
base::Bind(&EmitEventInUI,
|
base::Unretained(this),
|
||||||
"intercepted",
|
"intercepted", scheme));
|
||||||
scheme));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
|
||||||
|
|
||||||
// Check if the protocol handler is intercepted.
|
|
||||||
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
||||||
job_factory->GetProtocolHandler(scheme));
|
job_factory_->GetProtocolHandler(scheme));
|
||||||
if (handler->original_handler() == NULL) {
|
if (handler->original_handler() == NULL) {
|
||||||
content::BrowserThread::PostTask(
|
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
||||||
content::BrowserThread::UI,
|
&Protocol::EmitEventInUI,
|
||||||
FROM_HERE,
|
base::Unretained(this),
|
||||||
base::Bind(&EmitEventInUI,
|
"error", "The protocol is not intercpeted"));
|
||||||
"error",
|
|
||||||
"The protocol is not intercpeted"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the protocol handler to the orignal one and delete current
|
// Reset the protocol handler to the orignal one and delete current protocol
|
||||||
// protocol handler.
|
// handler.
|
||||||
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
|
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
|
||||||
delete job_factory->ReplaceProtocol(scheme, original_handler);
|
delete job_factory_->ReplaceProtocol(scheme, original_handler);
|
||||||
|
BrowserThread::PostTask(BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&Protocol::EmitEventInUI,
|
||||||
|
base::Unretained(this),
|
||||||
|
"unintercepted", scheme));
|
||||||
|
}
|
||||||
|
|
||||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
void Protocol::EmitEventInUI(const std::string& event,
|
||||||
FROM_HERE,
|
const std::string& parameter) {
|
||||||
base::Bind(&EmitEventInUI,
|
base::ListValue args;
|
||||||
"unintercepted",
|
args.AppendString(parameter);
|
||||||
scheme));
|
Emit(event, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Protocol::Initialize(v8::Handle<v8::Object> target) {
|
mate::Handle<Protocol> Protocol::Create(v8::Isolate* isolate) {
|
||||||
// Remember the protocol object, used for emitting event later.
|
return CreateHandle(isolate, new Protocol);
|
||||||
g_protocol_object.reset(target);
|
|
||||||
|
|
||||||
// Make sure the job factory has been created.
|
|
||||||
AtomBrowserContext::Get()->url_request_context_getter()->
|
|
||||||
GetURLRequestContext();
|
|
||||||
|
|
||||||
NODE_SET_METHOD(target, "registerProtocol", RegisterProtocol);
|
|
||||||
NODE_SET_METHOD(target, "unregisterProtocol", UnregisterProtocol);
|
|
||||||
NODE_SET_METHOD(target, "isHandledProtocol", IsHandledProtocol);
|
|
||||||
NODE_SET_METHOD(target, "interceptProtocol", InterceptProtocol);
|
|
||||||
NODE_SET_METHOD(target, "uninterceptProtocol", UninterceptProtocol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
||||||
NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)
|
namespace {
|
||||||
|
|
||||||
|
void Initialize(v8::Handle<v8::Object> exports) {
|
||||||
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
mate::Dictionary dict(isolate, exports);
|
||||||
|
dict.Set("protocol", atom::api::Protocol::Create(isolate));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NODE_MODULE(atom_browser_protocol, Initialize)
|
||||||
|
|
|
@ -8,36 +8,68 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "atom/browser/api/event_emitter.h"
|
||||||
#include "v8/include/v8.h"
|
#include "base/callback.h"
|
||||||
|
#include "native_mate/handle.h"
|
||||||
|
|
||||||
|
namespace net {
|
||||||
|
class URLRequest;
|
||||||
|
}
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
|
class AtomURLRequestJobFactory;
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
class Protocol {
|
class Protocol : public mate::EventEmitter {
|
||||||
public:
|
public:
|
||||||
static void Initialize(v8::Handle<v8::Object> target);
|
typedef base::Callback<v8::Handle<v8::Value>(const net::URLRequest*)>
|
||||||
|
JsProtocolHandler;
|
||||||
|
|
||||||
|
static mate::Handle<Protocol> Create(v8::Isolate* isolate);
|
||||||
|
|
||||||
|
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Protocol();
|
||||||
|
|
||||||
|
// mate::Wrappable implementations:
|
||||||
|
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||||
|
v8::Isolate* isolate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void RegisterProtocol(const v8::FunctionCallbackInfo<v8::Value>& args);
|
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
|
||||||
static void UnregisterProtocol(
|
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
static void IsHandledProtocol(
|
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
||||||
|
|
||||||
static void InterceptProtocol(
|
// Register/unregister an networking |scheme| which would be handled by
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
// |callback|.
|
||||||
static void UninterceptProtocol(
|
void RegisterProtocol(const std::string& scheme,
|
||||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
const JsProtocolHandler& callback);
|
||||||
|
void UnregisterProtocol(const std::string& scheme);
|
||||||
|
|
||||||
static void RegisterProtocolInIO(const std::string& scheme);
|
// Returns whether a scheme has been registered.
|
||||||
static void UnregisterProtocolInIO(const std::string& scheme);
|
// FIXME Should accept a callback and be asynchronous so we do not have to use
|
||||||
|
// locks.
|
||||||
|
bool IsHandledProtocol(const std::string& scheme);
|
||||||
|
|
||||||
static void InterceptProtocolInIO(const std::string& scheme);
|
// Intercept/unintercept an existing protocol handler.
|
||||||
static void UninterceptProtocolInIO(const std::string& scheme);
|
void InterceptProtocol(const std::string& scheme,
|
||||||
|
const JsProtocolHandler& callback);
|
||||||
|
void UninterceptProtocol(const std::string& scheme);
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Protocol);
|
// The networking related operations have to be done in IO thread.
|
||||||
|
void RegisterProtocolInIO(const std::string& scheme);
|
||||||
|
void UnregisterProtocolInIO(const std::string& scheme);
|
||||||
|
void InterceptProtocolInIO(const std::string& scheme);
|
||||||
|
void UninterceptProtocolInIO(const std::string& scheme);
|
||||||
|
|
||||||
|
// Do protocol.emit(event, parameter) under UI thread.
|
||||||
|
void EmitEventInUI(const std::string& event, const std::string& parameter);
|
||||||
|
|
||||||
|
AtomURLRequestJobFactory* job_factory_;
|
||||||
|
ProtocolHandlersMap protocol_handlers_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Protocol);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
protocol = process.atomBinding 'protocol'
|
protocol = process.atomBinding('protocol').protocol
|
||||||
EventEmitter = require('events').EventEmitter
|
EventEmitter = require('events').EventEmitter
|
||||||
|
|
||||||
protocol[key] = value for key, value of EventEmitter.prototype
|
protocol.__proto__ = EventEmitter.prototype
|
||||||
|
|
||||||
protocol.RequestStringJob =
|
protocol.RequestStringJob =
|
||||||
class RequestStringJob
|
class RequestStringJob
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe 'protocol module', ->
|
||||||
describe 'protocol.registerProtocol', ->
|
describe 'protocol.registerProtocol', ->
|
||||||
it 'throws error when scheme is already registered', (done) ->
|
it 'throws error when scheme is already registered', (done) ->
|
||||||
register = -> protocol.registerProtocol('test1', ->)
|
register = -> protocol.registerProtocol('test1', ->)
|
||||||
protocol.once 'registered', (scheme) ->
|
protocol.once 'registered', (event, scheme) ->
|
||||||
assert.equal scheme, 'test1'
|
assert.equal scheme, 'test1'
|
||||||
assert.throws register, /The scheme is already registered/
|
assert.throws register, /The scheme is already registered/
|
||||||
protocol.unregisterProtocol 'test1'
|
protocol.unregisterProtocol 'test1'
|
||||||
|
@ -85,28 +85,28 @@ describe 'protocol module', ->
|
||||||
describe 'protocol.interceptProtocol', ->
|
describe 'protocol.interceptProtocol', ->
|
||||||
it 'throws error when scheme is not a registered one', ->
|
it 'throws error when scheme is not a registered one', ->
|
||||||
register = -> protocol.interceptProtocol('test-intercept', ->)
|
register = -> protocol.interceptProtocol('test-intercept', ->)
|
||||||
assert.throws register, /Cannot intercept procotol/
|
assert.throws register, /Scheme does not exist/
|
||||||
|
|
||||||
it 'throws error when scheme is a custom protocol', (done) ->
|
it 'throws error when scheme is a custom protocol', (done) ->
|
||||||
protocol.once 'unregistered', (scheme) ->
|
protocol.once 'unregistered', (event, scheme) ->
|
||||||
assert.equal scheme, 'atom'
|
assert.equal scheme, 'atom'
|
||||||
done()
|
done()
|
||||||
protocol.once 'registered', (scheme) ->
|
protocol.once 'registered', (event, scheme) ->
|
||||||
assert.equal scheme, 'atom'
|
assert.equal scheme, 'atom'
|
||||||
register = -> protocol.interceptProtocol('test-intercept', ->)
|
register = -> protocol.interceptProtocol('test-intercept', ->)
|
||||||
assert.throws register, /Cannot intercept procotol/
|
assert.throws register, /Scheme does not exist/
|
||||||
protocol.unregisterProtocol scheme
|
protocol.unregisterProtocol scheme
|
||||||
protocol.registerProtocol('atom', ->)
|
protocol.registerProtocol('atom', ->)
|
||||||
|
|
||||||
it 'returns original job when callback returns nothing', (done) ->
|
it 'returns original job when callback returns nothing', (done) ->
|
||||||
targetScheme = 'file'
|
targetScheme = 'file'
|
||||||
protocol.once 'intercepted', (scheme) ->
|
protocol.once 'intercepted', (event, scheme) ->
|
||||||
assert.equal scheme, targetScheme
|
assert.equal scheme, targetScheme
|
||||||
free = -> protocol.uninterceptProtocol targetScheme
|
free = -> protocol.uninterceptProtocol targetScheme
|
||||||
$.ajax
|
$.ajax
|
||||||
url: "#{targetScheme}://#{__filename}",
|
url: "#{targetScheme}://#{__filename}",
|
||||||
success: ->
|
success: ->
|
||||||
protocol.once 'unintercepted', (scheme) ->
|
protocol.once 'unintercepted', (event, scheme) ->
|
||||||
assert.equal scheme, targetScheme
|
assert.equal scheme, targetScheme
|
||||||
done()
|
done()
|
||||||
free()
|
free()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue