Compare commits

..

59 Commits

Author SHA1 Message Date
Cheng Zhao
d7cf460918 docs: callback => completion in some places 2015-08-21 20:16:56 +08:00
Cheng Zhao
68a98d5dc2 Bump v0.31.0 2015-08-21 19:51:56 +08:00
Cheng Zhao
7c32378a73 Merge pull request #2474 from atom/chrome44
Upgrade to Chrome 44
2015-08-21 19:49:00 +08:00
Cheng Zhao
9212a1db8e Merge branch 'master' into chrome44 2015-08-21 19:29:34 +08:00
Cheng Zhao
d931a49e89 Warn about removed protocol APIs 2015-08-21 18:02:58 +08:00
Cheng Zhao
61b7a3afe3 No need to ship ffmpeg in dist 2015-08-21 16:27:29 +08:00
Cheng Zhao
cf6a904f95 win: Fix release build 2015-08-21 16:21:20 +08:00
Cheng Zhao
00e5290dc8 win: Update libchromium to fix .pdb missing errors 2015-08-21 16:19:19 +08:00
Cheng Zhao
627fe75a6a Update brightray to fix building on Linux 2015-08-21 16:14:47 +08:00
Cheng Zhao
bc5ebb9911 Update to io.js v3.1.0 2015-08-21 14:28:37 +08:00
Cheng Zhao
1bd8a9869a Run build script on arm and ia32 Linux 2015-08-21 14:18:04 +08:00
Cheng Zhao
0ee6e5334a Now working at 0.31.0 2015-08-21 13:58:49 +08:00
Cheng Zhao
c18ec7f5bc runas@3.x 2015-08-21 13:52:05 +08:00
Cheng Zhao
7d97bb6fe0 docs: Rewrite docs for new protocol API 2015-08-14 13:44:18 +08:00
Cheng Zhao
86eb0a5eaa Create both Uint8Array and ArrayBuffer from blink 2015-08-14 12:40:03 +08:00
Cheng Zhao
62d5c89f62 spec: Rewrite tests for new protocol API 2015-08-13 22:39:11 +08:00
Cheng Zhao
a88f951b2f Always set headers for response
When intercepting HTTP protocols Chromium will assume there is always headers
set, so we have to provide headers for all the responses to avoid the
crash.
2015-08-13 22:26:27 +08:00
Cheng Zhao
467ba6b7a9 Rename protocol.isHandledProtocol to protocol.isProtocolHandled 2015-08-13 21:29:23 +08:00
Cheng Zhao
02714d466c Fix crash when requesting invalid url 2015-08-13 21:21:23 +08:00
Cheng Zhao
741c8f3d98 Implement protocol.uninterceptProtocol 2015-08-13 20:19:02 +08:00
Cheng Zhao
773e932e98 Implement protocol.interceptProtocol 2015-08-13 20:10:05 +08:00
Cheng Zhao
374d83ed9c Implement protocol.isHandledProtocol 2015-08-13 19:33:53 +08:00
Cheng Zhao
05fd81ebdc Implement protocol.unregisterProtocol 2015-08-13 19:26:18 +08:00
Cheng Zhao
777f99193f Update native_mate to fix VS compilation error 2015-08-13 13:44:37 +08:00
Cheng Zhao
d0ef43bd12 Completion callback is called on IO thread 2015-08-12 23:16:17 +08:00
Cheng Zhao
78171e2072 Don't use C++11 to not crash VS 2015-08-12 23:14:20 +08:00
Cheng Zhao
94c1fb32a7 Try work around VS's bug 2015-08-12 23:07:15 +08:00
Cheng Zhao
d9b845fcdf Make session parameter work with null value 2015-08-12 22:57:25 +08:00
Cheng Zhao
225321b580 Make the completion callback optional 2015-08-12 21:32:52 +08:00
Cheng Zhao
f493eb34ae Implement protocol.registerHttpProtocol 2015-08-12 21:09:44 +08:00
Cheng Zhao
1f2d7d1cd8 Implement protocol.registerBufferProtocol 2015-08-12 20:37:52 +08:00
Cheng Zhao
ebb1ddc0df Support converting Buffer to Value 2015-08-12 15:39:33 +08:00
Cheng Zhao
d2681d2ba1 Implement protocol.registerFileProtocol 2015-08-12 15:22:19 +08:00
Cheng Zhao
337460cdc2 Enable return error for arbitray request job 2015-08-12 13:50:31 +08:00
Cheng Zhao
ee51e37db7 Guard against callback being called twice 2015-08-12 13:43:27 +08:00
Cheng Zhao
96d53d279e Initial implementation of new protocol API 2015-08-12 13:30:19 +08:00
Cheng Zhao
1e9eaba423 win: Fix compiler warning 2015-08-11 23:41:43 +08:00
Cheng Zhao
a8681b0072 Fix emitting did-attach event 2015-08-11 15:59:16 +08:00
Cheng Zhao
e6a2b0a479 Fix finding the WebContents of a pending renderer process
Apparently after Chrome 44 a renderer process can be started before the
corresponding render view is created, though it can be patched but from
the source code Chromium is enforcing this everywhere now, so fixing it
on our side seems the only reliable solution.

