diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index cc760b46b195..190898fdef9a 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -12,6 +12,7 @@ #include "atom/browser/bridge_task_runner.h" #include "atom/browser/browser.h" #include "atom/browser/javascript_environment.h" +#include "atom/browser/node_debugger.h" #include "atom/common/api/atom_bindings.h" #include "atom/common/asar/asar_util.h" #include "atom/common/node_bindings.h" @@ -133,6 +134,10 @@ void AtomBrowserMainParts::PostEarlyInitialization() { node_bindings_->CreateEnvironment(js_env_->context()); node_env_.reset(new NodeEnvironment(env)); + // Enable support for v8 inspector + node_debugger_.reset(new NodeDebugger(env)); + node_debugger_->Start(); + // Add Electron extended APIs. atom_bindings_->BindTo(js_env_->isolate(), env->process_object()); diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index 4067f542b429..2ba7d341f430 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -21,6 +21,7 @@ class AtomBindings; class Browser; class JavascriptEnvironment; class NodeBindings; +class NodeDebugger; class NodeEnvironment; class BridgeTaskRunner; @@ -82,6 +83,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { std::unique_ptr node_bindings_; std::unique_ptr atom_bindings_; std::unique_ptr node_env_; + std::unique_ptr node_debugger_; base::Timer gc_timer_; diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc index 9fdeb6099e6a..2f17d468011a 100644 --- a/atom/browser/node_debugger.cc +++ b/atom/browser/node_debugger.cc @@ -4,202 +4,47 @@ #include "atom/browser/node_debugger.h" -#include - -#include "base/bind.h" #include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "content/public/browser/browser_thread.h" -#include "net/test/embedded_test_server/tcp_listen_socket.h" - -#include "atom/common/node_includes.h" +#include "libplatform/libplatform.h" +#include "native_mate/dictionary.h" namespace atom { -namespace { - -// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been -// taken by gin, blink and node, using 2 is a safe option for now. -const int kIsolateSlot = 2; - -const char* kContentLength = "Content-Length"; - -} // namespace - -NodeDebugger::NodeDebugger(v8::Isolate* isolate) - : isolate_(isolate), - thread_("NodeDebugger"), - content_length_(-1), - weak_factory_(this) { - bool use_debug_agent = false; - int port = 5858; - - std::string port_str; - base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch("debug")) { - use_debug_agent = true; - port_str = cmd->GetSwitchValueASCII("debug"); - } else if (cmd->HasSwitch("debug-brk")) { - use_debug_agent = true; - port_str = cmd->GetSwitchValueASCII("debug-brk"); - } - - if (use_debug_agent) { - if (!port_str.empty()) - base::StringToInt(port_str, &port); - - isolate_->SetData(kIsolateSlot, this); - v8::Debug::SetMessageHandler(isolate_, DebugMessageHandler); - - weak_up_ui_handle_.data = this; - uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI); - - // Start a new IO thread. - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - if (!thread_.StartWithOptions(options)) { - LOG(ERROR) << "Unable to start debugger thread"; - return; - } - - // Start the server in new IO thread. - thread_.task_runner()->PostTask( - FROM_HERE, - base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(), - port)); - } +NodeDebugger::NodeDebugger(node::Environment* env) : env_(env) { } NodeDebugger::~NodeDebugger() { - thread_.Stop(); } -bool NodeDebugger::IsRunning() const { - return thread_.IsRunning(); -} - -void NodeDebugger::StartServer(int port) { - server_ = net::test_server::TCPListenSocket::CreateAndListen( - "127.0.0.1", port, this); - if (!server_) { - LOG(ERROR) << "Cannot start debugger server"; +void NodeDebugger::Start() { + auto inspector = env_->inspector_agent(); + if (inspector == nullptr) return; - } -} -void NodeDebugger::CloseSession() { - accepted_socket_.reset(); -} - -void NodeDebugger::OnMessage(const std::string& message) { - if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") != - std::string::npos) - CloseSession(); - - base::string16 message16 = base::UTF8ToUTF16(message); - v8::Debug::SendCommand( - isolate_, - reinterpret_cast(message16.data()), message16.size()); - - uv_async_send(&weak_up_ui_handle_); -} - -void NodeDebugger::SendMessage(const std::string& message) { - if (accepted_socket_) { - std::string header = base::StringPrintf( - "%s: %d\r\n\r\n", kContentLength, static_cast(message.size())); - accepted_socket_->Send(header); - accepted_socket_->Send(message); - } -} - -void NodeDebugger::SendConnectMessage() { - accepted_socket_->Send(base::StringPrintf( - "Type: connect\r\n" - "V8-Version: %s\r\n" - "Protocol-Version: 1\r\n" - "Embedding-Host: %s\r\n" - "%s: 0\r\n", - v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true); -} - -// static -void NodeDebugger::ProcessMessageInUI(uv_async_t* handle) { - NodeDebugger* self = static_cast(handle->data); - v8::Debug::ProcessDebugMessages(self->isolate_); -} - -// static -void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) { - NodeDebugger* self = static_cast( - message.GetIsolate()->GetData(kIsolateSlot)); - - if (self) { - std::string message8(*v8::String::Utf8Value(message.GetJSON())); - self->thread_.task_runner()->PostTask( - FROM_HERE, - base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(), - message8)); - } -} - -void NodeDebugger::DidAccept( - net::test_server::StreamListenSocket* server, - std::unique_ptr socket) { - // Only accept one session. - if (accepted_socket_) { - socket->Send(std::string("Remote debugging session already active"), true); - return; + node::DebugOptions options; + for (auto& arg : base::CommandLine::ForCurrentProcess()->argv()) { +#if defined(OS_WIN) + options.ParseOption(base::UTF16ToUTF8(arg)); +#else + options.ParseOption(arg); +#endif } - accepted_socket_ = std::move(socket); - SendConnectMessage(); -} + if (options.inspector_enabled()) { + // Use custom platform since the gin platform does not work correctly + // with node's inspector agent + platform_.reset(v8::platform::CreateDefaultPlatform()); -void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket, - const char* data, - int len) { - buffer_.append(data, len); - - do { - if (buffer_.empty()) - return; - - // Read the "Content-Length" header. - if (content_length_ < 0) { - size_t pos = buffer_.find("\r\n\r\n"); - if (pos == std::string::npos) - return; - - // We can be sure that the header is "Content-Length: xxx\r\n". - std::string content_length = buffer_.substr(16, pos - 16); - if (!base::StringToInt(content_length, &content_length_)) { - DidClose(accepted_socket_.get()); - return; - } - - // Strip header from buffer. - buffer_ = buffer_.substr(pos + 4); + // Set process._debugWaitConnect if --inspect-brk was specified to stop + // the debugger on the first line + if (options.wait_for_connect()) { + mate::Dictionary process(env_->isolate(), env_->process_object()); + process.Set("_debugWaitConnect", true); } - // Read the message. - if (buffer_.size() >= static_cast(content_length_)) { - std::string message = buffer_.substr(0, content_length_); - buffer_ = buffer_.substr(content_length_); - - OnMessage(message); - - // Get ready for next message. - content_length_ = -1; - } - } while (true); -} - -void NodeDebugger::DidClose(net::test_server::StreamListenSocket* socket) { - // If we lost the connection, then simulate a disconnect msg: - OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}"); + inspector->Start(platform_.get(), nullptr, options); + } } } // namespace atom diff --git a/atom/browser/node_debugger.h b/atom/browser/node_debugger.h index 118812a139a5..a3553192b4ec 100644 --- a/atom/browser/node_debugger.h +++ b/atom/browser/node_debugger.h @@ -6,56 +6,22 @@ #define ATOM_BROWSER_NODE_DEBUGGER_H_ #include -#include -#include "base/memory/weak_ptr.h" -#include "base/threading/thread.h" -#include "net/test/embedded_test_server/stream_listen_socket.h" -#include "v8/include/v8-debug.h" -#include "vendor/node/deps/uv/include/uv.h" +#include "atom/common/node_includes.h" namespace atom { -// Add support for node's "--debug" switch. -class NodeDebugger : public net::test_server::StreamListenSocket::Delegate { +// Add support for node's "--inspect" switch. +class NodeDebugger { public: - explicit NodeDebugger(v8::Isolate* isolate); - virtual ~NodeDebugger(); + explicit NodeDebugger(node::Environment* env); + ~NodeDebugger(); - bool IsRunning() const; + void Start(); private: - void StartServer(int port); - void CloseSession(); - void OnMessage(const std::string& message); - void SendMessage(const std::string& message); - void SendConnectMessage(); - - static void ProcessMessageInUI(uv_async_t* handle); - - static void DebugMessageHandler(const v8::Debug::Message& message); - - // net::test_server::StreamListenSocket::Delegate: - void DidAccept( - net::test_server::StreamListenSocket* server, - std::unique_ptr socket) override; - void DidRead(net::test_server::StreamListenSocket* socket, - const char* data, - int len) override; - void DidClose(net::test_server::StreamListenSocket* socket) override; - - v8::Isolate* isolate_; - - uv_async_t weak_up_ui_handle_; - - base::Thread thread_; - std::unique_ptr server_; - std::unique_ptr accepted_socket_; - - std::string buffer_; - int content_length_; - - base::WeakPtrFactory weak_factory_; + node::Environment* env_; + std::unique_ptr platform_; DISALLOW_COPY_AND_ASSIGN(NodeDebugger); }; diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index ae757b1da883..2a7be5762769 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -198,12 +198,6 @@ node::Environment* NodeBindings::CreateEnvironment( PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path); process.Set("helperExecPath", helper_exec_path); - // Set process._debugWaitConnect if --debug-brk was specified to stop - // the debugger on the first line - if (browser_env_ == BROWSER && - base::CommandLine::ForCurrentProcess()->HasSwitch("debug-brk")) - process.Set("_debugWaitConnect", true); - return env; } diff --git a/atom/common/node_includes.h b/atom/common/node_includes.h index b6cbf36090c9..5e9c3fdbec8c 100644 --- a/atom/common/node_includes.h +++ b/atom/common/node_includes.h @@ -29,6 +29,7 @@ #include "vendor/node/src/env-inl.h" #include "vendor/node/src/node.h" #include "vendor/node/src/node_buffer.h" +#include "vendor/node/src/node_debug_options.h" #include "vendor/node/src/node_internals.h" #endif // ATOM_COMMON_NODE_INCLUDES_H_ diff --git a/atom/node/osfhandle.cc b/atom/node/osfhandle.cc index e9ec03a5c81f..f21f55a792a4 100644 --- a/atom/node/osfhandle.cc +++ b/atom/node/osfhandle.cc @@ -6,9 +6,11 @@ #include +#if !defined(DEBUG) #define U_I18N_IMPLEMENTATION #define U_COMMON_IMPLEMENTATION #define U_COMBINED_IMPLEMENTATION +#endif #include "third_party/icu/source/common/unicode/ubidi.h" #include "third_party/icu/source/common/unicode/uchar.h" diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc b/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc deleted file mode 100644 index 6cdc1e6ea934..000000000000 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/test/embedded_test_server/stream_listen_socket.h" - -#include - -#if defined(OS_WIN) -// winsock2.h must be included first in order to ensure it is included before -// windows.h. -#include -#elif defined(OS_POSIX) -#include -#include -#include -#include -#include -#include "net/base/net_errors.h" -#endif - -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/posix/eintr_wrapper.h" -#include "base/sys_byteorder.h" -#include "base/threading/platform_thread.h" -#include "build/build_config.h" -#include "net/base/ip_endpoint.h" -#include "net/base/net_errors.h" -#include "net/base/network_interfaces.h" -#include "net/base/sockaddr_storage.h" -#include "net/socket/socket_descriptor.h" - -using std::string; - -#if defined(OS_WIN) -typedef int socklen_t; -#endif // defined(OS_WIN) - -namespace net { - -namespace test_server { - -namespace { - -const int kReadBufSize = 4096; - -} // namespace - -#if defined(OS_WIN) -const int StreamListenSocket::kSocketError = SOCKET_ERROR; -#elif defined(OS_POSIX) -const int StreamListenSocket::kSocketError = -1; -#endif - -StreamListenSocket::StreamListenSocket(SocketDescriptor s, - StreamListenSocket::Delegate* del) - : socket_delegate_(del), -#if defined(OS_POSIX) - watcher_(FROM_HERE), -#endif - socket_(s), - reads_paused_(false), - has_pending_reads_(false) { -#if defined(OS_WIN) - socket_event_ = WSACreateEvent(); - // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT. - WatchSocket(NOT_WAITING); -#elif defined(OS_POSIX) - wait_state_ = NOT_WAITING; -#endif -} - -StreamListenSocket::~StreamListenSocket() { - CloseSocket(); -#if defined(OS_WIN) - if (socket_event_) { - WSACloseEvent(socket_event_); - socket_event_ = WSA_INVALID_EVENT; - } -#endif -} - -void StreamListenSocket::Send(const char* bytes, - int len, - bool append_linefeed) { - SendInternal(bytes, len); - if (append_linefeed) - SendInternal("\r\n", 2); -} - -void StreamListenSocket::Send(const string& str, bool append_linefeed) { - Send(str.data(), static_cast(str.length()), append_linefeed); -} - -int StreamListenSocket::GetLocalAddress(IPEndPoint* address) const { - SockaddrStorage storage; - if (getsockname(socket_, storage.addr, &storage.addr_len)) { -#if defined(OS_WIN) - int err = WSAGetLastError(); -#else - int err = errno; -#endif - return MapSystemError(err); - } - if (!address->FromSockAddr(storage.addr, storage.addr_len)) - return ERR_ADDRESS_INVALID; - return OK; -} - -int StreamListenSocket::GetPeerAddress(IPEndPoint* address) const { - SockaddrStorage storage; - if (getpeername(socket_, storage.addr, &storage.addr_len)) { -#if defined(OS_WIN) - int err = WSAGetLastError(); -#else - int err = errno; -#endif - return MapSystemError(err); - } - - if (!address->FromSockAddr(storage.addr, storage.addr_len)) - return ERR_ADDRESS_INVALID; - - return OK; -} - -SocketDescriptor StreamListenSocket::AcceptSocket() { - SocketDescriptor conn = HANDLE_EINTR(accept(socket_, NULL, NULL)); - if (conn == kInvalidSocket) - LOG(ERROR) << "Error accepting connection."; - else - base::SetNonBlocking(conn); - return conn; -} - -void StreamListenSocket::SendInternal(const char* bytes, int len) { - char* send_buf = const_cast(bytes); - int len_left = len; - while (true) { - int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0)); - if (sent == len_left) { // A shortcut to avoid extraneous checks. - break; - } - if (sent == kSocketError) { -#if defined(OS_WIN) - if (WSAGetLastError() != WSAEWOULDBLOCK) { - LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); -#elif defined(OS_POSIX) - if (errno != EWOULDBLOCK && errno != EAGAIN) { - LOG(ERROR) << "send failed: errno==" << errno; -#endif - break; - } - // Otherwise we would block, and now we have to wait for a retry. - // Fall through to PlatformThread::YieldCurrentThread() - } else { - // sent != len_left according to the shortcut above. - // Shift the buffer start and send the remainder after a short while. - send_buf += sent; - len_left -= sent; - } - base::PlatformThread::YieldCurrentThread(); - } -} - -void StreamListenSocket::Listen() { - int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? - if (listen(socket_, backlog) == -1) { - // TODO(erikkay): error handling. - LOG(ERROR) << "Could not listen on socket."; - return; - } -#if defined(OS_POSIX) - WatchSocket(WAITING_ACCEPT); -#endif -} - -void StreamListenSocket::Read() { - char buf[kReadBufSize + 1]; // +1 for null termination. - int len; - do { - len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0)); - if (len == kSocketError) { -#if defined(OS_WIN) - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { -#elif defined(OS_POSIX) - if (errno == EWOULDBLOCK || errno == EAGAIN) { -#endif - break; - } else { - // TODO(ibrar): some error handling required here. - break; - } - } else if (len == 0) { -#if defined(OS_POSIX) - // In Windows, Close() is called by OnObjectSignaled. In POSIX, we need - // to call it here. - Close(); -#endif - } else { - // TODO(ibrar): maybe change DidRead to take a length instead. - DCHECK_GT(len, 0); - DCHECK_LE(len, kReadBufSize); - buf[len] = 0; // Already create a buffer with +1 length. - socket_delegate_->DidRead(this, buf, len); - } - } while (len == kReadBufSize); -} - -void StreamListenSocket::Close() { -#if defined(OS_POSIX) - if (wait_state_ == NOT_WAITING) - return; - wait_state_ = NOT_WAITING; -#endif - UnwatchSocket(); - socket_delegate_->DidClose(this); -} - -void StreamListenSocket::CloseSocket() { - if (socket_ != kInvalidSocket) { - UnwatchSocket(); -#if defined(OS_WIN) - closesocket(socket_); -#elif defined(OS_POSIX) - close(socket_); -#endif - } -} - -void StreamListenSocket::WatchSocket(WaitState state) { -#if defined(OS_WIN) - WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ); - watcher_.StartWatchingOnce(socket_event_, this); -#elif defined(OS_POSIX) - // Implicitly calls StartWatchingFileDescriptor(). - base::MessageLoopForIO::current()->WatchFileDescriptor( - socket_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this); - wait_state_ = state; -#endif -} - -void StreamListenSocket::UnwatchSocket() { -#if defined(OS_WIN) - watcher_.StopWatching(); -#elif defined(OS_POSIX) - watcher_.StopWatchingFileDescriptor(); -#endif -} - -// TODO(ibrar): We can add these functions into OS dependent files. -#if defined(OS_WIN) -// MessageLoop watcher callback. -void StreamListenSocket::OnObjectSignaled(HANDLE object) { - WSANETWORKEVENTS ev; - if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) { - // TODO - return; - } - - // If both FD_CLOSE and FD_READ are set we only call Read(). - // This will cause OnObjectSignaled to be called immediately again - // unless this socket is destroyed in Read(). - if ((ev.lNetworkEvents & (FD_CLOSE | FD_READ)) == FD_CLOSE) { - Close(); - // Close might have deleted this object. We should return immediately. - return; - } - // The object was reset by WSAEnumNetworkEvents. Watch for the next signal. - watcher_.StartWatchingOnce(object, this); - - if (ev.lNetworkEvents == 0) { - // Occasionally the event is set even though there is no new data. - // The net seems to think that this is ignorable. - return; - } - if (ev.lNetworkEvents & FD_ACCEPT) { - Accept(); - } - if (ev.lNetworkEvents & FD_READ) { - if (reads_paused_) { - has_pending_reads_ = true; - } else { - Read(); - // Read might have deleted this object. We should return immediately. - } - } -} -#elif defined(OS_POSIX) -void StreamListenSocket::OnFileCanReadWithoutBlocking(int fd) { - switch (wait_state_) { - case WAITING_ACCEPT: - Accept(); - break; - case WAITING_READ: - if (reads_paused_) { - has_pending_reads_ = true; - } else { - Read(); - } - break; - default: - // Close() is called by Read() in the Linux case. - NOTREACHED(); - break; - } -} - -void StreamListenSocket::OnFileCanWriteWithoutBlocking(int fd) { - // MessagePumpLibevent callback, we don't listen for write events - // so we shouldn't ever reach here. - NOTREACHED(); -} - -#endif - -void StreamListenSocket::PauseReads() { - DCHECK(!reads_paused_); - reads_paused_ = true; -} - -void StreamListenSocket::ResumeReads() { - DCHECK(reads_paused_); - reads_paused_ = false; - if (has_pending_reads_) { - has_pending_reads_ = false; - Read(); - } -} - -} // namespace test_server - -} // namespace net diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.h b/chromium_src/net/test/embedded_test_server/stream_listen_socket.h deleted file mode 100644 index 00d4b58dcf3b..000000000000 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Stream-based listen socket implementation that handles reading and writing -// to the socket, but does not handle creating the socket nor connecting -// sockets, which are handled by subclasses on creation and in Accept, -// respectively. - -// StreamListenSocket handles IO asynchronously in the specified MessageLoop. -// This class is NOT thread safe. It uses WSAEVENT handles to monitor activity -// in a given MessageLoop. This means that callbacks will happen in that loop's -// thread always and that all other methods (including constructor and -// destructor) should also be called from the same thread. - -#ifndef NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_ -#define NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_ - -#include - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#endif -#include -#if defined(OS_WIN) -#include "base/win/object_watcher.h" -#elif defined(OS_POSIX) -#include "base/message_loop/message_loop.h" -#endif - -#include "base/macros.h" -#include "base/compiler_specific.h" -#include "net/base/net_export.h" -#include "net/socket/socket_descriptor.h" - -namespace net { - -class IPEndPoint; - -namespace test_server { - -class StreamListenSocket : -#if defined(OS_WIN) - public base::win::ObjectWatcher::Delegate { -#elif defined(OS_POSIX) - public base::MessageLoopForIO::Watcher { -#endif - - public: - ~StreamListenSocket() override; - - // TODO(erikkay): this delegate should really be split into two parts - // to split up the listener from the connected socket. Perhaps this class - // should be split up similarly. - class Delegate { - public: - // |server| is the original listening Socket, connection is the new - // Socket that was created. - virtual void DidAccept(StreamListenSocket* server, - std::unique_ptr connection) = 0; - virtual void DidRead(StreamListenSocket* connection, - const char* data, - int len) = 0; - virtual void DidClose(StreamListenSocket* sock) = 0; - - protected: - virtual ~Delegate() {} - }; - - // Send data to the socket. - void Send(const char* bytes, int len, bool append_linefeed = false); - void Send(const std::string& str, bool append_linefeed = false); - - // Copies the local address to |address|. Returns a network error code. - // This method is virtual to support unit testing. - virtual int GetLocalAddress(IPEndPoint* address) const; - // Copies the peer address to |address|. Returns a network error code. - // This method is virtual to support unit testing. - virtual int GetPeerAddress(IPEndPoint* address) const; - - static const int kSocketError; - - protected: - enum WaitState { NOT_WAITING = 0, WAITING_ACCEPT = 1, WAITING_READ = 2 }; - - StreamListenSocket(SocketDescriptor s, Delegate* del); - - SocketDescriptor AcceptSocket(); - virtual void Accept() = 0; - - void Listen(); - void Read(); - void Close(); - void CloseSocket(); - - // Pass any value in case of Windows, because in Windows - // we are not using state. - void WatchSocket(WaitState state); - void UnwatchSocket(); - - Delegate* const socket_delegate_; - - private: - friend class TransportClientSocketTest; - - void SendInternal(const char* bytes, int len); - -#if defined(OS_WIN) - // ObjectWatcher delegate. - void OnObjectSignaled(HANDLE object) override; - base::win::ObjectWatcher watcher_; - HANDLE socket_event_; -#elif defined(OS_POSIX) - // Called by MessagePumpLibevent when the socket is ready to do I/O. - void OnFileCanReadWithoutBlocking(int fd) override; - void OnFileCanWriteWithoutBlocking(int fd) override; - WaitState wait_state_; - // The socket's libevent wrapper. - base::MessageLoopForIO::FileDescriptorWatcher watcher_; -#endif - - // NOTE: This is for unit test use only! - // Pause/Resume calling Read(). Note that ResumeReads() will also call - // Read() if there is anything to read. - void PauseReads(); - void ResumeReads(); - - const SocketDescriptor socket_; - bool reads_paused_; - bool has_pending_reads_; - - DISALLOW_COPY_AND_ASSIGN(StreamListenSocket); -}; - -// Abstract factory that must be subclassed for each subclass of -// StreamListenSocket. -class StreamListenSocketFactory { - public: - virtual ~StreamListenSocketFactory() {} - - // Returns a new instance of StreamListenSocket or NULL if an error occurred. - virtual std::unique_ptr CreateAndListen( - StreamListenSocket::Delegate* delegate) const = 0; -}; - -} // namespace test_server - -} // namespace net - -#endif // NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_ diff --git a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc deleted file mode 100644 index 50aac809052e..000000000000 --- a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/test/embedded_test_server/tcp_listen_socket.h" - -#if defined(OS_WIN) -// winsock2.h must be included first in order to ensure it is included before -// windows.h. -#include -#include -#elif defined(OS_POSIX) -#include -#include -#include -#include -#include -#include "net/base/net_errors.h" -#endif - -#include "base/logging.h" -#include "base/sys_byteorder.h" -#include "base/threading/platform_thread.h" -#include "build/build_config.h" -#include "net/base/network_interfaces.h" -#include "net/base/winsock_init.h" -#include "net/socket/socket_descriptor.h" - -using std::string; - -namespace net { - -namespace test_server { - -// static -std::unique_ptr TCPListenSocket::CreateAndListen( - const string& ip, - uint16_t port, - StreamListenSocket::Delegate* del) { - SocketDescriptor s = CreateAndBind(ip, port); - if (s == kInvalidSocket) - return std::unique_ptr(); - std::unique_ptr sock(new TCPListenSocket(s, del)); - sock->Listen(); - return sock; -} - -TCPListenSocket::TCPListenSocket(SocketDescriptor s, - StreamListenSocket::Delegate* del) - : StreamListenSocket(s, del) { -} - -TCPListenSocket::~TCPListenSocket() { -} - -SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, - uint16_t port) { - SocketDescriptor s = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s != kInvalidSocket) { -#if defined(OS_POSIX) - // Allow rapid reuse. - static const int kOn = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); -#endif - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr(ip.c_str()); - addr.sin_port = base::HostToNet16(port); - if (bind(s, reinterpret_cast(&addr), sizeof(addr))) { -#if defined(OS_WIN) - closesocket(s); -#elif defined(OS_POSIX) - close(s); -#endif - LOG(ERROR) << "Could not bind socket to " << ip << ":" << port; - s = kInvalidSocket; - } - } - return s; -} - -SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip, - uint16_t* port) { - SocketDescriptor s = CreateAndBind(ip, 0); - if (s == kInvalidSocket) - return kInvalidSocket; - sockaddr_in addr; - socklen_t addr_size = sizeof(addr); - bool failed = getsockname(s, reinterpret_cast(&addr), - &addr_size) != 0; - if (addr_size != sizeof(addr)) - failed = true; - if (failed) { - LOG(ERROR) << "Could not determine bound port, getsockname() failed"; -#if defined(OS_WIN) - closesocket(s); -#elif defined(OS_POSIX) - close(s); -#endif - return kInvalidSocket; - } - *port = base::NetToHost16(addr.sin_port); - return s; -} - -void TCPListenSocket::Accept() { - SocketDescriptor conn = AcceptSocket(); - if (conn == kInvalidSocket) - return; - std::unique_ptr sock(new TCPListenSocket(conn, socket_delegate_)); -#if defined(OS_POSIX) - sock->WatchSocket(WAITING_READ); -#endif - socket_delegate_->DidAccept(this, std::move(sock)); -} - -} // namespace test_server - -} // namespace net diff --git a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h deleted file mode 100644 index db18fd0f0eb4..000000000000 --- a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_ -#define NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_ - -#include - -#include "base/macros.h" -#include "net/base/net_export.h" -#include "net/socket/socket_descriptor.h" -#include "net/test/embedded_test_server/stream_listen_socket.h" - -namespace net { - -namespace test_server { - -// Implements a TCP socket. -class TCPListenSocket : public StreamListenSocket { - public: - ~TCPListenSocket() override; - - // Listen on port for the specified IP address. Use 127.0.0.1 to only - // accept local connections. - static std::unique_ptr CreateAndListen( - const std::string& ip, - uint16_t port, - StreamListenSocket::Delegate* del); - - protected: - TCPListenSocket(SocketDescriptor s, StreamListenSocket::Delegate* del); - - // Implements StreamListenSocket::Accept. - void Accept() override; - - private: - friend class EmbeddedTestServer; - friend class TCPListenSocketTester; - - // Get raw TCP socket descriptor bound to ip:port. - static SocketDescriptor CreateAndBind(const std::string& ip, uint16_t port); - - // Get raw TCP socket descriptor bound to ip and return port it is bound to. - static SocketDescriptor CreateAndBindAnyPort(const std::string& ip, - uint16_t* port); - - DISALLOW_COPY_AND_ASSIGN(TCPListenSocket); -}; - -} // namespace test_server - -} // namespace net - -#endif // NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_ diff --git a/common.gypi b/common.gypi index ee8b1e857680..6f1ad5f75216 100644 --- a/common.gypi +++ b/common.gypi @@ -43,7 +43,7 @@ 'V8_BASE': '', 'v8_postmortem_support': 'false', 'v8_enable_i18n_support': 'false', - 'v8_inspector': 'false', + 'v8_inspector': 'true', }, # Settings to compile node under Windows. 'target_defaults': { diff --git a/docs/api/chrome-command-line-switches.md b/docs/api/chrome-command-line-switches.md index 7308c5d45183..4aa809b02c14 100644 --- a/docs/api/chrome-command-line-switches.md +++ b/docs/api/chrome-command-line-switches.md @@ -28,7 +28,7 @@ Disables the disk cache for HTTP requests. Disable HTTP/2 and SPDY/3.1 protocols. -## --debug=`port` and --debug-brk=`port` +## --inspect=`port` and --inspect-brk=`port` Debug-related flags, see the [Debugging the Main Process][debugging-main-process] guide for details. diff --git a/docs/tutorial/debugging-main-process-node-inspector.md b/docs/tutorial/debugging-main-process-node-inspector.md deleted file mode 100644 index 2c42ef3139a1..000000000000 --- a/docs/tutorial/debugging-main-process-node-inspector.md +++ /dev/null @@ -1,131 +0,0 @@ -# Debugging the Main Process in node-inspector - -[`node-inspector`][node-inspector] provides a familiar DevTools GUI that can -be used in Chrome to debug Electron's main process, however, because -`node-inspector` relies on some native Node modules they must be rebuilt to -target the version of Electron you wish to debug. You can either rebuild -the `node-inspector` dependencies yourself, or let -[`electron-inspector`][electron-inspector] do it for you, both approaches are -covered in this document. - -**Note**: At the time of writing the latest release of `node-inspector` -(0.12.8) can't be rebuilt to target Electron 1.3.0 or later without patching -one of its dependencies. If you use `electron-inspector` it will take care of -this for you. - - -## Use `electron-inspector` for Debugging - -### 1. Install the [node-gyp required tools][node-gyp-required-tools] - -### 2. Install [`electron-rebuild`][electron-rebuild], if you haven't done so already. - -```shell -npm install electron-rebuild --save-dev -``` - -### 3. Install [`electron-inspector`][electron-inspector] - -```shell -npm install electron-inspector --save-dev -``` - -### 4. Start Electron - -Launch Electron with the `--debug` switch: - -```shell -electron --debug=5858 your/app -``` - -or, to pause execution on the first line of JavaScript: - -```shell -electron --debug-brk=5858 your/app -``` - -### 5. Start electron-inspector - -On macOS / Linux: - -```shell -node_modules/.bin/electron-inspector -``` - -On Windows: - -```shell -node_modules\\.bin\\electron-inspector -``` - -`electron-inspector` will need to rebuild `node-inspector` dependencies on the -first run, and any time you change your Electron version. The rebuild process -may require an internet connection to download Node headers and libs, and may -take a few minutes. - -### 6. Load the debugger UI - -Open http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 in the Chrome -browser. You may have to click pause if starting with `--debug-brk` to force -the UI to update. - - -## Use `node-inspector` for Debugging - -### 1. Install the [node-gyp required tools][node-gyp-required-tools] - -### 2. Install [`node-inspector`][node-inspector] - -```bash -$ npm install node-inspector -``` - -### 3. Install [`node-pre-gyp`][node-pre-gyp] - -```bash -$ npm install node-pre-gyp -``` - -### 4. Recompile the `node-inspector` `v8` modules for Electron - -**Note:** Update the target argument to be your Electron version number - -```bash -$ node_modules/.bin/node-pre-gyp --target=1.2.5 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall -$ node_modules/.bin/node-pre-gyp --target=1.2.5 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall -``` - -See also [How to install native modules][how-to-install-native-modules]. - -### 5. Enable debug mode for Electron - -You can either start Electron with a debug flag like: - -```bash -$ electron --debug=5858 your/app -``` - -or, to pause your script on the first line: - -```bash -$ electron --debug-brk=5858 your/app -``` - -### 6. Start the [`node-inspector`][node-inspector] server using Electron - -```bash -$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js -``` - -### 7. Load the debugger UI - -Open http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 in the Chrome -browser. You may have to click pause if starting with `--debug-brk` to see the -entry line. - -[electron-inspector]: https://github.com/enlight/electron-inspector -[electron-rebuild]: https://github.com/electron/electron-rebuild -[node-inspector]: https://github.com/node-inspector/node-inspector -[node-pre-gyp]: https://github.com/mapbox/node-pre-gyp -[node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation -[how-to-install-native-modules]: using-native-node-modules.md#how-to-install-native-modules diff --git a/docs/tutorial/debugging-main-process.md b/docs/tutorial/debugging-main-process.md index fb5759e4995f..a30760671d07 100644 --- a/docs/tutorial/debugging-main-process.md +++ b/docs/tutorial/debugging-main-process.md @@ -3,31 +3,31 @@ The DevTools in an Electron browser window can only debug JavaScript that's executed in that window (i.e. the web pages). To debug JavaScript that's executed in the main process you will need to use an external debugger and -launch Electron with the `--debug` or `--debug-brk` switch. +launch Electron with the `--inspector` or `--inspector-brk` switch. ## Command Line Switches Use one of the following command line switches to enable debugging of the main process: -### `--debug=[port]` +### `--inspect=[port]` -Electron will listen for V8 debugger protocol messages on the specified `port`, +Electron will listen for V8 inspector protocol messages on the specified `port`, an external debugger will need to connect on this port. The default `port` is `5858`. ```shell -electron --debug=5858 your/app +electron --inspect=5858 your/app ``` -### `--debug-brk=[port]` +### `--inspect-brk=[port]` -Like `--debug` but pauses execution on the first line of JavaScript. +Like `--inspector` but pauses execution on the first line of JavaScript. ## External Debuggers -You will need to use a debugger that supports the V8 debugger protocol, -the following guides should help you to get started: +You will need to use a debugger that supports the V8 inspector protocol. +- Connect Chrome by visiting `chrome://inspect` and selecting to inspect the + launched Electron app present there. - [Debugging the Main Process in VSCode](debugging-main-process-vscode.md) -- [Debugging the Main Process in node-inspector](debugging-main-process-node-inspector.md) diff --git a/electron.gyp b/electron.gyp index 9bfcbcee7c0e..e0c91c151fd9 100644 --- a/electron.gyp +++ b/electron.gyp @@ -227,6 +227,7 @@ # We need to access internal implementations of Node. 'NODE_WANT_INTERNALS=1', 'NODE_SHARED_MODE', + 'HAVE_INSPECTOR=1', # This is defined in skia/skia_common.gypi. 'SK_SUPPORT_LEGACY_GETTOPDEVICE', # Disable warnings for g_settings_list_schemas. diff --git a/filenames.gypi b/filenames.gypi index 54ddf4dde195..570d20ab10cb 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -634,10 +634,6 @@ 'chromium_src/extensions/common/url_pattern.h', 'chromium_src/library_loaders/libspeechd_loader.cc', 'chromium_src/library_loaders/libspeechd.h', - 'chromium_src/net/test/embedded_test_server/stream_listen_socket.cc', - 'chromium_src/net/test/embedded_test_server/stream_listen_socket.h', - 'chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc', - 'chromium_src/net/test/embedded_test_server/tcp_listen_socket.h', '<@(native_mate_files)', '<(SHARED_INTERMEDIATE_DIR)/atom_natives.h', '<(SHARED_INTERMEDIATE_DIR)/grit/pdf_viewer_resources_map.cc', diff --git a/vendor/node b/vendor/node index df227c3a5db7..3cdf4532cf3d 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit df227c3a5db7aa8eab64c86f54588c6cd2d6c623 +Subproject commit 3cdf4532cf3da20af37e57cbbd59eb860be233aa