Simplify protocol api.

This commit is contained in:
Cheng Zhao 2014-04-21 16:33:32 +08:00
parent dd6caba082
commit a13c29f0e6
4 changed files with 243 additions and 265 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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()