This fix is very similar to what we did, but instead of blindly setting
swapped process, we now remember which process the pending process is
going to replace, so we should not have those race conditions.
2015-08-11 15:39:17 +08:00
Cheng Zhao
0f990d40cc Use blink's allocator in Node's Buffer 2015-08-11 12:31:41 +08:00
Cheng Zhao
2dc533c4b9 Fix search path of ffmpeg
It is somehow set to @load_path by Chromium.
2015-08-11 10:55:27 +08:00
Cheng Zhao
bc06195409 Link with a few more static libraries on Linux and OS X 2015-08-11 10:45:40 +08:00
Cheng Zhao
e43c63ae08 Update chrome_version.h 2015-08-11 10:40:41 +08:00
Cheng Zhao
cc34bc844d Tell compiler we want to ignore result of SetPrototype 2015-08-11 10:10:07 +08:00
Cheng Zhao
7423c89968 Fix compilation warnings caused by chrome44 update 2015-08-11 10:08:34 +08:00
Cheng Zhao
4337c07425 Define node_byteorder and node_release_urlbase 2015-08-11 10:02:46 +08:00
Cheng Zhao
5c57f92ba5 Update io.js to v3.0.0 2015-08-11 09:58:36 +08:00
Cheng Zhao
c5e540823b Update to Chrome 44 2015-08-11 09:50:19 +08:00
Haojian Wu
28093a4d2d Fix a crash issue in GetProcessOwner if no renderer view host is found. 2015-08-11 09:48:55 +08:00
Haojian Wu
4e3187fbbd No need to specify ffmpeg library as it's a normal built library in libchromiumcontent. 2015-08-11 09:48:55 +08:00
Haojian Wu
f9fee9174a net::URLFetcher::Create now returns object with scoped_ptr. 2015-08-11 09:48:55 +08:00
Haojian Wu
0e8a585157 Fix content::BrowserPluginDelegate::DidResizeElement API changes.
Chromium has removed old_size in DidResizeElement interface as the 'old_size'
is internal.
2015-08-11 09:48:55 +08:00
Haojian Wu
11ffb9dfb6 Fix node::Buffer API changes. 2015-08-11 09:48:29 +08:00
Haojian Wu
46c7ba734b Fix WillAttach API changes in content::BrowserPluginGuestDelegate. 2015-08-11 09:48:29 +08:00
Haojian Wu
fc4031ec26 Now the value in ScopedPtrHashMap is required to be scoped_ptr. 2015-08-11 09:48:29 +08:00
Haojian Wu
d003b1bb57 LoadV8Snapshot has been moved from gin::IsolateHolder to gin::V8Initializer. 2015-08-11 09:48:29 +08:00
Haojian Wu
8fda175264 Update base::Value::CreateNullValue API changes. 2015-08-11 09:48:29 +08:00
Haojian Wu
d08392a0c4 No need base/float_util.h since VS2013 supports well enough. 2015-08-11 09:48:29 +08:00
Haojian Wu
48ccb0f2ab No gfx::SingletonHwnd::Observer any more.
Using gfx::SingletonHwndObserver instead.
2015-08-11 09:48:29 +08:00
59 changed files with 1558 additions and 1255 deletions

