| Index: net/server/http_server.cc
|
| diff --git a/net/server/http_server.cc b/net/server/http_server.cc
|
| index 061731a9d2b1b5ae7260d68ed1df49783645eab6..b2601ecd6695df245de4baebfa724cc2e2a31adf 100644
|
| --- a/net/server/http_server.cc
|
| +++ b/net/server/http_server.cc
|
| @@ -6,12 +6,11 @@
|
|
|
| #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_server_request_info.h"
|
| +#include "net/server/web_socket.h"
|
|
|
| #if defined(OS_WIN)
|
| #include <winsock2.h>
|
| @@ -21,7 +20,7 @@
|
|
|
| namespace net {
|
|
|
| -int HttpServer::Connection::lastId_ = 0;
|
| +int Connection::lastId_ = 0;
|
|
|
| HttpServer::HttpServer(const std::string& host,
|
| int port,
|
| @@ -38,7 +37,7 @@ HttpServer::~HttpServer() {
|
| server_ = NULL;
|
| }
|
|
|
| -std::string GetHeaderValue(
|
| +static std::string GetHeaderValue(
|
| const HttpServerRequestInfo& request,
|
| const std::string& header_name) {
|
| HttpServerRequestInfo::HeadersMap::iterator it =
|
| @@ -48,90 +47,31 @@ std::string GetHeaderValue(
|
| 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) {
|
| +void HttpServer::Send(int connection_id, const std::string& data) {
|
| 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);
|
| + connection->Send(data);
|
| }
|
|
|
| -void HttpServer::SendOverWebSocket(int connection_id,
|
| - const std::string& data) {
|
| - Connection* connection = FindConnection(connection_id);
|
| - if (connection == NULL)
|
| +void Connection::Send(const std::string& data) {
|
| + if (!socket_)
|
| 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);
|
| + socket_->Send(data);
|
| }
|
|
|
| -void HttpServer::Send(int connection_id, const std::string& data) {
|
| +void HttpServer::Send(int connection_id, const char* bytes, int len) {
|
| Connection* connection = FindConnection(connection_id);
|
| if (connection == NULL)
|
| return;
|
|
|
| - connection->socket_->Send(data);
|
| + connection->Send(bytes, len);
|
| }
|
|
|
| -void HttpServer::Send(int connection_id, const char* bytes, int len) {
|
| - Connection* connection = FindConnection(connection_id);
|
| - if (connection == NULL)
|
| +void Connection::Send(const char* bytes, int len) {
|
| + if (!socket_)
|
| return;
|
| -
|
| - connection->socket_->Send(bytes, len);
|
| + socket_->Send(bytes, len);
|
| }
|
|
|
| void HttpServer::Send200(int connection_id,
|
| @@ -140,23 +80,34 @@ void HttpServer::Send200(int connection_id,
|
| Connection* connection = FindConnection(connection_id);
|
| if (connection == NULL)
|
| return;
|
| + connection->Send200(data, content_type);
|
| +}
|
|
|
| - connection->socket_->Send(base::StringPrintf(
|
| +void Connection::Send200(const std::string& data,
|
| + const std::string& content_type) {
|
| + if (!socket_)
|
| + return;
|
| + 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);
|
| + socket_->Send(data);
|
| }
|
|
|
| void HttpServer::Send404(int connection_id) {
|
| Connection* connection = FindConnection(connection_id);
|
| if (connection == NULL)
|
| return;
|
| + connection->Send404();
|
| +}
|
|
|
| - connection->socket_->Send(
|
| +void Connection::Send404() {
|
| + if (!socket_)
|
| + return;
|
| + socket_->Send(
|
| "HTTP/1.1 404 Not Found\r\n"
|
| "Content-Length: 0\r\n"
|
| "\r\n");
|
| @@ -166,8 +117,13 @@ void HttpServer::Send500(int connection_id, const std::string& message) {
|
| Connection* connection = FindConnection(connection_id);
|
| if (connection == NULL)
|
| return;
|
| + connection->Send500(message);
|
| +}
|
|
|
| - connection->socket_->Send(base::StringPrintf(
|
| +void Connection::Send500(const std::string& message) {
|
| + if (!socket_)
|
| + return;
|
| + socket_->Send(base::StringPrintf(
|
| "HTTP/1.1 500 Internal Error\r\n"
|
| "Content-Type:text/html\r\n"
|
| "Content-Length:%d\r\n"
|
| @@ -186,23 +142,22 @@ void HttpServer::Close(int connection_id)
|
| connection->DetachSocket();
|
| }
|
|
|
| -HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock)
|
| +Connection::Connection(HttpServer* server, ListenSocket* sock)
|
| : server_(server),
|
| - socket_(sock),
|
| - is_web_socket_(false) {
|
| + socket_(sock) {
|
| id_ = lastId_++;
|
| }
|
|
|
| -HttpServer::Connection::~Connection() {
|
| +Connection::~Connection() {
|
| DetachSocket();
|
| server_->delegate_->OnClose(id_);
|
| }
|
|
|
| -void HttpServer::Connection::DetachSocket() {
|
| +void Connection::DetachSocket() {
|
| socket_ = NULL;
|
| }
|
|
|
| -void HttpServer::Connection::Shift(int num_bytes) {
|
| +void Connection::Shift(int num_bytes) {
|
| recv_data_ = recv_data_.substr(num_bytes);
|
| }
|
|
|
| @@ -222,8 +177,6 @@ enum header_parse_inputs {
|
| INPUT_CR,
|
| INPUT_LF,
|
| INPUT_COLON,
|
| - INPUT_00,
|
| - INPUT_FF,
|
| INPUT_DEFAULT,
|
| MAX_INPUTS,
|
| };
|
| @@ -237,9 +190,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 +197,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 +219,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,
|
| 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 +268,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 +278,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;
|
| }
|
| @@ -361,7 +295,7 @@ bool HttpServer::ParseHeaders(Connection* connection,
|
| void HttpServer::DidAccept(ListenSocket* server,
|
| ListenSocket* socket) {
|
| Connection* connection = new Connection(this, socket);
|
| - id_to_connection_[connection->id_] = connection;
|
| + id_to_connection_[connection->Id()] = connection;
|
| socket_to_connection_[socket] = connection;
|
| }
|
|
|
| @@ -375,42 +309,37 @@ void HttpServer::DidRead(ListenSocket* socket,
|
|
|
| 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::FrameIncomplete)
|
| + break;
|
|
|
| - if (connection->is_web_socket_) {
|
| - delegate_->OnWebSocketMessage(connection->id_, request.data);
|
| - connection->Shift(pos);
|
| + if (result == WebSocket::FrameError) {
|
| + Close(connection->Id());
|
| + break;
|
| + }
|
| + delegate_->OnWebSocketMessage(connection->Id(), message);
|
| continue;
|
| }
|
|
|
| + HttpServerRequestInfo request;
|
| + size_t pos = 0;
|
| + if (!ParseHeaders(connection, &request, &pos))
|
| + break;
|
| +
|
| 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");
|
| -
|
| - 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.
|
| + connection->web_socket_.reset(WebSocket::createWebSocket(
|
| + connection, request, &pos));
|
| + if (!connection->web_socket_.get()) // Not enought data was received.
|
| break;
|
| - }
|
| -
|
| - 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;
|
| - }
|
| + 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);
|
| }
|
| }
|
| @@ -418,23 +347,43 @@ void HttpServer::DidRead(ListenSocket* socket,
|
| void HttpServer::DidClose(ListenSocket* socket) {
|
| Connection* 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) {
|
| +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;
|
| }
|
|
|
| -HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) {
|
| +Connection* 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) {
|
| + Connection* 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) {
|
| + Connection* connection = FindConnection(connection_id);
|
| + if (connection == NULL)
|
| + return;
|
| + DCHECK(connection->web_socket_.get());
|
| + connection->web_socket_->Send(data);
|
| +}
|
| +
|
| } // namespace net
|
|
|