diff options
author | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-03 17:23:24 +0000 |
---|---|---|
committer | pfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-03 17:23:24 +0000 |
commit | a33721a77396c8f7607d330cd3d07b82f4ebc0ed (patch) | |
tree | eee496f02500b7acefee4450aa9d6859aad3901c | |
parent | 2d354bbcb647825dab961834b23ed6756489b73a (diff) | |
download | chromium_src-a33721a77396c8f7607d330cd3d07b82f4ebc0ed.zip chromium_src-a33721a77396c8f7607d330cd3d07b82f4ebc0ed.tar.gz chromium_src-a33721a77396c8f7607d330cd3d07b82f4ebc0ed.tar.bz2 |
DevTools: split http_listen_socket into http_server and connection.
BUG=
TEST=
Review URL: http://codereview.chromium.org/6410033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73631 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/debugger/devtools_http_protocol_handler.cc | 197 | ||||
-rw-r--r-- | chrome/browser/debugger/devtools_http_protocol_handler.h | 51 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | net/base/listen_socket.cc | 5 | ||||
-rw-r--r-- | net/net.gyp | 6 | ||||
-rw-r--r-- | net/server/http_listen_socket.h | 72 | ||||
-rw-r--r-- | net/server/http_server.cc (renamed from net/server/http_listen_socket.cc) | 283 | ||||
-rw-r--r-- | net/server/http_server.h | 96 |
8 files changed, 402 insertions, 310 deletions
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.cc b/chrome/browser/debugger/devtools_http_protocol_handler.cc index 940e942..9351b40 100644 --- a/chrome/browser/debugger/devtools_http_protocol_handler.cc +++ b/chrome/browser/debugger/devtools_http_protocol_handler.cc @@ -22,7 +22,6 @@ #include "chrome/common/net/url_request_context_getter.h" #include "googleurl/src/gurl.h" #include "net/base/io_buffer.h" -#include "net/base/listen_socket.h" #include "net/server/http_server_request_info.h" #include "net/url_request/url_request_context.h" @@ -34,8 +33,12 @@ namespace { // messages sent for DevToolsClient to a DebuggerShell instance. class DevToolsClientHostImpl : public DevToolsClientHost { public: - explicit DevToolsClientHostImpl(HttpListenSocket* socket) - : socket_(socket) {} + DevToolsClientHostImpl( + HttpServer* server, + int connection_id) + : server_(server), + connection_id_(connection_id) { + } ~DevToolsClientHostImpl() {} // DevToolsClientHost interface @@ -43,8 +46,9 @@ class DevToolsClientHostImpl : public DevToolsClientHost { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(socket_, - &HttpListenSocket::Close)); + NewRunnableMethod(server_, + &HttpServer::Close, + connection_id_)); } virtual void SendMessageToClient(const IPC::Message& msg) { @@ -64,10 +68,18 @@ class DevToolsClientHostImpl : public DevToolsClientHost { private: // Message handling routines void OnDispatchOnInspectorFrontend(const std::string& data) { - socket_->SendOverWebSocket(data); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + NewRunnableMethod(server_, + &HttpServer::SendOverWebSocket, + connection_id_, + data)); } + virtual void FrameNavigating(const std::string& url) {} - HttpListenSocket* socket_; + HttpServer* server_; + int connection_id_; }; } // namespace @@ -102,7 +114,7 @@ void DevToolsHttpProtocolHandler::Stop() { } void DevToolsHttpProtocolHandler::OnHttpRequest( - HttpListenSocket* socket, + int connection_id, const HttpServerRequestInfo& info) { if (info.path == "" || info.path == "/") { // Pages discovery request. @@ -111,28 +123,28 @@ void DevToolsHttpProtocolHandler::OnHttpRequest( FROM_HERE, NewRunnableMethod(this, &DevToolsHttpProtocolHandler::OnHttpRequestUI, - make_scoped_refptr(socket), + connection_id, info)); return; } size_t pos = info.path.find("/devtools/"); if (pos != 0) { - socket->Send404(); + server_->Send404(connection_id); return; } // Proxy static files from chrome://devtools/*. net::URLRequest* request = new net::URLRequest( GURL("chrome:/" + info.path), this); - Bind(request, socket); + Bind(request, connection_id); request->set_context( Profile::GetDefaultRequestContext()->GetURLRequestContext()); request->Start(); } void DevToolsHttpProtocolHandler::OnWebSocketRequest( - HttpListenSocket* socket, + int connection_id, const HttpServerRequestInfo& request) { BrowserThread::PostTask( BrowserThread::UI, @@ -140,35 +152,37 @@ void DevToolsHttpProtocolHandler::OnWebSocketRequest( NewRunnableMethod( this, &DevToolsHttpProtocolHandler::OnWebSocketRequestUI, - make_scoped_refptr(socket), + connection_id, request)); } -void DevToolsHttpProtocolHandler::OnWebSocketMessage(HttpListenSocket* socket, - const std::string& data) { +void DevToolsHttpProtocolHandler::OnWebSocketMessage( + int connection_id, + const std::string& data) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod( this, &DevToolsHttpProtocolHandler::OnWebSocketMessageUI, - make_scoped_refptr(socket), + connection_id, data)); } -void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) { - SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket); - if (it != socket_to_requests_io_.end()) { +void DevToolsHttpProtocolHandler::OnClose(int connection_id) { + ConnectionToRequestsMap::iterator it = + connection_to_requests_io_.find(connection_id); + if (it != connection_to_requests_io_.end()) { // Dispose delegating socket. for (std::set<net::URLRequest*>::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { net::URLRequest* request = *it2; request->Cancel(); - request_to_socket_io_.erase(request); + request_to_connection_io_.erase(request); request_to_buffer_io_.erase(request); delete request; } - socket_to_requests_io_.erase(socket); + connection_to_requests_io_.erase(connection_id); } BrowserThread::PostTask( @@ -177,11 +191,11 @@ void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) { NewRunnableMethod( this, &DevToolsHttpProtocolHandler::OnCloseUI, - make_scoped_refptr(socket))); + connection_id)); } void DevToolsHttpProtocolHandler::OnHttpRequestUI( - HttpListenSocket* socket, + int connection_id, const HttpServerRequestInfo& info) { std::string response = "<html><body><script>" "function addTab(id, url, attached, frontendUrl) {" @@ -226,51 +240,53 @@ void DevToolsHttpProtocolHandler::OnHttpRequestUI( } response += "</script></body></html>"; - Send200(socket, response, "text/html; charset=UTF-8"); + Send200(connection_id, response, "text/html; charset=UTF-8"); } void DevToolsHttpProtocolHandler::OnWebSocketRequestUI( - HttpListenSocket* socket, + int connection_id, const HttpServerRequestInfo& request) { std::string prefix = "/devtools/page/"; size_t pos = request.path.find(prefix); if (pos != 0) { - Send404(socket); + Send404(connection_id); return; } std::string page_id = request.path.substr(prefix.length()); int id = 0; if (!base::StringToInt(page_id, &id)) { - Send500(socket, "Invalid page id: " + page_id); + Send500(connection_id, "Invalid page id: " + page_id); return; } TabContents* tab_contents = GetTabContents(id); if (tab_contents == NULL) { - Send500(socket, "No such page id: " + page_id); + Send500(connection_id, "No such page id: " + page_id); return; } DevToolsManager* manager = DevToolsManager::GetInstance(); if (manager->GetDevToolsClientHostFor(tab_contents->render_view_host())) { - Send500(socket, "Page with given id is being inspected: " + page_id); + Send500(connection_id, "Page with given id is being inspected: " + page_id); return; } - DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(socket); - socket_to_client_host_ui_[socket] = client_host; + DevToolsClientHostImpl* client_host = + new DevToolsClientHostImpl(server_, connection_id); + connection_to_client_host_ui_[connection_id] = client_host; manager->RegisterDevToolsClientHostFor( tab_contents->render_view_host(), client_host); - AcceptWebSocket(socket, request); + AcceptWebSocket(connection_id, request); } void DevToolsHttpProtocolHandler::OnWebSocketMessageUI( - HttpListenSocket* socket, + int connection_id, const std::string& data) { - SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket); - if (it == socket_to_client_host_ui_.end()) + ConnectionToClientHostMap::iterator it = + connection_to_client_host_ui_.find(connection_id); + if (it == connection_to_client_host_ui_.end()) return; DevToolsManager* manager = DevToolsManager::GetInstance(); @@ -287,35 +303,24 @@ void DevToolsHttpProtocolHandler::OnWebSocketMessageUI( DevToolsAgentMsg_DispatchOnInspectorBackend(data)); } -void DevToolsHttpProtocolHandler::OnCloseUI(HttpListenSocket* socket) { - SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket); - if (it != socket_to_client_host_ui_.end()) { +void DevToolsHttpProtocolHandler::OnCloseUI(int connection_id) { + ConnectionToClientHostMap::iterator it = + connection_to_client_host_ui_.find(connection_id); + if (it != connection_to_client_host_ui_.end()) { DevToolsClientHostImpl* client_host = static_cast<DevToolsClientHostImpl*>(it->second); client_host->NotifyCloseListener(); delete client_host; - socket_to_client_host_ui_.erase(socket); + connection_to_client_host_ui_.erase(connection_id); } - - // We are holding last reference to scoped refptr 'socket' here. - // We can't exit method just like that since 'socket' is going to - // be destroyed on the UI thread then. Schedule no-op to IO thread - // so that socket is destroyed on IO instead. - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - NewRunnableMethod( - this, - &DevToolsHttpProtocolHandler::ReleaseSocket, - make_scoped_refptr(socket))); } void DevToolsHttpProtocolHandler::OnResponseStarted(net::URLRequest* request) { - RequestToSocketMap::iterator it = request_to_socket_io_.find(request); - if (it == request_to_socket_io_.end()) + RequestToSocketMap::iterator it = request_to_connection_io_.find(request); + if (it == request_to_connection_io_.end()) return; - HttpListenSocket* socket = it->second; + int connection_id = it->second; int expected_size = static_cast<int>(request->GetExpectedContentSize()); @@ -323,14 +328,14 @@ void DevToolsHttpProtocolHandler::OnResponseStarted(net::URLRequest* request) { request->GetMimeType(&content_type); if (request->status().is_success()) { - socket->Send(StringPrintf("HTTP/1.1 200 OK\r\n" - "Content-Type:%s\r\n" - "Content-Length:%d\r\n" - "\r\n", - content_type.c_str(), - expected_size)); + server_->Send(connection_id, StringPrintf("HTTP/1.1 200 OK\r\n" + "Content-Type:%s\r\n" + "Content-Length:%d\r\n" + "\r\n", + content_type.c_str(), + expected_size)); } else { - socket->Send404(); + server_->Send404(connection_id); } int bytes_read = 0; @@ -346,17 +351,17 @@ void DevToolsHttpProtocolHandler::OnResponseStarted(net::URLRequest* request) { void DevToolsHttpProtocolHandler::OnReadCompleted(net::URLRequest* request, int bytes_read) { - RequestToSocketMap::iterator it = request_to_socket_io_.find(request); - if (it == request_to_socket_io_.end()) + RequestToSocketMap::iterator it = request_to_connection_io_.find(request); + if (it == request_to_connection_io_.end()) return; - HttpListenSocket* socket = it->second; + int connection_id = it->second; net::IOBuffer* buffer = request_to_buffer_io_[request].get(); do { if (!request->status().is_success() || bytes_read <= 0) break; - socket->Send(buffer->data(), bytes_read); + server_->Send(connection_id, buffer->data(), bytes_read); } while (request->Read(buffer, kBufferSize, &bytes_read)); // See comments re: HEAD requests in OnResponseStarted(). @@ -370,14 +375,13 @@ DevToolsHttpProtocolHandler::DevToolsHttpProtocolHandler( TabContentsProvider* provider) : port_(port), overriden_frontend_url_(frontend_host), - server_(NULL), tab_contents_provider_(provider) { if (overriden_frontend_url_.empty()) overriden_frontend_url_ = "/devtools/devtools.html"; } void DevToolsHttpProtocolHandler::Init() { - server_ = HttpListenSocket::Listen("127.0.0.1", port_, this); + server_ = new HttpServer("127.0.0.1", port_, this); } // Run on I/O thread @@ -386,74 +390,75 @@ void DevToolsHttpProtocolHandler::Teardown() { } void DevToolsHttpProtocolHandler::Bind(net::URLRequest* request, - HttpListenSocket* socket) { - request_to_socket_io_[request] = socket; - SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket); - if (it == socket_to_requests_io_.end()) { - std::pair<HttpListenSocket*, std::set<net::URLRequest*> > value( - socket, + int connection_id) { + request_to_connection_io_[request] = connection_id; + ConnectionToRequestsMap::iterator it = + connection_to_requests_io_.find(connection_id); + if (it == connection_to_requests_io_.end()) { + std::pair<int, std::set<net::URLRequest*> > value( + connection_id, std::set<net::URLRequest*>()); - it = socket_to_requests_io_.insert(value).first; + it = connection_to_requests_io_.insert(value).first; } it->second.insert(request); request_to_buffer_io_[request] = new net::IOBuffer(kBufferSize); } void DevToolsHttpProtocolHandler::RequestCompleted(net::URLRequest* request) { - RequestToSocketMap::iterator it = request_to_socket_io_.find(request); - if (it == request_to_socket_io_.end()) + RequestToSocketMap::iterator it = request_to_connection_io_.find(request); + if (it == request_to_connection_io_.end()) return; - HttpListenSocket* socket = it->second; - request_to_socket_io_.erase(request); - SocketToRequestsMap::iterator it2 = socket_to_requests_io_.find(socket); + int connection_id = it->second; + request_to_connection_io_.erase(request); + ConnectionToRequestsMap::iterator it2 = + connection_to_requests_io_.find(connection_id); it2->second.erase(request); request_to_buffer_io_.erase(request); delete request; } -void DevToolsHttpProtocolHandler::Send200(HttpListenSocket* socket, +void DevToolsHttpProtocolHandler::Send200(int connection_id, const std::string& data, const std::string& mime_type) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(socket, - &HttpListenSocket::Send200, + NewRunnableMethod(server_.get(), + &HttpServer::Send200, + connection_id, data, mime_type)); } -void DevToolsHttpProtocolHandler::Send404(HttpListenSocket* socket) { +void DevToolsHttpProtocolHandler::Send404(int connection_id) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(socket, - &HttpListenSocket::Send404)); + NewRunnableMethod(server_.get(), + &HttpServer::Send404, + connection_id)); } -void DevToolsHttpProtocolHandler::Send500(HttpListenSocket* socket, +void DevToolsHttpProtocolHandler::Send500(int connection_id, const std::string& message) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(socket, - &HttpListenSocket::Send500, + NewRunnableMethod(server_.get(), + &HttpServer::Send500, + connection_id, message)); } void DevToolsHttpProtocolHandler::AcceptWebSocket( - HttpListenSocket* socket, + int connection_id, const HttpServerRequestInfo& request) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - NewRunnableMethod(socket, - &HttpListenSocket::AcceptWebSocket, + NewRunnableMethod(server_.get(), + &HttpServer::AcceptWebSocket, + connection_id, request)); } -void DevToolsHttpProtocolHandler::ReleaseSocket( - HttpListenSocket* socket) { - // This in fact is scoped ref ptr. It'll get nuked on exit. -} - TabContents* DevToolsHttpProtocolHandler::GetTabContents(int session_id) { InspectableTabs inspectable_tabs = tab_contents_provider_->GetInspectableTabs(); diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.h b/chrome/browser/debugger/devtools_http_protocol_handler.h index 1bb4726..bfa2de8 100644 --- a/chrome/browser/debugger/devtools_http_protocol_handler.h +++ b/chrome/browser/debugger/devtools_http_protocol_handler.h @@ -12,7 +12,7 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" -#include "net/server/http_listen_socket.h" +#include "net/server/http_server.h" #include "net/url_request/url_request.h" class DevToolsClientHost; @@ -21,7 +21,7 @@ class TabContents; class TabContentsWrapper; class DevToolsHttpProtocolHandler - : public HttpListenSocket::Delegate, + : public HttpServer::Delegate, public net::URLRequest::Delegate, public base::RefCountedThreadSafe<DevToolsHttpProtocolHandler> { public: @@ -54,22 +54,22 @@ class DevToolsHttpProtocolHandler virtual ~DevToolsHttpProtocolHandler(); void Start(); - // HttpListenSocket::Delegate implementation. - virtual void OnHttpRequest(HttpListenSocket* socket, + // HttpServer::Delegate implementation. + virtual void OnHttpRequest(int connection_id, const HttpServerRequestInfo& info); - virtual void OnWebSocketRequest(HttpListenSocket* socket, + virtual void OnWebSocketRequest(int connection_id, const HttpServerRequestInfo& info); - virtual void OnWebSocketMessage(HttpListenSocket* socket, + virtual void OnWebSocketMessage(int connection_id, const std::string& data); - virtual void OnClose(HttpListenSocket* socket); + virtual void OnClose(int connection_id); - virtual void OnHttpRequestUI(HttpListenSocket* socket, + virtual void OnHttpRequestUI(int connection_id, const HttpServerRequestInfo& info); - virtual void OnWebSocketRequestUI(HttpListenSocket* socket, + virtual void OnWebSocketRequestUI(int connection_id, const HttpServerRequestInfo& info); - virtual void OnWebSocketMessageUI(HttpListenSocket* socket, + virtual void OnWebSocketMessageUI(int connection_id, const std::string& data); - virtual void OnCloseUI(HttpListenSocket* socket); + virtual void OnCloseUI(int connection_id); // net::URLRequest::Delegate implementation. virtual void OnResponseStarted(net::URLRequest* request); @@ -77,36 +77,35 @@ class DevToolsHttpProtocolHandler void Init(); void Teardown(); - void Bind(net::URLRequest* request, HttpListenSocket* socket); + void Bind(net::URLRequest* request, int connection_id); void RequestCompleted(net::URLRequest* request); - void Send200(HttpListenSocket* socket, + void Send200(int connection_id, const std::string& data, const std::string& mime_type = "text/html"); - void Send404(HttpListenSocket* socket); - void Send500(HttpListenSocket* socket, + void Send404(int connection_id); + void Send500(int connection_id, const std::string& message); - void AcceptWebSocket(HttpListenSocket* socket, + void AcceptWebSocket(int connection_id, const HttpServerRequestInfo& request); - void ReleaseSocket(HttpListenSocket* socket); TabContents* GetTabContents(int session_id); int port_; std::string overriden_frontend_url_; - scoped_refptr<HttpListenSocket> server_; - typedef std::map<net::URLRequest*, HttpListenSocket*> + scoped_refptr<HttpServer> server_; + typedef std::map<net::URLRequest*, int> RequestToSocketMap; - RequestToSocketMap request_to_socket_io_; - typedef std::map<HttpListenSocket*, std::set<net::URLRequest*> > - SocketToRequestsMap; - SocketToRequestsMap socket_to_requests_io_; + RequestToSocketMap request_to_connection_io_; + typedef std::map<int, std::set<net::URLRequest*> > + ConnectionToRequestsMap; + ConnectionToRequestsMap connection_to_requests_io_; typedef std::map<net::URLRequest*, scoped_refptr<net::IOBuffer> > BuffersMap; BuffersMap request_to_buffer_io_; - typedef std::map<HttpListenSocket*, DevToolsClientHost*> - SocketToClientHostMap; - SocketToClientHostMap socket_to_client_host_ui_; + typedef std::map<int, DevToolsClientHost*> + ConnectionToClientHostMap; + ConnectionToClientHostMap connection_to_client_host_ui_; scoped_ptr<TabContentsProvider> tab_contents_provider_; DISALLOW_COPY_AND_ASSIGN(DevToolsHttpProtocolHandler); }; diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 63c9480..f1da091e 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -498,7 +498,7 @@ 'dependencies': [ 'chrome_resources', 'chrome_strings', - '../net/net.gyp:http_listen_socket', + '../net/net.gyp:http_server', 'theme_resources', '../skia/skia.gyp:skia', '../third_party/icu/icu.gyp:icui18n', diff --git a/net/base/listen_socket.cc b/net/base/listen_socket.cc index 274837a..6ca8dcc 100644 --- a/net/base/listen_socket.cc +++ b/net/base/listen_socket.cc @@ -107,6 +107,11 @@ ListenSocket::~ListenSocket() { SOCKET ListenSocket::Listen(std::string ip, int port) { SOCKET s = socket(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; diff --git a/net/net.gyp b/net/net.gyp index c242f27..bda8cb4 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1292,7 +1292,7 @@ ], }, { - 'target_name': 'http_listen_socket', + 'target_name': 'http_server', 'type': '<(library)', 'dependencies': [ 'net', @@ -1301,8 +1301,8 @@ ], 'msvs_guid': 'FCB894A4-CC6C-48C2-B495-52C80527E9BE', 'sources': [ - 'server/http_listen_socket.cc', - 'server/http_listen_socket.h', + 'server/http_server.cc', + 'server/http_server.h', 'server/http_server_request_info.cc', 'server/http_server_request_info.h', ], diff --git a/net/server/http_listen_socket.h b/net/server/http_listen_socket.h deleted file mode 100644 index 8b0bbc2..0000000 --- a/net/server/http_listen_socket.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2010 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_SERVER_HTTP_LISTEN_SOCKET_H_ -#define NET_SERVER_HTTP_LISTEN_SOCKET_H_ -#pragma once - -#include "net/base/listen_socket.h" - -class HttpServerRequestInfo; - -// Implements a simple HTTP listen socket on top of the raw socket interface. -class HttpListenSocket : public ListenSocket, - public ListenSocket::ListenSocketDelegate { - public: - class Delegate { - public: - virtual void OnHttpRequest(HttpListenSocket* socket, - const HttpServerRequestInfo& info) = 0; - - virtual void OnWebSocketRequest(HttpListenSocket* socket, - const HttpServerRequestInfo& info) = 0; - - virtual void OnWebSocketMessage(HttpListenSocket* socket, - const std::string& data) = 0; - - virtual void OnClose(HttpListenSocket* socket) = 0; - protected: - virtual ~Delegate() {} - }; - - virtual void Accept(); - - static HttpListenSocket* Listen(const std::string& ip, - int port, - HttpListenSocket::Delegate* delegate); - - void AcceptWebSocket(const HttpServerRequestInfo& request); - - void SendOverWebSocket(const std::string& data); - - void Send200(const std::string& data, const std::string& mime_type); - void Send404(); - void Send500(const std::string& message); - - virtual void Close(); - virtual void Listen(); - - // ListenSocketDelegate - virtual void DidAccept(ListenSocket* server, ListenSocket* connection); - virtual void DidRead(ListenSocket* connection, const char* data, int len); - virtual void DidClose(ListenSocket* sock); - - private: - static const int kReadBufSize = 16 * 1024; - HttpListenSocket(SOCKET s, HttpListenSocket::Delegate* del); - virtual ~HttpListenSocket(); - - // Expects the raw data to be stored in recv_data_. If parsing is successful, - // will remove the data parsed from recv_data_, leaving only the unused - // recv data. - bool ParseHeaders(HttpServerRequestInfo* info); - - HttpListenSocket::Delegate* delegate_; - bool is_web_socket_; - std::string recv_data_; - - DISALLOW_COPY_AND_ASSIGN(HttpListenSocket); -}; - -#endif // NET_SERVER_HTTP_LISTEN_SOCKET_H_ diff --git a/net/server/http_listen_socket.cc b/net/server/http_server.cc index a946bd9..87b50fa 100644 --- a/net/server/http_listen_socket.cc +++ b/net/server/http_server.cc @@ -2,64 +2,37 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <map> + #ifdef _WIN32 #include <winsock2.h> #else #include <arpa/inet.h> #endif -#include <map> - #include "base/compiler_specific.h" #include "base/logging.h" #include "base/md5.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/stringprintf.h" -#include "net/server/http_listen_socket.h" +#include "net/server/http_server.h" #include "net/server/http_server_request_info.h" -// must run in the IO thread -HttpListenSocket::HttpListenSocket(SOCKET s, - HttpListenSocket::Delegate* delegate) - : ALLOW_THIS_IN_INITIALIZER_LIST(ListenSocket(s, this)), - delegate_(delegate), - is_web_socket_(false) { +int HttpServer::Connection::lastId_ = 0; +HttpServer::HttpServer(const std::string& host, + int port, + HttpServer::Delegate* del) + : delegate_(del) { + server_ = ListenSocket::Listen(host, port, this); } -// must run in the IO thread -HttpListenSocket::~HttpListenSocket() { -} +HttpServer::~HttpServer() { + IdToConnectionMap copy = id_to_connection_; + for (IdToConnectionMap::iterator it = copy.begin(); it != copy.end(); ++it) + delete it->second; -void HttpListenSocket::Accept() { - SOCKET conn = ListenSocket::Accept(socket_); - DCHECK_NE(conn, ListenSocket::kInvalidSocket); - if (conn == ListenSocket::kInvalidSocket) { - // TODO - } else { - scoped_refptr<HttpListenSocket> sock( - new HttpListenSocket(conn, delegate_)); -#if defined(OS_POSIX) - sock->WatchSocket(WAITING_READ); -#endif - // it's up to the delegate to AddRef if it wants to keep it around - DidAccept(this, sock); - } -} - -HttpListenSocket* HttpListenSocket::Listen( - const std::string& ip, - int port, - HttpListenSocket::Delegate* delegate) { - SOCKET s = ListenSocket::Listen(ip, port); - if (s == ListenSocket::kInvalidSocket) { - // TODO (ibrar): error handling - } else { - HttpListenSocket *serv = new HttpListenSocket(s, delegate); - serv->Listen(); - return serv; - } - return NULL; + server_ = NULL; } std::string GetHeaderValue( @@ -91,7 +64,13 @@ uint32 WebSocketKeyFingerprint(const std::string& str) { return htonl(static_cast<uint32>(number / spaces)); } -void HttpListenSocket::AcceptWebSocket(const HttpServerRequestInfo& request) { +void HttpServer::AcceptWebSocket( + int connection_id, + const HttpServerRequestInfo& request) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); @@ -109,52 +88,113 @@ void HttpListenSocket::AcceptWebSocket(const HttpServerRequestInfo& request) { std::string origin = GetHeaderValue(request, "Origin"); std::string host = GetHeaderValue(request, "Host"); std::string location = "ws://" + host + request.path; - is_web_socket_ = true; - Send(base::StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Origin: %s\r\n" - "Sec-WebSocket-Location: %s\r\n" - "\r\n", - origin.c_str(), - location.c_str())); - Send(reinterpret_cast<char*>(digest.a), 16); + connection->is_web_socket_ = true; + connection->socket_->Send(base::StringPrintf( + "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" + "Upgrade: WebSocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Origin: %s\r\n" + "Sec-WebSocket-Location: %s\r\n" + "\r\n", + origin.c_str(), + location.c_str())); + connection->socket_->Send(reinterpret_cast<char*>(digest.a), 16); } -void HttpListenSocket::SendOverWebSocket(const std::string& data) { - DCHECK(is_web_socket_); +void HttpServer::SendOverWebSocket(int connection_id, + const std::string& data) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + DCHECK(connection->is_web_socket_); char message_start = 0; char message_end = -1; - Send(&message_start, 1); - Send(data); - Send(&message_end, 1); + connection->socket_->Send(&message_start, 1); + connection->socket_->Send(data); + connection->socket_->Send(&message_end, 1); +} + +void HttpServer::Send(int connection_id, const std::string& data) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + connection->socket_->Send(data); +} + +void HttpServer::Send(int connection_id, const char* bytes, int len) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + connection->socket_->Send(bytes, len); } -void HttpListenSocket::Send200(const std::string& data, - const std::string& content_type) { - Send(base::StringPrintf("HTTP/1.1 200 OK\r\n" - "Content-Type:%s\r\n" - "Content-Length:%d\r\n" - "\r\n", - content_type.c_str(), - static_cast<int>(data.length()))); - Send(data); +void HttpServer::Send200(int connection_id, + const std::string& data, + const std::string& content_type) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + connection->socket_->Send(base::StringPrintf( + "HTTP/1.1 200 OK\r\n" + "Content-Type:%s\r\n" + "Content-Length:%d\r\n" + "\r\n", + content_type.c_str(), + static_cast<int>(data.length()))); + connection->socket_->Send(data); } -void HttpListenSocket::Send404() { - Send("HTTP/1.1 404 Not Found\r\n" - "Content-Length: 0\r\n" - "\r\n"); +void HttpServer::Send404(int connection_id) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + connection->socket_->Send( + "HTTP/1.1 404 Not Found\r\n" + "Content-Length: 0\r\n" + "\r\n"); +} + +void HttpServer::Send500(int connection_id, const std::string& message) { + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + connection->socket_->Send(base::StringPrintf( + "HTTP/1.1 500 Internal Error\r\n" + "Content-Type:text/html\r\n" + "Content-Length:%d\r\n" + "\r\n" + "%s", + static_cast<int>(message.length()), + message.c_str())); +} + +void HttpServer::Close(int connection_id) +{ + Connection* connection = FindConnection(connection_id); + if (connection == NULL) + return; + + connection->DetachSocket(); } -void HttpListenSocket::Send500(const std::string& message) { - Send(base::StringPrintf("HTTP/1.1 500 Internal Error\r\n" - "Content-Type:text/html\r\n" - "Content-Length:%d\r\n" - "\r\n" - "%s", - static_cast<int>(message.length()), - message.c_str())); +HttpServer::Connection::Connection(ListenSocket* sock) + : socket_(sock), + is_web_socket_(false) { + id_ = lastId_++; +} + +HttpServer::Connection::~Connection() { + DetachSocket(); +} + +void HttpServer::Connection::DetachSocket() { + socket_ = NULL; } // @@ -231,15 +271,16 @@ int charToInput(char ch) { return INPUT_DEFAULT; } -bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) { +bool HttpServer::ParseHeaders(Connection* connection, + HttpServerRequestInfo* info) { int pos = 0; - int data_len = recv_data_.length(); - int state = is_web_socket_ ? ST_WS_READY : ST_METHOD; + int data_len = connection->recv_data_.length(); + int state = connection->is_web_socket_ ? ST_WS_READY : ST_METHOD; std::string buffer; std::string header_name; std::string header_value; while (pos < data_len) { - char ch = recv_data_[pos++]; + char ch = connection->recv_data_[pos++]; int input = charToInput(ch); int next_state = parser_state[state][input]; @@ -275,7 +316,7 @@ bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) { buffer.append(&ch, 1); break; case ST_WS_FRAME: - recv_data_ = recv_data_.substr(pos); + connection->recv_data_ = connection->recv_data_.substr(pos); info->data = buffer; buffer.clear(); return true; @@ -294,12 +335,12 @@ bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) { buffer.append(&ch, 1); break; case ST_DONE: - recv_data_ = recv_data_.substr(pos); - info->data = recv_data_; - recv_data_.clear(); + connection->recv_data_ = connection->recv_data_.substr(pos); + info->data = connection->recv_data_; + connection->recv_data_.clear(); return true; case ST_WS_CLOSE: - is_web_socket_ = false; + connection->is_web_socket_ = false; return false; case ST_ERR: return false; @@ -310,48 +351,66 @@ bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) { return false; } -void HttpListenSocket::Close() { - ListenSocket::Close(); +void HttpServer::DidAccept(ListenSocket* server, + ListenSocket* socket) { + Connection* connection = new Connection(socket); + id_to_connection_[connection->id_] = connection; + socket_to_connection_[socket] = connection; } -void HttpListenSocket::Listen() { - ListenSocket::Listen(); -} +void HttpServer::DidRead(ListenSocket* socket, + const char* data, + int len) { + Connection* connection = FindConnection(socket); + DCHECK(connection != NULL); + if (connection == NULL) + return; -void HttpListenSocket::DidAccept(ListenSocket* server, - ListenSocket* connection) { - connection->AddRef(); -} - -void HttpListenSocket::DidRead(ListenSocket*, - const char* data, - int len) { - recv_data_.append(data, len); - while (recv_data_.length()) { + connection->recv_data_.append(data, len); + while (connection->recv_data_.length()) { HttpServerRequestInfo request; - if (!ParseHeaders(&request)) + if (!ParseHeaders(connection, &request)) break; - if (is_web_socket_) { - delegate_->OnWebSocketMessage(this, request.data); + if (connection->is_web_socket_) { + delegate_->OnWebSocketMessage(connection->id_, request.data); continue; } - std::string connection = GetHeaderValue(request, "Connection"); - if (connection == "Upgrade") { + std::string connection_header = GetHeaderValue(request, "Connection"); + if (connection_header == "Upgrade") { // Is this WebSocket and if yes, upgrade the connection. std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); if (!key1.empty() && !key2.empty()) { - delegate_->OnWebSocketRequest(this, request); + delegate_->OnWebSocketRequest(connection->id_, request); continue; } } - delegate_->OnHttpRequest(this, request); + delegate_->OnHttpRequest(connection->id_, request); } + +} + +void HttpServer::DidClose(ListenSocket* socket) { + Connection* connection = FindConnection(socket); + DCHECK(connection != NULL); + delegate_->OnClose(connection->id_); + id_to_connection_.erase(connection->id_); + socket_to_connection_.erase(connection->socket_); + delete connection; +} + +HttpServer::Connection* HttpServer::FindConnection(int connection_id) { + IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); + if (it == id_to_connection_.end()) + return NULL; + return it->second; } -void HttpListenSocket::DidClose(ListenSocket* sock) { - delegate_->OnClose(this); - sock->Release(); +HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) { + SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); + if (it == socket_to_connection_.end()) + return NULL; + return it->second; } diff --git a/net/server/http_server.h b/net/server/http_server.h new file mode 100644 index 0000000..fc87cdb --- /dev/null +++ b/net/server/http_server.h @@ -0,0 +1,96 @@ +// Copyright (c) 2010 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_SERVER_HTTP_SERVER_H_ +#define NET_SERVER_HTTP_SERVER_H_ +#pragma once + +#include <list> +#include <map> + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "net/base/listen_socket.h" + +class HttpServerRequestInfo; + +class HttpServer : public ListenSocket::ListenSocketDelegate, + public base::RefCountedThreadSafe<HttpServer> { + public: + class Delegate { + public: + virtual void OnHttpRequest(int connection_id, + const HttpServerRequestInfo& info) = 0; + + virtual void OnWebSocketRequest(int connection_id, + const HttpServerRequestInfo& info) = 0; + + virtual void OnWebSocketMessage(int connection_id, + const std::string& data) = 0; + + virtual void OnClose(int connection_id) = 0; + protected: + virtual ~Delegate() {} + }; + + HttpServer(const std::string& host, int port, HttpServer::Delegate* del); + virtual ~HttpServer(); + + void AcceptWebSocket(int connection_id, + const HttpServerRequestInfo& request); + void SendOverWebSocket(int connection_id, const std::string& data); + void Send(int connection_id, const std::string& data); + void Send(int connection_id, const char* bytes, int len); + void Send200(int connection_id, + const std::string& data, + const std::string& mime_type); + void Send404(int connection_id); + void Send500(int connection_id, const std::string& message); + void Close(int connection_id); + +private: + friend class base::RefCountedThreadSafe<HttpServer>; + class Connection { + private: + static int lastId_; + friend class HttpServer; + + explicit Connection(ListenSocket* sock); + ~Connection(); + + void DetachSocket(); + + scoped_refptr<ListenSocket> socket_; + bool is_web_socket_; + std::string recv_data_; + int id_; + + DISALLOW_COPY_AND_ASSIGN(Connection); + }; + + + // ListenSocketDelegate + virtual void DidAccept(ListenSocket* server, ListenSocket* socket); + virtual void DidRead(ListenSocket* socket, const char* data, int len); + virtual void DidClose(ListenSocket* socket); + + // Expects the raw data to be stored in recv_data_. If parsing is successful, + // will remove the data parsed from recv_data_, leaving only the unused + // recv data. + bool ParseHeaders(Connection* connection, HttpServerRequestInfo* info); + + Connection* FindConnection(int connection_id); + Connection* FindConnection(ListenSocket* socket); + + HttpServer::Delegate* delegate_; + scoped_refptr<ListenSocket> server_; + typedef std::map<int, Connection*> IdToConnectionMap; + IdToConnectionMap id_to_connection_; + typedef std::map<ListenSocket*, Connection*> SocketToConnectionMap; + SocketToConnectionMap socket_to_connection_; + + DISALLOW_COPY_AND_ASSIGN(HttpServer); +}; + +#endif // NET_SERVER_HTTP_SERVER_H_ |