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 /net/server | |
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
Diffstat (limited to 'net/server')
-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 |
3 files changed, 267 insertions, 184 deletions
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_ |