diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc index afdebfcf7f2f..093df2a1d4ef 100644 --- a/atom/browser/api/atom_api_power_monitor.cc +++ b/atom/browser/api/atom_api_power_monitor.cc @@ -41,8 +41,9 @@ void PowerMonitor::OnResume() { // static v8::Local PowerMonitor::Create(v8::Isolate* isolate) { if (!Browser::Get()->is_ready()) { - node::ThrowError("Cannot initialize \"power-monitor\" module" - "before app is ready"); + node::ThrowError( + isolate, + "Cannot initialize \"power-monitor\" module before app is ready"); return v8::Null(isolate); } diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index 323d282b19a9..083ea32b2010 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -192,28 +192,19 @@ Protocol::JsProtocolHandler Protocol::GetProtocolHandler( mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) - .SetMethod("registerProtocol", - base::Bind(&Protocol::RegisterProtocol, - base::Unretained(this))) - .SetMethod("unregisterProtocol", - base::Bind(&Protocol::UnregisterProtocol, - base::Unretained(this))) - .SetMethod("isHandledProtocol", - base::Bind(&Protocol::IsHandledProtocol, - base::Unretained(this))) - .SetMethod("interceptProtocol", - base::Bind(&Protocol::InterceptProtocol, - base::Unretained(this))) - .SetMethod("uninterceptProtocol", - base::Bind(&Protocol::UninterceptProtocol, - base::Unretained(this))); + .SetMethod("registerProtocol", &Protocol::RegisterProtocol) + .SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol) + .SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol) + .SetMethod("interceptProtocol", &Protocol::InterceptProtocol) + .SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol); } -void Protocol::RegisterProtocol(const std::string& scheme, +void Protocol::RegisterProtocol(v8::Isolate* isolate, + const std::string& scheme, const JsProtocolHandler& callback) { if (ContainsKey(protocol_handlers_, scheme) || job_factory_->IsHandledProtocol(scheme)) - return node::ThrowError("The scheme is already registered"); + return node::ThrowError(isolate, "The scheme is already registered"); protocol_handlers_[scheme] = callback; BrowserThread::PostTask(BrowserThread::IO, @@ -222,10 +213,11 @@ void Protocol::RegisterProtocol(const std::string& scheme, base::Unretained(this), scheme)); } -void Protocol::UnregisterProtocol(const std::string& scheme) { +void Protocol::UnregisterProtocol(v8::Isolate* isolate, + const std::string& scheme) { ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme)); if (it == protocol_handlers_.end()) - return node::ThrowError("The scheme has not been registered"); + return node::ThrowError(isolate, "The scheme has not been registered"); protocol_handlers_.erase(it); BrowserThread::PostTask(BrowserThread::IO, @@ -238,13 +230,14 @@ bool Protocol::IsHandledProtocol(const std::string& scheme) { return job_factory_->IsHandledProtocol(scheme); } -void Protocol::InterceptProtocol(const std::string& scheme, +void Protocol::InterceptProtocol(v8::Isolate* isolate, + const std::string& scheme, const JsProtocolHandler& callback) { if (!job_factory_->HasProtocolHandler(scheme)) - return node::ThrowError("Scheme does not exist."); + return node::ThrowError(isolate, "Scheme does not exist."); if (ContainsKey(protocol_handlers_, scheme)) - return node::ThrowError("Cannot intercept custom procotols"); + return node::ThrowError(isolate, "Cannot intercept custom procotols"); protocol_handlers_[scheme] = callback; BrowserThread::PostTask(BrowserThread::IO, @@ -253,10 +246,11 @@ void Protocol::InterceptProtocol(const std::string& scheme, base::Unretained(this), scheme)); } -void Protocol::UninterceptProtocol(const std::string& scheme) { +void Protocol::UninterceptProtocol(v8::Isolate* isolate, + const std::string& scheme) { ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme)); if (it == protocol_handlers_.end()) - return node::ThrowError("The scheme has not been registered"); + return node::ThrowError(isolate, "The scheme has not been registered"); protocol_handlers_.erase(it); BrowserThread::PostTask(BrowserThread::IO, diff --git a/atom/browser/api/atom_api_protocol.h b/atom/browser/api/atom_api_protocol.h index deef277333b5..34725cecc925 100644 --- a/atom/browser/api/atom_api_protocol.h +++ b/atom/browser/api/atom_api_protocol.h @@ -43,9 +43,10 @@ class Protocol : public mate::EventEmitter { // Register/unregister an networking |scheme| which would be handled by // |callback|. - void RegisterProtocol(const std::string& scheme, + void RegisterProtocol(v8::Isolate* isolate, + const std::string& scheme, const JsProtocolHandler& callback); - void UnregisterProtocol(const std::string& scheme); + void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme); // Returns whether a scheme has been registered. // FIXME Should accept a callback and be asynchronous so we do not have to use @@ -53,9 +54,10 @@ class Protocol : public mate::EventEmitter { bool IsHandledProtocol(const std::string& scheme); // Intercept/unintercept an existing protocol handler. - void InterceptProtocol(const std::string& scheme, + void InterceptProtocol(v8::Isolate* isolate, + const std::string& scheme, const JsProtocolHandler& callback); - void UninterceptProtocol(const std::string& scheme); + void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme); // The networking related operations have to be done in IO thread. void RegisterProtocolInIO(const std::string& scheme); diff --git a/atom/browser/api/atom_api_screen.cc b/atom/browser/api/atom_api_screen.cc index c042cc3f1f08..9f81cf6eeff7 100644 --- a/atom/browser/api/atom_api_screen.cc +++ b/atom/browser/api/atom_api_screen.cc @@ -113,13 +113,14 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder( // static v8::Local Screen::Create(v8::Isolate* isolate) { if (!Browser::Get()->is_ready()) { - node::ThrowError("Cannot initialize \"screen\" module before app is ready"); + node::ThrowError(isolate, + "Cannot initialize \"screen\" module before app is ready"); return v8::Null(isolate); } gfx::Screen* screen = gfx::Screen::GetNativeScreen(); if (!screen) { - node::ThrowError("Failed to get screen information"); + node::ThrowError(isolate, "Failed to get screen information"); return v8::Null(isolate); } diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index 6d7a9e5dedbd..2672f6f67ae5 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -32,9 +32,9 @@ Tray::~Tray() { } // static -mate::Wrappable* Tray::New(const gfx::Image& image) { +mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) { if (!Browser::Get()->is_ready()) { - node::ThrowError("Cannot create Tray before app is ready"); + node::ThrowError(isolate, "Cannot create Tray before app is ready"); return nullptr; } return new Tray(image); diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index 9fe3513094d8..6bbbe6d2d90c 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -31,7 +31,7 @@ class Menu; class Tray : public mate::EventEmitter, public TrayIconObserver { public: - static mate::Wrappable* New(const gfx::Image& image); + static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 76aaa3baaff5..7461bc736855 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -189,7 +189,8 @@ void Window::OnDevToolsClosed() { mate::Wrappable* Window::New(v8::Isolate* isolate, const mate::Dictionary& options) { if (!Browser::Get()->is_ready()) { - node::ThrowError("Cannot create BrowserWindow before app is ready"); + node::ThrowError(isolate, + "Cannot create BrowserWindow before app is ready"); return nullptr; } return new Window(options); diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 88aa5b77755c..ec519fa4f822 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -14,16 +14,20 @@ #include "atom/browser/window_list.h" #include "atom/common/options_switches.h" #include "base/command_line.h" +#include "base/files/file_util.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/printing/printing_message_filter.h" #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" #include "chrome/browser/speech/tts_message_filter.h" #include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/web_preferences.h" +#include "net/cert/x509_certificate.h" +#include "net/ssl/ssl_cert_request_info.h" #include "ppapi/host/ppapi_host.h" #include "ui/base/l10n/l10n_util.h" @@ -67,6 +71,23 @@ ProcessOwner GetProcessOwner(int process_id, return OWNER_NONE; } +scoped_refptr ImportCertFromFile( + const base::FilePath& path) { + std::string cert_data; + if (!base::ReadFileToString(path, &cert_data)) + return nullptr; + + net::CertificateList certs = + net::X509Certificate::CreateCertificateListFromBytes( + cert_data.data(), cert_data.size(), + net::X509Certificate::FORMAT_AUTO); + + if (certs.empty()) + return nullptr; + + return certs[0]; +} + } // namespace // static @@ -189,6 +210,29 @@ content::QuotaPermissionContext* return new AtomQuotaPermissionContext; } +void AtomBrowserClient::SelectClientCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) { + auto command_line = base::CommandLine::ForCurrentProcess(); + auto cert_path = command_line->GetSwitchValueNative( + switches::kClientCertificate); + + // TODO(zcbenz): allow users to select certificate from + // client_cert list. Right now defaults to first certificate + // in the list. + scoped_refptr certificate; + if (cert_path.empty()) { + if (!cert_request_info->client_certs.empty()) + certificate = cert_request_info->client_certs[0]; + } else { + certificate = ImportCertFromFile(base::FilePath(cert_path)); + } + + if (certificate.get()) + delegate->ContinueWithCertificate(certificate.get()); +} + brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts( const content::MainFunctionParams&) { v8::V8::Initialize(); // Init V8 before creating main parts. diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index 6aebc3128a48..c8a26da7099f 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -11,6 +11,11 @@ namespace content { class QuotaPermissionContext; +class ClientCertificateDelegate; +} + +namespace net { +class SSLCertRequestInfo; } namespace atom { @@ -41,6 +46,10 @@ class AtomBrowserClient : public brightray::BrowserClient { int child_process_id) override; void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; + void SelectClientCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) override; private: brightray::BrowserMainParts* OverrideCreateBrowserMainParts( diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index 48d00e9bd23b..ab86a0c45518 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -7,6 +7,7 @@ v8Util = process.atomBinding 'v8_util' valueToMeta = (sender, value) -> meta = type: typeof value + meta.type = 'buffer' if Buffer.isBuffer value meta.type = 'value' if value is null meta.type = 'array' if Array.isArray value @@ -26,6 +27,8 @@ valueToMeta = (sender, value) -> meta.members = [] meta.members.push {name: prop, type: typeof field} for prop, field of value + else if meta.type is 'buffer' + meta.value = Array::slice.call value, 0 else meta.type = 'value' meta.value = value @@ -43,6 +46,7 @@ unwrapArgs = (sender, args) -> when 'value' then meta.value when 'remote-object' then objectsRegistry.get meta.id when 'array' then unwrapArgs sender, meta.value + when 'buffer' then new Buffer(meta.value) when 'object' ret = v8Util.createObjectWithName meta.name for member in meta.members diff --git a/atom/common/api/atom_api_clipboard.cc b/atom/common/api/atom_api_clipboard.cc index da624a0a1ad3..273d30d96770 100644 --- a/atom/common/api/atom_api_clipboard.cc +++ b/atom/common/api/atom_api_clipboard.cc @@ -7,6 +7,7 @@ #include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" +#include "native_mate/arguments.h" #include "native_mate/dictionary.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard.h" @@ -15,44 +16,32 @@ #include "atom/common/node_includes.h" -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - ui::ClipboardType* out) { - std::string type; - if (!Converter::FromV8(isolate, val, &type)) - return false; - - if (type == "selection") - *out = ui::CLIPBOARD_TYPE_SELECTION; - else - *out = ui::CLIPBOARD_TYPE_COPY_PASTE; - return true; - } -}; - -} // namespace mate - namespace { -std::vector AvailableFormats(ui::ClipboardType type) { +ui::ClipboardType GetClipboardType(mate::Arguments* args) { + std::string type; + if (args->GetNext(&type) && type == "selection") + return ui::CLIPBOARD_TYPE_SELECTION; + else + return ui::CLIPBOARD_TYPE_COPY_PASTE; +} + +std::vector AvailableFormats(mate::Arguments* args) { std::vector format_types; bool ignore; ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - clipboard->ReadAvailableTypes(type, &format_types, &ignore); + clipboard->ReadAvailableTypes(GetClipboardType(args), &format_types, &ignore); return format_types; } -bool Has(const std::string& format_string, ui::ClipboardType type) { +bool Has(const std::string& format_string, mate::Arguments* args) { ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string)); - return clipboard->IsFormatAvailable(format, type); + return clipboard->IsFormatAvailable(format, GetClipboardType(args)); } std::string Read(const std::string& format_string, - ui::ClipboardType type) { + mate::Arguments* args) { ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string)); @@ -61,62 +50,62 @@ std::string Read(const std::string& format_string, return data; } -base::string16 ReadText(ui::ClipboardType type) { +base::string16 ReadText(mate::Arguments* args) { base::string16 data; - ui::Clipboard::GetForCurrentThread()->ReadText(type, &data); + ui::Clipboard::GetForCurrentThread()->ReadText(GetClipboardType(args), &data); return data; } -void WriteText(const base::string16& text, ui::ClipboardType type) { - ui::ScopedClipboardWriter writer(type); +void WriteText(const base::string16& text, mate::Arguments* args) { + ui::ScopedClipboardWriter writer(GetClipboardType(args)); writer.WriteText(text); } -base::string16 ReadHtml(ui::ClipboardType type) { +base::string16 ReadHtml(mate::Arguments* args) { base::string16 data; base::string16 html; std::string url; uint32 start; uint32 end; - ui::Clipboard::GetForCurrentThread()->ReadHTML(type, &html, &url, - &start, &end); + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + clipboard->ReadHTML(GetClipboardType(args), &html, &url, &start, &end); data = html.substr(start, end - start); return data; } -void WriteHtml(const base::string16& html, - ui::ClipboardType type) { - ui::ScopedClipboardWriter writer(type); +void WriteHtml(const base::string16& html, mate::Arguments* args) { + ui::ScopedClipboardWriter writer(GetClipboardType(args)); writer.WriteHTML(html, std::string()); } -gfx::Image ReadImage(ui::ClipboardType type) { - SkBitmap bitmap = ui::Clipboard::GetForCurrentThread()->ReadImage(type); +gfx::Image ReadImage(mate::Arguments* args) { + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + SkBitmap bitmap = clipboard->ReadImage(GetClipboardType(args)); return gfx::Image::CreateFrom1xBitmap(bitmap); } -void WriteImage(const gfx::Image& image, ui::ClipboardType type) { - ui::ScopedClipboardWriter writer(type); +void WriteImage(const gfx::Image& image, mate::Arguments* args) { + ui::ScopedClipboardWriter writer(GetClipboardType(args)); writer.WriteImage(image.AsBitmap()); } -void Clear(ui::ClipboardType type) { - ui::Clipboard::GetForCurrentThread()->Clear(type); +void Clear(mate::Arguments* args) { + ui::Clipboard::GetForCurrentThread()->Clear(GetClipboardType(args)); } void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("_availableFormats", &AvailableFormats); - dict.SetMethod("_has", &Has); - dict.SetMethod("_read", &Read); - dict.SetMethod("_readText", &ReadText); - dict.SetMethod("_writeText", &WriteText); - dict.SetMethod("_readHtml", &ReadHtml); - dict.SetMethod("_writeHtml", &WriteHtml); - dict.SetMethod("_readImage", &ReadImage); - dict.SetMethod("_writeImage", &WriteImage); - dict.SetMethod("_clear", &Clear); + dict.SetMethod("availableFormats", &AvailableFormats); + dict.SetMethod("has", &Has); + dict.SetMethod("read", &Read); + dict.SetMethod("readText", &ReadText); + dict.SetMethod("writeText", &WriteText); + dict.SetMethod("readHtml", &ReadHtml); + dict.SetMethod("writeHtml", &WriteHtml); + dict.SetMethod("readImage", &ReadImage); + dict.SetMethod("writeImage", &WriteImage); + dict.SetMethod("clear", &Clear); } } // namespace diff --git a/atom/common/api/atom_api_id_weak_map.cc b/atom/common/api/atom_api_id_weak_map.cc index cc2af821de18..614683c473a5 100644 --- a/atom/common/api/atom_api_id_weak_map.cc +++ b/atom/common/api/atom_api_id_weak_map.cc @@ -35,7 +35,7 @@ int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Local object) { v8::Local IDWeakMap::Get(v8::Isolate* isolate, int32_t key) { if (!Has(key)) { - node::ThrowError("Invalid key"); + node::ThrowError(isolate, "Invalid key"); return v8::Undefined(isolate); } diff --git a/atom/common/api/lib/clipboard.coffee b/atom/common/api/lib/clipboard.coffee index 44dadb8cd9ee..5c4bb10d4ae5 100644 --- a/atom/common/api/lib/clipboard.coffee +++ b/atom/common/api/lib/clipboard.coffee @@ -1,12 +1,5 @@ -binding = process.atomBinding 'clipboard' -module.exports = - availableFormats: (type='standard') -> binding._availableFormats type - has: (format, type='standard') -> binding._has format, type - read: (format, type='standard') -> binding._read format, type - readText: (type='standard') -> binding._readText type - writeText: (text, type='standard') -> binding._writeText text, type - readHtml: (type='standard') -> binding._readHtml type - writeHtml: (markup, type='standard') -> binding._writeHtml markup, type - readImage: (type='standard') -> binding._readImage type - writeImage: (image, type='standard') -> binding._writeImage image, type - clear: (type='standard') -> binding._clear type +if process.platform is 'linux' and process.type is 'renderer' + # On Linux we could not access clipboard in renderer process. + module.exports = require('remote').require 'clipboard' +else + module.exports = process.atomBinding 'clipboard' diff --git a/atom/common/crash_reporter/crash_reporter.cc b/atom/common/crash_reporter/crash_reporter.cc index 365860b256c7..59b7fd51e45e 100644 --- a/atom/common/crash_reporter/crash_reporter.cc +++ b/atom/common/crash_reporter/crash_reporter.cc @@ -46,7 +46,8 @@ std::vector CrashReporter::GetUploadedReports(const std::string& path) { std::string file_content; std::vector result; - if (base::ReadFileToString(base::FilePath(path), &file_content)) { + if (base::ReadFileToString(base::FilePath::FromUTF8Unsafe(path), + &file_content)) { std::vector reports; base::SplitString(file_content, '\n', &reports); for (const std::string& report : reports) { diff --git a/atom/common/lib/asar.coffee b/atom/common/lib/asar.coffee index a17ac729253d..7ce89156285d 100644 --- a/atom/common/lib/asar.coffee +++ b/atom/common/lib/asar.coffee @@ -310,6 +310,38 @@ exports.wrapFsWithAsar = (fs) -> files + internalModuleReadFile = process.binding('fs').internalModuleReadFile + process.binding('fs').internalModuleReadFile = (p) -> + [isAsar, asarPath, filePath] = splitPath p + return internalModuleReadFile p unless isAsar + + archive = getOrCreateArchive asarPath + return undefined unless archive + + info = archive.getFileInfo filePath + return undefined unless info + return '' if info.size is 0 + + buffer = new Buffer(info.size) + fd = archive.getFd() + retrun undefined unless fd >= 0 + + fs.readSync fd, buffer, 0, info.size, info.offset + buffer.toString 'utf8' + + internalModuleStat = process.binding('fs').internalModuleStat + process.binding('fs').internalModuleStat = (p) -> + [isAsar, asarPath, filePath] = splitPath p + return internalModuleStat p unless isAsar + + archive = getOrCreateArchive asarPath + return -34 unless archive # -ENOENT + + stats = archive.stat filePath + return -34 unless stats # -ENOENT + + if stats.isDirectory then return 1 else return 0 + overrideAPI fs, 'open' overrideAPI child_process, 'execFile' overrideAPISync process, 'dlopen', 1 diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index c9997996fed8..2764f86a5fcf 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -87,6 +87,9 @@ const char kDisableAutoHideCursor[] = "disable-auto-hide-cursor"; // Use the OS X's standard window instead of the textured window. const char kStandardWindow[] = "standard-window"; +// Path to client certificate. +const char kClientCertificate[] = "client-certificate"; + // Web runtime features. const char kExperimentalFeatures[] = "experimental-features"; const char kExperimentalCanvasFeatures[] = "experimental-canvas-features"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index 071459afac73..e6d85063341a 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -45,6 +45,7 @@ extern const char kTransparent[]; extern const char kType[]; extern const char kDisableAutoHideCursor[]; extern const char kStandardWindow[]; +extern const char kClientCertificate[]; extern const char kExperimentalFeatures[]; extern const char kExperimentalCanvasFeatures[]; diff --git a/atom/renderer/api/atom_api_renderer_ipc.cc b/atom/renderer/api/atom_api_renderer_ipc.cc index 00a5ba861650..d222f8f73b85 100644 --- a/atom/renderer/api/atom_api_renderer_ipc.cc +++ b/atom/renderer/api/atom_api_renderer_ipc.cc @@ -30,7 +30,9 @@ RenderView* GetCurrentRenderView() { return RenderView::FromWebView(view); } -void Send(const base::string16& channel, const base::ListValue& arguments) { +void Send(v8::Isolate* isolate, + const base::string16& channel, + const base::ListValue& arguments) { RenderView* render_view = GetCurrentRenderView(); if (render_view == NULL) return; @@ -39,10 +41,11 @@ void Send(const base::string16& channel, const base::ListValue& arguments) { render_view->GetRoutingID(), channel, arguments)); if (!success) - node::ThrowError("Unable to send AtomViewHostMsg_Message"); + node::ThrowError(isolate, "Unable to send AtomViewHostMsg_Message"); } -base::string16 SendSync(const base::string16& channel, +base::string16 SendSync(v8::Isolate* isolate, + const base::string16& channel, const base::ListValue& arguments) { base::string16 json; @@ -57,7 +60,7 @@ base::string16 SendSync(const base::string16& channel, bool success = render_view->Send(message); if (!success) - node::ThrowError("Unable to send AtomViewHostMsg_Message_Sync"); + node::ThrowError(isolate, "Unable to send AtomViewHostMsg_Message_Sync"); return json; } diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 569678476587..4c4970f0932f 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -10,6 +10,8 @@ wrapArgs = (args) -> valueToMeta = (value) -> if Array.isArray value type: 'array', value: wrapArgs(value) + else if Buffer.isBuffer value + type: 'buffer', value: Array::slice.call(value, 0) else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId' type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId' else if value? and typeof value is 'object' @@ -30,6 +32,7 @@ metaToValue = (meta) -> switch meta.type when 'value' then meta.value when 'array' then (metaToValue(el) for el in meta.members) + when 'buffer' then new Buffer(meta.value) when 'error' throw new Error("#{meta.message}\n#{meta.stack}") else diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index da6f55c8fe35..a815dc6499dc 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -173,7 +173,7 @@ class WebViewImpl params = instanceId: @viewInstanceId userAgentOverride: @userAgentOverride - for attributeName, attribute of @attributes + for own attributeName, attribute of @attributes params[attributeName] = attribute.getValue() # When the WebView is not participating in layout (display:none) # then getBoundingClientRect() would report a width and height of 0. diff --git a/common.gypi b/common.gypi index c6f3320c0a5b..14b89393a534 100644 --- a/common.gypi +++ b/common.gypi @@ -9,6 +9,7 @@ 'component%': 'static_library', 'python': 'python', 'openssl_no_asm': 1, + 'node_target_type': 'shared_library', 'node_install_npm': 'false', 'node_prefix': '', 'node_shared_cares': 'false', @@ -26,6 +27,7 @@ 'uv_library': 'static_library', 'uv_parent_path': 'vendor/node/deps/uv', 'uv_use_dtrace': 'false', + 'V8_BASE': '', 'v8_postmortem_support': 'false', 'v8_enable_i18n_support': 'false', # Required by Linux (empty for now, should support it in future). @@ -99,7 +101,10 @@ ], }], ['_target_name=="node"', { - 'include_dirs': [ '<(libchromiumcontent_src_dir)/v8/include' ], + 'include_dirs': [ + '<(libchromiumcontent_src_dir)/v8', + '<(libchromiumcontent_src_dir)/v8/include', + ], 'conditions': [ ['OS=="mac" and libchromiumcontent_component==0', { # -all_load is the "whole-archive" on OS X. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index e60a7d227995..4211ac8020fd 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -43,7 +43,7 @@ You can also create a window without chrome by using other windows * `fullscreen` Boolean - Whether the window should show in fullscreen, when set to `false` the fullscreen button would also be hidden on OS X - * `skip-taskbar` Boolean - Do not show window in Taskbar + * `skip-taskbar` Boolean - Do not show window in taskbar * `zoom-factor` Number - The default zoom factor of the page, zoom factor is zoom percent / 100, so `3.0` represents `300%` * `kiosk` Boolean - The kiosk mode @@ -131,9 +131,9 @@ window.onbeforeunload = function(e) { console.log('I do not want to be closed'); // Unlike usual browsers, in which a string should be returned and the user is - // prompted to confirm the page unload. Electron gives the power completely - // to the developers, return empty string or false would prevent the unloading - // now. You can also use the dialog API to let user confirm it. + // prompted to confirm the page unload, Electron gives developers more options. + // Returning empty string or false would prevent the unloading now. + // You can also use the dialog API to let the user confirm closing the application. return false; }; ``` @@ -464,7 +464,7 @@ Starts or stops flashing the window to attract user's attention. * `skip` Boolean -Makes the window do not show in Taskbar. +Makes the window not show in the taskbar. ### BrowserWindow.setKiosk(flag) @@ -483,13 +483,13 @@ Returns whether the window is in kiosk mode. Sets the pathname of the file the window represents, and the icon of the file will show in window's title bar. -__Note__: This API is available only on OS X. +__Note__: This API is only available on OS X. ### BrowserWindow.getRepresentedFilename() Returns the pathname of the file the window represents. -__Note__: This API is available only on OS X. +__Note__: This API is only available on OS X. ### BrowserWindow.setDocumentEdited(edited) @@ -498,13 +498,13 @@ __Note__: This API is available only on OS X. Specifies whether the window’s document has been edited, and the icon in title bar will become grey when set to `true`. -__Note__: This API is available only on OS X. +__Note__: This API is only available on OS X. ### BrowserWindow.IsDocumentEdited() Whether the window's document has been edited. -__Note__: This API is available only on OS X. +__Note__: This API is only available on OS X. ### BrowserWindow.openDevTools([options]) @@ -604,20 +604,20 @@ it will assume `app.getName().desktop`. ### BrowserWindow.setOverlayIcon(overlay, description) * `overlay` [NativeImage](native-image.md) - the icon to display on the bottom -right corner of the Taskbar icon. If this parameter is `null`, the overlay is +right corner of the taskbar icon. If this parameter is `null`, the overlay is cleared * `description` String - a description that will be provided to Accessibility screen readers -Sets a 16px overlay onto the current Taskbar icon, usually used to convey some sort of application status or to passively notify the user. +Sets a 16px overlay onto the current taskbar icon, usually used to convey some sort of application status or to passively notify the user. -__Note:__ This API is only available on Windows, Win7 or above +__Note:__ This API is only available on Windows (Windows 7 and above) ### BrowserWindow.showDefinitionForSelection() Shows pop-up dictionary that searches the selected word on the page. -__Note__: This API is available only on OS X. +__Note__: This API is only available on OS X. ### BrowserWindow.setAutoHideMenuBar(hide) @@ -753,7 +753,7 @@ Calling `event.preventDefault()` can prevent creating new windows. Emitted when user or the page wants to start an navigation, it can happen when `window.location` object is changed or user clicks a link in the page. -This event will not emit when the navigation is started programmely with APIs +This event will not emit when the navigation is started programmatically with APIs like `WebContents.loadUrl` and `WebContents.back`. Calling `event.preventDefault()` can prevent the navigation. diff --git a/docs/api/chrome-command-line-switches.md b/docs/api/chrome-command-line-switches.md index 2ea1a29fb86f..0eaefbe1551c 100644 --- a/docs/api/chrome-command-line-switches.md +++ b/docs/api/chrome-command-line-switches.md @@ -1,6 +1,6 @@ # Supported Chrome command line switches -Following command lines switches in Chrome browser are also Supported in +The following command lines switches in Chrome browser are also supported in Electron, you can use [app.commandLine.appendSwitch][append-switch] to append them in your app's main script before the [ready][ready] event of [app][app] module is emitted: @@ -11,9 +11,14 @@ app.commandLine.appendSwitch('remote-debugging-port', '8315'); app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); app.on('ready', function() { + // Your code here }); ``` +## --client-certificate=`path` + +Sets `path` of client certificate file. + ## --disable-http-cache Disables the disk cache for HTTP requests. diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 05b8650a0198..f8058649ae57 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -36,8 +36,8 @@ selected, an example is: filters: [ { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, - { name: 'Custom File Type', extensions: ['as'] }, - ], + { name: 'Custom File Type', extensions: ['as'] } + ] } ``` diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index fe3b33388d9b..498a65b225db 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -28,7 +28,7 @@ var win = new BrowserWindow({ transparent: true, frame: false }); API to set window shape to solve this, but currently blocked at an [upstream bug](https://code.google.com/p/chromium/issues/detail?id=387234). * Transparent window is not resizable, setting `resizable` to `true` may make - transprent window stop working on some platforms. + transparent window stop working on some platforms. * The `blur` filter only applies to the web page, so there is no way to apply blur effect to the content below the window. * On Windows transparent window will not work when DWM is disabled. diff --git a/docs/api/global-shortcut.md b/docs/api/global-shortcut.md index 2d27398aae4b..871357f89f9f 100644 --- a/docs/api/global-shortcut.md +++ b/docs/api/global-shortcut.md @@ -9,8 +9,10 @@ var globalShortcut = require('global-shortcut'); // Register a 'ctrl+x' shortcut listener. var ret = globalShortcut.register('ctrl+x', function() { console.log('ctrl+x is pressed'); }) -if (!ret) - console.log('registerion fails'); + +if (!ret) { + console.log('registration failed'); +} // Check whether a shortcut is registered. console.log(globalShortcut.isRegistered('ctrl+x')); diff --git a/docs/api/menu.md b/docs/api/menu.md index 60e37884e352..db149a29680a 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -29,8 +29,11 @@ window.addEventListener('contextmenu', function (e) { Another example of creating the application menu with the simple template API: -```javascript -// main.js +```html + + ``` ## Class: Menu @@ -281,10 +285,10 @@ Template: ```javascript [ - {label: '4', id: '4'} - {label: '5', id: '5'} - {label: '1', id: '1', position: 'before=4'} - {label: '2', id: '2'} + {label: '4', id: '4'}, + {label: '5', id: '5'}, + {label: '1', id: '1', position: 'before=4'}, + {label: '2', id: '2'}, {label: '3', id: '3'} ] ``` @@ -303,11 +307,11 @@ Template: ```javascript [ - {label: 'a', position: 'endof=letters'} - {label: '1', position: 'endof=numbers'} - {label: 'b', position: 'endof=letters'} - {label: '2', position: 'endof=numbers'} - {label: 'c', position: 'endof=letters'} + {label: 'a', position: 'endof=letters'}, + {label: '1', position: 'endof=numbers'}, + {label: 'b', position: 'endof=letters'}, + {label: '2', position: 'endof=numbers'}, + {label: 'c', position: 'endof=letters'}, {label: '3', position: 'endof=numbers'} ] ``` diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 65554e052105..181a2e57f733 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -7,8 +7,8 @@ An example of implementing a protocol that has the same effect with the `file://` protocol: ```javascript -var app = require('app'), - path = require('path'); +var app = require('app'); +var path = require('path'); app.on('ready', function() { var protocol = require('protocol'); diff --git a/docs/api/tray.md b/docs/api/tray.md index d85ac1a1dac8..3be241dde9a2 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -15,7 +15,7 @@ app.on('ready', function(){ { label: 'Item1', type: 'radio' }, { label: 'Item2', type: 'radio' }, { label: 'Item3', type: 'radio', checked: true }, - { label: 'Item4', type: 'radio' }, + { label: 'Item4', type: 'radio' } ]); appIcon.setToolTip('This is my application.'); appIcon.setContextMenu(contextMenu); diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index 210b15f9e8b4..c83994768478 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -18,7 +18,7 @@ form, the `webview` tag includes the `src` of the web page and css styles that control the appearance of the `webview` container: ```html - + ``` If you want to control the guest content in any way, you can write JavaScript @@ -398,7 +398,7 @@ without regard for log level or other properties. ```javascript webview.addEventListener('console-message', function(e) { - console.log('Guest page logged a message: ', e.message); + console.log('Guest page logged a message:', e.message); }); ``` @@ -456,7 +456,7 @@ webview.send('ping'); var ipc = require('ipc'); ipc.on('ping', function() { ipc.sendToHost('pong'); -}) +}); ``` ### crashed diff --git a/docs/tutorial/application-distribution.md b/docs/tutorial/application-distribution.md index 5c76f14d504a..c96a53bcbeee 100644 --- a/docs/tutorial/application-distribution.md +++ b/docs/tutorial/application-distribution.md @@ -35,7 +35,7 @@ exposing your app's source code to users. To use an `asar` archive to replace the `app` folder, you need to rename the archive to `app.asar`, and put it under Electron's resources directory like -bellow, and Electron will then try read the archive and start from it. +below, and Electron will then try read the archive and start from it. On OS X: diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 3f65df234dfe..5dee6fdf4ec3 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -70,9 +70,9 @@ var dockMenu = Menu.buildFromTemplate([ { label: 'New Window', click: function() { console.log('New Window'); } }, { label: 'New Window with Settings', submenu: [ { label: 'Basic' }, - { label: 'Pro'}, + { label: 'Pro'} ]}, - { label: 'New Command...'}, + { label: 'New Command...'} ]); app.dock.setMenu(dockMenu); ``` @@ -119,7 +119,7 @@ app.setUserTasks([ iconPath: process.execPath, iconIndex: 0, title: 'New Window', - description: 'Create a new window', + description: 'Create a new window' } ]); ``` @@ -149,8 +149,8 @@ On Windows, a taskbar button can be used to display a progress bar. This enables a window to provide progress information to the user without that user having to switch to the window itself. -The Unity DE also has a simililar feature that allows you to specify progress -bar in the lancher. +The Unity DE also has a similar feature that allows you to specify the progress +bar in the launcher. __Progress bar in taskbar button:__ diff --git a/docs/tutorial/devtools-extension.md b/docs/tutorial/devtools-extension.md index e93013d6ed19..731de4e13f8b 100644 --- a/docs/tutorial/devtools-extension.md +++ b/docs/tutorial/devtools-extension.md @@ -20,14 +20,14 @@ Then you can load the extension in Electron by opening devtools in any window, and then running the following code in the devtools console: ```javascript -require('remote').require('browser-window').addDevToolsExtension('/some-directory/react-devtools') +require('remote').require('browser-window').addDevToolsExtension('/some-directory/react-devtools'); ``` To unload the extension, you can call `BrowserWindow.removeDevToolsExtension` API with its name and it will not load the next time you open the devtools: ```javascript -require('remote').require('browser-window').removeDevToolsExtension('React Developer Tools') +require('remote').require('browser-window').removeDevToolsExtension('React Developer Tools'); ``` ## Format of devtools extension diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index 073d2ee40c95..644793f62378 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -82,8 +82,9 @@ var mainWindow = null; // Quit when all windows are closed. app.on('window-all-closed', function() { - if (process.platform != 'darwin') + if (process.platform != 'darwin') { app.quit(); + } }); // This method will be called when Electron has done everything diff --git a/docs/tutorial/using-pepper-flash-plugin.md b/docs/tutorial/using-pepper-flash-plugin.md index bbb37862da44..20b29c4114a9 100644 --- a/docs/tutorial/using-pepper-flash-plugin.md +++ b/docs/tutorial/using-pepper-flash-plugin.md @@ -23,8 +23,9 @@ var mainWindow = null; // Quit when all windows are closed. app.on('window-all-closed', function() { - if (process.platform != 'darwin') + if (process.platform != 'darwin') { app.quit(); + } }); // Specify flash path. diff --git a/docs/tutorial/using-selenium-and-webdriver.md b/docs/tutorial/using-selenium-and-webdriver.md index cda69c0d6184..13934c01b086 100644 --- a/docs/tutorial/using-selenium-and-webdriver.md +++ b/docs/tutorial/using-selenium-and-webdriver.md @@ -49,14 +49,14 @@ and where to find Electron's binary: ```javascript var webdriver = require('selenium-webdriver'); -var driver = new webdriver.Builder(). - // The "9515" is the port opened by chrome driver. - usingServer('http://localhost:9515'). - withCapabilities({chromeOptions: { - // Here is the path to your Electron binary. - binary: '/Path-to-Your-App.app/Contents/MacOS/Atom'}}). - forBrowser('electron'). - build(); +var driver = new webdriver.Builder() + // The "9515" is the port opened by chrome driver. + .usingServer('http://localhost:9515') + .withCapabilities({chromeOptions: { + // Here is the path to your Electron binary. + binary: '/Path-to-Your-App.app/Contents/MacOS/Atom'}}) + .forBrowser('electron') + .build(); driver.get('http://www.google.com'); driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); diff --git a/script/update.py b/script/update.py index aaa07526c05f..23497ff9e5ac 100755 --- a/script/update.py +++ b/script/update.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import os +import platform import subprocess import sys @@ -43,10 +44,19 @@ def run_gyp(target_arch, component): defines = [ '-Dlibchromiumcontent_component={0}'.format(component), '-Dtarget_arch={0}'.format(target_arch), + '-Dhost_arch={0}'.format(target_arch), '-Dlibrary=static_library', ] return subprocess.call([python, gyp, '-f', 'ninja', '--depth', '.', 'atom.gyp', '-Icommon.gypi'] + defines) + +def get_host_arch(): + if platform.architecture()[0] == '32bit': + return 'ia32' + else: + return 'x64' + + if __name__ == '__main__': sys.exit(main()) diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index ea3e06c9d406..390f29bf2f0c 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -188,6 +188,7 @@ describe 'browser-window module', -> w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html') describe 'new-window event', -> + return if isCI and process.platform is 'darwin' it 'emits when window.open is called', (done) -> w.webContents.once 'new-window', (e, url, frameName) -> e.preventDefault() @@ -230,6 +231,7 @@ describe 'browser-window module', -> w.minimize() describe 'will-navigate event', -> + return if isCI and process.platform is 'darwin' it 'emits when user starts a navigation', (done) -> @timeout 10000 w.webContents.on 'will-navigate', (event, url) -> @@ -239,6 +241,7 @@ describe 'browser-window module', -> w.loadUrl "file://#{fixtures}/pages/will-navigate.html" describe 'dom-ready event', -> + return if isCI and process.platform is 'darwin' it 'emits when document is loaded', (done) -> ipc = remote.require 'ipc' server = http.createServer (req, res) -> diff --git a/vendor/brightray b/vendor/brightray index 1cba3a459e96..7c6c530608e1 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 1cba3a459e9629916655c98716b32ccd1869ef56 +Subproject commit 7c6c530608e17ee569edea3dc2607736f3cdb376 diff --git a/vendor/node b/vendor/node index b772c19a8f9d..ab1b3ba0b007 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit b772c19a8f9db65673184822fb294235eff9c364 +Subproject commit ab1b3ba0b0076d7aa72e80caf8045fb6f7a68be0