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
22namespace net {
23
24int HttpServer::Connection::lastId_ = 0;
25
26HttpServer::HttpServer(const std::string& host,
27                       int port,
28                       HttpServer::Delegate* del)
29    : delegate_(del) {
30  server_ = ListenSocket::Listen(host, port, this);
31}
32
33HttpServer::~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
41std::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
51uint32 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
70void 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
107void 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
121void 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
129void 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
137void 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
154void 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
165void 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
180void HttpServer::Close(int connection_id)
181{
182  Connection* connection = FindConnection(connection_id);
183  if (connection == NULL)
184    return;
185
186  connection->DetachSocket();
187}
188
189HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock)
190    : server_(server),
191      socket_(sock),
192      is_web_socket_(false) {
193  id_ = lastId_++;
194}
195
196HttpServer::Connection::~Connection() {
197  DetachSocket();
198  server_->delegate_->OnClose(id_);
199}
200
201void HttpServer::Connection::DetachSocket() {
202  socket_ = NULL;
203}
204
205void 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.
220enum 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.
232enum 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
249int 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.
265int 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
283bool 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
361void 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
368void 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
418void 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
426HttpServer::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
433HttpServer::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