Home | History | Annotate | Download | only in server
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/server/http_server.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/logging.h"
      9 #include "base/md5.h"
     10 #include "base/string_number_conversions.h"
     11 #include "base/string_util.h"
     12 #include "base/stringprintf.h"
     13 #include "build/build_config.h"
     14 #include "net/server/http_server_request_info.h"
     15 
     16 #if defined(OS_WIN)
     17 #include <winsock2.h>
     18 #else
     19 #include <arpa/inet.h>
     20 #endif
     21 
     22 namespace net {
     23 
     24 int HttpServer::Connection::lastId_ = 0;
     25 
     26 HttpServer::HttpServer(const std::string& host,
     27                        int port,
     28                        HttpServer::Delegate* del)
     29     : delegate_(del) {
     30   server_ = ListenSocket::Listen(host, port, this);
     31 }
     32 
     33 HttpServer::~HttpServer() {
     34   IdToConnectionMap copy = id_to_connection_;
     35   for (IdToConnectionMap::iterator it = copy.begin(); it != copy.end(); ++it)
     36     delete it->second;
     37 
     38   server_ = NULL;
     39 }
     40 
     41 std::string GetHeaderValue(
     42     const HttpServerRequestInfo& request,
     43     const std::string& header_name) {
     44   HttpServerRequestInfo::HeadersMap::iterator it =
     45       request.headers.find(header_name);
     46   if (it != request.headers.end())
     47     return it->second;
     48   return "";
     49 }
     50 
     51 uint32 WebSocketKeyFingerprint(const std::string& str) {
     52   std::string result;
     53   const char* pChar = str.c_str();
     54   int length = str.length();
     55   int spaces = 0;
     56   for (int i = 0; i < length; ++i) {
     57     if (pChar[i] >= '0' && pChar[i] <= '9')
     58       result.append(&pChar[i], 1);
     59     else if (pChar[i] == ' ')
     60       spaces++;
     61   }
     62   if (spaces == 0)
     63     return 0;
     64   int64 number = 0;
     65   if (!base::StringToInt64(result, &number))
     66     return 0;
     67   return htonl(static_cast<uint32>(number / spaces));
     68 }
     69 
     70 void HttpServer::AcceptWebSocket(
     71     int connection_id,
     72     const HttpServerRequestInfo& request) {
     73   Connection* connection = FindConnection(connection_id);
     74   if (connection == NULL)
     75     return;
     76 
     77   std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
     78   std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
     79 
     80   uint32 fp1 = WebSocketKeyFingerprint(key1);
     81   uint32 fp2 = WebSocketKeyFingerprint(key2);
     82 
     83   char data[16];
     84   memcpy(data, &fp1, 4);
     85   memcpy(data + 4, &fp2, 4);
     86   memcpy(data + 8, &request.data[0], 8);
     87 
     88   MD5Digest digest;
     89   MD5Sum(data, 16, &digest);
     90 
     91   std::string origin = GetHeaderValue(request, "Origin");
     92   std::string host = GetHeaderValue(request, "Host");
     93   std::string location = "ws://" + host + request.path;
     94   connection->is_web_socket_ = true;
     95   connection->socket_->Send(base::StringPrintf(
     96       "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
     97       "Upgrade: WebSocket\r\n"
     98       "Connection: Upgrade\r\n"
     99       "Sec-WebSocket-Origin: %s\r\n"
    100       "Sec-WebSocket-Location: %s\r\n"
    101       "\r\n",
    102       origin.c_str(),
    103       location.c_str()));
    104   connection->socket_->Send(reinterpret_cast<char*>(digest.a), 16);
    105 }
    106 
    107 void HttpServer::SendOverWebSocket(int connection_id,
    108                                    const std::string& data) {
    109   Connection* connection = FindConnection(connection_id);
    110   if (connection == NULL)
    111     return;
    112 
    113   DCHECK(connection->is_web_socket_);
    114   char message_start = 0;
    115   char message_end = -1;
    116   connection->socket_->Send(&message_start, 1);
    117   connection->socket_->Send(data);
    118   connection->socket_->Send(&message_end, 1);
    119 }
    120 
    121 void HttpServer::Send(int connection_id, const std::string& data) {
    122   Connection* connection = FindConnection(connection_id);
    123   if (connection == NULL)
    124     return;
    125 
    126   connection->socket_->Send(data);
    127 }
    128 
    129 void HttpServer::Send(int connection_id, const char* bytes, int len) {
    130   Connection* connection = FindConnection(connection_id);
    131   if (connection == NULL)
    132     return;
    133 
    134   connection->socket_->Send(bytes, len);
    135 }
    136 
    137 void HttpServer::Send200(int connection_id,
    138                          const std::string& data,
    139                          const std::string& content_type) {
    140   Connection* connection = FindConnection(connection_id);
    141   if (connection == NULL)
    142     return;
    143 
    144   connection->socket_->Send(base::StringPrintf(
    145       "HTTP/1.1 200 OK\r\n"
    146       "Content-Type:%s\r\n"
    147       "Content-Length:%d\r\n"
    148       "\r\n",
    149       content_type.c_str(),
    150       static_cast<int>(data.length())));
    151   connection->socket_->Send(data);
    152 }
    153 
    154 void HttpServer::Send404(int connection_id) {
    155   Connection* connection = FindConnection(connection_id);
    156   if (connection == NULL)
    157     return;
    158 
    159   connection->socket_->Send(
    160       "HTTP/1.1 404 Not Found\r\n"
    161       "Content-Length: 0\r\n"
    162       "\r\n");
    163 }
    164 
    165 void HttpServer::Send500(int connection_id, const std::string& message) {
    166   Connection* connection = FindConnection(connection_id);
    167   if (connection == NULL)
    168     return;
    169 
    170   connection->socket_->Send(base::StringPrintf(
    171       "HTTP/1.1 500 Internal Error\r\n"
    172       "Content-Type:text/html\r\n"
    173       "Content-Length:%d\r\n"
    174       "\r\n"
    175       "%s",
    176       static_cast<int>(message.length()),
    177       message.c_str()));
    178 }
    179 
    180 void HttpServer::Close(int connection_id)
    181 {
    182   Connection* connection = FindConnection(connection_id);
    183   if (connection == NULL)
    184     return;
    185 
    186   connection->DetachSocket();
    187 }
    188 
    189 HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock)
    190     : server_(server),
    191       socket_(sock),
    192       is_web_socket_(false) {
    193   id_ = lastId_++;
    194 }
    195 
    196 HttpServer::Connection::~Connection() {
    197   DetachSocket();
    198   server_->delegate_->OnClose(id_);
    199 }
    200 
    201 void HttpServer::Connection::DetachSocket() {
    202   socket_ = NULL;
    203 }
    204 
    205 void HttpServer::Connection::Shift(int num_bytes) {
    206   recv_data_ = recv_data_.substr(num_bytes);
    207 }
    208 
    209 //
    210 // HTTP Request Parser
    211 // This HTTP request parser uses a simple state machine to quickly parse
    212 // through the headers.  The parser is not 100% complete, as it is designed
    213 // for use in this simple test driver.
    214 //
    215 // Known issues:
    216 //   - does not handle whitespace on first HTTP line correctly.  Expects
    217 //     a single space between the method/url and url/protocol.
    218 
    219 // Input character types.
    220 enum header_parse_inputs {
    221   INPUT_SPACE,
    222   INPUT_CR,
    223   INPUT_LF,
    224   INPUT_COLON,
    225   INPUT_00,
    226   INPUT_FF,
    227   INPUT_DEFAULT,
    228   MAX_INPUTS,
    229 };
    230 
    231 // Parser states.
    232 enum header_parse_states {
    233   ST_METHOD,     // Receiving the method
    234   ST_URL,        // Receiving the URL
    235   ST_PROTO,      // Receiving the protocol
    236   ST_HEADER,     // Starting a Request Header
    237   ST_NAME,       // Receiving a request header name
    238   ST_SEPARATOR,  // Receiving the separator between header name and value
    239   ST_VALUE,      // Receiving a request header value
    240   ST_WS_READY,   // Ready to receive web socket frame
    241   ST_WS_FRAME,   // Receiving WebSocket frame
    242   ST_WS_CLOSE,   // Closing the connection WebSocket connection
    243   ST_DONE,       // Parsing is complete and successful
    244   ST_ERR,        // Parsing encountered invalid syntax.
    245   MAX_STATES
    246 };
    247 
    248 // State transition table
    249 int parser_state[MAX_STATES][MAX_INPUTS] = {
    250 /* METHOD    */ { ST_URL,       ST_ERR,      ST_ERR,      ST_ERR,       ST_ERR,      ST_ERR,      ST_METHOD },
    251 /* URL       */ { ST_PROTO,     ST_ERR,      ST_ERR,      ST_URL,       ST_ERR,      ST_ERR,      ST_URL },
    252 /* PROTOCOL  */ { ST_ERR,       ST_HEADER,   ST_NAME,     ST_ERR,       ST_ERR,      ST_ERR,      ST_PROTO },
    253 /* HEADER    */ { ST_ERR,       ST_ERR,      ST_NAME,     ST_ERR,       ST_ERR,      ST_ERR,      ST_ERR },
    254 /* NAME      */ { ST_SEPARATOR, ST_DONE,     ST_ERR,      ST_SEPARATOR, ST_ERR,      ST_ERR,      ST_NAME },
    255 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR,      ST_ERR,      ST_SEPARATOR, ST_ERR,      ST_ERR,      ST_VALUE },
    256 /* VALUE     */ { ST_VALUE,     ST_HEADER,   ST_NAME,     ST_VALUE,     ST_ERR,      ST_ERR,      ST_VALUE },
    257 /* WS_READY  */ { ST_ERR,       ST_ERR,      ST_ERR,      ST_ERR,       ST_WS_FRAME, ST_WS_CLOSE, ST_ERR},
    258 /* WS_FRAME  */ { ST_WS_FRAME,  ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME,  ST_ERR,      ST_WS_READY, ST_WS_FRAME },
    259 /* WS_CLOSE  */ { ST_ERR,       ST_ERR,      ST_ERR,      ST_ERR,       ST_WS_CLOSE, ST_ERR,      ST_ERR },
    260 /* DONE      */ { ST_DONE,      ST_DONE,     ST_DONE,     ST_DONE,      ST_DONE,     ST_DONE,     ST_DONE },
    261 /* ERR       */ { ST_ERR,       ST_ERR,      ST_ERR,      ST_ERR,       ST_ERR,      ST_ERR,      ST_ERR }
    262 };
    263 
    264 // Convert an input character to the parser's input token.
    265 int charToInput(char ch) {
    266   switch(ch) {
    267     case ' ':
    268       return INPUT_SPACE;
    269     case '\r':
    270       return INPUT_CR;
    271     case '\n':
    272       return INPUT_LF;
    273     case ':':
    274       return INPUT_COLON;
    275     case 0x0:
    276       return INPUT_00;
    277     case static_cast<char>(-1):
    278       return INPUT_FF;
    279   }
    280   return INPUT_DEFAULT;
    281 }
    282 
    283 bool HttpServer::ParseHeaders(Connection* connection,
    284                               HttpServerRequestInfo* info,
    285                               int* ppos) {
    286   int& pos = *ppos;
    287   int data_len = connection->recv_data_.length();
    288   int state = connection->is_web_socket_ ? ST_WS_READY : ST_METHOD;
    289   std::string buffer;
    290   std::string header_name;
    291   std::string header_value;
    292   while (pos < data_len) {
    293     char ch = connection->recv_data_[pos++];
    294     int input = charToInput(ch);
    295     int next_state = parser_state[state][input];
    296 
    297     bool transition = (next_state != state);
    298     if (transition) {
    299       // Do any actions based on state transitions.
    300       switch (state) {
    301         case ST_METHOD:
    302           info->method = buffer;
    303           buffer.clear();
    304           break;
    305         case ST_URL:
    306           info->path = buffer;
    307           buffer.clear();
    308           break;
    309         case ST_PROTO:
    310           // TODO(mbelshe): Deal better with parsing protocol.
    311           DCHECK(buffer == "HTTP/1.1");
    312           buffer.clear();
    313           break;
    314         case ST_NAME:
    315           header_name = buffer;
    316           buffer.clear();
    317           break;
    318         case ST_VALUE:
    319           header_value = buffer;
    320           // TODO(mbelshe): Deal better with duplicate headers
    321           DCHECK(info->headers.find(header_name) == info->headers.end());
    322           info->headers[header_name] = header_value;
    323           buffer.clear();
    324           break;
    325         case ST_SEPARATOR:
    326           buffer.append(&ch, 1);
    327           break;
    328         case ST_WS_FRAME:
    329           info->data = buffer;
    330           buffer.clear();
    331           return true;
    332           break;
    333       }
    334       state = next_state;
    335     } else {
    336       // Do any actions based on current state
    337       switch (state) {
    338         case ST_METHOD:
    339         case ST_URL:
    340         case ST_PROTO:
    341         case ST_VALUE:
    342         case ST_NAME:
    343         case ST_WS_FRAME:
    344           buffer.append(&ch, 1);
    345           break;
    346         case ST_DONE:
    347           DCHECK(input == INPUT_LF);
    348           return true;
    349         case ST_WS_CLOSE:
    350           connection->is_web_socket_ = false;
    351           return false;
    352         case ST_ERR:
    353           return false;
    354       }
    355     }
    356   }
    357   // No more characters, but we haven't finished parsing yet.
    358   return false;
    359 }
    360 
    361 void HttpServer::DidAccept(ListenSocket* server,
    362                            ListenSocket* socket) {
    363   Connection* connection = new Connection(this, socket);
    364   id_to_connection_[connection->id_] = connection;
    365   socket_to_connection_[socket] = connection;
    366 }
    367 
    368 void HttpServer::DidRead(ListenSocket* socket,
    369                          const char* data,
    370                          int len) {
    371   Connection* connection = FindConnection(socket);
    372   DCHECK(connection != NULL);
    373   if (connection == NULL)
    374     return;
    375 
    376   connection->recv_data_.append(data, len);
    377   while (connection->recv_data_.length()) {
    378     int pos = 0;
    379     HttpServerRequestInfo request;
    380     if (!ParseHeaders(connection, &request, &pos))
    381       break;
    382 
    383     if (connection->is_web_socket_) {
    384       delegate_->OnWebSocketMessage(connection->id_, request.data);
    385       connection->Shift(pos);
    386       continue;
    387     }
    388 
    389     std::string connection_header = GetHeaderValue(request, "Connection");
    390     if (connection_header == "Upgrade") {
    391       // Is this WebSocket and if yes, upgrade the connection.
    392       std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
    393       std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
    394 
    395       const int websocket_handshake_body_len = 8;
    396       if (pos + websocket_handshake_body_len >
    397               static_cast<int>(connection->recv_data_.length())) {
    398         // We haven't received websocket handshake body yet. Wait.
    399         break;
    400       }
    401 
    402       if (!key1.empty() && !key2.empty()) {
    403         request.data = connection->recv_data_.substr(
    404             pos,
    405             pos + websocket_handshake_body_len);
    406         pos += websocket_handshake_body_len;
    407         delegate_->OnWebSocketRequest(connection->id_, request);
    408         connection->Shift(pos);
    409         continue;
    410       }
    411     }
    412     // Request body is not supported. It is always empty.
    413     delegate_->OnHttpRequest(connection->id_, request);
    414     connection->Shift(pos);
    415   }
    416 }
    417 
    418 void HttpServer::DidClose(ListenSocket* socket) {
    419   Connection* connection = FindConnection(socket);
    420   DCHECK(connection != NULL);
    421   id_to_connection_.erase(connection->id_);
    422   socket_to_connection_.erase(connection->socket_);
    423   delete connection;
    424 }
    425 
    426 HttpServer::Connection* HttpServer::FindConnection(int connection_id) {
    427   IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
    428   if (it == id_to_connection_.end())
    429     return NULL;
    430   return it->second;
    431 }
    432 
    433 HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) {
    434   SocketToConnectionMap::iterator it = socket_to_connection_.find(socket);
    435   if (it == socket_to_connection_.end())
    436     return NULL;
    437   return it->second;
    438 }
    439 
    440 }  // namespace net
    441