Merge pull request #65 from atom/custom-protocol
Support custom protocols
This commit is contained in:
commit
3b7dd85d3f
25 changed files with 1184 additions and 24 deletions
9
atom.gyp
9
atom.gyp
|
@ -19,6 +19,7 @@
|
||||||
'browser/api/lib/menu.coffee',
|
'browser/api/lib/menu.coffee',
|
||||||
'browser/api/lib/menu-item.coffee',
|
'browser/api/lib/menu-item.coffee',
|
||||||
'browser/api/lib/power-monitor.coffee',
|
'browser/api/lib/power-monitor.coffee',
|
||||||
|
'browser/api/lib/protocol.coffee',
|
||||||
'browser/atom/atom.coffee',
|
'browser/atom/atom.coffee',
|
||||||
'browser/atom/objects-registry.coffee',
|
'browser/atom/objects-registry.coffee',
|
||||||
'browser/atom/rpc-server.coffee',
|
'browser/atom/rpc-server.coffee',
|
||||||
|
@ -54,6 +55,8 @@
|
||||||
'browser/api/atom_api_menu_win.h',
|
'browser/api/atom_api_menu_win.h',
|
||||||
'browser/api/atom_api_power_monitor.cc',
|
'browser/api/atom_api_power_monitor.cc',
|
||||||
'browser/api/atom_api_power_monitor.h',
|
'browser/api/atom_api_power_monitor.h',
|
||||||
|
'browser/api/atom_api_protocol.cc',
|
||||||
|
'browser/api/atom_api_protocol.h',
|
||||||
'browser/api/atom_api_window.cc',
|
'browser/api/atom_api_window.cc',
|
||||||
'browser/api/atom_api_window.h',
|
'browser/api/atom_api_window.h',
|
||||||
'browser/api/atom_browser_bindings.cc',
|
'browser/api/atom_browser_bindings.cc',
|
||||||
|
@ -94,6 +97,12 @@
|
||||||
'browser/native_window_win.cc',
|
'browser/native_window_win.cc',
|
||||||
'browser/native_window_win.h',
|
'browser/native_window_win.h',
|
||||||
'browser/native_window_observer.h',
|
'browser/native_window_observer.h',
|
||||||
|
'browser/net/adapter_request_job.cc',
|
||||||
|
'browser/net/adapter_request_job.h',
|
||||||
|
'browser/net/atom_url_request_job_factory.cc',
|
||||||
|
'browser/net/atom_url_request_job_factory.h',
|
||||||
|
'browser/net/url_request_string_job.cc',
|
||||||
|
'browser/net/url_request_string_job.h',
|
||||||
'browser/ui/accelerator_util.cc',
|
'browser/ui/accelerator_util.cc',
|
||||||
'browser/ui/accelerator_util.h',
|
'browser/ui/accelerator_util.h',
|
||||||
'browser/ui/accelerator_util_mac.mm',
|
'browser/ui/accelerator_util_mac.mm',
|
||||||
|
|
363
browser/api/atom_api_protocol.cc
Normal file
363
browser/api/atom_api_protocol.cc
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "browser/api/atom_api_protocol.h"
|
||||||
|
|
||||||
|
#include "base/stl_util.h"
|
||||||
|
#include "browser/atom_browser_context.h"
|
||||||
|
#include "browser/net/adapter_request_job.h"
|
||||||
|
#include "browser/net/atom_url_request_job_factory.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "net/url_request/url_request_context.h"
|
||||||
|
#include "net/url_request/url_request_context_getter.h"
|
||||||
|
#include "vendor/node/src/node.h"
|
||||||
|
#include "vendor/node/src/node_internals.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// The protocol module object.
|
||||||
|
v8::Persistent<v8::Object> g_protocol_object;
|
||||||
|
|
||||||
|
// Registered protocol handlers.
|
||||||
|
typedef std::map<std::string, v8::Persistent<v8::Function>> HandlersMap;
|
||||||
|
static HandlersMap g_handlers;
|
||||||
|
|
||||||
|
// Emit an event for the protocol module.
|
||||||
|
void EmitEventInUI(const std::string& event, const std::string& parameter) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
|
||||||
|
v8::Local<v8::Value> argv[] = {
|
||||||
|
v8::String::New(event.data(), event.size()),
|
||||||
|
v8::String::New(parameter.data(), parameter.size()),
|
||||||
|
};
|
||||||
|
node::MakeCallback(g_protocol_object, "emit", arraysize(argv), 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(v8::String::New("method"),
|
||||||
|
v8::String::New(request->method().c_str()));
|
||||||
|
obj->Set(v8::String::New("url"),
|
||||||
|
v8::String::New(request->url().spec().c_str()));
|
||||||
|
obj->Set(v8::String::New("referrer"),
|
||||||
|
v8::String::New(request->referrer().c_str()));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the job factory.
|
||||||
|
AtomURLRequestJobFactory* GetRequestJobFactory() {
|
||||||
|
return static_cast<AtomURLRequestJobFactory*>(
|
||||||
|
const_cast<net::URLRequestJobFactory*>(
|
||||||
|
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
|
||||||
|
GetRequestContext()->GetURLRequestContext()->job_factory()));
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||||
|
public:
|
||||||
|
CustomProtocolRequestJob(ProtocolHandler* protocol_handler,
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate)
|
||||||
|
: AdapterRequestJob(protocol_handler, request, network_delegate) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdapterRequestJob:
|
||||||
|
virtual void GetJobTypeInUI() OVERRIDE {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
||||||
|
|
||||||
|
// Call the JS handler.
|
||||||
|
v8::HandleScope scope;
|
||||||
|
v8::Handle<v8::Value> argv[] = {
|
||||||
|
ConvertURLRequestToV8Object(request()),
|
||||||
|
};
|
||||||
|
v8::Handle<v8::Value> result = g_handlers[request()->url().scheme()]->Call(
|
||||||
|
v8::Context::GetCurrent()->Global(), arraysize(argv), argv);
|
||||||
|
|
||||||
|
// Determine the type of the job we are going to create.
|
||||||
|
if (result->IsString()) {
|
||||||
|
std::string data = *v8::String::Utf8Value(result);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||||
|
GetWeakPtr(),
|
||||||
|
"text/plain",
|
||||||
|
"UTF-8",
|
||||||
|
data));
|
||||||
|
return;
|
||||||
|
} else if (result->IsObject()) {
|
||||||
|
v8::Handle<v8::Object> obj = result->ToObject();
|
||||||
|
std::string name = *v8::String::Utf8Value(obj->GetConstructorName());
|
||||||
|
if (name == "RequestStringJob") {
|
||||||
|
std::string mime_type = *v8::String::Utf8Value(obj->Get(
|
||||||
|
v8::String::New("mimeType")));
|
||||||
|
std::string charset = *v8::String::Utf8Value(obj->Get(
|
||||||
|
v8::String::New("charset")));
|
||||||
|
std::string data = *v8::String::Utf8Value(obj->Get(
|
||||||
|
v8::String::New("data")));
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||||
|
GetWeakPtr(),
|
||||||
|
mime_type,
|
||||||
|
charset,
|
||||||
|
data));
|
||||||
|
return;
|
||||||
|
} else if (name == "RequestFileJob") {
|
||||||
|
base::FilePath path = base::FilePath::FromUTF8Unsafe(
|
||||||
|
*v8::String::Utf8Value(obj->Get(v8::String::New("path"))));
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
||||||
|
GetWeakPtr(),
|
||||||
|
path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try the default protocol handler if we have.
|
||||||
|
if (default_protocol_handler()) {
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
||||||
|
GetWeakPtr()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to the not implemented error.
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||||
|
GetWeakPtr(),
|
||||||
|
net::ERR_NOT_IMPLEMENTED));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Always return the same CustomProtocolRequestJob for all requests, because
|
||||||
|
// the content API needs the ProtocolHandler to return a job immediately, and
|
||||||
|
// getting the real job from the JS requires asynchronous calls, so we have
|
||||||
|
// to create an adapter job first.
|
||||||
|
// Users can also pass an extra ProtocolHandler as the fallback one when
|
||||||
|
// registered handler doesn't want to deal with the request.
|
||||||
|
class CustomProtocolHandler : public ProtocolHandler {
|
||||||
|
public:
|
||||||
|
explicit CustomProtocolHandler(ProtocolHandler* protocol_handler = NULL)
|
||||||
|
: protocol_handler_(protocol_handler) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual net::URLRequestJob* MaybeCreateJob(
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate) const OVERRIDE {
|
||||||
|
return new CustomProtocolRequestJob(protocol_handler_.get(),
|
||||||
|
request,
|
||||||
|
network_delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
||||||
|
return protocol_handler_.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
scoped_ptr<ProtocolHandler> protocol_handler_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// static
|
||||||
|
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
|
||||||
|
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||||
|
if (g_handlers.find(scheme) != g_handlers.end() ||
|
||||||
|
net::URLRequest::IsHandledProtocol(scheme))
|
||||||
|
return node::ThrowError("The scheme is already registered");
|
||||||
|
|
||||||
|
// Store the handler in a map.
|
||||||
|
if (!args[1]->IsFunction())
|
||||||
|
return node::ThrowError("Handler must be a function");
|
||||||
|
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
|
||||||
|
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&RegisterProtocolInIO, scheme));
|
||||||
|
|
||||||
|
return v8::Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
|
||||||
|
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
g_handlers.erase(it);
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&UnregisterProtocolInIO, scheme));
|
||||||
|
|
||||||
|
return v8::Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
v8::Handle<v8::Value> Protocol::IsHandledProtocol(const v8::Arguments& args) {
|
||||||
|
return v8::Boolean::New(net::URLRequest::IsHandledProtocol(
|
||||||
|
*v8::String::Utf8Value(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
|
||||||
|
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||||
|
if (!GetRequestJobFactory()->HasProtocolHandler(scheme))
|
||||||
|
return node::ThrowError("Cannot intercept procotol");
|
||||||
|
|
||||||
|
if (ContainsKey(g_handlers, scheme))
|
||||||
|
return node::ThrowError("Cannot intercept custom procotols");
|
||||||
|
|
||||||
|
// Store the handler in a map.
|
||||||
|
if (!args[1]->IsFunction())
|
||||||
|
return node::ThrowError("Handler must be a function");
|
||||||
|
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
|
||||||
|
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&InterceptProtocolInIO, scheme));
|
||||||
|
return v8::Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
v8::Handle<v8::Value> Protocol::UninterceptProtocol(const v8::Arguments& args) {
|
||||||
|
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
g_handlers.erase(it);
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&UninterceptProtocolInIO,
|
||||||
|
scheme));
|
||||||
|
return v8::Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||||
|
job_factory->SetProtocolHandler(scheme, new CustomProtocolHandler);
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&EmitEventInUI,
|
||||||
|
"registered",
|
||||||
|
scheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||||
|
job_factory->SetProtocolHandler(scheme, NULL);
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&EmitEventInUI,
|
||||||
|
"unregistered",
|
||||||
|
scheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||||
|
ProtocolHandler* original_handler = job_factory->GetProtocolHandler(scheme);
|
||||||
|
if (original_handler == NULL) {
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&EmitEventInUI,
|
||||||
|
"error",
|
||||||
|
"There is no protocol handler to intercpet"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
job_factory->ReplaceProtocol(scheme,
|
||||||
|
new CustomProtocolHandler(original_handler));
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&EmitEventInUI,
|
||||||
|
"intercepted",
|
||||||
|
scheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||||
|
|
||||||
|
// Check if the protocol handler is intercepted.
|
||||||
|
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
||||||
|
job_factory->GetProtocolHandler(scheme));
|
||||||
|
if (handler->original_handler() == NULL) {
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&EmitEventInUI,
|
||||||
|
"error",
|
||||||
|
"The protocol is not intercpeted"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the protocol handler to the orignal one and delete current
|
||||||
|
// protocol handler.
|
||||||
|
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
|
||||||
|
delete job_factory->ReplaceProtocol(scheme, original_handler);
|
||||||
|
|
||||||
|
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&EmitEventInUI,
|
||||||
|
"unintercepted",
|
||||||
|
scheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Protocol::Initialize(v8::Handle<v8::Object> target) {
|
||||||
|
// Remember the protocol object, used for emitting event later.
|
||||||
|
g_protocol_object = v8::Persistent<v8::Object>::New(
|
||||||
|
node::node_isolate, target);
|
||||||
|
|
||||||
|
node::SetMethod(target, "registerProtocol", RegisterProtocol);
|
||||||
|
node::SetMethod(target, "unregisterProtocol", UnregisterProtocol);
|
||||||
|
node::SetMethod(target, "isHandledProtocol", IsHandledProtocol);
|
||||||
|
node::SetMethod(target, "interceptProtocol", InterceptProtocol);
|
||||||
|
node::SetMethod(target, "uninterceptProtocol", UninterceptProtocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)
|
43
browser/api/atom_api_protocol.h
Normal file
43
browser/api/atom_api_protocol.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
|
||||||
|
#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
#include "v8/include/v8.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
class Protocol {
|
||||||
|
public:
|
||||||
|
static void Initialize(v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static v8::Handle<v8::Value> RegisterProtocol(const v8::Arguments& args);
|
||||||
|
static v8::Handle<v8::Value> UnregisterProtocol(const v8::Arguments& args);
|
||||||
|
static v8::Handle<v8::Value> IsHandledProtocol(const v8::Arguments& args);
|
||||||
|
|
||||||
|
static v8::Handle<v8::Value> InterceptProtocol(const v8::Arguments& args);
|
||||||
|
static v8::Handle<v8::Value> UninterceptProtocol(const v8::Arguments& args);
|
||||||
|
|
||||||
|
static void RegisterProtocolInIO(const std::string& scheme);
|
||||||
|
static void UnregisterProtocolInIO(const std::string& scheme);
|
||||||
|
|
||||||
|
static void InterceptProtocolInIO(const std::string& scheme);
|
||||||
|
static void UninterceptProtocolInIO(const std::string& scheme);
|
||||||
|
|
||||||
|
DISALLOW_IMPLICIT_CONSTRUCTORS(Protocol);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
|
20
browser/api/lib/protocol.coffee
Normal file
20
browser/api/lib/protocol.coffee
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
protocol = process.atomBinding 'protocol'
|
||||||
|
EventEmitter = require('events').EventEmitter
|
||||||
|
|
||||||
|
protocol[key] = value for key, value of EventEmitter.prototype
|
||||||
|
|
||||||
|
protocol.RequestStringJob =
|
||||||
|
class RequestStringJob
|
||||||
|
constructor: ({mimeType, charset, data}) ->
|
||||||
|
if typeof data isnt 'string' and not data instanceof Buffer
|
||||||
|
throw new TypeError('Data should be string or Buffer')
|
||||||
|
|
||||||
|
@mimeType = mimeType ? 'text/plain'
|
||||||
|
@charset = charset ? 'UTF-8'
|
||||||
|
@data = String data
|
||||||
|
|
||||||
|
protocol.RequestFileJob =
|
||||||
|
class RequestFileJob
|
||||||
|
constructor: (@path) ->
|
||||||
|
|
||||||
|
module.exports = protocol
|
|
@ -44,10 +44,13 @@ unwrapArgs = (processId, routingId, args) ->
|
||||||
when 'remote-object' then objectsRegistry.get meta.id
|
when 'remote-object' then objectsRegistry.get meta.id
|
||||||
when 'array' then unwrapArgs processId, routingId, meta.value
|
when 'array' then unwrapArgs processId, routingId, meta.value
|
||||||
when 'object'
|
when 'object'
|
||||||
ret = {}
|
ret = v8Util.createObjectWithName meta.name
|
||||||
for member in meta.members
|
for member in meta.members
|
||||||
ret[member.name] = metaToValue(member.value)
|
ret[member.name] = metaToValue(member.value)
|
||||||
ret
|
ret
|
||||||
|
when 'function-with-return-value'
|
||||||
|
returnValue = metaToValue meta.value
|
||||||
|
-> returnValue
|
||||||
when 'function'
|
when 'function'
|
||||||
ret = ->
|
ret = ->
|
||||||
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
|
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
|
||||||
|
@ -101,6 +104,16 @@ ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) ->
|
||||||
catch e
|
catch e
|
||||||
event.result = errorToMeta e
|
event.result = errorToMeta e
|
||||||
|
|
||||||
|
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, method, args) ->
|
||||||
|
try
|
||||||
|
args = unwrapArgs processId, routingId, args
|
||||||
|
constructor = objectsRegistry.get(id)[method]
|
||||||
|
# Call new with array of arguments.
|
||||||
|
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||||
|
event.result = valueToMeta processId, routingId, obj
|
||||||
|
catch e
|
||||||
|
event.result = errorToMeta e
|
||||||
|
|
||||||
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) ->
|
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) ->
|
||||||
try
|
try
|
||||||
args = unwrapArgs processId, routingId, args
|
args = unwrapArgs processId, routingId, args
|
||||||
|
|
|
@ -5,6 +5,13 @@
|
||||||
#include "browser/atom_browser_client.h"
|
#include "browser/atom_browser_client.h"
|
||||||
|
|
||||||
#include "browser/atom_browser_main_parts.h"
|
#include "browser/atom_browser_main_parts.h"
|
||||||
|
#include "browser/net/atom_url_request_job_factory.h"
|
||||||
|
#include "content/public/common/url_constants.h"
|
||||||
|
#include "net/url_request/data_protocol_handler.h"
|
||||||
|
#include "net/url_request/file_protocol_handler.h"
|
||||||
|
#include "net/url_request/url_request_context.h"
|
||||||
|
#include "net/url_request/url_request_context_storage.h"
|
||||||
|
#include "vendor/brightray/browser/url_request_context_getter.h"
|
||||||
#include "webkit/glue/webpreferences.h"
|
#include "webkit/glue/webpreferences.h"
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
@ -15,6 +22,36 @@ AtomBrowserClient::AtomBrowserClient() {
|
||||||
AtomBrowserClient::~AtomBrowserClient() {
|
AtomBrowserClient::~AtomBrowserClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
|
content::ProtocolHandlerMap* protocol_handlers) {
|
||||||
|
content::ProtocolHandlerMap preset_handlers;
|
||||||
|
std::swap(preset_handlers, *protocol_handlers);
|
||||||
|
|
||||||
|
// Create our implementaton of job factory.
|
||||||
|
AtomURLRequestJobFactory* job_factory = new AtomURLRequestJobFactory;
|
||||||
|
content::ProtocolHandlerMap::iterator it;
|
||||||
|
for (it = preset_handlers.begin(); it != preset_handlers.end(); ++it)
|
||||||
|
job_factory->SetProtocolHandler(it->first, it->second.release());
|
||||||
|
job_factory->SetProtocolHandler(chrome::kDataScheme,
|
||||||
|
new net::DataProtocolHandler);
|
||||||
|
job_factory->SetProtocolHandler(chrome::kFileScheme,
|
||||||
|
new net::FileProtocolHandler);
|
||||||
|
|
||||||
|
// Go through default procedure.
|
||||||
|
net::URLRequestContextGetter* request_context_getter =
|
||||||
|
brightray::BrowserClient::CreateRequestContext(browser_context,
|
||||||
|
protocol_handlers);
|
||||||
|
net::URLRequestContext* request_context =
|
||||||
|
request_context_getter->GetURLRequestContext();
|
||||||
|
|
||||||
|
// Replace default job factory.
|
||||||
|
storage_.reset(new net::URLRequestContextStorage(request_context));
|
||||||
|
storage_->set_job_factory(job_factory);
|
||||||
|
|
||||||
|
return request_context_getter;
|
||||||
|
}
|
||||||
|
|
||||||
void AtomBrowserClient::OverrideWebkitPrefs(
|
void AtomBrowserClient::OverrideWebkitPrefs(
|
||||||
content::RenderViewHost* render_view_host,
|
content::RenderViewHost* render_view_host,
|
||||||
const GURL& url,
|
const GURL& url,
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
#include "brightray/browser/browser_client.h"
|
#include "brightray/browser/browser_client.h"
|
||||||
|
|
||||||
|
namespace net {
|
||||||
|
class URLRequestContextStorage;
|
||||||
|
}
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
class AtomBrowserClient : public brightray::BrowserClient {
|
class AtomBrowserClient : public brightray::BrowserClient {
|
||||||
|
@ -15,6 +19,9 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||||
virtual ~AtomBrowserClient();
|
virtual ~AtomBrowserClient();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
net::URLRequestContextGetter* CreateRequestContext(
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
|
content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
|
||||||
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
||||||
const GURL& url,
|
const GURL& url,
|
||||||
WebPreferences* prefs) OVERRIDE;
|
WebPreferences* prefs) OVERRIDE;
|
||||||
|
@ -27,6 +34,8 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||||
virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
||||||
const content::MainFunctionParams&) OVERRIDE;
|
const content::MainFunctionParams&) OVERRIDE;
|
||||||
|
|
||||||
|
scoped_ptr<net::URLRequestContextStorage> storage_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
105
browser/net/adapter_request_job.cc
Normal file
105
browser/net/adapter_request_job.cc
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "browser/net/adapter_request_job.h"
|
||||||
|
|
||||||
|
#include "browser/net/url_request_string_job.h"
|
||||||
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
#include "net/base/net_errors.h"
|
||||||
|
#include "net/url_request/url_request_error_job.h"
|
||||||
|
#include "net/url_request/url_request_file_job.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate)
|
||||||
|
: URLRequestJob(request, network_delegate),
|
||||||
|
protocol_handler_(protocol_handler),
|
||||||
|
weak_factory_(this) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdapterRequestJob::Start() {
|
||||||
|
DCHECK(!real_job_);
|
||||||
|
content::BrowserThread::PostTask(
|
||||||
|
content::BrowserThread::UI,
|
||||||
|
FROM_HERE,
|
||||||
|
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
|
||||||
|
weak_factory_.GetWeakPtr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdapterRequestJob::Kill() {
|
||||||
|
DCHECK(real_job_);
|
||||||
|
real_job_->Kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
|
||||||
|
int buf_size,
|
||||||
|
int *bytes_read) {
|
||||||
|
DCHECK(real_job_);
|
||||||
|
return real_job_->ReadRawData(buf, buf_size, bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
|
||||||
|
int* http_status_code) {
|
||||||
|
DCHECK(real_job_);
|
||||||
|
return real_job_->IsRedirectResponse(location, http_status_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
net::Filter* AdapterRequestJob::SetupFilter() const {
|
||||||
|
DCHECK(real_job_);
|
||||||
|
return real_job_->SetupFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
|
||||||
|
DCHECK(real_job_);
|
||||||
|
return real_job_->GetMimeType(mime_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdapterRequestJob::GetCharset(std::string* charset) {
|
||||||
|
DCHECK(real_job_);
|
||||||
|
return real_job_->GetCharset(charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
|
||||||
|
return weak_factory_.GetWeakPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdapterRequestJob::CreateErrorJobAndStart(int error_code) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
|
||||||
|
real_job_ = new net::URLRequestErrorJob(
|
||||||
|
request(), network_delegate(), error_code);
|
||||||
|
real_job_->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdapterRequestJob::CreateStringJobAndStart(const std::string& mime_type,
|
||||||
|
const std::string& charset,
|
||||||
|
const std::string& data) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
|
||||||
|
real_job_ = new URLRequestStringJob(
|
||||||
|
request(), network_delegate(), mime_type, charset, data);
|
||||||
|
real_job_->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
|
||||||
|
real_job_ = new net::URLRequestFileJob(request(), network_delegate(), path);
|
||||||
|
real_job_->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
|
||||||
|
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||||
|
DCHECK(protocol_handler_);
|
||||||
|
real_job_ = protocol_handler_->MaybeCreateJob(request(),
|
||||||
|
network_delegate());
|
||||||
|
if (!real_job_.get())
|
||||||
|
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
|
||||||
|
else
|
||||||
|
real_job_->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
68
browser/net/adapter_request_job.h
Normal file
68
browser/net/adapter_request_job.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||||
|
#define ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||||
|
|
||||||
|
#include "base/memory/weak_ptr.h"
|
||||||
|
#include "net/url_request/url_request_job.h"
|
||||||
|
#include "net/url_request/url_request_job_factory.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
class FilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
// Ask JS which type of job it wants, and then delegate corresponding methods.
|
||||||
|
class AdapterRequestJob : public net::URLRequestJob {
|
||||||
|
public:
|
||||||
|
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||||
|
|
||||||
|
AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// net::URLRequestJob:
|
||||||
|
virtual void Start() OVERRIDE;
|
||||||
|
virtual void Kill() OVERRIDE;
|
||||||
|
virtual bool ReadRawData(net::IOBuffer* buf,
|
||||||
|
int buf_size,
|
||||||
|
int *bytes_read) OVERRIDE;
|
||||||
|
virtual bool IsRedirectResponse(GURL* location,
|
||||||
|
int* http_status_code) OVERRIDE;
|
||||||
|
virtual net::Filter* SetupFilter() const OVERRIDE;
|
||||||
|
virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
|
||||||
|
virtual bool GetCharset(std::string* charset) OVERRIDE;
|
||||||
|
|
||||||
|
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
|
||||||
|
|
||||||
|
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
|
||||||
|
|
||||||
|
// Override this function to determine which job should be started.
|
||||||
|
virtual void GetJobTypeInUI() = 0;
|
||||||
|
|
||||||
|
void CreateErrorJobAndStart(int error_code);
|
||||||
|
void CreateStringJobAndStart(const std::string& mime_type,
|
||||||
|
const std::string& charset,
|
||||||
|
const std::string& data);
|
||||||
|
void CreateFileJobAndStart(const base::FilePath& path);
|
||||||
|
void CreateJobFromProtocolHandlerAndStart();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The delegated request job.
|
||||||
|
scoped_refptr<net::URLRequestJob> real_job_;
|
||||||
|
|
||||||
|
// Default protocol handler.
|
||||||
|
ProtocolHandler* protocol_handler_;
|
||||||
|
|
||||||
|
base::WeakPtrFactory<AdapterRequestJob> weak_factory_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(AdapterRequestJob);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
105
browser/net/atom_url_request_job_factory.cc
Normal file
105
browser/net/atom_url_request_job_factory.cc
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "browser/net/atom_url_request_job_factory.h"
|
||||||
|
|
||||||
|
#include "base/stl_util.h"
|
||||||
|
#include "googleurl/src/gurl.h"
|
||||||
|
#include "net/base/load_flags.h"
|
||||||
|
#include "net/url_request/url_request.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||||
|
|
||||||
|
AtomURLRequestJobFactory::AtomURLRequestJobFactory() {}
|
||||||
|
|
||||||
|
AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
|
||||||
|
STLDeleteValues(&protocol_handler_map_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||||
|
const std::string& scheme,
|
||||||
|
ProtocolHandler* protocol_handler) {
|
||||||
|
DCHECK(CalledOnValidThread());
|
||||||
|
|
||||||
|
base::AutoLock locked(lock_);
|
||||||
|
|
||||||
|
if (!protocol_handler) {
|
||||||
|
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
|
||||||
|
if (it == protocol_handler_map_.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
delete it->second;
|
||||||
|
protocol_handler_map_.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContainsKey(protocol_handler_map_, scheme))
|
||||||
|
return false;
|
||||||
|
protocol_handler_map_[scheme] = protocol_handler;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
|
||||||
|
const std::string& scheme,
|
||||||
|
ProtocolHandler* protocol_handler) {
|
||||||
|
DCHECK(CalledOnValidThread());
|
||||||
|
DCHECK(protocol_handler);
|
||||||
|
|
||||||
|
base::AutoLock locked(lock_);
|
||||||
|
if (!ContainsKey(protocol_handler_map_, scheme))
|
||||||
|
return NULL;
|
||||||
|
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
|
||||||
|
protocol_handler_map_[scheme] = protocol_handler;
|
||||||
|
return original_protocol_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
|
||||||
|
const std::string& scheme) const {
|
||||||
|
DCHECK(CalledOnValidThread());
|
||||||
|
|
||||||
|
base::AutoLock locked(lock_);
|
||||||
|
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
|
||||||
|
if (it == protocol_handler_map_.end())
|
||||||
|
return NULL;
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomURLRequestJobFactory::HasProtocolHandler(
|
||||||
|
const std::string& scheme) const {
|
||||||
|
base::AutoLock locked(lock_);
|
||||||
|
return ContainsKey(protocol_handler_map_, scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
|
||||||
|
const std::string& scheme,
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate) const {
|
||||||
|
DCHECK(CalledOnValidThread());
|
||||||
|
|
||||||
|
base::AutoLock locked(lock_);
|
||||||
|
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
|
||||||
|
if (it == protocol_handler_map_.end())
|
||||||
|
return NULL;
|
||||||
|
return it->second->MaybeCreateJob(request, network_delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomURLRequestJobFactory::IsHandledProtocol(
|
||||||
|
const std::string& scheme) const {
|
||||||
|
DCHECK(CalledOnValidThread());
|
||||||
|
return HasProtocolHandler(scheme) ||
|
||||||
|
net::URLRequest::IsHandledProtocol(scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AtomURLRequestJobFactory::IsHandledURL(const GURL& url) const {
|
||||||
|
if (!url.is_valid()) {
|
||||||
|
// We handle error cases.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return IsHandledProtocol(url.scheme());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
61
browser/net/atom_url_request_job_factory.h
Normal file
61
browser/net/atom_url_request_job_factory.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
|
||||||
|
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
#include "base/compiler_specific.h"
|
||||||
|
#include "base/synchronization/lock.h"
|
||||||
|
#include "net/url_request/url_request_job_factory.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
|
||||||
|
public:
|
||||||
|
AtomURLRequestJobFactory();
|
||||||
|
virtual ~AtomURLRequestJobFactory();
|
||||||
|
|
||||||
|
// Sets the ProtocolHandler for a scheme. Returns true on success, false on
|
||||||
|
// failure (a ProtocolHandler already exists for |scheme|). On success,
|
||||||
|
// URLRequestJobFactory takes ownership of |protocol_handler|.
|
||||||
|
bool SetProtocolHandler(const std::string& scheme,
|
||||||
|
ProtocolHandler* protocol_handler);
|
||||||
|
|
||||||
|
// Intercepts the ProtocolHandler for a scheme. Returns the original protocol
|
||||||
|
// handler on success, otherwise returns NULL.
|
||||||
|
ProtocolHandler* ReplaceProtocol(const std::string& scheme,
|
||||||
|
ProtocolHandler* protocol_handler);
|
||||||
|
|
||||||
|
// Returns the protocol handler registered with scheme.
|
||||||
|
ProtocolHandler* GetProtocolHandler(const std::string& scheme) const;
|
||||||
|
|
||||||
|
// Whether the protocol handler is registered by the job factory.
|
||||||
|
bool HasProtocolHandler(const std::string& scheme) const;
|
||||||
|
|
||||||
|
// URLRequestJobFactory implementation
|
||||||
|
virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
|
||||||
|
const std::string& scheme,
|
||||||
|
net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate) const OVERRIDE;
|
||||||
|
virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE;
|
||||||
|
virtual bool IsHandledURL(const GURL& url) const OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap;
|
||||||
|
|
||||||
|
ProtocolHandlerMap protocol_handler_map_;
|
||||||
|
|
||||||
|
mutable base::Lock lock_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
|
33
browser/net/url_request_string_job.cc
Normal file
33
browser/net/url_request_string_job.cc
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "browser/net/url_request_string_job.h"
|
||||||
|
|
||||||
|
#include "net/base/net_errors.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate,
|
||||||
|
const std::string& mime_type,
|
||||||
|
const std::string& charset,
|
||||||
|
const std::string& data)
|
||||||
|
: net::URLRequestSimpleJob(request, network_delegate),
|
||||||
|
mime_type_(mime_type),
|
||||||
|
charset_(charset),
|
||||||
|
data_(data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int URLRequestStringJob::GetData(
|
||||||
|
std::string* mime_type,
|
||||||
|
std::string* charset,
|
||||||
|
std::string* data,
|
||||||
|
const net::CompletionCallback& callback) const {
|
||||||
|
*mime_type = mime_type_;
|
||||||
|
*charset = charset_;
|
||||||
|
*data = data_;
|
||||||
|
return net::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
36
browser/net/url_request_string_job.h
Normal file
36
browser/net/url_request_string_job.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||||
|
#define ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||||
|
|
||||||
|
#include "net/url_request/url_request_simple_job.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
class URLRequestStringJob : public net::URLRequestSimpleJob {
|
||||||
|
public:
|
||||||
|
URLRequestStringJob(net::URLRequest* request,
|
||||||
|
net::NetworkDelegate* network_delegate,
|
||||||
|
const std::string& mime_type,
|
||||||
|
const std::string& charset,
|
||||||
|
const std::string& data);
|
||||||
|
|
||||||
|
// URLRequestSimpleJob:
|
||||||
|
virtual int GetData(std::string* mime_type,
|
||||||
|
std::string* charset,
|
||||||
|
std::string* data,
|
||||||
|
const net::CompletionCallback& callback) const OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mime_type_;
|
||||||
|
std::string charset_;
|
||||||
|
std::string data_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(URLRequestStringJob);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
|
@ -16,6 +16,7 @@ NODE_EXT_LIST_ITEM(atom_browser_dialog)
|
||||||
NODE_EXT_LIST_ITEM(atom_browser_ipc)
|
NODE_EXT_LIST_ITEM(atom_browser_ipc)
|
||||||
NODE_EXT_LIST_ITEM(atom_browser_menu)
|
NODE_EXT_LIST_ITEM(atom_browser_menu)
|
||||||
NODE_EXT_LIST_ITEM(atom_browser_power_monitor)
|
NODE_EXT_LIST_ITEM(atom_browser_power_monitor)
|
||||||
|
NODE_EXT_LIST_ITEM(atom_browser_protocol)
|
||||||
NODE_EXT_LIST_ITEM(atom_browser_window)
|
NODE_EXT_LIST_ITEM(atom_browser_window)
|
||||||
|
|
||||||
// Module names start with `atom_renderer_` can only be used by renderer
|
// Module names start with `atom_renderer_` can only be used by renderer
|
||||||
|
|
|
@ -31,8 +31,9 @@ Browser side modules:
|
||||||
* [menu](menu.md)
|
* [menu](menu.md)
|
||||||
* [menu-item](menu-item.md)
|
* [menu-item](menu-item.md)
|
||||||
* [power-monitor](power-monitor.md)
|
* [power-monitor](power-monitor.md)
|
||||||
|
* [protocol](protocol.md)
|
||||||
|
|
||||||
Common modules:
|
Common modules:
|
||||||
|
|
||||||
* [clipboard](clipboard.md)
|
* [clipboard](clipboard.md)
|
||||||
* [shell](shell.md)
|
* [shell](shell.md)
|
||||||
|
|
68
docs/protocol.md
Normal file
68
docs/protocol.md
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
## Synopsis
|
||||||
|
|
||||||
|
The `protocol` module can register a new protocol or intercept an existing
|
||||||
|
protocol, so you can custom the response to the requests for vairous protocols.
|
||||||
|
|
||||||
|
An example of implementing a protocol that has the same effect with the
|
||||||
|
`file://` protocol:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var protocol = require('protocol');
|
||||||
|
protocol.registerProtocol('atom', function(request) {
|
||||||
|
var path = request.url.substr(7)
|
||||||
|
return new protocol.RequestFileJob(path);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## protocol.registerProtocol(scheme, handler)
|
||||||
|
|
||||||
|
* `scheme` String
|
||||||
|
* `handler` Function
|
||||||
|
|
||||||
|
Registers a custom protocol of `scheme`, the `handler` would be called with
|
||||||
|
`handler(request)` when the a request with registered `scheme` is made.
|
||||||
|
|
||||||
|
You need to return a request job in the `handler` to specify which type of
|
||||||
|
response you would like to send.
|
||||||
|
|
||||||
|
## protocol.unregisterProtocol(scheme)
|
||||||
|
|
||||||
|
* `scheme` String
|
||||||
|
|
||||||
|
Unregisters the custom protocol of `scheme`.
|
||||||
|
|
||||||
|
## protocol.isHandledProtocol(scheme)
|
||||||
|
|
||||||
|
* `scheme` String
|
||||||
|
|
||||||
|
Returns whether the `scheme` can be handled already.
|
||||||
|
|
||||||
|
## protocol.interceptProtocol(scheme, handler)
|
||||||
|
|
||||||
|
* `scheme` String
|
||||||
|
* `handler` Function
|
||||||
|
|
||||||
|
Intercepts an existing protocol with `scheme`, returning `null` or `undefined`
|
||||||
|
in `handler` would use the original protocol handler to handle the request.
|
||||||
|
|
||||||
|
## protocol.uninterceptProtocol(scheme)
|
||||||
|
|
||||||
|
* `scheme` String
|
||||||
|
|
||||||
|
Unintercepts a protocol.
|
||||||
|
|
||||||
|
## Class: protocol.RequestFileJob(path)
|
||||||
|
|
||||||
|
* `path` String
|
||||||
|
|
||||||
|
Create a request job which would query a file of `path` and set corresponding
|
||||||
|
mime types.
|
||||||
|
|
||||||
|
## Class: protocol.RequestStringJob(options)
|
||||||
|
|
||||||
|
* `options` Object
|
||||||
|
* `mimeType` String - Default is `text/plain`
|
||||||
|
* `charset` String - Default is `UTF-8`
|
||||||
|
* `data` String
|
||||||
|
|
||||||
|
Create a request job which sends a string as response.
|
|
@ -13,9 +13,11 @@ wrapArgs = (args) ->
|
||||||
else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId'
|
else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId'
|
||||||
type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId'
|
type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId'
|
||||||
else if value? and typeof value is 'object'
|
else if value? and typeof value is 'object'
|
||||||
ret = type: 'object', members: []
|
ret = type: 'object', name: value.constructor.name, members: []
|
||||||
ret.members.push(name: prop, value: valueToMeta(field)) for prop, field of value
|
ret.members.push(name: prop, value: valueToMeta(field)) for prop, field of value
|
||||||
ret
|
ret
|
||||||
|
else if typeof value is 'function' and v8Util.getHiddenValue value, 'returnValue'
|
||||||
|
type: 'function-with-return-value', value: valueToMeta(value())
|
||||||
else if typeof value is 'function'
|
else if typeof value is 'function'
|
||||||
type: 'function', id: callbacksRegistry.add(value)
|
type: 'function', id: callbacksRegistry.add(value)
|
||||||
else
|
else
|
||||||
|
@ -29,8 +31,7 @@ metaToValue = (meta) ->
|
||||||
when 'value' then meta.value
|
when 'value' then meta.value
|
||||||
when 'array' then (metaToValue(el) for el in meta.members)
|
when 'array' then (metaToValue(el) for el in meta.members)
|
||||||
when 'error'
|
when 'error'
|
||||||
console.log meta.stack
|
throw new Error("#{meta.message}\n#{meta.stack}")
|
||||||
throw new Error(meta.message)
|
|
||||||
else
|
else
|
||||||
if meta.type is 'function'
|
if meta.type is 'function'
|
||||||
# A shadow class to represent the remote function object.
|
# A shadow class to represent the remote function object.
|
||||||
|
@ -56,10 +57,17 @@ metaToValue = (meta) ->
|
||||||
for member in meta.members
|
for member in meta.members
|
||||||
do (member) ->
|
do (member) ->
|
||||||
if member.type is 'function'
|
if member.type is 'function'
|
||||||
ret[member.name] = ->
|
ret[member.name] =
|
||||||
# Call member function.
|
class RemoteMemberFunction
|
||||||
ret = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
|
constructor: ->
|
||||||
metaToValue ret
|
if @constructor is RemoteMemberFunction
|
||||||
|
# Constructor call.
|
||||||
|
obj = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', meta.id, member.name, wrapArgs(arguments)
|
||||||
|
return metaToValue obj
|
||||||
|
else
|
||||||
|
# Call member function.
|
||||||
|
ret = ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
|
||||||
|
return metaToValue ret
|
||||||
else
|
else
|
||||||
ret.__defineSetter__ member.name, (value) ->
|
ret.__defineSetter__ member.name, (value) ->
|
||||||
# Set member data.
|
# Set member data.
|
||||||
|
@ -121,3 +129,9 @@ processCache = null
|
||||||
exports.__defineGetter__ 'process', ->
|
exports.__defineGetter__ 'process', ->
|
||||||
processCache = exports.getGlobal('process') unless processCache?
|
processCache = exports.getGlobal('process') unless processCache?
|
||||||
processCache
|
processCache
|
||||||
|
|
||||||
|
# Create a funtion that will return the specifed value when called in browser.
|
||||||
|
exports.createFunctionWithReturnValue = (returnValue) ->
|
||||||
|
func = -> returnValue
|
||||||
|
v8Util.setHiddenValue func, 'returnValue', true
|
||||||
|
func
|
||||||
|
|
|
@ -16,7 +16,14 @@ describe 'ipc', ->
|
||||||
a = remote.require path.join(fixtures, 'module', 'id.js')
|
a = remote.require path.join(fixtures, 'module', 'id.js')
|
||||||
assert.equal a.id, 1127
|
assert.equal a.id, 1127
|
||||||
|
|
||||||
describe 'remote object', ->
|
describe 'remote.createFunctionWithReturnValue', ->
|
||||||
|
it 'should be called in browser synchronously', ->
|
||||||
|
buf = new Buffer('test')
|
||||||
|
call = remote.require path.join(fixtures, 'module', 'call.js')
|
||||||
|
result = call.call remote.createFunctionWithReturnValue(buf)
|
||||||
|
assert.equal result.constructor.name, 'Buffer'
|
||||||
|
|
||||||
|
describe 'remote object in renderer', ->
|
||||||
it 'can change its properties', ->
|
it 'can change its properties', ->
|
||||||
property = remote.require path.join(fixtures, 'module', 'property.js')
|
property = remote.require path.join(fixtures, 'module', 'property.js')
|
||||||
assert.equal property.property, 1127
|
assert.equal property.property, 1127
|
||||||
|
@ -28,6 +35,17 @@ describe 'ipc', ->
|
||||||
# Restore.
|
# Restore.
|
||||||
property.property = 1127
|
property.property = 1127
|
||||||
|
|
||||||
|
it 'can construct an object from its member', ->
|
||||||
|
call = remote.require path.join(fixtures, 'module', 'call.js')
|
||||||
|
obj = new call.constructor
|
||||||
|
assert.equal obj.test, 'test'
|
||||||
|
|
||||||
|
describe 'remote value in browser', ->
|
||||||
|
it 'keeps its constructor name for objects', ->
|
||||||
|
buf = new Buffer('test')
|
||||||
|
print_name = remote.require path.join(fixtures, 'module', 'print_name.js')
|
||||||
|
assert.equal print_name.print(buf), 'Buffer'
|
||||||
|
|
||||||
describe 'ipc.send', ->
|
describe 'ipc.send', ->
|
||||||
it 'should work when sending an object containing id property', (done) ->
|
it 'should work when sending an object containing id property', (done) ->
|
||||||
obj = id: 1, name: 'ly'
|
obj = id: 1, name: 'ly'
|
||||||
|
|
132
spec/api/protocol.coffee
Normal file
132
spec/api/protocol.coffee
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
assert = require 'assert'
|
||||||
|
ipc = require 'ipc'
|
||||||
|
remote = require 'remote'
|
||||||
|
protocol = remote.require 'protocol'
|
||||||
|
|
||||||
|
describe 'protocol API', ->
|
||||||
|
describe 'protocol.registerProtocol', ->
|
||||||
|
it 'throws error when scheme is already registered', (done) ->
|
||||||
|
register = -> protocol.registerProtocol('test1', ->)
|
||||||
|
protocol.once 'registered', (scheme) ->
|
||||||
|
assert.equal scheme, 'test1'
|
||||||
|
assert.throws register, /The scheme is already registered/
|
||||||
|
protocol.unregisterProtocol 'test1'
|
||||||
|
done()
|
||||||
|
register()
|
||||||
|
|
||||||
|
it 'calls the callback when scheme is visited', (done) ->
|
||||||
|
protocol.registerProtocol 'test2', (request) ->
|
||||||
|
assert.equal request.url, 'test2://test2'
|
||||||
|
assert.equal request.referrer, window.location.toString()
|
||||||
|
protocol.unregisterProtocol 'test2'
|
||||||
|
done()
|
||||||
|
$.get 'test2://test2', ->
|
||||||
|
|
||||||
|
describe 'protocol.unregisterProtocol', ->
|
||||||
|
it 'throws error when scheme does not exist', ->
|
||||||
|
unregister = -> protocol.unregisterProtocol 'test3'
|
||||||
|
assert.throws unregister, /The scheme has not been registered/
|
||||||
|
|
||||||
|
describe 'registered protocol callback', ->
|
||||||
|
it 'returns string should send the string as request content', (done) ->
|
||||||
|
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||||
|
protocol.registerProtocol 'atom-string', handler
|
||||||
|
|
||||||
|
$.ajax
|
||||||
|
url: 'atom-string://fake-host'
|
||||||
|
success: (data) ->
|
||||||
|
assert.equal data, handler()
|
||||||
|
protocol.unregisterProtocol 'atom-string'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) ->
|
||||||
|
assert false, 'Got error: ' + errorType + ' ' + error
|
||||||
|
protocol.unregisterProtocol 'atom-string'
|
||||||
|
|
||||||
|
it 'returns RequestStringJob should send string', (done) ->
|
||||||
|
data = 'valar morghulis'
|
||||||
|
job = new protocol.RequestStringJob(mimeType: 'text/html', data: data)
|
||||||
|
handler = remote.createFunctionWithReturnValue job
|
||||||
|
protocol.registerProtocol 'atom-string-job', handler
|
||||||
|
|
||||||
|
$.ajax
|
||||||
|
url: 'atom-string-job://fake-host'
|
||||||
|
success: (response) ->
|
||||||
|
assert.equal response, data
|
||||||
|
protocol.unregisterProtocol 'atom-string-job'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) ->
|
||||||
|
assert false, 'Got error: ' + errorType + ' ' + error
|
||||||
|
protocol.unregisterProtocol 'atom-string-job'
|
||||||
|
|
||||||
|
it 'returns RequestFileJob should send file', (done) ->
|
||||||
|
job = new protocol.RequestFileJob(__filename)
|
||||||
|
handler = remote.createFunctionWithReturnValue job
|
||||||
|
protocol.registerProtocol 'atom-file-job', handler
|
||||||
|
|
||||||
|
$.ajax
|
||||||
|
url: 'atom-file-job://' + __filename
|
||||||
|
success: (data) ->
|
||||||
|
content = require('fs').readFileSync __filename
|
||||||
|
assert.equal data, String(content)
|
||||||
|
protocol.unregisterProtocol 'atom-file-job'
|
||||||
|
done()
|
||||||
|
error: (xhr, errorType, error) ->
|
||||||
|
assert false, 'Got error: ' + errorType + ' ' + error
|
||||||
|
protocol.unregisterProtocol 'atom-file-job'
|
||||||
|
|
||||||
|
describe 'protocol.isHandledProtocol', ->
|
||||||
|
it 'returns true if the scheme can be handled', ->
|
||||||
|
assert.equal protocol.isHandledProtocol('file'), true
|
||||||
|
assert.equal protocol.isHandledProtocol('http'), true
|
||||||
|
assert.equal protocol.isHandledProtocol('https'), true
|
||||||
|
assert.equal protocol.isHandledProtocol('atom'), false
|
||||||
|
|
||||||
|
describe 'protocol.interceptProtocol', ->
|
||||||
|
it 'throws error when scheme is not a registered one', ->
|
||||||
|
register = -> protocol.interceptProtocol('test-intercept', ->)
|
||||||
|
assert.throws register, /Cannot intercept procotol/
|
||||||
|
|
||||||
|
it 'throws error when scheme is a custom protocol', (done) ->
|
||||||
|
protocol.once 'unregistered', (scheme) ->
|
||||||
|
assert.equal scheme, 'atom'
|
||||||
|
done()
|
||||||
|
protocol.once 'registered', (scheme) ->
|
||||||
|
assert.equal scheme, 'atom'
|
||||||
|
register = -> protocol.interceptProtocol('test-intercept', ->)
|
||||||
|
assert.throws register, /Cannot intercept procotol/
|
||||||
|
protocol.unregisterProtocol scheme
|
||||||
|
protocol.registerProtocol('atom', ->)
|
||||||
|
|
||||||
|
it 'returns original job when callback returns nothing', (done) ->
|
||||||
|
targetScheme = 'file'
|
||||||
|
protocol.once 'intercepted', (scheme) ->
|
||||||
|
assert.equal scheme, targetScheme
|
||||||
|
free = -> protocol.uninterceptProtocol targetScheme
|
||||||
|
$.ajax
|
||||||
|
url: "#{targetScheme}://#{__filename}",
|
||||||
|
success: ->
|
||||||
|
protocol.once 'unintercepted', (scheme) ->
|
||||||
|
assert.equal scheme, targetScheme
|
||||||
|
done()
|
||||||
|
free()
|
||||||
|
error: (xhr, errorType, error) ->
|
||||||
|
free()
|
||||||
|
assert false, 'Got error: ' + errorType + ' ' + error
|
||||||
|
protocol.interceptProtocol targetScheme, (request) ->
|
||||||
|
assert.equal request.url, "#{targetScheme}://#{__filename}"
|
||||||
|
|
||||||
|
it 'can override original protocol handler', (done) ->
|
||||||
|
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||||
|
protocol.once 'intercepted', ->
|
||||||
|
free = -> protocol.uninterceptProtocol 'file'
|
||||||
|
$.ajax
|
||||||
|
url: 'file://fake-host'
|
||||||
|
success: (data) ->
|
||||||
|
protocol.once 'unintercepted', ->
|
||||||
|
assert.equal data, handler()
|
||||||
|
done()
|
||||||
|
free()
|
||||||
|
error: (xhr, errorType, error) ->
|
||||||
|
assert false, 'Got error: ' + errorType + ' ' + error
|
||||||
|
free()
|
||||||
|
protocol.interceptProtocol 'file', handler
|
7
spec/fixtures/module/call.js
vendored
Normal file
7
spec/fixtures/module/call.js
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
exports.call = function(func) {
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.constructor = function() {
|
||||||
|
this.test = 'test';
|
||||||
|
}
|
3
spec/fixtures/module/print_name.js
vendored
Normal file
3
spec/fixtures/module/print_name.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
exports.print = function(obj) {
|
||||||
|
return obj.constructor.name;
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta name="referrer" content="always">
|
||||||
<link href="../node_modules/mocha/mocha.css" rel="stylesheet">
|
<link href="../node_modules/mocha/mocha.css" rel="stylesheet">
|
||||||
|
<script src="jquery-2.0.3.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
@ -24,21 +26,23 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
require('coffee-script'); // Supports .coffee tests.
|
require('coffee-script'); // Supports .coffee tests.
|
||||||
|
var ipc = require('ipc');
|
||||||
|
|
||||||
// Rediret all output to browser.
|
// Rediret all output to browser.
|
||||||
var ipc = require('ipc');
|
if (isCi) {
|
||||||
global.__defineGetter__('console', function() {
|
global.__defineGetter__('console', function() {
|
||||||
return {
|
return {
|
||||||
log: function() {
|
log: function() {
|
||||||
args = Array.prototype.slice.call(arguments);
|
args = Array.prototype.slice.call(arguments);
|
||||||
ipc.sendChannel('console.log', args);
|
ipc.sendChannel('console.log', args);
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
args = Array.prototype.slice.call(arguments);
|
args = Array.prototype.slice.call(arguments);
|
||||||
ipc.sendChannel('console.error', args);
|
ipc.sendChannel('console.error', args);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var Mocha = require('mocha');
|
var Mocha = require('mocha');
|
||||||
|
|
||||||
|
|
6
spec/jquery-2.0.3.min.js
vendored
Normal file
6
spec/jquery-2.0.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -22,6 +22,10 @@ ipc.on('process.exit', function(pid, rid, code) {
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipc.on('eval', function(ev, pid, rid, script) {
|
||||||
|
ev.result = eval(script);
|
||||||
|
});
|
||||||
|
|
||||||
process.on('uncaughtException', function() {
|
process.on('uncaughtException', function() {
|
||||||
window.openDevTools();
|
window.openDevTools();
|
||||||
});
|
});
|
||||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit c62f91a82e5426996d149dcb63259f967a7e78fb
|
Subproject commit 3cb2782cff77081df2788c68948163dea53530d5
|
Loading…
Add table
Add a link
Reference in a new issue