View File

@@ -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': [

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)});"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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
View 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_

View 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

View 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_

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,7 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.30.5</string>
<string>0.31.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>NSMainNibFile</key>

View File

@@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,30,5,0
PRODUCTVERSION 0,30,5,0
FILEVERSION 0,31,0,0
PRODUCTVERSION 0,31,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.30.5"
VALUE "FileVersion", "0.31.0"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.30.5"
VALUE "ProductVersion", "0.31.0"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 30
#define ATOM_PATCH_VERSION 5
#define ATOM_MINOR_VERSION 31
#define ATOM_PATCH_VERSION 0
#define ATOM_VERSION_IS_RELEASE 1

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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_;
}
}

View File

@@ -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': '',

View File

@@ -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)
* `scheme` String
* `callback` 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)
* `scheme` String
* `callback` Function
`callback` returns a boolean whether the `scheme` can be handled already.
## protocol.interceptProtocol(scheme, handler, callback)
## protocol.registerBufferProtocol(scheme, handler[, completion])
* `scheme` String
* `handler` Function
* `callback` Function
* `completion` Function
Intercepts an existing protocol with `scheme`, returning `null` or `undefined`
in `handler` would use the original protocol handler to handle the request.
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.
## protocol.uninterceptProtocol(scheme, callback)
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.isProtocolHandled(scheme, callback)
* `scheme` String
* `callback` Function
Unintercepts a protocol.
The `callback` will be called with a boolean that indicates whether there is
already a handler for `scheme`.
## Class: protocol.RequestFileJob(path)
## protocol.interceptFileProtocol(scheme, handler[, completion])
* `path` String
* `scheme` String
* `handler` Function
* `completion` Function
Create a request job which would query a file of `path` and set corresponding
mime types.
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
which sends file as response.
## Class: protocol.RequestStringJob(options)
## protocol.interceptStringProtocol(scheme, handler[, completion])
* `options` Object
* `mimeType` String - Default is `text/plain`
* `charset` String - Default is `UTF-8`
* `data` String
* `scheme` String
* `handler` Function
* `completion` Function
Create a request job which sends a string as response.
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
which sends String as response.
## Class: protocol.RequestBufferJob(options)
## protocol.interceptBufferProtocol(scheme, handler[, completion])
* `options` Object
* `mimeType` String - Default is `application/octet-stream`
* `encoding` String - Default is `UTF-8`
* `data` Buffer
* `scheme` String
* `handler` Function
* `completion` Function
Create a request job which sends a buffer as response.
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
which sends `Buffer` as response.
## Class: protocol.RequestHttpJob(options)
## protocol.interceptHttpProtocol(scheme, handler[, completion])
* `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
* `scheme` String
* `handler` Function
* `completion` Function
Send a request to `url` and pipe the response back.
Intercepts `scheme` protocol and use `handler` as the protocol's new handler
which sends a new HTTP request as response.
## Class: protocol.RequestErrorJob(code)
## protocol.uninterceptProtocol(scheme[, completion])
* `code` Integer
* `scheme` String
* `completion` Function
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.

View File

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

View File

@@ -5,7 +5,7 @@
"coffee-script": "^1.9.2",
"coffeelint": "^1.9.4",
"request": "*",
"runas": "^2.0.0"
"runas": "3.x"
},
"private": true,
"scripts": {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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/node vendored