commit
7c32378a73
56 changed files with 1555 additions and 1252 deletions
17
atom.gyp
17
atom.gyp
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.30.5',
|
||||
'version%': '0.31.0',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
|
@ -144,7 +144,6 @@
|
|||
'destination': '<(PRODUCT_DIR)',
|
||||
'files': [
|
||||
'<@(copied_libraries)',
|
||||
'<(libchromiumcontent_dir)/ffmpegsumo.dll',
|
||||
'<(libchromiumcontent_dir)/libEGL.dll',
|
||||
'<(libchromiumcontent_dir)/libGLESv2.dll',
|
||||
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||
|
@ -193,7 +192,6 @@
|
|||
'destination': '<(PRODUCT_DIR)',
|
||||
'files': [
|
||||
'<@(copied_libraries)',
|
||||
'<(libchromiumcontent_dir)/libffmpegsumo.so',
|
||||
'<(libchromiumcontent_dir)/icudtl.dat',
|
||||
'<(libchromiumcontent_dir)/content_shell.pak',
|
||||
'<(libchromiumcontent_dir)/natives_blob.bin',
|
||||
|
@ -226,8 +224,6 @@
|
|||
# Defined in Chromium but not exposed in its gyp file.
|
||||
'V8_USE_EXTERNAL_STARTUP_DATA',
|
||||
'ENABLE_PLUGINS',
|
||||
# Needed by Node.
|
||||
'NODE_WANT_INTERNALS=1',
|
||||
],
|
||||
'sources': [
|
||||
'<@(lib_sources)',
|
||||
|
@ -441,7 +437,6 @@
|
|||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Libraries',
|
||||
'files': [
|
||||
'<@(copied_libraries)',
|
||||
'<(libchromiumcontent_dir)/ffmpegsumo.so',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -462,6 +457,16 @@
|
|||
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
||||
],
|
||||
},
|
||||
{
|
||||
'postbuild_name': 'Fix path of ffmpeg',
|
||||
'action': [
|
||||
'install_name_tool',
|
||||
'-change',
|
||||
'@loader_path/libffmpeg.dylib',
|
||||
'@rpath/libffmpeg.dylib',
|
||||
'${BUILT_PRODUCTS_DIR}/<(product_name) Framework.framework/Versions/A/<(product_name) Framework',
|
||||
],
|
||||
},
|
||||
{
|
||||
'postbuild_name': 'Add symlinks for framework subdirectories',
|
||||
'action': [
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#include "atom/app/node_main.h"
|
||||
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -19,7 +21,7 @@ int NodeMain(int argc, char *argv[]) {
|
|||
|
||||
int exit_code = 1;
|
||||
{
|
||||
gin::IsolateHolder::LoadV8Snapshot();
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
gin::IsolateHolder::Initialize(
|
||||
gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
|
|
|
@ -7,15 +7,12 @@
|
|||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/url_request_async_asar_job.h"
|
||||
#include "atom/browser/net/url_request_buffer_job.h"
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
#include "atom/browser/net/url_request_string_job.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
|
@ -41,230 +38,35 @@ namespace atom {
|
|||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
|
||||
scoped_refptr<base::RefCountedBytes> BufferToRefCountedBytes(
|
||||
v8::Local<v8::Value> buf) {
|
||||
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes);
|
||||
auto start = reinterpret_cast<const unsigned char*>(node::Buffer::Data(buf));
|
||||
data->data().assign(start, start + node::Buffer::Length(buf));
|
||||
return data;
|
||||
}
|
||||
|
||||
class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
public:
|
||||
CustomProtocolRequestJob(Protocol* registry,
|
||||
ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: AdapterRequestJob(protocol_handler, request, network_delegate),
|
||||
registry_(registry) {
|
||||
}
|
||||
|
||||
void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Locker locker(registry_->isolate());
|
||||
v8::HandleScope handle_scope(registry_->isolate());
|
||||
|
||||
// Call the JS handler.
|
||||
v8::Local<v8::Value> result = callback.Run(request());
|
||||
|
||||
// Determine the type of the job we are going to create.
|
||||
if (result->IsString()) {
|
||||
std::string data = mate::V8ToString(result);
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||
GetWeakPtr(), "text/plain", "UTF-8", data));
|
||||
return;
|
||||
} else if (result->IsObject()) {
|
||||
v8::Local<v8::Object> obj = result->ToObject();
|
||||
mate::Dictionary dict(registry_->isolate(), obj);
|
||||
std::string name = mate::V8ToString(obj->GetConstructorName());
|
||||
if (name == "RequestStringJob") {
|
||||
std::string mime_type, charset, data;
|
||||
dict.Get("mimeType", &mime_type);
|
||||
dict.Get("charset", &charset);
|
||||
dict.Get("data", &data);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||
GetWeakPtr(), mime_type, charset, data));
|
||||
return;
|
||||
} else if (name == "RequestBufferJob") {
|
||||
std::string mime_type, encoding;
|
||||
v8::Local<v8::Value> buffer;
|
||||
dict.Get("mimeType", &mime_type);
|
||||
dict.Get("encoding", &encoding);
|
||||
dict.Get("data", &buffer);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateBufferJobAndStart,
|
||||
GetWeakPtr(), mime_type, encoding,
|
||||
BufferToRefCountedBytes(buffer)));
|
||||
return;
|
||||
} else if (name == "RequestFileJob") {
|
||||
base::FilePath path;
|
||||
dict.Get("path", &path);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
||||
GetWeakPtr(), path));
|
||||
return;
|
||||
} else if (name == "RequestErrorJob") {
|
||||
int error = net::ERR_NOT_IMPLEMENTED;
|
||||
dict.Get("error", &error);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||
GetWeakPtr(), error));
|
||||
return;
|
||||
} else if (name == "RequestHttpJob") {
|
||||
GURL url;
|
||||
std::string method, referrer;
|
||||
dict.Get("url", &url);
|
||||
dict.Get("method", &method);
|
||||
dict.Get("referrer", &referrer);
|
||||
|
||||
v8::Local<v8::Value> value;
|
||||
mate::Handle<Session> session;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter;
|
||||
// "session" null -> pass nullptr;
|
||||
// "session" a Session object -> use passed session.
|
||||
// "session" undefined -> use current session;
|
||||
if (dict.Get("session", &session))
|
||||
request_context_getter =
|
||||
session->browser_context()->GetRequestContext();
|
||||
else if (dict.Get("session", &value) && value->IsNull())
|
||||
request_context_getter = nullptr;
|
||||
else
|
||||
request_context_getter = registry_->request_context_getter();
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
|
||||
request_context_getter, url, method, referrer));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try the default protocol handler if we have.
|
||||
if (default_protocol_handler()) {
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
||||
GetWeakPtr()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to the not implemented error.
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
|
||||
}
|
||||
|
||||
// AdapterRequestJob:
|
||||
void GetJobType() override {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&CustomProtocolRequestJob::GetJobTypeInUI,
|
||||
base::Unretained(this),
|
||||
registry_->GetProtocolHandler(request()->url().scheme())));
|
||||
}
|
||||
|
||||
private:
|
||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||
};
|
||||
|
||||
// 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:
|
||||
CustomProtocolHandler(api::Protocol* registry,
|
||||
ProtocolHandler* protocol_handler = NULL)
|
||||
: registry_(registry), protocol_handler_(protocol_handler) {
|
||||
}
|
||||
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override {
|
||||
return new CustomProtocolRequestJob(registry_, protocol_handler_.get(),
|
||||
request, network_delegate);
|
||||
}
|
||||
|
||||
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
||||
return protocol_handler_.release();
|
||||
}
|
||||
|
||||
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
||||
|
||||
private:
|
||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||
scoped_ptr<ProtocolHandler> protocol_handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
std::string ConvertErrorCode(int error_code) {
|
||||
switch (error_code) {
|
||||
case Protocol::ERR_SCHEME_REGISTERED:
|
||||
return "The Scheme is already registered";
|
||||
case Protocol::ERR_SCHEME_UNREGISTERED:
|
||||
return "The Scheme has not been registered";
|
||||
case Protocol::ERR_SCHEME_INTERCEPTED:
|
||||
return "There is no protocol handler to intercept";
|
||||
case Protocol::ERR_SCHEME_UNINTERCEPTED:
|
||||
return "The protocol is not intercepted";
|
||||
case Protocol::ERR_NO_SCHEME:
|
||||
return "The Scheme does not exist.";
|
||||
case Protocol::ERR_SCHEME:
|
||||
return "Cannot intercept custom protocols";
|
||||
default:
|
||||
NOTREACHED();
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Protocol::Protocol(AtomBrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()),
|
||||
job_factory_(browser_context->job_factory()) {
|
||||
CHECK(job_factory_);
|
||||
}
|
||||
|
||||
Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
|
||||
const std::string& scheme) {
|
||||
return protocol_handlers_[scheme];
|
||||
}
|
||||
|
||||
void Protocol::OnIOActionCompleted(const JsCompletionCallback& callback,
|
||||
int error) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
if (error) {
|
||||
callback.Run(v8::Exception::Error(
|
||||
mate::StringToV8(isolate(), ConvertErrorCode(error))));
|
||||
return;
|
||||
}
|
||||
|
||||
callback.Run(v8::Null(isolate()));
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
|
||||
.SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
|
||||
.SetMethod("_registerProtocol", &Protocol::RegisterProtocol)
|
||||
.SetMethod("_unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("_interceptProtocol", &Protocol::InterceptProtocol)
|
||||
.SetMethod("_uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
.SetMethod("registerStringProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestStringJob>)
|
||||
.SetMethod("registerBufferProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestBufferJob>)
|
||||
.SetMethod("registerFileProtocol",
|
||||
&Protocol::RegisterProtocol<UrlRequestAsyncAsarJob>)
|
||||
.SetMethod("registerHttpProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled)
|
||||
.SetMethod("interceptStringProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestStringJob>)
|
||||
.SetMethod("interceptBufferProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestBufferJob>)
|
||||
.SetMethod("interceptFileProtocol",
|
||||
&Protocol::InterceptProtocol<UrlRequestAsyncAsarJob>)
|
||||
.SetMethod("interceptHttpProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
}
|
||||
|
||||
void Protocol::RegisterStandardSchemes(
|
||||
|
@ -272,131 +74,86 @@ void Protocol::RegisterStandardSchemes(
|
|||
atom::AtomBrowserClient::SetCustomSchemes(schemes);
|
||||
}
|
||||
|
||||
void Protocol::IsHandledProtocol(const std::string& scheme,
|
||||
const net::CompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AtomURLRequestJobFactory::IsHandledProtocol,
|
||||
base::Unretained(job_factory_), scheme),
|
||||
void Protocol::UnregisterProtocol(
|
||||
const std::string& scheme, mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
Protocol::ProtocolError Protocol::UnregisterProtocolInIO(
|
||||
const std::string& scheme) {
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return PROTOCOL_NOT_REGISTERED;
|
||||
job_factory_->SetProtocolHandler(scheme, nullptr);
|
||||
return PROTOCOL_OK;
|
||||
}
|
||||
|
||||
void Protocol::IsProtocolHandled(const std::string& scheme,
|
||||
const BooleanCallback& callback) {
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::IsProtocolHandledInIO,
|
||||
base::Unretained(this), scheme),
|
||||
callback);
|
||||
}
|
||||
|
||||
void Protocol::RegisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::RegisterProtocolInIO,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
bool Protocol::IsProtocolHandledInIO(const std::string& scheme) {
|
||||
return job_factory_->IsHandledProtocol(scheme);
|
||||
}
|
||||
|
||||
void Protocol::UnregisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::InterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::InterceptProtocolInIO,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::UninterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
void Protocol::UninterceptProtocol(
|
||||
const std::string& scheme, mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UninterceptProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
int Protocol::RegisterProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
if (ContainsKey(protocol_handlers_, scheme) ||
|
||||
job_factory_->IsHandledProtocol(scheme)) {
|
||||
return ERR_SCHEME_REGISTERED;
|
||||
}
|
||||
|
||||
protocol_handlers_[scheme] = handler;
|
||||
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
|
||||
|
||||
return OK;
|
||||
Protocol::ProtocolError Protocol::UninterceptProtocolInIO(
|
||||
const std::string& scheme) {
|
||||
if (!original_protocols_.contains(scheme))
|
||||
return PROTOCOL_NOT_INTERCEPTED;
|
||||
job_factory_->ReplaceProtocol(scheme,
|
||||
original_protocols_.take_and_erase(scheme));
|
||||
return PROTOCOL_OK;
|
||||
}
|
||||
|
||||
int Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
void Protocol::OnIOCompleted(
|
||||
const CompletionCallback& callback, ProtocolError error) {
|
||||
// The completion callback is optional.
|
||||
if (callback.is_null())
|
||||
return;
|
||||
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end()) {
|
||||
return ERR_SCHEME_UNREGISTERED;
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
if (error == PROTOCOL_OK) {
|
||||
callback.Run(v8::Null(isolate()));
|
||||
} else {
|
||||
std::string str = ErrorCodeToString(error);
|
||||
callback.Run(v8::Exception::Error(mate::StringToV8(isolate(), str)));
|
||||
}
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
job_factory_->SetProtocolHandler(scheme, NULL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int Protocol::InterceptProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
// Force the request context to initialize, otherwise we might have nothing
|
||||
// to intercept.
|
||||
request_context_getter_->GetURLRequestContext();
|
||||
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return ERR_NO_SCHEME;
|
||||
|
||||
if (ContainsKey(protocol_handlers_, scheme))
|
||||
return ERR_SCHEME;
|
||||
|
||||
protocol_handlers_[scheme] = handler;
|
||||
ProtocolHandler* original_handler = job_factory_->GetProtocolHandler(scheme);
|
||||
if (original_handler == nullptr) {
|
||||
return ERR_SCHEME_INTERCEPTED;
|
||||
std::string Protocol::ErrorCodeToString(ProtocolError error) {
|
||||
switch (error) {
|
||||
case PROTOCOL_FAIL: return "Failed to manipulate protocol factory";
|
||||
case PROTOCOL_REGISTERED: return "The scheme has been registred";
|
||||
case PROTOCOL_NOT_REGISTERED: return "The scheme has not been registred";
|
||||
case PROTOCOL_INTERCEPTED: return "The scheme has been intercepted";
|
||||
case PROTOCOL_NOT_INTERCEPTED: return "The scheme has not been intercepted";
|
||||
default: return "Unexpected error";
|
||||
}
|
||||
|
||||
job_factory_->ReplaceProtocol(
|
||||
scheme, new CustomProtocolHandler(this, original_handler));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end())
|
||||
return ERR_SCHEME_UNREGISTERED;
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
||||
job_factory_->GetProtocolHandler(scheme));
|
||||
if (handler->original_handler() == nullptr) {
|
||||
return ERR_SCHEME_UNINTERCEPTED;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -9,10 +9,14 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/containers/scoped_ptr_hash_map.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/arguments.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/base/completion_callback.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace net {
|
||||
class URLRequest;
|
||||
|
@ -26,31 +30,16 @@ class AtomURLRequestJobFactory;
|
|||
|
||||
namespace api {
|
||||
|
||||
class Protocol : public mate::EventEmitter {
|
||||
class Protocol : public mate::Wrappable {
|
||||
public:
|
||||
using JsProtocolHandler =
|
||||
base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>;
|
||||
using JsCompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
enum {
|
||||
OK = 0,
|
||||
ERR_SCHEME_REGISTERED,
|
||||
ERR_SCHEME_UNREGISTERED,
|
||||
ERR_SCHEME_INTERCEPTED,
|
||||
ERR_SCHEME_UNINTERCEPTED,
|
||||
ERR_NO_SCHEME,
|
||||
ERR_SCHEME
|
||||
};
|
||||
using Handler =
|
||||
base::Callback<void(const net::URLRequest*, v8::Local<v8::Value>)>;
|
||||
using CompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
using BooleanCallback = base::Callback<void(bool)>;
|
||||
|
||||
static mate::Handle<Protocol> Create(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
|
||||
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter() {
|
||||
return request_context_getter_.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit Protocol(AtomBrowserContext* browser_context);
|
||||
|
||||
|
@ -59,48 +48,139 @@ class Protocol : public mate::EventEmitter {
|
|||
v8::Isolate* isolate);
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
|
||||
// Possible errors.
|
||||
enum ProtocolError {
|
||||
PROTOCOL_OK, // no error
|
||||
PROTOCOL_FAIL, // operation failed, should never occur
|
||||
PROTOCOL_REGISTERED,
|
||||
PROTOCOL_NOT_REGISTERED,
|
||||
PROTOCOL_INTERCEPTED,
|
||||
PROTOCOL_NOT_INTERCEPTED,
|
||||
};
|
||||
|
||||
// Callback called after performing action on IO thread.
|
||||
void OnIOActionCompleted(const JsCompletionCallback& callback,
|
||||
int error);
|
||||
// The protocol handler that will create a protocol handler for certain
|
||||
// request job.
|
||||
template<typename RequestJob>
|
||||
class CustomProtocolHandler
|
||||
: public net::URLRequestJobFactory::ProtocolHandler {
|
||||
public:
|
||||
CustomProtocolHandler(
|
||||
v8::Isolate* isolate,
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context,
|
||||
const Handler& handler)
|
||||
: isolate_(isolate),
|
||||
request_context_(request_context),
|
||||
handler_(handler) {}
|
||||
~CustomProtocolHandler() override {}
|
||||
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override {
|
||||
RequestJob* request_job = new RequestJob(request, network_delegate);
|
||||
request_job->SetHandlerInfo(isolate_, request_context_, handler_);
|
||||
return request_job;
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_;
|
||||
Protocol::Handler handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
// Register schemes to standard scheme list.
|
||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
|
||||
|
||||
// Returns whether a scheme has been registered.
|
||||
void IsHandledProtocol(const std::string& scheme,
|
||||
const net::CompletionCallback& callback);
|
||||
// Register the protocol with certain request job.
|
||||
template<typename RequestJob>
|
||||
void RegisterProtocol(const std::string& scheme,
|
||||
const Handler& handler,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::RegisterProtocolInIO<RequestJob>,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
template<typename RequestJob>
|
||||
ProtocolError RegisterProtocolInIO(const std::string& scheme,
|
||||
const Handler& handler) {
|
||||
if (job_factory_->IsHandledProtocol(scheme))
|
||||
return PROTOCOL_REGISTERED;
|
||||
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
|
||||
new CustomProtocolHandler<RequestJob>(
|
||||
isolate(), request_context_getter_, handler));
|
||||
if (job_factory_->SetProtocolHandler(scheme, protocol_handler.Pass()))
|
||||
return PROTOCOL_OK;
|
||||
else
|
||||
return PROTOCOL_FAIL;
|
||||
}
|
||||
|
||||
// Register/unregister an networking |scheme| which would be handled by
|
||||
// |callback|.
|
||||
void RegisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback);
|
||||
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme,
|
||||
const JsCompletionCallback& callback);
|
||||
// Unregister the protocol handler that handles |scheme|.
|
||||
void UnregisterProtocol(const std::string& scheme, mate::Arguments* args);
|
||||
ProtocolError UnregisterProtocolInIO(const std::string& scheme);
|
||||
|
||||
// Intercept/unintercept an existing protocol handler.
|
||||
void InterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback);
|
||||
void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme,
|
||||
const JsCompletionCallback& callback);
|
||||
// Whether the protocol has handler registered.
|
||||
void IsProtocolHandled(const std::string& scheme,
|
||||
const BooleanCallback& callback);
|
||||
bool IsProtocolHandledInIO(const std::string& scheme);
|
||||
|
||||
// The networking related operations have to be done in IO thread.
|
||||
int RegisterProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler);
|
||||
int UnregisterProtocolInIO(const std::string& scheme);
|
||||
int InterceptProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler);
|
||||
int UninterceptProtocolInIO(const std::string& scheme);
|
||||
// Replace the protocol handler with a new one.
|
||||
template<typename RequestJob>
|
||||
void InterceptProtocol(const std::string& scheme,
|
||||
const Handler& handler,
|
||||
mate::Arguments* args) {
|
||||
CompletionCallback callback;
|
||||
args->GetNext(&callback);
|
||||
content::BrowserThread::PostTaskAndReplyWithResult(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::InterceptProtocolInIO<RequestJob>,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
template<typename RequestJob>
|
||||
ProtocolError InterceptProtocolInIO(const std::string& scheme,
|
||||
const Handler& handler) {
|
||||
if (!job_factory_->IsHandledProtocol(scheme))
|
||||
return PROTOCOL_NOT_REGISTERED;
|
||||
// It is possible a protocol is handled but can not be intercepted.
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return PROTOCOL_FAIL;
|
||||
if (ContainsKey(original_protocols_, scheme))
|
||||
return PROTOCOL_INTERCEPTED;
|
||||
scoped_ptr<CustomProtocolHandler<RequestJob>> protocol_handler(
|
||||
new CustomProtocolHandler<RequestJob>(
|
||||
isolate(), request_context_getter_, handler));
|
||||
original_protocols_.set(
|
||||
scheme,
|
||||
job_factory_->ReplaceProtocol(scheme, protocol_handler.Pass()));
|
||||
return PROTOCOL_OK;
|
||||
}
|
||||
|
||||
// Restore the |scheme| to its original protocol handler.
|
||||
void UninterceptProtocol(const std::string& scheme, mate::Arguments* args);
|
||||
ProtocolError UninterceptProtocolInIO(const std::string& scheme);
|
||||
|
||||
// Convert error code to JS exception and call the callback.
|
||||
void OnIOCompleted(const CompletionCallback& callback, ProtocolError error);
|
||||
|
||||
// Convert error code to string.
|
||||
std::string ErrorCodeToString(ProtocolError error);
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
ProtocolHandlersMap protocol_handlers_;
|
||||
// Map that stores the original protocols of schemes.
|
||||
using OriginalProtocolsMap = base::ScopedPtrHashMap<
|
||||
std::string,
|
||||
scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>>;
|
||||
OriginalProtocolsMap original_protocols_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_; // weak ref
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Protocol);
|
||||
};
|
||||
|
|
|
@ -56,7 +56,7 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
|||
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
||||
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
||||
event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||
(void)event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||
return event;
|
||||
}
|
||||
|
|
|
@ -2,63 +2,23 @@ app = require 'app'
|
|||
throw new Error('Can not initialize protocol module before app is ready') unless app.isReady()
|
||||
|
||||
protocol = process.atomBinding('protocol').protocol
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
protocol.__proto__ = EventEmitter.prototype
|
||||
|
||||
GetWrappedCallback = (scheme, callback, notification) ->
|
||||
wrappedCallback = (error) ->
|
||||
if not callback?
|
||||
if error
|
||||
throw error
|
||||
else
|
||||
protocol.emit notification, scheme
|
||||
else
|
||||
callback error, scheme
|
||||
|
||||
# Compatibility with old api.
|
||||
# Warn about removed APIs.
|
||||
logAndThrow = (callback, message) ->
|
||||
console.error message
|
||||
if callback then callback(new Error(message)) else throw new Error(message)
|
||||
protocol.registerProtocol = (scheme, handler, callback) ->
|
||||
protocol._registerProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'registered')
|
||||
|
||||
protocol.unregisterProtocol = (scheme, callback) ->
|
||||
protocol._unregisterProtocol scheme, GetWrappedCallback(scheme, callback, 'unregistered')
|
||||
|
||||
logAndThrow callback,
|
||||
'registerProtocol API has been replaced by the
|
||||
register[File/Http/Buffer/String]Protocol API family, please
|
||||
switch to the new APIs.'
|
||||
protocol.isHandledProtocol = (scheme, callback) ->
|
||||
logAndThrow callback,
|
||||
'isHandledProtocol API has been replaced by isProtocolHandled.'
|
||||
protocol.interceptProtocol = (scheme, handler, callback) ->
|
||||
protocol._interceptProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'intercepted')
|
||||
|
||||
protocol.uninterceptProtocol = (scheme, callback) ->
|
||||
protocol._uninterceptProtocol scheme, GetWrappedCallback(scheme, callback, 'unintercepted')
|
||||
|
||||
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.RequestBufferJob =
|
||||
class RequestBufferJob
|
||||
constructor: ({mimeType, encoding, data}) ->
|
||||
if not data instanceof Buffer
|
||||
throw new TypeError('Data should be Buffer')
|
||||
|
||||
@mimeType = mimeType ? 'application/octet-stream'
|
||||
@encoding = encoding ? 'utf8'
|
||||
@data = new Buffer(data)
|
||||
|
||||
protocol.RequestFileJob =
|
||||
class RequestFileJob
|
||||
constructor: (@path) ->
|
||||
|
||||
protocol.RequestErrorJob =
|
||||
class RequestErrorJob
|
||||
constructor: (@error) ->
|
||||
|
||||
protocol.RequestHttpJob =
|
||||
class RequestHttpJob
|
||||
constructor: ({@session, @url, @method, @referrer}) ->
|
||||
logAndThrow callback,
|
||||
'interceptProtocol API has been replaced by the
|
||||
intercept[File/Http/Buffer/String]Protocol API family, please
|
||||
switch to the new APIs.'
|
||||
|
||||
module.exports = protocol
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "chrome/browser/printing/printing_message_filter.h"
|
||||
|
@ -58,20 +59,19 @@ enum ProcessOwner {
|
|||
OWNER_GUEST_WEB_CONTENTS,
|
||||
OWNER_NONE, // it might be devtools though.
|
||||
};
|
||||
|
||||
ProcessOwner GetProcessOwner(int process_id,
|
||||
NativeWindow** window,
|
||||
WebViewManager::WebViewInfo* info) {
|
||||
auto web_contents = content::WebContents::FromRenderViewHost(
|
||||
content::WebContents* web_contents = content::WebContents::FromRenderViewHost(
|
||||
content::RenderViewHost::FromID(process_id, kDefaultRoutingID));
|
||||
if (!web_contents)
|
||||
return OWNER_NONE;
|
||||
|
||||
// First search for NativeWindow.
|
||||
for (auto native_window : *WindowList::GetInstance())
|
||||
if (web_contents == native_window->web_contents()) {
|
||||
*window = native_window;
|
||||
return OWNER_NATIVE_WINDOW;
|
||||
}
|
||||
*window = NativeWindow::FromWebContents(web_contents);
|
||||
if (*window)
|
||||
return OWNER_NATIVE_WINDOW;
|
||||
|
||||
// Then search for guest WebContents.
|
||||
if (WebViewManager::GetInfoForWebContents(web_contents, info))
|
||||
|
@ -185,6 +185,13 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
|||
return;
|
||||
|
||||
*new_instance = content::SiteInstance::CreateForURL(browser_context, url);
|
||||
|
||||
// Remember the original renderer process of the pending renderer process.
|
||||
auto current_process = current_instance->GetProcess();
|
||||
auto pending_process = (*new_instance)->GetProcess();
|
||||
pending_processes_[pending_process->GetID()] = current_process->GetID();
|
||||
// Clear the entry in map when process ends.
|
||||
current_process->AddObserver(this);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
|
@ -208,6 +215,10 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
|||
}
|
||||
#endif
|
||||
|
||||
// If the process is a pending process, we should use the old one.
|
||||
if (ContainsKey(pending_processes_, process_id))
|
||||
process_id = pending_processes_[process_id];
|
||||
|
||||
NativeWindow* window;
|
||||
WebViewManager::WebViewInfo info;
|
||||
ProcessOwner owner = GetProcessOwner(process_id, &window, &info);
|
||||
|
@ -264,4 +275,15 @@ brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
|
|||
return new AtomBrowserMainParts;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::RenderProcessHostDestroyed(
|
||||
content::RenderProcessHost* host) {
|
||||
int process_id = host->GetID();
|
||||
for (const auto& entry : pending_processes_) {
|
||||
if (entry.first == process_id || entry.second == process_id) {
|
||||
pending_processes_.erase(entry.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
#ifndef ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "brightray/browser/browser_client.h"
|
||||
#include "content/public/browser/render_process_host_observer.h"
|
||||
|
||||
namespace content {
|
||||
class QuotaPermissionContext;
|
||||
|
@ -21,7 +23,8 @@ class SSLCertRequestInfo;
|
|||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserClient : public brightray::BrowserClient {
|
||||
class AtomBrowserClient : public brightray::BrowserClient,
|
||||
public content::RenderProcessHostObserver {
|
||||
public:
|
||||
AtomBrowserClient();
|
||||
virtual ~AtomBrowserClient();
|
||||
|
@ -54,10 +57,17 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
|||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
|
||||
|
||||
private:
|
||||
// brightray::BrowserClient:
|
||||
brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) override;
|
||||
|
||||
// content::RenderProcessHostObserver:
|
||||
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
|
||||
|
||||
private:
|
||||
// pending_render_process => current_render_process.
|
||||
std::map<int, int> pending_processes_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
||||
};
|
||||
|
||||
|
|
|
@ -85,32 +85,37 @@ net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
|
|||
content::URLRequestInterceptorScopedVector* interceptors) {
|
||||
scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_);
|
||||
|
||||
for (content::ProtocolHandlerMap::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
job_factory->SetProtocolHandler(it->first, it->second.release());
|
||||
for (auto& it : *handlers) {
|
||||
job_factory->SetProtocolHandler(it.first,
|
||||
make_scoped_ptr(it.second.release()));
|
||||
}
|
||||
handlers->clear();
|
||||
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kDataScheme, new net::DataProtocolHandler);
|
||||
url::kDataScheme, make_scoped_ptr(new net::DataProtocolHandler));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kFileScheme, new asar::AsarProtocolHandler(
|
||||
url::kFileScheme, make_scoped_ptr(new asar::AsarProtocolHandler(
|
||||
BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kHttpScheme, new HttpProtocolHandler(url::kHttpScheme));
|
||||
url::kHttpScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kHttpScheme)));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kHttpsScheme, new HttpProtocolHandler(url::kHttpsScheme));
|
||||
url::kHttpsScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kHttpsScheme)));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kWsScheme, new HttpProtocolHandler(url::kWsScheme));
|
||||
url::kWsScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kWsScheme)));
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kWssScheme, new HttpProtocolHandler(url::kWssScheme));
|
||||
url::kWssScheme,
|
||||
make_scoped_ptr(new HttpProtocolHandler(url::kWssScheme)));
|
||||
|
||||
auto host_resolver = url_request_context_getter()
|
||||
->GetURLRequestContext()
|
||||
->host_resolver();
|
||||
auto host_resolver =
|
||||
url_request_context_getter()->GetURLRequestContext()->host_resolver();
|
||||
job_factory->SetProtocolHandler(
|
||||
url::kFtpScheme, new net::FtpProtocolHandler(
|
||||
new net::FtpNetworkLayer(host_resolver)));
|
||||
url::kFtpScheme,
|
||||
make_scoped_ptr(new net::FtpProtocolHandler(
|
||||
new net::FtpNetworkLayer(host_resolver))));
|
||||
|
||||
// Set up interceptors in the reverse order.
|
||||
scoped_ptr<net::URLRequestJobFactory> top_job_factory = job_factory.Pass();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "atom/browser/javascript_environment.h"
|
||||
|
||||
#include "gin/array_buffer.h"
|
||||
#include "gin/v8_initializer.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -19,7 +20,7 @@ JavascriptEnvironment::JavascriptEnvironment()
|
|||
}
|
||||
|
||||
bool JavascriptEnvironment::Initialize() {
|
||||
gin::IsolateHolder::LoadV8Snapshot();
|
||||
gin::V8Initializer::LoadV8Snapshot();
|
||||
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
|
||||
gin::ArrayBufferAllocator::SharedInstance());
|
||||
return true;
|
||||
|
|
|
@ -64,14 +64,16 @@ app.once 'ready', ->
|
|||
catch e
|
||||
|
||||
# The chrome-extension: can map a extension URL request to real file path.
|
||||
protocol.registerProtocol 'chrome-extension', (request) ->
|
||||
chromeExtensionHandler = (request, callback) ->
|
||||
parsed = url.parse request.url
|
||||
return unless parsed.hostname and parsed.path?
|
||||
return unless /extension-\d+/.test parsed.hostname
|
||||
return callback() unless parsed.hostname and parsed.path?
|
||||
return callback() unless /extension-\d+/.test parsed.hostname
|
||||
|
||||
directory = getPathForHost parsed.hostname
|
||||
return unless directory?
|
||||
return new protocol.RequestFileJob(path.join(directory, parsed.path))
|
||||
return callback() unless directory?
|
||||
callback path.join(directory, parsed.path)
|
||||
protocol.registerFileProtocol 'chrome-extension', chromeExtensionHandler, (error) ->
|
||||
console.error 'Unable to register chrome-extension protocol' if error
|
||||
|
||||
BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) ->
|
||||
@devToolsWebContents?.executeJavaScript "DevToolsAPI.addExtensions(#{JSON.stringify(extensionInfoArray)});"
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "atom/browser/net/url_request_buffer_job.h"
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
#include "atom/browser/net/url_request_string_job.h"
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/common/asar/asar_util.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_.get());
|
||||
GetJobType();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Kill() {
|
||||
if (real_job_.get()) // Kill could happen when real_job_ is created.
|
||||
real_job_->Kill();
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int *bytes_read) {
|
||||
DCHECK(!real_job_.get());
|
||||
// Read post-filtered data if available.
|
||||
if (real_job_->HasFilter())
|
||||
return real_job_->Read(buf, buf_size, bytes_read);
|
||||
else
|
||||
return real_job_->ReadRawData(buf, buf_size, bytes_read);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->IsRedirectResponse(location, http_status_code);
|
||||
}
|
||||
|
||||
net::Filter* AdapterRequestJob::SetupFilter() const {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->SetupFilter();
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::GetCharset(std::string* charset) {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->GetCharset(charset);
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
real_job_->GetResponseInfo(info);
|
||||
}
|
||||
|
||||
int AdapterRequestJob::GetResponseCode() const {
|
||||
return real_job_->GetResponseCode();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const {
|
||||
real_job_->GetLoadTimingInfo(load_timing_info);
|
||||
}
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateErrorJobAndStart(int error_code) {
|
||||
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) {
|
||||
real_job_ = new URLRequestStringJob(
|
||||
request(), network_delegate(), mime_type, charset, data);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateBufferJobAndStart(
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data) {
|
||||
real_job_ = new URLRequestBufferJob(
|
||||
request(), network_delegate(), mime_type, charset, data);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
|
||||
real_job_ = asar::CreateJobFromPath(
|
||||
path,
|
||||
request(),
|
||||
network_delegate(),
|
||||
content::BrowserThread::GetBlockingPool()->
|
||||
GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer) {
|
||||
if (!url.is_valid()) {
|
||||
CreateErrorJobAndStart(net::ERR_INVALID_URL);
|
||||
return;
|
||||
}
|
||||
|
||||
real_job_ = new URLRequestFetchJob(request_context_getter, request(),
|
||||
network_delegate(), url, method, referrer);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
|
||||
real_job_ = protocol_handler_->MaybeCreateJob(request(),
|
||||
network_delegate());
|
||||
if (!real_job_.get()) {
|
||||
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
|
||||
} else {
|
||||
// Copy headers from original request.
|
||||
real_job_->SetExtraRequestHeaders(request()->extra_request_headers());
|
||||
real_job_->Start();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
#define ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
// 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:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int *bytes_read) override;
|
||||
bool IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) override;
|
||||
net::Filter* SetupFilter() const override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
bool GetCharset(std::string* charset) override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
int GetResponseCode() const override;
|
||||
void GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const override;
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
|
||||
|
||||
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
|
||||
|
||||
// Override this function to determine which job should be started.
|
||||
virtual void GetJobType() = 0;
|
||||
|
||||
void CreateErrorJobAndStart(int error_code);
|
||||
void CreateStringJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data);
|
||||
void CreateBufferJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data);
|
||||
void CreateFileJobAndStart(const base::FilePath& path);
|
||||
void CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
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_
|
|
@ -5,45 +5,11 @@
|
|||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "atom/common/asar/asar_util.h"
|
||||
#include "net/base/filename_util.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 asar {
|
||||
|
||||
// static
|
||||
net::URLRequestJob* CreateJobFromPath(
|
||||
const base::FilePath& full_path,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner) {
|
||||
// Create asar:// job when the path contains "xxx.asar/", otherwise treat the
|
||||
// URL request as file://.
|
||||
base::FilePath asar_path, relative_path;
|
||||
if (!GetAsarArchivePath(full_path, &asar_path, &relative_path))
|
||||
return new net::URLRequestFileJob(request, network_delegate, full_path,
|
||||
file_task_runner);
|
||||
|
||||
std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
|
||||
Archive::FileInfo file_info;
|
||||
if (!archive || !archive->GetFileInfo(relative_path, &file_info))
|
||||
return new net::URLRequestErrorJob(request, network_delegate,
|
||||
net::ERR_FILE_NOT_FOUND);
|
||||
|
||||
if (file_info.unpacked) {
|
||||
base::FilePath real_path;
|
||||
archive->CopyFileOut(relative_path, &real_path);
|
||||
return new net::URLRequestFileJob(request, network_delegate, real_path,
|
||||
file_task_runner);
|
||||
}
|
||||
|
||||
return new URLRequestAsarJob(request, network_delegate, archive,
|
||||
relative_path, file_info, file_task_runner);
|
||||
}
|
||||
|
||||
AsarProtocolHandler::AsarProtocolHandler(
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner)
|
||||
: file_task_runner_(file_task_runner) {}
|
||||
|
@ -56,8 +22,9 @@ net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob(
|
|||
net::NetworkDelegate* network_delegate) const {
|
||||
base::FilePath full_path;
|
||||
net::FileURLToFilePath(request->url(), &full_path);
|
||||
return CreateJobFromPath(full_path, request, network_delegate,
|
||||
file_task_runner_);
|
||||
URLRequestAsarJob* job = new URLRequestAsarJob(request, network_delegate);
|
||||
job->Initialize(file_task_runner_, full_path);
|
||||
return job;
|
||||
}
|
||||
|
||||
bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {
|
||||
|
|
|
@ -5,48 +5,128 @@
|
|||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/task_runner.h"
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "atom/common/asar/asar_util.h"
|
||||
#include "net/base/file_stream.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/filter/filter.h"
|
||||
#include "net/http/http_util.h"
|
||||
#include "net/url_request/url_request_status.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/shortcut.h"
|
||||
#endif
|
||||
|
||||
namespace asar {
|
||||
|
||||
URLRequestAsarJob::FileMetaInfo::FileMetaInfo()
|
||||
: file_size(0),
|
||||
mime_type_result(false),
|
||||
file_exists(false),
|
||||
is_directory(false) {
|
||||
}
|
||||
|
||||
URLRequestAsarJob::URLRequestAsarJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info,
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner)
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: net::URLRequestJob(request, network_delegate),
|
||||
archive_(archive),
|
||||
file_path_(file_path),
|
||||
file_info_(file_info),
|
||||
stream_(new net::FileStream(file_task_runner)),
|
||||
type_(TYPE_ERROR),
|
||||
remaining_bytes_(0),
|
||||
file_task_runner_(file_task_runner),
|
||||
weak_ptr_factory_(this) {}
|
||||
|
||||
URLRequestAsarJob::~URLRequestAsarJob() {}
|
||||
|
||||
void URLRequestAsarJob::Start() {
|
||||
remaining_bytes_ = static_cast<int64>(file_info_.size);
|
||||
void URLRequestAsarJob::Initialize(
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path) {
|
||||
// Determine whether it is an asar file.
|
||||
base::FilePath asar_path, relative_path;
|
||||
if (!GetAsarArchivePath(file_path, &asar_path, &relative_path)) {
|
||||
InitializeFileJob(file_task_runner, file_path);
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = base::File::FLAG_OPEN |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_ASYNC;
|
||||
int rv = stream_->Open(archive_->path(), flags,
|
||||
base::Bind(&URLRequestAsarJob::DidOpen,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
DidOpen(rv);
|
||||
std::shared_ptr<Archive> archive = GetOrCreateAsarArchive(asar_path);
|
||||
Archive::FileInfo file_info;
|
||||
if (!archive || !archive->GetFileInfo(relative_path, &file_info)) {
|
||||
type_ = TYPE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_info.unpacked) {
|
||||
base::FilePath real_path;
|
||||
archive->CopyFileOut(relative_path, &real_path);
|
||||
InitializeFileJob(file_task_runner, real_path);
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeAsarJob(file_task_runner, archive, relative_path, file_info);
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::InitializeAsarJob(
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info) {
|
||||
type_ = TYPE_ASAR;
|
||||
file_task_runner_ = file_task_runner;
|
||||
stream_.reset(new net::FileStream(file_task_runner_));
|
||||
archive_ = archive;
|
||||
file_path_ = file_path;
|
||||
file_info_ = file_info;
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::InitializeFileJob(
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path) {
|
||||
type_ = TYPE_FILE;
|
||||
file_task_runner_ = file_task_runner;
|
||||
stream_.reset(new net::FileStream(file_task_runner_));
|
||||
file_path_ = file_path;
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::Start() {
|
||||
if (type_ == TYPE_ASAR) {
|
||||
remaining_bytes_ = static_cast<int64>(file_info_.size);
|
||||
|
||||
int flags = base::File::FLAG_OPEN |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_ASYNC;
|
||||
int rv = stream_->Open(archive_->path(), flags,
|
||||
base::Bind(&URLRequestAsarJob::DidOpen,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
DidOpen(rv);
|
||||
} else if (type_ == TYPE_FILE) {
|
||||
FileMetaInfo* meta_info = new FileMetaInfo();
|
||||
file_task_runner_->PostTaskAndReply(
|
||||
FROM_HERE,
|
||||
base::Bind(&URLRequestAsarJob::FetchMetaInfo, file_path_,
|
||||
base::Unretained(meta_info)),
|
||||
base::Bind(&URLRequestAsarJob::DidFetchMetaInfo,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
base::Owned(meta_info)));
|
||||
} else {
|
||||
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_FILE_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::Kill() {
|
||||
stream_.reset();
|
||||
weak_ptr_factory_.InvalidateWeakPtrs();
|
||||
|
||||
URLRequestJob::Kill();
|
||||
}
|
||||
|
||||
|
@ -85,8 +165,97 @@ bool URLRequestAsarJob::ReadRawData(net::IOBuffer* dest,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool URLRequestAsarJob::IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) {
|
||||
if (type_ != TYPE_FILE)
|
||||
return false;
|
||||
#if defined(OS_WIN)
|
||||
// Follow a Windows shortcut.
|
||||
// We just resolve .lnk file, ignore others.
|
||||
if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
|
||||
return false;
|
||||
|
||||
base::FilePath new_path = file_path_;
|
||||
bool resolved;
|
||||
resolved = base::win::ResolveShortcut(new_path, &new_path, NULL);
|
||||
|
||||
// If shortcut is not resolved succesfully, do not redirect.
|
||||
if (!resolved)
|
||||
return false;
|
||||
|
||||
*location = net::FilePathToFileURL(new_path);
|
||||
*http_status_code = 301;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
net::Filter* URLRequestAsarJob::SetupFilter() const {
|
||||
// Bug 9936 - .svgz files needs to be decompressed.
|
||||
return LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
|
||||
? net::Filter::GZipFactory() : NULL;
|
||||
}
|
||||
|
||||
bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const {
|
||||
return net::GetMimeTypeFromFile(file_path_, mime_type);
|
||||
if (type_ == TYPE_ASAR) {
|
||||
return net::GetMimeTypeFromFile(file_path_, mime_type);
|
||||
} else {
|
||||
if (meta_info_.mime_type_result) {
|
||||
*mime_type = meta_info_.mime_type;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::SetExtraRequestHeaders(
|
||||
const net::HttpRequestHeaders& headers) {
|
||||
std::string range_header;
|
||||
if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
|
||||
// We only care about "Range" header here.
|
||||
std::vector<net::HttpByteRange> ranges;
|
||||
if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
|
||||
if (ranges.size() == 1) {
|
||||
byte_range_ = ranges[0];
|
||||
} else {
|
||||
NotifyDone(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::FetchMetaInfo(const base::FilePath& file_path,
|
||||
FileMetaInfo* meta_info) {
|
||||
base::File::Info file_info;
|
||||
meta_info->file_exists = base::GetFileInfo(file_path, &file_info);
|
||||
if (meta_info->file_exists) {
|
||||
meta_info->file_size = file_info.size;
|
||||
meta_info->is_directory = file_info.is_directory;
|
||||
}
|
||||
// On Windows GetMimeTypeFromFile() goes to the registry. Thus it should be
|
||||
// done in WorkerPool.
|
||||
meta_info->mime_type_result =
|
||||
net::GetMimeTypeFromFile(file_path, &meta_info->mime_type);
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::DidFetchMetaInfo(const FileMetaInfo* meta_info) {
|
||||
meta_info_ = *meta_info;
|
||||
if (!meta_info_.file_exists || meta_info_.is_directory) {
|
||||
DidOpen(net::ERR_FILE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = base::File::FLAG_OPEN |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_ASYNC;
|
||||
int rv = stream_->Open(file_path_, flags,
|
||||
base::Bind(&URLRequestAsarJob::DidOpen,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
DidOpen(rv);
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::DidOpen(int result) {
|
||||
|
@ -95,24 +264,59 @@ void URLRequestAsarJob::DidOpen(int result) {
|
|||
return;
|
||||
}
|
||||
|
||||
int rv = stream_->Seek(base::File::FROM_BEGIN,
|
||||
file_info_.offset,
|
||||
base::Bind(&URLRequestAsarJob::DidSeek,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING) {
|
||||
// stream_->Seek() failed, so pass an intentionally erroneous value
|
||||
// into DidSeek().
|
||||
DidSeek(-1);
|
||||
if (type_ == TYPE_ASAR) {
|
||||
int rv = stream_->Seek(base::File::FROM_BEGIN,
|
||||
file_info_.offset,
|
||||
base::Bind(&URLRequestAsarJob::DidSeek,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING) {
|
||||
// stream_->Seek() failed, so pass an intentionally erroneous value
|
||||
// into DidSeek().
|
||||
DidSeek(-1);
|
||||
}
|
||||
} else {
|
||||
if (!byte_range_.ComputeBounds(meta_info_.file_size)) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
}
|
||||
|
||||
remaining_bytes_ = byte_range_.last_byte_position() -
|
||||
byte_range_.first_byte_position() + 1;
|
||||
|
||||
if (remaining_bytes_ > 0 && byte_range_.first_byte_position() != 0) {
|
||||
int rv = stream_->Seek(base::File::FROM_BEGIN,
|
||||
byte_range_.first_byte_position(),
|
||||
base::Bind(&URLRequestAsarJob::DidSeek,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (rv != net::ERR_IO_PENDING) {
|
||||
// stream_->Seek() failed, so pass an intentionally erroneous value
|
||||
// into DidSeek().
|
||||
DidSeek(-1);
|
||||
}
|
||||
} else {
|
||||
// We didn't need to call stream_->Seek() at all, so we pass to DidSeek()
|
||||
// the value that would mean seek success. This way we skip the code
|
||||
// handling seek failure.
|
||||
DidSeek(byte_range_.first_byte_position());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestAsarJob::DidSeek(int64 result) {
|
||||
if (result != static_cast<int64>(file_info_.offset)) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
if (type_ == TYPE_ASAR) {
|
||||
if (result != static_cast<int64>(file_info_.offset)) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (result != byte_range_.first_byte_position()) {
|
||||
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
|
||||
net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
set_expected_content_size(remaining_bytes_);
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "atom/common/asar/archive.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/http/http_byte_range.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
|
||||
namespace base {
|
||||
|
@ -34,11 +36,20 @@ net::URLRequestJob* CreateJobFromPath(
|
|||
class URLRequestAsarJob : public net::URLRequestJob {
|
||||
public:
|
||||
URLRequestAsarJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info,
|
||||
const scoped_refptr<base::TaskRunner>& file_task_runner);
|
||||
net::NetworkDelegate* network_delegate);
|
||||
|
||||
void Initialize(const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path);
|
||||
|
||||
protected:
|
||||
virtual ~URLRequestAsarJob();
|
||||
|
||||
void InitializeAsarJob(const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
std::shared_ptr<Archive> archive,
|
||||
const base::FilePath& file_path,
|
||||
const Archive::FileInfo& file_info);
|
||||
void InitializeFileJob(const scoped_refptr<base::TaskRunner> file_task_runner,
|
||||
const base::FilePath& file_path);
|
||||
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
|
@ -46,12 +57,39 @@ class URLRequestAsarJob : public net::URLRequestJob {
|
|||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int* bytes_read) override;
|
||||
bool IsRedirectResponse(GURL* location, int* http_status_code) override;
|
||||
net::Filter* SetupFilter() const override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
|
||||
protected:
|
||||
virtual ~URLRequestAsarJob();
|
||||
void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
|
||||
|
||||
private:
|
||||
// Meta information about the file. It's used as a member in the
|
||||
// URLRequestFileJob and also passed between threads because disk access is
|
||||
// necessary to obtain it.
|
||||
struct FileMetaInfo {
|
||||
FileMetaInfo();
|
||||
|
||||
// Size of the file.
|
||||
int64 file_size;
|
||||
// Mime type associated with the file.
|
||||
std::string mime_type;
|
||||
// Result returned from GetMimeTypeFromFile(), i.e. flag showing whether
|
||||
// obtaining of the mime type was successful.
|
||||
bool mime_type_result;
|
||||
// Flag showing whether the file exists.
|
||||
bool file_exists;
|
||||
// Flag showing whether the file name actually refers to a directory.
|
||||
bool is_directory;
|
||||
};
|
||||
|
||||
// Fetches file info on a background thread.
|
||||
static void FetchMetaInfo(const base::FilePath& file_path,
|
||||
FileMetaInfo* meta_info);
|
||||
|
||||
// Callback after fetching file info on a background thread.
|
||||
void DidFetchMetaInfo(const FileMetaInfo* meta_info);
|
||||
|
||||
|
||||
// Callback after opening file on a background thread.
|
||||
void DidOpen(int result);
|
||||
|
||||
|
@ -62,14 +100,24 @@ class URLRequestAsarJob : public net::URLRequestJob {
|
|||
// Callback after data is asynchronously read from the file into |buf|.
|
||||
void DidRead(scoped_refptr<net::IOBuffer> buf, int result);
|
||||
|
||||
// The type of this job.
|
||||
enum JobType {
|
||||
TYPE_ERROR,
|
||||
TYPE_ASAR,
|
||||
TYPE_FILE,
|
||||
};
|
||||
JobType type_;
|
||||
|
||||
std::shared_ptr<Archive> archive_;
|
||||
base::FilePath file_path_;
|
||||
Archive::FileInfo file_info_;
|
||||
|
||||
scoped_ptr<net::FileStream> stream_;
|
||||
int64 remaining_bytes_;
|
||||
FileMetaInfo meta_info_;
|
||||
scoped_refptr<base::TaskRunner> file_task_runner_;
|
||||
|
||||
const scoped_refptr<base::TaskRunner> file_task_runner_;
|
||||
net::HttpByteRange byte_range_;
|
||||
int64 remaining_bytes_;
|
||||
|
||||
base::WeakPtrFactory<URLRequestAsarJob> weak_ptr_factory_;
|
||||
|
||||
|
|
|
@ -23,10 +23,7 @@ AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
|
|||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler) {
|
||||
if (!protocol_handler) {
|
||||
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
|
@ -39,21 +36,17 @@ bool AtomURLRequestJobFactory::SetProtocolHandler(
|
|||
|
||||
if (ContainsKey(protocol_handler_map_, scheme))
|
||||
return false;
|
||||
protocol_handler_map_[scheme] = protocol_handler;
|
||||
protocol_handler_map_[scheme] = protocol_handler.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
DCHECK(protocol_handler);
|
||||
|
||||
scoped_ptr<ProtocolHandler> AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler) {
|
||||
if (!ContainsKey(protocol_handler_map_, scheme))
|
||||
return nullptr;
|
||||
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
|
||||
protocol_handler_map_[scheme] = protocol_handler;
|
||||
return original_protocol_handler;
|
||||
protocol_handler_map_[scheme] = protocol_handler.release();
|
||||
return make_scoped_ptr(original_protocol_handler);
|
||||
}
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
|
@ -25,13 +24,13 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
|
|||
// 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);
|
||||
bool SetProtocolHandler(
|
||||
const std::string& scheme, scoped_ptr<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);
|
||||
scoped_ptr<ProtocolHandler> ReplaceProtocol(
|
||||
const std::string& scheme, scoped_ptr<ProtocolHandler> protocol_handler);
|
||||
|
||||
// Returns the protocol handler registered with scheme.
|
||||
ProtocolHandler* GetProtocolHandler(const std::string& scheme) const;
|
||||
|
|
131
atom/browser/net/js_asker.cc
Normal file
131
atom/browser/net/js_asker.cc
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/v8_value_converter.h"
|
||||
#include "native_mate/function_template.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
struct CallbackHolder {
|
||||
ResponseCallback callback;
|
||||
};
|
||||
|
||||
// Cached JavaScript version of |HandlerCallback|.
|
||||
v8::Persistent<v8::FunctionTemplate> g_handler_callback_;
|
||||
|
||||
// The callback which is passed to |handler|.
|
||||
void HandlerCallback(v8::Isolate* isolate,
|
||||
v8::Local<v8::External> external,
|
||||
v8::Local<v8::Object> state,
|
||||
mate::Arguments* args) {
|
||||
// Check if the callback has already been called.
|
||||
v8::Local<v8::String> called_symbol = mate::StringToSymbol(isolate, "called");
|
||||
if (state->Has(called_symbol))
|
||||
return; // no nothing
|
||||
else
|
||||
state->Set(called_symbol, v8::Boolean::New(isolate, true));
|
||||
|
||||
// If there is no argument passed then we failed.
|
||||
scoped_ptr<CallbackHolder> holder(
|
||||
static_cast<CallbackHolder*>(external->Value()));
|
||||
CHECK(holder);
|
||||
v8::Local<v8::Value> value;
|
||||
if (!args->GetNext(&value)) {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(holder->callback, false, nullptr));
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass whatever user passed to the actaul request job.
|
||||
V8ValueConverter converter;
|
||||
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
|
||||
scoped_ptr<base::Value> options(converter.FromV8Value(value, context));
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(holder->callback, true, base::Passed(&options)));
|
||||
}
|
||||
|
||||
// func.bind(func, arg1, arg2).
|
||||
// NB(zcbenz): Using C++11 version crashes VS.
|
||||
v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Function> func,
|
||||
v8::Local<v8::Value> arg1,
|
||||
v8::Local<v8::Value> arg2) {
|
||||
v8::MaybeLocal<v8::Value> bind = func->Get(mate::StringToV8(isolate, "bind"));
|
||||
CHECK(!bind.IsEmpty());
|
||||
v8::Local<v8::Function> bind_func =
|
||||
v8::Local<v8::Function>::Cast(bind.ToLocalChecked());
|
||||
v8::Local<v8::Value> converted[] = { func, arg1, arg2 };
|
||||
return bind_func->Call(
|
||||
context, func, arraysize(converted), converted).ToLocalChecked();
|
||||
}
|
||||
|
||||
// Generate the callback that will be passed to |handler|.
|
||||
v8::MaybeLocal<v8::Value> GenerateCallback(v8::Isolate* isolate,
|
||||
v8::Local<v8::Context> context,
|
||||
const ResponseCallback& callback) {
|
||||
// The FunctionTemplate is cached.
|
||||
if (g_handler_callback_.IsEmpty())
|
||||
g_handler_callback_.Reset(
|
||||
isolate,
|
||||
mate::CreateFunctionTemplate(isolate, base::Bind(&HandlerCallback)));
|
||||
|
||||
v8::Local<v8::FunctionTemplate> handler_callback =
|
||||
v8::Local<v8::FunctionTemplate>::New(isolate, g_handler_callback_);
|
||||
CallbackHolder* holder = new CallbackHolder;
|
||||
holder->callback = callback;
|
||||
return BindFunctionWith(isolate, context, handler_callback->GetFunction(),
|
||||
v8::External::New(isolate, holder),
|
||||
v8::Object::New(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AskForOptions(v8::Isolate* isolate,
|
||||
const JavaScriptHandler& handler,
|
||||
net::URLRequest* request,
|
||||
const ResponseCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
// We don't convert the callback to C++ directly because creating
|
||||
// FunctionTemplate will cause memory leak since V8 never releases it. So we
|
||||
// have to create the function object in JavaScript to work around it.
|
||||
v8::MaybeLocal<v8::Value> wrapped_callback = GenerateCallback(
|
||||
isolate, context, callback);
|
||||
if (wrapped_callback.IsEmpty()) {
|
||||
callback.Run(false, nullptr);
|
||||
return;
|
||||
}
|
||||
handler.Run(request, wrapped_callback.ToLocalChecked());
|
||||
}
|
||||
|
||||
bool IsErrorOptions(base::Value* value, int* error) {
|
||||
if (value->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(value);
|
||||
if (dict->GetInteger("error", error))
|
||||
return true;
|
||||
} else if (value->IsType(base::Value::TYPE_INTEGER)) {
|
||||
if (value->GetAsInteger(error))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace atom
|
102
atom/browser/net/js_asker.h
Normal file
102
atom/browser/net/js_asker.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_JS_ASKER_H_
|
||||
#define ATOM_BROWSER_NET_JS_ASKER_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
using JavaScriptHandler =
|
||||
base::Callback<void(const net::URLRequest*, v8::Local<v8::Value>)>;
|
||||
|
||||
namespace internal {
|
||||
|
||||
using ResponseCallback =
|
||||
base::Callback<void(bool, scoped_ptr<base::Value> options)>;
|
||||
|
||||
// Ask handler for options in UI thread.
|
||||
void AskForOptions(v8::Isolate* isolate,
|
||||
const JavaScriptHandler& handler,
|
||||
net::URLRequest* request,
|
||||
const ResponseCallback& callback);
|
||||
|
||||
// Test whether the |options| means an error.
|
||||
bool IsErrorOptions(base::Value* value, int* error);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<typename RequestJob>
|
||||
class JsAsker : public RequestJob {
|
||||
public:
|
||||
JsAsker(net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: RequestJob(request, network_delegate), weak_factory_(this) {}
|
||||
|
||||
// Called by |CustomProtocolHandler| to store handler related information.
|
||||
void SetHandlerInfo(
|
||||
v8::Isolate* isolate,
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const JavaScriptHandler& handler) {
|
||||
isolate_ = isolate;
|
||||
request_context_getter_ = request_context_getter;
|
||||
handler_ = handler;
|
||||
}
|
||||
|
||||
// Subclass should do initailze work here.
|
||||
virtual void StartAsync(scoped_ptr<base::Value> options) = 0;
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter() const {
|
||||
return request_context_getter_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
// RequestJob:
|
||||
void Start() override {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&internal::AskForOptions,
|
||||
isolate_,
|
||||
handler_,
|
||||
RequestJob::request(),
|
||||
base::Bind(&JsAsker::OnResponse,
|
||||
weak_factory_.GetWeakPtr())));
|
||||
}
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override {
|
||||
info->headers = new net::HttpResponseHeaders("");
|
||||
}
|
||||
|
||||
// Called when the JS handler has sent the response, we need to decide whether
|
||||
// to start, or fail the job.
|
||||
void OnResponse(bool success, scoped_ptr<base::Value> value) {
|
||||
int error = net::ERR_NOT_IMPLEMENTED;
|
||||
if (success && value && !internal::IsErrorOptions(value.get(), &error)) {
|
||||
StartAsync(value.Pass());
|
||||
} else {
|
||||
RequestJob::NotifyStartError(
|
||||
net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
|
||||
}
|
||||
}
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
JavaScriptHandler handler_;
|
||||
|
||||
base::WeakPtrFactory<JsAsker> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(JsAsker);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_JS_ASKER_H_
|
37
atom/browser/net/url_request_async_asar_job.cc
Normal file
37
atom/browser/net/url_request_async_asar_job.cc
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/url_request_async_asar_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
UrlRequestAsyncAsarJob::UrlRequestAsyncAsarJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<asar::URLRequestAsarJob>(request, network_delegate) {
|
||||
}
|
||||
|
||||
void UrlRequestAsyncAsarJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
base::FilePath::StringType file_path;
|
||||
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
static_cast<base::DictionaryValue*>(options.get())->GetString(
|
||||
"path", &file_path);
|
||||
} else if (options->IsType(base::Value::TYPE_STRING)) {
|
||||
options->GetAsString(&file_path);
|
||||
}
|
||||
|
||||
if (file_path.empty()) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
|
||||
} else {
|
||||
asar::URLRequestAsarJob::Initialize(
|
||||
content::BrowserThread::GetBlockingPool()->
|
||||
GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
|
||||
base::FilePath(file_path));
|
||||
asar::URLRequestAsarJob::Start();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
27
atom/browser/net/url_request_async_asar_job.h
Normal file
27
atom/browser/net/url_request_async_asar_job.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
#define ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
||||
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Like URLRequestAsarJob, but asks the JavaScript handler for file path.
|
||||
class UrlRequestAsyncAsarJob : public JsAsker<asar::URLRequestAsarJob> {
|
||||
public:
|
||||
UrlRequestAsyncAsarJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(UrlRequestAsyncAsarJob);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_
|
|
@ -11,15 +11,32 @@
|
|||
namespace atom {
|
||||
|
||||
URLRequestBufferJob::URLRequestBufferJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data)
|
||||
: net::URLRequestSimpleJob(request, network_delegate),
|
||||
mime_type_(mime_type),
|
||||
charset_(charset),
|
||||
buffer_data_(data) {
|
||||
net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestSimpleJob>(request, network_delegate) {
|
||||
}
|
||||
|
||||
void URLRequestBufferJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
const base::BinaryValue* binary = nullptr;
|
||||
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("mimeType", &mime_type_);
|
||||
dict->GetString("charset", &charset_);
|
||||
dict->GetBinary("data", &binary);
|
||||
} else if (options->IsType(base::Value::TYPE_BINARY)) {
|
||||
options->GetAsBinary(&binary);
|
||||
}
|
||||
|
||||
if (!binary) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
|
||||
return;
|
||||
}
|
||||
|
||||
data_ = new base::RefCountedBytes(
|
||||
reinterpret_cast<const unsigned char*>(binary->GetBuffer()),
|
||||
binary->GetSize());
|
||||
net::URLRequestSimpleJob::Start();
|
||||
}
|
||||
|
||||
int URLRequestBufferJob::GetRefCountedData(
|
||||
|
@ -29,7 +46,7 @@ int URLRequestBufferJob::GetRefCountedData(
|
|||
const net::CompletionCallback& callback) const {
|
||||
*mime_type = mime_type_;
|
||||
*charset = charset_;
|
||||
*data = buffer_data_;
|
||||
*data = data_;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,19 +7,18 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class URLRequestBufferJob : public net::URLRequestSimpleJob {
|
||||
class URLRequestBufferJob : public JsAsker<net::URLRequestSimpleJob> {
|
||||
public:
|
||||
URLRequestBufferJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data);
|
||||
URLRequestBufferJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
int GetRefCountedData(std::string* mime_type,
|
||||
|
@ -30,7 +29,7 @@ class URLRequestBufferJob : public net::URLRequestSimpleJob {
|
|||
private:
|
||||
std::string mime_type_;
|
||||
std::string charset_;
|
||||
scoped_refptr<base::RefCountedBytes> buffer_data_;
|
||||
scoped_refptr<base::RefCountedBytes> data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestBufferJob);
|
||||
};
|
||||
|
|
|
@ -75,42 +75,65 @@ class ResponsePiper : public net::URLFetcherResponseWriter {
|
|||
} // namespace
|
||||
|
||||
URLRequestFetchJob::URLRequestFetchJob(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer)
|
||||
: net::URLRequestJob(request, network_delegate),
|
||||
net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestJob>(request, network_delegate),
|
||||
pending_buffer_size_(0) {
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
if (!options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url, method, referrer;
|
||||
base::Value* session = nullptr;
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("url", &url);
|
||||
dict->GetString("method", &method);
|
||||
dict->GetString("referrer", &referrer);
|
||||
dict->Get("session", &session);
|
||||
|
||||
// Check if URL is valid.
|
||||
GURL formated_url(url);
|
||||
if (!formated_url.is_valid()) {
|
||||
NotifyStartError(net::URLRequestStatus(
|
||||
net::URLRequestStatus::FAILED, net::ERR_INVALID_URL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use |request|'s method if |method| is not specified.
|
||||
net::URLFetcher::RequestType request_type;
|
||||
if (method.empty())
|
||||
request_type = GetRequestType(request->method());
|
||||
request_type = GetRequestType(request()->method());
|
||||
else
|
||||
request_type = GetRequestType(method);
|
||||
|
||||
fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
|
||||
// Use request context if provided else create one.
|
||||
if (request_context_getter)
|
||||
fetcher_->SetRequestContext(request_context_getter.get());
|
||||
else
|
||||
fetcher_->SetRequestContext(GetRequestContext());
|
||||
|
||||
fetcher_ = net::URLFetcher::Create(formated_url, request_type, this);
|
||||
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
|
||||
|
||||
// When |session| is set to |null| we use a new request context for fetch job.
|
||||
if (session && session->IsType(base::Value::TYPE_NULL))
|
||||
fetcher_->SetRequestContext(CreateRequestContext());
|
||||
else
|
||||
fetcher_->SetRequestContext(request_context_getter());
|
||||
|
||||
// Use |request|'s referrer if |referrer| is not specified.
|
||||
if (referrer.empty()) {
|
||||
fetcher_->SetReferrer(request->referrer());
|
||||
} else {
|
||||
if (referrer.empty())
|
||||
fetcher_->SetReferrer(request()->referrer());
|
||||
else
|
||||
fetcher_->SetReferrer(referrer);
|
||||
}
|
||||
|
||||
// Use |request|'s headers.
|
||||
fetcher_->SetExtraRequestHeaders(request->extra_request_headers().ToString());
|
||||
fetcher_->SetExtraRequestHeaders(
|
||||
request()->extra_request_headers().ToString());
|
||||
|
||||
fetcher_->Start();
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* URLRequestFetchJob::GetRequestContext() {
|
||||
net::URLRequestContextGetter* URLRequestFetchJob::CreateRequestContext() {
|
||||
if (!url_request_context_getter_.get()) {
|
||||
auto task_runner = base::ThreadTaskRunnerHandle::Get();
|
||||
net::URLRequestContextBuilder builder;
|
||||
|
@ -150,12 +173,8 @@ int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, int num_bytes) {
|
|||
return bytes_read;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Start() {
|
||||
fetcher_->Start();
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Kill() {
|
||||
URLRequestJob::Kill();
|
||||
JsAsker<URLRequestJob>::Kill();
|
||||
fetcher_.reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_fetcher_delegate.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
|
@ -15,22 +16,20 @@ namespace atom {
|
|||
|
||||
class AtomBrowserContext;
|
||||
|
||||
class URLRequestFetchJob : public net::URLRequestJob,
|
||||
class URLRequestFetchJob : public JsAsker<net::URLRequestJob>,
|
||||
public net::URLFetcherDelegate {
|
||||
public:
|
||||
URLRequestFetchJob(scoped_refptr<net::URLRequestContextGetter> context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
URLRequestFetchJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
net::URLRequestContextGetter* GetRequestContext();
|
||||
// Called by response writer.
|
||||
void HeadersCompleted();
|
||||
int DataAvailable(net::IOBuffer* buffer, int num_bytes);
|
||||
|
||||
protected:
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
|
@ -43,6 +42,9 @@ class URLRequestFetchJob : public net::URLRequestJob,
|
|||
void OnURLFetchComplete(const net::URLFetcher* source) override;
|
||||
|
||||
private:
|
||||
// Create a independent request context.
|
||||
net::URLRequestContextGetter* CreateRequestContext();
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
|
||||
scoped_ptr<net::URLFetcher> fetcher_;
|
||||
scoped_refptr<net::IOBuffer> pending_buffer_;
|
||||
|
|
|
@ -10,15 +10,22 @@
|
|||
|
||||
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) {
|
||||
URLRequestStringJob::URLRequestStringJob(
|
||||
net::URLRequest* request, net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestSimpleJob>(request, network_delegate) {
|
||||
}
|
||||
|
||||
void URLRequestStringJob::StartAsync(scoped_ptr<base::Value> options) {
|
||||
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
dict->GetString("mimeType", &mime_type_);
|
||||
dict->GetString("charset", &charset_);
|
||||
dict->GetString("data", &data_);
|
||||
} else if (options->IsType(base::Value::TYPE_STRING)) {
|
||||
options->GetAsString(&data_);
|
||||
}
|
||||
net::URLRequestSimpleJob::Start();
|
||||
}
|
||||
|
||||
int URLRequestStringJob::GetData(
|
||||
|
|
|
@ -5,19 +5,19 @@
|
|||
#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"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class URLRequestStringJob : public net::URLRequestSimpleJob {
|
||||
class URLRequestStringJob : public JsAsker<net::URLRequestSimpleJob> {
|
||||
public:
|
||||
URLRequestStringJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data);
|
||||
URLRequestStringJob(net::URLRequest*, net::NetworkDelegate*);
|
||||
|
||||
// JsAsker:
|
||||
void StartAsync(scoped_ptr<base::Value> options) override;
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
int GetData(std::string* mime_type,
|
||||
|
|
|
@ -158,9 +158,11 @@ void WebViewGuestDelegate::SetGuestHost(content::GuestHost* guest_host) {
|
|||
void WebViewGuestDelegate::WillAttach(
|
||||
content::WebContents* embedder_web_contents,
|
||||
int element_instance_id,
|
||||
bool is_full_page_plugin) {
|
||||
bool is_full_page_plugin,
|
||||
const base::Closure& completion_callback) {
|
||||
embedder_web_contents_ = embedder_web_contents;
|
||||
is_full_page_plugin_ = is_full_page_plugin;
|
||||
completion_callback.Run();
|
||||
}
|
||||
|
||||
void WebViewGuestDelegate::GuestSizeChangedDueToAutoSize(
|
||||
|
|
|
@ -70,7 +70,8 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
|
|||
void SetGuestHost(content::GuestHost* guest_host) final;
|
||||
void WillAttach(content::WebContents* embedder_web_contents,
|
||||
int element_instance_id,
|
||||
bool is_full_page_plugin) final;
|
||||
bool is_full_page_plugin,
|
||||
const base::Closure& completion_callback) final;
|
||||
|
||||
private:
|
||||
// This method is invoked when the contents auto-resized to give the container
|
||||
|
|
|
@ -180,17 +180,18 @@ mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
|
|||
|
||||
v8::Local<v8::Value> NativeImage::ToPNG(v8::Isolate* isolate) {
|
||||
scoped_refptr<base::RefCountedMemory> png = image_.As1xPNGBytes();
|
||||
return node::Buffer::New(isolate,
|
||||
reinterpret_cast<const char*>(png->front()),
|
||||
png->size());
|
||||
return node::Buffer::Copy(isolate,
|
||||
reinterpret_cast<const char*>(png->front()),
|
||||
static_cast<size_t>(png->size())).ToLocalChecked();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> NativeImage::ToJPEG(v8::Isolate* isolate, int quality) {
|
||||
std::vector<unsigned char> output;
|
||||
gfx::JPEG1xEncodedDataFromImage(image_, quality, &output);
|
||||
return node::Buffer::New(isolate,
|
||||
reinterpret_cast<const char*>(&output.front()),
|
||||
output.size());
|
||||
return node::Buffer::Copy(
|
||||
isolate,
|
||||
reinterpret_cast<const char*>(&output.front()),
|
||||
static_cast<size_t>(output.size())).ToLocalChecked();
|
||||
}
|
||||
|
||||
std::string NativeImage::ToDataURL() {
|
||||
|
|
|
@ -73,7 +73,8 @@ class Archive {
|
|||
scoped_ptr<base::DictionaryValue> header_;
|
||||
|
||||
// Cached external temporary files.
|
||||
base::ScopedPtrHashMap<base::FilePath, ScopedTemporaryFile> external_files_;
|
||||
base::ScopedPtrHashMap<base::FilePath, scoped_ptr<ScopedTemporaryFile>>
|
||||
external_files_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Archive);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#ifndef ATOM_COMMON_CHROME_VERSION_H_
|
||||
#define ATOM_COMMON_CHROME_VERSION_H_
|
||||
|
||||
#define CHROME_VERSION_STRING "43.0.2357.65"
|
||||
#define CHROME_VERSION_STRING "44.0.2403.125"
|
||||
#define CHROME_VERSION "v" CHROME_VERSION_STRING
|
||||
|
||||
#endif // ATOM_COMMON_CHROME_VERSION_H_
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/values.h"
|
||||
#include "vendor/node/src/node_buffer.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -211,7 +212,7 @@ base::Value* V8ValueConverter::FromV8ValueImpl(
|
|||
return NULL;
|
||||
|
||||
if (val->IsNull())
|
||||
return base::Value::CreateNullValue();
|
||||
return base::Value::CreateNullValue().release();
|
||||
|
||||
if (val->IsBoolean())
|
||||
return new base::FundamentalValue(val->ToBoolean()->Value());
|
||||
|
@ -258,6 +259,10 @@ base::Value* V8ValueConverter::FromV8ValueImpl(
|
|||
return FromV8Object(val->ToObject(), state, isolate);
|
||||
}
|
||||
|
||||
if (node::Buffer::HasInstance(val)) {
|
||||
return FromNodeBuffer(val, state, isolate);
|
||||
}
|
||||
|
||||
if (val->IsObject()) {
|
||||
return FromV8Object(val->ToObject(), state, isolate);
|
||||
}
|
||||
|
@ -271,7 +276,7 @@ base::Value* V8ValueConverter::FromV8Array(
|
|||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
if (!state->UpdateAndCheckUniqueness(val))
|
||||
return base::Value::CreateNullValue();
|
||||
return base::Value::CreateNullValue().release();
|
||||
|
||||
scoped_ptr<v8::Context::Scope> scope;
|
||||
// If val was created in a different context than our current one, change to
|
||||
|
@ -305,12 +310,20 @@ base::Value* V8ValueConverter::FromV8Array(
|
|||
return result;
|
||||
}
|
||||
|
||||
base::Value* V8ValueConverter::FromNodeBuffer(
|
||||
v8::Local<v8::Value> value,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
return base::BinaryValue::CreateWithCopiedBuffer(
|
||||
node::Buffer::Data(value), node::Buffer::Length(value));
|
||||
}
|
||||
|
||||
base::Value* V8ValueConverter::FromV8Object(
|
||||
v8::Local<v8::Object> val,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const {
|
||||
if (!state->UpdateAndCheckUniqueness(val))
|
||||
return base::Value::CreateNullValue();
|
||||
return base::Value::CreateNullValue().release();
|
||||
|
||||
scoped_ptr<v8::Context::Scope> scope;
|
||||
// If val was created in a different context than our current one, change to
|
||||
|
|
|
@ -48,7 +48,9 @@ class V8ValueConverter {
|
|||
base::Value* FromV8Array(v8::Local<v8::Array> array,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const;
|
||||
|
||||
base::Value* FromNodeBuffer(v8::Local<v8::Value> value,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const;
|
||||
base::Value* FromV8Object(v8::Local<v8::Object> object,
|
||||
FromV8ValueState* state,
|
||||
v8::Isolate* isolate) const;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "atom/renderer/atom_render_view_observer.h"
|
||||
|
@ -19,11 +20,14 @@
|
|||
#include "content/public/renderer/render_frame.h"
|
||||
#include "content/public/renderer/render_frame_observer.h"
|
||||
#include "content/public/renderer/render_thread.h"
|
||||
#include "third_party/WebKit/public/web/WebArrayBuffer.h"
|
||||
#include "third_party/WebKit/public/web/WebArrayBufferConverter.h"
|
||||
#include "third_party/WebKit/public/web/WebCustomElement.h"
|
||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebPluginParams.h"
|
||||
#include "third_party/WebKit/public/web/WebKit.h"
|
||||
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
|
||||
#include "third_party/WebKit/Source/wtf/ArrayBufferContents.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
|
@ -52,6 +56,37 @@ bool IsGuestFrame(blink::WebFrame* frame) {
|
|||
return frame->uniqueName().utf8() == "ATOM_SHELL_GUEST_WEB_VIEW";
|
||||
}
|
||||
|
||||
// global.Uint8Array;
|
||||
v8::Local<v8::Function> GetUint8ArrayConstructor(
|
||||
v8::Isolate* isolate, v8::Local<v8::Context> context) {
|
||||
v8::Local<v8::Value> constructor = context->Global()->Get(
|
||||
mate::StringToV8(isolate, "Uint8Array"));
|
||||
return v8::Local<v8::Function>::Cast(constructor);
|
||||
}
|
||||
|
||||
// new ArrayBuffer(size);
|
||||
v8::Local<v8::ArrayBuffer> BlinkArrayBufferCreate(
|
||||
v8::Isolate* isolate, size_t size) {
|
||||
blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(size, 1);
|
||||
return v8::Local<v8::ArrayBuffer>::Cast(
|
||||
blink::WebArrayBufferConverter::toV8Value(
|
||||
&buffer, isolate->GetCurrentContext()->Global(), isolate));
|
||||
}
|
||||
|
||||
// new Uint8Array(array_buffer, offset, size);
|
||||
v8::Local<v8::Uint8Array> BlinkUint8ArrayCreate(
|
||||
v8::Local<v8::ArrayBuffer> ab, size_t offset, size_t size) {
|
||||
v8::Local<v8::Context> context = ab->CreationContext();
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Function> constructor =
|
||||
GetUint8ArrayConstructor(isolate, context);
|
||||
v8::Local<v8::Value> args[] = {
|
||||
ab, mate::ConvertToV8(isolate, offset), mate::ConvertToV8(isolate, size)
|
||||
};
|
||||
return v8::Local<v8::Uint8Array>::Cast(constructor->NewInstance(
|
||||
context, arraysize(args), args).ToLocalChecked());
|
||||
}
|
||||
|
||||
// Helper class to forward the messages to the client.
|
||||
class AtomRenderFrameObserver : public content::RenderFrameObserver {
|
||||
public:
|
||||
|
@ -91,6 +126,10 @@ void AtomRendererClient::WebKitInitialized() {
|
|||
blink::WebCustomElement::addEmbedderCustomElementName("webview");
|
||||
blink::WebCustomElement::addEmbedderCustomElementName("browserplugin");
|
||||
|
||||
// Override Node's ArrayBuffer with DOM's ArrayBuffer.
|
||||
node::Buffer::SetArrayBufferCreator(&BlinkArrayBufferCreate,
|
||||
&BlinkUint8ArrayCreate);
|
||||
|
||||
node_bindings_->Initialize();
|
||||
node_bindings_->PrepareMessageLoop();
|
||||
|
||||
|
|
|
@ -47,14 +47,12 @@ void GuestViewContainer::SetElementInstanceID(int element_instance_id) {
|
|||
std::make_pair(element_instance_id, this));
|
||||
}
|
||||
|
||||
void GuestViewContainer::DidResizeElement(const gfx::Size& old_size,
|
||||
const gfx::Size& new_size) {
|
||||
void GuestViewContainer::DidResizeElement(const gfx::Size& new_size) {
|
||||
if (element_resize_callback_.is_null())
|
||||
return;
|
||||
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(element_resize_callback_, old_size, new_size));
|
||||
FROM_HERE, base::Bind(element_resize_callback_, new_size));
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -16,8 +16,7 @@ namespace atom {
|
|||
|
||||
class GuestViewContainer : public content::BrowserPluginDelegate {
|
||||
public:
|
||||
typedef base::Callback<void(const gfx::Size&, const gfx::Size&)>
|
||||
ResizeCallback;
|
||||
typedef base::Callback<void(const gfx::Size&)> ResizeCallback;
|
||||
|
||||
explicit GuestViewContainer(content::RenderFrame* render_frame);
|
||||
~GuestViewContainer() override;
|
||||
|
@ -28,8 +27,7 @@ class GuestViewContainer : public content::BrowserPluginDelegate {
|
|||
|
||||
// content::BrowserPluginDelegate:
|
||||
void SetElementInstanceID(int element_instance_id) final;
|
||||
void DidResizeElement(const gfx::Size& old_size,
|
||||
const gfx::Size& new_size) final;
|
||||
void DidResizeElement(const gfx::Size& new_size) final;
|
||||
|
||||
private:
|
||||
int element_instance_id_;
|
||||
|
|
|
@ -123,11 +123,9 @@ class WebViewImpl
|
|||
# changed.
|
||||
@dispatchEvent webViewEvent
|
||||
|
||||
onElementResize: (oldSize, newSize) ->
|
||||
onElementResize: (newSize) ->
|
||||
# Dispatch the 'resize' event.
|
||||
resizeEvent = new Event('resize', bubbles: true)
|
||||
resizeEvent.oldWidth = oldSize.width
|
||||
resizeEvent.oldHeight = oldSize.height
|
||||
resizeEvent.newWidth = newSize.width
|
||||
resizeEvent.newHeight = newSize.height
|
||||
@dispatchEvent resizeEvent
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener_win.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/bind_helpers.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/events/keycodes/keyboard_code_conversion_win.h"
|
||||
#include "ui/gfx/win/singleton_hwnd.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
|
@ -35,14 +38,17 @@ GlobalShortcutListenerWin::~GlobalShortcutListenerWin() {
|
|||
void GlobalShortcutListenerWin::StartListening() {
|
||||
DCHECK(!is_listening_); // Don't start twice.
|
||||
DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered.
|
||||
gfx::SingletonHwnd::GetInstance()->AddObserver(this);
|
||||
singleton_hwnd_observer_.reset(new gfx::SingletonHwndObserver(
|
||||
base::Bind(
|
||||
&GlobalShortcutListenerWin::OnWndProc, base::Unretained(this))));
|
||||
|
||||
is_listening_ = true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerWin::StopListening() {
|
||||
DCHECK(is_listening_); // No point if we are not already listening.
|
||||
DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending.
|
||||
gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
|
||||
singleton_hwnd_observer_.reset(nullptr);
|
||||
is_listening_ = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,26 +7,24 @@
|
|||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
#include "ui/gfx/win/singleton_hwnd.h"
|
||||
#include "ui/gfx/win/singleton_hwnd_observer.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// Windows-specific implementation of the GlobalShortcutListener class that
|
||||
// listens for global shortcuts. Handles setting up a keyboard hook and
|
||||
// forwarding its output to the base class for processing.
|
||||
class GlobalShortcutListenerWin : public GlobalShortcutListener,
|
||||
public gfx::SingletonHwnd::Observer {
|
||||
class GlobalShortcutListenerWin : public GlobalShortcutListener {
|
||||
public:
|
||||
GlobalShortcutListenerWin();
|
||||
virtual ~GlobalShortcutListenerWin();
|
||||
|
||||
private:
|
||||
// The implementation of our Window Proc, called by SingletonHwnd.
|
||||
virtual void OnWndProc(HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam) override;
|
||||
// The implementation of our Window Proc, called by SingletonHwndObserver.
|
||||
void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
// GlobalShortcutListener implementation.
|
||||
virtual void StartListening() override;
|
||||
|
@ -43,6 +41,8 @@ class GlobalShortcutListenerWin : public GlobalShortcutListener,
|
|||
typedef std::map<ui::Accelerator, int> HotkeyIdMap;
|
||||
HotkeyIdMap hotkey_ids_;
|
||||
|
||||
scoped_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin);
|
||||
};
|
||||
|
||||
|
|
|
@ -125,8 +125,8 @@ void PrintPreviewMessageHandler::RunPrintToPDFCallback(
|
|||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (data) {
|
||||
v8::Local<v8::Value> buffer = node::Buffer::Use(isolate,
|
||||
data, static_cast<size_t>(data_size));
|
||||
v8::Local<v8::Value> buffer = node::Buffer::New(isolate,
|
||||
data, static_cast<size_t>(data_size)).ToLocalChecked();
|
||||
print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer);
|
||||
} else {
|
||||
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(isolate,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/float_util.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/speech/tts_platform.h"
|
||||
|
@ -461,4 +460,4 @@ void TtsControllerImpl::SetTtsEngineDelegate(
|
|||
|
||||
TtsEngineDelegate* TtsControllerImpl::GetTtsEngineDelegate() {
|
||||
return tts_engine_delegate_;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
'python': 'python',
|
||||
'openssl_fips': '',
|
||||
'openssl_no_asm': 1,
|
||||
'node_release_urlbase': 'https://atom.io/download/atom-shell',
|
||||
'node_byteorder': '<!(python -c "import sys; print sys.byteorder")',
|
||||
'node_target_type': 'shared_library',
|
||||
'node_install_npm': 'false',
|
||||
'node_prefix': '',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# protocol
|
||||
|
||||
The `protocol` module can register a new protocol or intercept an existing
|
||||
protocol, so you can customize the response to the requests for various protocols.
|
||||
The `protocol` module can register a custom protocol or intercept an existing
|
||||
protocol.
|
||||
|
||||
An example of implementing a protocol that has the same effect with the
|
||||
`file://` protocol:
|
||||
|
@ -12,130 +12,149 @@ var path = require('path');
|
|||
|
||||
app.on('ready', function() {
|
||||
var protocol = require('protocol');
|
||||
protocol.registerProtocol('atom', function(request) {
|
||||
var url = request.url.substr(7)
|
||||
return new protocol.RequestFileJob(path.normalize(__dirname + '/' + url));
|
||||
}, function (error, scheme) {
|
||||
if (!error)
|
||||
console.log(scheme, ' registered successfully')
|
||||
protocol.registerFileProtocol('atom', function(request, callback) {
|
||||
var url = request.url.substr(7);
|
||||
callback({path: path.normalize(__dirname + '/' + url)});
|
||||
}, function (error) {
|
||||
if (error)
|
||||
console.error('Failed to register protocol')
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Note:** This module can only be used after the `ready` event
|
||||
was emitted.
|
||||
**Note:** This module can only be used after the `ready` event was emitted.
|
||||
|
||||
## protocol.registerProtocol(scheme, handler, callback)
|
||||
## protocol.registerStandardSchemes(schemes)
|
||||
|
||||
* `schemes` Array - Custom schemes to be registered as standard schemes.
|
||||
|
||||
A standard scheme adheres to what RFC 3986 calls
|
||||
[generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3). This
|
||||
includes `file:` and `filesystem:`.
|
||||
|
||||
## protocol.registerFileProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `callback` Function
|
||||
* `completion` Function
|
||||
|
||||
Registers a custom protocol of `scheme`, the `handler` would be called with
|
||||
`handler(request)` when the a request with registered `scheme` is made.
|
||||
Registers a protocol of `scheme` that will send file as response, the `handler`
|
||||
will be called with `handler(request, callback)` when a `request` is going to be
|
||||
created with `scheme`, and `completion` will be called with `completion(null)`
|
||||
when `scheme` is successfully registered, or `completion(error)` when failed.
|
||||
|
||||
You need to return a request job in the `handler` to specify which type of
|
||||
response you would like to send.
|
||||
To handle the `request`, the `callback` should be called with either file's path
|
||||
or an object that has `path` property, e.g. `callback(filePath)` or
|
||||
`callback({path: filePath})`.
|
||||
|
||||
When `callback` is called with nothing, or a number, or an object that has
|
||||
`error` property, the `request` will be failed with the `error` number you
|
||||
specified. For the available error numbers you can use, please check:
|
||||
https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
|
||||
|
||||
By default the scheme is treated like `http:`, which is parsed differently
|
||||
from protocols that follows "generic URI syntax" like `file:`, so you probably
|
||||
want to call `protocol.registerStandardSchemes` to make your scheme treated as
|
||||
standard scheme.
|
||||
|
||||
## protocol.unregisterProtocol(scheme, callback)
|
||||
## protocol.registerBufferProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `callback` Function
|
||||
* `handler` Function
|
||||
* `completion` Function
|
||||
|
||||
Registers a protocol of `scheme` that will send `Buffer` as response, the
|
||||
`callback` should be called with either an `Buffer` object, or an object that
|
||||
has `data`, `mimeType`, `chart` properties.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
protocol.registerBufferProtocol('atom', function(request, callback) {
|
||||
callback({mimeType: 'text/html', data: new Buffer('<h5>Response</h5>')});
|
||||
}, function (error) {
|
||||
if (error)
|
||||
console.error('Failed to register protocol')
|
||||
});
|
||||
```
|
||||
|
||||
## protocol.registerStringProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `completion` Function
|
||||
|
||||
Registers a protocol of `scheme` that will send `String` as response, the
|
||||
`callback` should be called with either a `String`, or an object that
|
||||
has `data`, `mimeType`, `chart` properties.
|
||||
|
||||
## protocol.registerHttpProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `completion` Function
|
||||
|
||||
Registers a protocol of `scheme` that will send a HTTP request as response, the
|
||||
`callback` should be called with an object that has `url`, `method`, `referer`,
|
||||
`session` properties.
|
||||
|
||||
By default the HTTP request will reuse current session, if you want the request
|
||||
to have different session you should specify `session` to `null`.
|
||||
|
||||
## protocol.unregisterProtocol(scheme[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `completion` Function
|
||||
|
||||
Unregisters the custom protocol of `scheme`.
|
||||
|
||||
## protocol.registerStandardSchemes(value)
|
||||
|
||||
* `value` Array
|
||||
|
||||
`value` is an array of custom schemes to be registered as standard schemes.
|
||||
|
||||
A standard scheme adheres to what RFC 3986 calls
|
||||
[generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3). This
|
||||
includes `file:` and `filesystem:`.
|
||||
|
||||
## protocol.isHandledProtocol(scheme, callback)
|
||||
## protocol.isProtocolHandled(scheme, callback)
|
||||
|
||||
* `scheme` String
|
||||
* `callback` Function
|
||||
|
||||
`callback` returns a boolean whether the `scheme` can be handled already.
|
||||
The `callback` will be called with a boolean that indicates whether there is
|
||||
already a handler for `scheme`.
|
||||
|
||||
## protocol.interceptProtocol(scheme, handler, callback)
|
||||
## protocol.interceptFileProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `callback` Function
|
||||
|
||||
Intercepts an existing protocol with `scheme`, returning `null` or `undefined`
|
||||
in `handler` would use the original protocol handler to handle the request.
|
||||
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
|
||||
which sends file as response.
|
||||
|
||||
## protocol.uninterceptProtocol(scheme, callback)
|
||||
## protocol.interceptStringProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `callback` Function
|
||||
|
||||
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
|
||||
which sends String as response.
|
||||
|
||||
## protocol.interceptBufferProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `callback` Function
|
||||
|
||||
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
|
||||
which sends `Buffer` as response.
|
||||
|
||||
## protocol.interceptHttpProtocol(scheme, handler[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `handler` Function
|
||||
* `callback` Function
|
||||
|
||||
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
|
||||
which sends a new HTTP request as response.
|
||||
|
||||
## protocol.uninterceptProtocol(scheme[, completion])
|
||||
|
||||
* `scheme` String
|
||||
* `callback` Function
|
||||
|
||||
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.
|
||||
|
||||
## Class: protocol.RequestBufferJob(options)
|
||||
|
||||
* `options` Object
|
||||
* `mimeType` String - Default is `application/octet-stream`
|
||||
* `encoding` String - Default is `UTF-8`
|
||||
* `data` Buffer
|
||||
|
||||
Create a request job which sends a buffer as response.
|
||||
|
||||
## Class: protocol.RequestHttpJob(options)
|
||||
|
||||
* `options` Object
|
||||
* `session` [Session](browser-window.md#class-session) - By default it is
|
||||
the app's default session, setting it to `null` will create a new session
|
||||
for the requests
|
||||
* `url` String
|
||||
* `method` String - Default is `GET`
|
||||
* `referrer` String
|
||||
|
||||
Send a request to `url` and pipe the response back.
|
||||
|
||||
## Class: protocol.RequestErrorJob(code)
|
||||
|
||||
* `code` Integer
|
||||
|
||||
Create a request job which sets appropriate network error message to console.
|
||||
Default message is `net::ERR_NOT_IMPLEMENTED`. Code should be in the following
|
||||
range.
|
||||
|
||||
* Ranges:
|
||||
* 0- 99 System related errors
|
||||
* 100-199 Connection related errors
|
||||
* 200-299 Certificate errors
|
||||
* 300-399 HTTP errors
|
||||
* 400-499 Cache errors
|
||||
* 500-599 ?
|
||||
* 600-699 FTP errors
|
||||
* 700-799 Certificate manager errors
|
||||
* 800-899 DNS resolver errors
|
||||
|
||||
Check the [network error list](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) for code and message relations.
|
||||
Remove the interceptor installed for `scheme` and restore its original handler.
|
||||
|
|
|
@ -146,8 +146,6 @@
|
|||
'atom/browser/native_window_mac.h',
|
||||
'atom/browser/native_window_mac.mm',
|
||||
'atom/browser/native_window_observer.h',
|
||||
'atom/browser/net/adapter_request_job.cc',
|
||||
'atom/browser/net/adapter_request_job.h',
|
||||
'atom/browser/net/asar/asar_protocol_handler.cc',
|
||||
'atom/browser/net/asar/asar_protocol_handler.h',
|
||||
'atom/browser/net/asar/url_request_asar_job.cc',
|
||||
|
@ -156,6 +154,10 @@
|
|||
'atom/browser/net/atom_url_request_job_factory.h',
|
||||
'atom/browser/net/http_protocol_handler.cc',
|
||||
'atom/browser/net/http_protocol_handler.h',
|
||||
'atom/browser/net/js_asker.cc',
|
||||
'atom/browser/net/js_asker.h',
|
||||
'atom/browser/net/url_request_async_asar_job.cc',
|
||||
'atom/browser/net/url_request_async_asar_job.h',
|
||||
'atom/browser/net/url_request_string_job.cc',
|
||||
'atom/browser/net/url_request_string_job.h',
|
||||
'atom/browser/net/url_request_buffer_job.cc',
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"coffee-script": "^1.9.2",
|
||||
"coffeelint": "^1.9.4",
|
||||
"request": "*",
|
||||
"runas": "^2.0.0"
|
||||
"runas": "3.x"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
|
|
@ -69,9 +69,9 @@ def main():
|
|||
run_script('build.py', ['-c', 'R'])
|
||||
run_script('create-dist.py')
|
||||
run_script('upload.py')
|
||||
elif PLATFORM == 'win32' or target_arch == 'x64':
|
||||
else:
|
||||
run_script('build.py', ['-c', 'D'])
|
||||
if PLATFORM != 'win32':
|
||||
if PLATFORM != 'win32' and target_arch == 'x64':
|
||||
run_script('test.py', ['--ci'])
|
||||
|
||||
run_script('clean.py')
|
||||
|
|
|
@ -31,7 +31,6 @@ TARGET_BINARIES = {
|
|||
'{0}.exe'.format(PROJECT_NAME), # 'electron.exe'
|
||||
'content_shell.pak',
|
||||
'd3dcompiler_47.dll',
|
||||
'ffmpegsumo.dll',
|
||||
'icudtl.dat',
|
||||
'libEGL.dll',
|
||||
'libGLESv2.dll',
|
||||
|
@ -50,7 +49,6 @@ TARGET_BINARIES = {
|
|||
PROJECT_NAME, # 'electron'
|
||||
'content_shell.pak',
|
||||
'icudtl.dat',
|
||||
'libffmpegsumo.so',
|
||||
'libnode.so',
|
||||
'natives_blob.bin',
|
||||
'snapshot_blob.bin',
|
||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
|||
|
||||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||
'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = 'dd51a41b42246b0b5159bfad5e327c8cf10bc585'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '42200d8ec0b77c7491d3a09611c23eb771e0862d'
|
||||
|
||||
PLATFORM = {
|
||||
'cygwin': 'win32',
|
||||
|
|
|
@ -1,278 +1,342 @@
|
|||
assert = require 'assert'
|
||||
ipc = require 'ipc'
|
||||
http = require 'http'
|
||||
path = require 'path'
|
||||
remote = require 'remote'
|
||||
protocol = remote.require 'protocol'
|
||||
|
||||
describe 'protocol module', ->
|
||||
describe 'protocol.registerProtocol', ->
|
||||
it 'error when scheme is already registered', (done) ->
|
||||
register = ->
|
||||
protocol.registerProtocol 'test1', ((request) ->), (error, scheme) ->
|
||||
if error?
|
||||
protocol.unregisterProtocol 'test1', (error, scheme) ->
|
||||
assert.equal scheme, 'test1'
|
||||
done()
|
||||
else
|
||||
assert.equal scheme, 'test1'
|
||||
register()
|
||||
register()
|
||||
protocolName = 'sp'
|
||||
text = 'valar morghulis'
|
||||
|
||||
it 'calls the callback when scheme is visited', (done) ->
|
||||
protocol.registerProtocol 'test2', (request) ->
|
||||
assert.equal request.url, 'test2://test2'
|
||||
protocol.unregisterProtocol 'test2'
|
||||
done()
|
||||
$.get 'test2://test2', ->
|
||||
afterEach (done) ->
|
||||
protocol.unregisterProtocol protocolName, ->
|
||||
protocol.uninterceptProtocol 'http', -> done()
|
||||
|
||||
describe 'protocol.register(Any)Protocol', ->
|
||||
emptyHandler = (request, callback) -> callback()
|
||||
it 'throws error when scheme is already registered', (done) ->
|
||||
protocol.registerStringProtocol protocolName, emptyHandler, (error) ->
|
||||
assert.equal error, null
|
||||
protocol.registerBufferProtocol protocolName, emptyHandler, (error) ->
|
||||
assert.notEqual error, null
|
||||
done()
|
||||
|
||||
it 'does not crash when handler is called twice', (done) ->
|
||||
doubleHandler = (request, callback) ->
|
||||
callback(text)
|
||||
callback()
|
||||
protocol.registerStringProtocol protocolName, doubleHandler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'sends error when callback is called with nothing', (done) ->
|
||||
protocol.registerBufferProtocol protocolName, emptyHandler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
it 'does not crash when callback is called in next tick', (done) ->
|
||||
handler = (request, callback) ->
|
||||
setImmediate -> callback(text)
|
||||
protocol.registerStringProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
describe 'protocol.unregisterProtocol', ->
|
||||
it 'throws error when scheme does not exist', ->
|
||||
protocol.unregisterProtocol 'test3', (->), (error, scheme) ->
|
||||
if (error)
|
||||
assert.equal scheme, 'test3'
|
||||
done()
|
||||
it 'returns error when scheme does not exist', (done) ->
|
||||
protocol.unregisterProtocol 'not-exist', (error) ->
|
||||
assert.notEqual error, null
|
||||
done()
|
||||
|
||||
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
|
||||
describe 'protocol.registerStringProtocol', ->
|
||||
it 'sends string as response', (done) ->
|
||||
handler = (request, callback) -> callback(text)
|
||||
protocol.registerStringProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
$.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 'sends object as response', (done) ->
|
||||
handler = (request, callback) -> callback(data: text, mimeType: 'text/html')
|
||||
protocol.registerStringProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data, statux, request) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
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
|
||||
it 'fails when sending object other than string', (done) ->
|
||||
handler = (request, callback) -> callback(new Date)
|
||||
protocol.registerBufferProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
$.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'
|
||||
describe 'protocol.registerBufferProtocol', ->
|
||||
buffer = new Buffer(text)
|
||||
|
||||
it 'returns RequestErrorJob should send error', (done) ->
|
||||
data = 'valar morghulis'
|
||||
job = new protocol.RequestErrorJob(-6)
|
||||
handler = remote.createFunctionWithReturnValue job
|
||||
protocol.registerProtocol 'atom-error-job', handler
|
||||
it 'sends Buffer as response', (done) ->
|
||||
handler = (request, callback) -> callback(buffer)
|
||||
protocol.registerBufferProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
$.ajax
|
||||
url: 'atom-error-job://fake-host'
|
||||
success: (response) ->
|
||||
assert false, 'should not reach here'
|
||||
error: (xhr, errorType, error) ->
|
||||
assert errorType, 'error'
|
||||
protocol.unregisterProtocol 'atom-error-job'
|
||||
done()
|
||||
it 'sends object as response', (done) ->
|
||||
handler = (request, callback) -> callback(data: buffer, mimeType: 'text/html')
|
||||
protocol.registerBufferProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data, statux, request) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'returns RequestHttpJob should send respone', (done) ->
|
||||
it 'fails when sending string', (done) ->
|
||||
handler = (request, callback) -> callback(text)
|
||||
protocol.registerBufferProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
describe 'protocol.registerFileProtocol', ->
|
||||
filePath = path.join __dirname, 'fixtures', 'asar', 'a.asar', 'file1'
|
||||
fileContent = require('fs').readFileSync(filePath)
|
||||
|
||||
normalPath = path.join __dirname, 'fixtures', 'pages', 'a.html'
|
||||
normalContent = require('fs').readFileSync(normalPath)
|
||||
|
||||
it 'sends file path as response', (done) ->
|
||||
handler = (request, callback) -> callback(filePath)
|
||||
protocol.registerFileProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, String(fileContent)
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'sends object as response', (done) ->
|
||||
handler = (request, callback) -> callback(path: filePath)
|
||||
protocol.registerFileProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data, statux, request) ->
|
||||
assert.equal data, String(fileContent)
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'can send normal file', (done) ->
|
||||
handler = (request, callback) -> callback(normalPath)
|
||||
protocol.registerFileProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, String(normalContent)
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'fails when sending unexist-file', (done) ->
|
||||
fakeFilePath = path.join __dirname, 'fixtures', 'asar', 'a.asar', 'not-exist'
|
||||
handler = (request, callback) -> callback(fakeFilePath)
|
||||
protocol.registerBufferProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
it 'fails when sending unsupported content', (done) ->
|
||||
handler = (request, callback) -> callback(new Date)
|
||||
protocol.registerBufferProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
describe 'protocol.registerHttpProtocol', ->
|
||||
it 'sends url as response', (done) ->
|
||||
server = http.createServer (req, res) ->
|
||||
assert.notEqual req.headers.accept, ''
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'})
|
||||
res.end('hello')
|
||||
res.end(text)
|
||||
server.close()
|
||||
server.listen 0, '127.0.0.1', ->
|
||||
{port} = server.address()
|
||||
url = "http://127.0.0.1:#{port}"
|
||||
job = new protocol.RequestHttpJob({url})
|
||||
handler = remote.createFunctionWithReturnValue job
|
||||
protocol.registerProtocol 'atom-http-job', handler
|
||||
handler = (request, callback) -> callback({url})
|
||||
protocol.registerHttpProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'fails when sending invalid url', (done) ->
|
||||
handler = (request, callback) -> callback({url: 'url'})
|
||||
protocol.registerHttpProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: 'atom-http-job://fake-host'
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
assert.equal data, 'hello'
|
||||
protocol.unregisterProtocol 'atom-http-job'
|
||||
done()
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert false, 'Got error: ' + errorType + ' ' + error
|
||||
protocol.unregisterProtocol 'atom-http-job'
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
it 'returns RequestBufferJob should send buffer', (done) ->
|
||||
data = new Buffer("hello")
|
||||
job = new protocol.RequestBufferJob(data: data)
|
||||
handler = remote.createFunctionWithReturnValue job
|
||||
protocol.registerProtocol 'atom-buffer-job', handler
|
||||
it 'fails when sending unsupported content', (done) ->
|
||||
handler = (request, callback) -> callback(new Date)
|
||||
protocol.registerHttpProtocol protocolName, handler, (error) ->
|
||||
$.ajax
|
||||
url: "#{protocolName}://fake-host"
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
$.ajax
|
||||
url: 'atom-buffer-job://fake-host'
|
||||
success: (response) ->
|
||||
assert.equal response.length, data.length
|
||||
buf = new Buffer(response.length)
|
||||
buf.write(response)
|
||||
assert buf.equals(data)
|
||||
protocol.unregisterProtocol 'atom-buffer-job'
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
assert false, 'Got error: ' + errorType + ' ' + error
|
||||
protocol.unregisterProtocol 'atom-buffer-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'
|
||||
|
||||
it 'returns RequestFileJob should send file from asar archive', (done) ->
|
||||
p = path.join __dirname, 'fixtures', 'asar', 'a.asar', 'file1'
|
||||
job = new protocol.RequestFileJob(p)
|
||||
handler = remote.createFunctionWithReturnValue job
|
||||
protocol.registerProtocol 'atom-file-job', handler
|
||||
|
||||
$.ajax
|
||||
url: 'atom-file-job://' + p
|
||||
success: (data) ->
|
||||
content = require('fs').readFileSync(p)
|
||||
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'
|
||||
|
||||
it 'returns RequestFileJob should send file from asar archive with unpacked file', (done) ->
|
||||
p = path.join __dirname, 'fixtures', 'asar', 'unpack.asar', 'a.txt'
|
||||
job = new protocol.RequestFileJob(p)
|
||||
handler = remote.createFunctionWithReturnValue job
|
||||
protocol.registerProtocol 'atom-file-job', handler
|
||||
|
||||
$.ajax
|
||||
url: 'atom-file-job://' + p
|
||||
success: (response) ->
|
||||
data = require('fs').readFileSync(p)
|
||||
assert.equal response.length, data.length
|
||||
buf = new Buffer(response.length)
|
||||
buf.write(response)
|
||||
assert buf.equals(data)
|
||||
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 file scheme can be handled', (done) ->
|
||||
protocol.isHandledProtocol 'file', (result) ->
|
||||
describe 'protocol.isProtocolHandled', ->
|
||||
it 'returns true for file:', (done) ->
|
||||
protocol.isProtocolHandled 'file', (result) ->
|
||||
assert.equal result, true
|
||||
done()
|
||||
it 'returns true if the http scheme can be handled', (done) ->
|
||||
protocol.isHandledProtocol 'http', (result) ->
|
||||
|
||||
it 'returns true for http:', (done) ->
|
||||
protocol.isProtocolHandled 'http', (result) ->
|
||||
assert.equal result, true
|
||||
done()
|
||||
it 'returns true if the https scheme can be handled', (done) ->
|
||||
protocol.isHandledProtocol 'https', (result) ->
|
||||
|
||||
it 'returns true for https:', (done) ->
|
||||
protocol.isProtocolHandled 'https', (result) ->
|
||||
assert.equal result, true
|
||||
done()
|
||||
it 'returns false if the atom scheme cannot be handled', (done) ->
|
||||
protocol.isHandledProtocol 'atom', (result) ->
|
||||
|
||||
it 'returns false when scheme is not registred', (done) ->
|
||||
protocol.isProtocolHandled 'no-exist', (result) ->
|
||||
assert.equal result, false
|
||||
done()
|
||||
|
||||
describe 'protocol.interceptProtocol', ->
|
||||
it 'throws error when scheme is not a registered one', (done) ->
|
||||
protocol.interceptProtocol 'test-intercept', ( ->), (error, scheme) ->
|
||||
if error?
|
||||
assert.equal scheme, 'test-intercept'
|
||||
it 'returns true for custom protocol', (done) ->
|
||||
emptyHandler = (request, callback) -> callback()
|
||||
protocol.registerStringProtocol protocolName, emptyHandler, (error) ->
|
||||
assert.equal error, null
|
||||
protocol.isProtocolHandled protocolName, (result) ->
|
||||
assert.equal result, true
|
||||
done()
|
||||
|
||||
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'
|
||||
protocol.interceptProtocol 'test-intercept', (->), (error, newScheme) ->
|
||||
if error?
|
||||
assert.equal newScheme, 'test-intercept'
|
||||
protocol.unregisterProtocol scheme
|
||||
protocol.registerProtocol('atom', ->)
|
||||
it 'returns true for intercepted protocol', (done) ->
|
||||
emptyHandler = (request, callback) -> callback()
|
||||
protocol.interceptStringProtocol 'http', emptyHandler, (error) ->
|
||||
assert.equal error, null
|
||||
protocol.isProtocolHandled 'http', (result) ->
|
||||
assert.equal result, true
|
||||
done()
|
||||
|
||||
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) ->
|
||||
if process.platform is 'win32'
|
||||
pathInUrl = path.normalize request.url.substr(8)
|
||||
assert.equal pathInUrl.toLowerCase(), __filename.toLowerCase()
|
||||
else
|
||||
assert.equal request.url, "#{targetScheme}://#{__filename}"
|
||||
describe 'protocol.intercept(Any)Protocol', ->
|
||||
emptyHandler = (request, callback) -> callback()
|
||||
|
||||
it 'can override original protocol handler', (done) ->
|
||||
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||
protocol.once 'intercepted', ->
|
||||
free = -> protocol.uninterceptProtocol 'file'
|
||||
it 'throws error when scheme is already intercepted', (done) ->
|
||||
protocol.interceptStringProtocol 'http', emptyHandler, (error) ->
|
||||
assert.equal error, null
|
||||
protocol.interceptBufferProtocol 'http', emptyHandler, (error) ->
|
||||
assert.notEqual error, null
|
||||
done()
|
||||
|
||||
it 'does not crash when handler is called twice', (done) ->
|
||||
doubleHandler = (request, callback) ->
|
||||
callback(text)
|
||||
callback()
|
||||
protocol.interceptStringProtocol 'http', doubleHandler, (error) ->
|
||||
$.ajax
|
||||
url: 'file://fake-host'
|
||||
url: 'http://fake-host'
|
||||
success: (data) ->
|
||||
protocol.once 'unintercepted', ->
|
||||
assert.equal data, handler()
|
||||
done()
|
||||
free()
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
assert false, 'Got error: ' + errorType + ' ' + error
|
||||
free()
|
||||
protocol.interceptProtocol 'file', handler
|
||||
done(error)
|
||||
|
||||
it 'can override http protocol handler', (done) ->
|
||||
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||
protocol.once 'intercepted', ->
|
||||
protocol.uninterceptProtocol 'http'
|
||||
done()
|
||||
protocol.interceptProtocol 'http', handler
|
||||
it 'sends error when callback is called with nothing', (done) ->
|
||||
protocol.interceptBufferProtocol 'http', emptyHandler, (error) ->
|
||||
$.ajax
|
||||
url: 'http://fake-host'
|
||||
success: (data) ->
|
||||
done('request succeeded but it should not')
|
||||
error: (xhr, errorType, error) ->
|
||||
assert.equal errorType, 'error'
|
||||
done()
|
||||
|
||||
it 'can override https protocol handler', (done) ->
|
||||
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||
protocol.once 'intercepted', ->
|
||||
protocol.uninterceptProtocol 'https'
|
||||
done()
|
||||
protocol.interceptProtocol 'https', handler
|
||||
describe 'protocol.interceptStringProtocol', ->
|
||||
it 'can intercept http protocol', (done) ->
|
||||
handler = (request, callback) -> callback(text)
|
||||
protocol.interceptStringProtocol 'http', handler, (error) ->
|
||||
$.ajax
|
||||
url: 'http://fake-host'
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'can override ws protocol handler', (done) ->
|
||||
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||
protocol.once 'intercepted', ->
|
||||
protocol.uninterceptProtocol 'ws'
|
||||
done()
|
||||
protocol.interceptProtocol 'ws', handler
|
||||
describe 'protocol.interceptBufferProtocol', ->
|
||||
it 'can intercept http protocol', (done) ->
|
||||
handler = (request, callback) -> callback(new Buffer(text))
|
||||
protocol.interceptBufferProtocol 'http', handler, (error) ->
|
||||
$.ajax
|
||||
url: 'http://fake-host'
|
||||
success: (data) ->
|
||||
assert.equal data, text
|
||||
done()
|
||||
error: (xhr, errorType, error) ->
|
||||
done(error)
|
||||
|
||||
it 'can override wss protocol handler', (done) ->
|
||||
handler = remote.createFunctionWithReturnValue 'valar morghulis'
|
||||
protocol.once 'intercepted', ->
|
||||
protocol.uninterceptProtocol 'wss'
|
||||
describe 'protocol.uninterceptProtocol', ->
|
||||
it 'returns error when scheme does not exist', (done) ->
|
||||
protocol.uninterceptProtocol 'not-exist', (error) ->
|
||||
assert.notEqual error, null
|
||||
done()
|
||||
|
||||
it 'returns error when scheme is not intercepted', (done) ->
|
||||
protocol.uninterceptProtocol 'http', (error) ->
|
||||
assert.notEqual error, null
|
||||
done()
|
||||
protocol.interceptProtocol 'wss', handler
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"graceful-fs": "3.0.5",
|
||||
"mocha": "2.1.0",
|
||||
"q": "0.9.7",
|
||||
"runas": "2.x",
|
||||
"runas": "3.x",
|
||||
"temp": "0.8.1",
|
||||
"walkdir": "0.0.7",
|
||||
"ws": "0.7.2"
|
||||
|
|
|
@ -135,7 +135,7 @@ app.on('ready', function() {
|
|||
app.setApplicationMenu(menu);
|
||||
|
||||
// Test if using protocol module would crash.
|
||||
require('protocol').registerProtocol('test-if-crashes', function() {});
|
||||
require('protocol').registerStringProtocol('test-if-crashes', function() {});
|
||||
|
||||
window = new BrowserWindow({
|
||||
title: 'Electron Tests',
|
||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f4470ee48a748888bccba21845bfd65caaa1a6ce
|
||||
Subproject commit 939a7b814282a6433b8d7e3c9cfc74451360c07f
|
2
vendor/native_mate
vendored
2
vendor/native_mate
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 67d9eaa215e8727d86dc7b1f7a10be8699848f1f
|
||||
Subproject commit b41635e80921bddbf1a36f030490e063cd593477
|
2
vendor/node
vendored
2
vendor/node
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 7888f607ce74cc100ceb78f3af258a55ee2f62c4
|
||||
Subproject commit 205b013ac86e5500678a791cd54f305580fa4f4b
|
Loading…
Reference in a new issue