summaryrefslogtreecommitdiffstats
path: root/net/server/http_server.cc
diff options
context:
space:
mode:
authorpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-02 19:49:25 +0000
committerpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-02 19:49:25 +0000
commit86c6a0b5a5c08aa5ed1244e4a4fc2796393ad5a5 (patch)
tree14d8273e6669c54599466a7708b437cd51facb03 /net/server/http_server.cc
parent33a4aca7c65ed0bb2636615ef5e5c83cf50ff6a0 (diff)
downloadchromium_src-86c6a0b5a5c08aa5ed1244e4a4fc2796393ad5a5.zip
chromium_src-86c6a0b5a5c08aa5ed1244e4a4fc2796393ad5a5.tar.gz
chromium_src-86c6a0b5a5c08aa5ed1244e4a4fc2796393ad5a5.tar.bz2
DevTools: no way to remote debug using ToT build as a client.
(rebaselined and brushed up loislo's http://codereview.chromium.org/7482041) BUG=90743 TEST= Review URL: http://codereview.chromium.org/7540023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95138 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/server/http_server.cc')
-rw-r--r--net/server/http_server.cc285
1 files changed, 79 insertions, 206 deletions
diff --git a/net/server/http_server.cc b/net/server/http_server.cc
index 061731a..42d5752 100644
--- a/net/server/http_server.cc
+++ b/net/server/http_server.cc
@@ -6,12 +6,12 @@
#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 "build/build_config.h"
+#include "net/server/http_connection.h"
#include "net/server/http_server_request_info.h"
+#include "net/server/web_socket.h"
#if defined(OS_WIN)
#include <winsock2.h>
@@ -21,8 +21,6 @@
namespace net {
-int HttpServer::Connection::lastId_ = 0;
-
HttpServer::HttpServer(const std::string& host,
int port,
HttpServer::Delegate* del)
@@ -38,174 +36,53 @@ HttpServer::~HttpServer() {
server_ = NULL;
}
-std::string GetHeaderValue(
- const HttpServerRequestInfo& request,
- const std::string& header_name) {
- HttpServerRequestInfo::HeadersMap::iterator it =
- request.headers.find(header_name);
- if (it != request.headers.end())
- return it->second;
- return "";
-}
-
-uint32 WebSocketKeyFingerprint(const std::string& str) {
- std::string result;
- const char* pChar = str.c_str();
- int length = str.length();
- int spaces = 0;
- for (int i = 0; i < length; ++i) {
- if (pChar[i] >= '0' && pChar[i] <= '9')
- result.append(&pChar[i], 1);
- else if (pChar[i] == ' ')
- spaces++;
- }
- if (spaces == 0)
- return 0;
- int64 number = 0;
- if (!base::StringToInt64(result, &number))
- return 0;
- return htonl(static_cast<uint32>(number / spaces));
-}
-
-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");
-
- uint32 fp1 = WebSocketKeyFingerprint(key1);
- uint32 fp2 = WebSocketKeyFingerprint(key2);
-
- char data[16];
- memcpy(data, &fp1, 4);
- memcpy(data + 4, &fp2, 4);
- memcpy(data + 8, &request.data[0], 8);
-
- base::MD5Digest digest;
- base::MD5Sum(data, 16, &digest);
-
- std::string origin = GetHeaderValue(request, "Origin");
- std::string host = GetHeaderValue(request, "Host");
- std::string location = "ws://" + host + request.path;
- 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 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;
- 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);
+ HttpConnection* connection = FindConnection(connection_id);
if (connection == NULL)
return;
-
- connection->socket_->Send(data);
+ connection->Send(data);
}
void HttpServer::Send(int connection_id, const char* bytes, int len) {
- Connection* connection = FindConnection(connection_id);
+ HttpConnection* connection = FindConnection(connection_id);
if (connection == NULL)
return;
- connection->socket_->Send(bytes, len);
+ connection->Send(bytes, len);
}
void HttpServer::Send200(int connection_id,
const std::string& data,
const std::string& content_type) {
- Connection* connection = FindConnection(connection_id);
+ HttpConnection* 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);
+ connection->Send200(data, content_type);
}
void HttpServer::Send404(int connection_id) {
- Connection* connection = FindConnection(connection_id);
+ HttpConnection* 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");
+ connection->Send404();
}
void HttpServer::Send500(int connection_id, const std::string& message) {
- Connection* connection = FindConnection(connection_id);
+ HttpConnection* 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()));
+ connection->Send500(message);
}
void HttpServer::Close(int connection_id)
{
- Connection* connection = FindConnection(connection_id);
+ HttpConnection* connection = FindConnection(connection_id);
if (connection == NULL)
return;
connection->DetachSocket();
}
-HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock)
- : server_(server),
- socket_(sock),
- is_web_socket_(false) {
- id_ = lastId_++;
-}
-
-HttpServer::Connection::~Connection() {
- DetachSocket();
- server_->delegate_->OnClose(id_);
-}
-
-void HttpServer::Connection::DetachSocket() {
- socket_ = NULL;
-}
-
-void HttpServer::Connection::Shift(int num_bytes) {
- recv_data_ = recv_data_.substr(num_bytes);
-}
-
//
// HTTP Request Parser
// This HTTP request parser uses a simple state machine to quickly parse
@@ -222,8 +99,6 @@ enum header_parse_inputs {
INPUT_CR,
INPUT_LF,
INPUT_COLON,
- INPUT_00,
- INPUT_FF,
INPUT_DEFAULT,
MAX_INPUTS,
};
@@ -237,9 +112,6 @@ enum header_parse_states {
ST_NAME, // Receiving a request header name
ST_SEPARATOR, // Receiving the separator between header name and value
ST_VALUE, // Receiving a request header value
- ST_WS_READY, // Ready to receive web socket frame
- ST_WS_FRAME, // Receiving WebSocket frame
- ST_WS_CLOSE, // Closing the connection WebSocket connection
ST_DONE, // Parsing is complete and successful
ST_ERR, // Parsing encountered invalid syntax.
MAX_STATES
@@ -247,18 +119,15 @@ enum header_parse_states {
// State transition table
int parser_state[MAX_STATES][MAX_INPUTS] = {
-/* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
-/* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_ERR, ST_ERR, ST_URL },
-/* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_ERR, ST_ERR, ST_PROTO },
-/* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR, ST_ERR, ST_ERR },
-/* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_ERR, ST_ERR, ST_NAME },
-/* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE },
-/* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_ERR, ST_ERR, ST_VALUE },
-/* WS_READY */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_WS_FRAME, ST_WS_CLOSE, ST_ERR},
-/* WS_FRAME */ { ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME, ST_ERR, ST_WS_READY, ST_WS_FRAME },
-/* WS_CLOSE */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_WS_CLOSE, ST_ERR, ST_ERR },
-/* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
-/* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
+/* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
+/* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL },
+/* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO },
+/* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR },
+/* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_NAME },
+/* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_VALUE },
+/* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE },
+/* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
+/* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
};
// Convert an input character to the parser's input token.
@@ -272,20 +141,16 @@ int charToInput(char ch) {
return INPUT_LF;
case ':':
return INPUT_COLON;
- case 0x0:
- return INPUT_00;
- case static_cast<char>(-1):
- return INPUT_FF;
}
return INPUT_DEFAULT;
}
-bool HttpServer::ParseHeaders(Connection* connection,
+bool HttpServer::ParseHeaders(HttpConnection* connection,
HttpServerRequestInfo* info,
- int* ppos) {
- int& pos = *ppos;
- int data_len = connection->recv_data_.length();
- int state = connection->is_web_socket_ ? ST_WS_READY : ST_METHOD;
+ size_t* ppos) {
+ size_t& pos = *ppos;
+ size_t data_len = connection->recv_data_.length();
+ int state = ST_METHOD;
std::string buffer;
std::string header_name;
std::string header_value;
@@ -325,11 +190,6 @@ bool HttpServer::ParseHeaders(Connection* connection,
case ST_SEPARATOR:
buffer.append(&ch, 1);
break;
- case ST_WS_FRAME:
- info->data = buffer;
- buffer.clear();
- return true;
- break;
}
state = next_state;
} else {
@@ -340,15 +200,11 @@ bool HttpServer::ParseHeaders(Connection* connection,
case ST_PROTO:
case ST_VALUE:
case ST_NAME:
- case ST_WS_FRAME:
buffer.append(&ch, 1);
break;
case ST_DONE:
DCHECK(input == INPUT_LF);
return true;
- case ST_WS_CLOSE:
- connection->is_web_socket_ = false;
- return false;
case ST_ERR:
return false;
}
@@ -360,81 +216,98 @@ bool HttpServer::ParseHeaders(Connection* connection,
void HttpServer::DidAccept(ListenSocket* server,
ListenSocket* socket) {
- Connection* connection = new Connection(this, socket);
- id_to_connection_[connection->id_] = connection;
+ HttpConnection* connection = new HttpConnection(this, socket);
+ id_to_connection_[connection->id()] = connection;
socket_to_connection_[socket] = connection;
}
void HttpServer::DidRead(ListenSocket* socket,
const char* data,
int len) {
- Connection* connection = FindConnection(socket);
+ HttpConnection* connection = FindConnection(socket);
DCHECK(connection != NULL);
if (connection == NULL)
return;
connection->recv_data_.append(data, len);
while (connection->recv_data_.length()) {
- int pos = 0;
- HttpServerRequestInfo request;
- if (!ParseHeaders(connection, &request, &pos))
- break;
+ if (connection->web_socket_.get()) {
+ std::string message;
+ WebSocket::ParseResult result = connection->web_socket_->Read(&message);
+ if (result == WebSocket::FRAME_INCOMPLETE)
+ break;
- if (connection->is_web_socket_) {
- delegate_->OnWebSocketMessage(connection->id_, request.data);
- connection->Shift(pos);
+ if (result == WebSocket::FRAME_ERROR) {
+ Close(connection->id());
+ break;
+ }
+ delegate_->OnWebSocketMessage(connection->id(), message);
continue;
}
- std::string connection_header = GetHeaderValue(request, "Connection");
+ HttpServerRequestInfo request;
+ size_t pos = 0;
+ if (!ParseHeaders(connection, &request, &pos))
+ break;
+
+ std::string connection_header = request.GetHeaderValue("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");
-
- const int websocket_handshake_body_len = 8;
- if (pos + websocket_handshake_body_len >
- static_cast<int>(connection->recv_data_.length())) {
- // We haven't received websocket handshake body yet. Wait.
- break;
- }
+ connection->web_socket_.reset(WebSocket::CreateWebSocket(connection,
+ request,
+ &pos));
- if (!key1.empty() && !key2.empty()) {
- request.data = connection->recv_data_.substr(
- pos,
- pos + websocket_handshake_body_len);
- pos += websocket_handshake_body_len;
- delegate_->OnWebSocketRequest(connection->id_, request);
- connection->Shift(pos);
- continue;
- }
+ if (!connection->web_socket_.get()) // Not enought data was received.
+ break;
+ delegate_->OnWebSocketRequest(connection->id(), request);
+ connection->Shift(pos);
+ continue;
}
// Request body is not supported. It is always empty.
- delegate_->OnHttpRequest(connection->id_, request);
+ delegate_->OnHttpRequest(connection->id(), request);
connection->Shift(pos);
}
}
void HttpServer::DidClose(ListenSocket* socket) {
- Connection* connection = FindConnection(socket);
+ HttpConnection* connection = FindConnection(socket);
DCHECK(connection != NULL);
- id_to_connection_.erase(connection->id_);
+ id_to_connection_.erase(connection->id());
socket_to_connection_.erase(connection->socket_);
delete connection;
}
-HttpServer::Connection* HttpServer::FindConnection(int connection_id) {
+HttpConnection* 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;
}
-HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) {
+HttpConnection* HttpServer::FindConnection(ListenSocket* socket) {
SocketToConnectionMap::iterator it = socket_to_connection_.find(socket);
if (it == socket_to_connection_.end())
return NULL;
return it->second;
}
+void HttpServer::AcceptWebSocket(
+ int connection_id,
+ const HttpServerRequestInfo& request) {
+ HttpConnection* connection = FindConnection(connection_id);
+ if (connection == NULL)
+ return;
+
+ DCHECK(connection->web_socket_.get());
+ connection->web_socket_->Accept(request);
+}
+
+void HttpServer::SendOverWebSocket(int connection_id,
+ const std::string& data) {
+ HttpConnection* connection = FindConnection(connection_id);
+ if (connection == NULL)
+ return;
+ DCHECK(connection->web_socket_.get());
+ connection->web_socket_->Send(data);
+}
+
} // namespace net