http_server.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
1// Copyright (c) 2012 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/stl_util.h" 10#include "base/strings/string_util.h" 11#include "base/strings/stringprintf.h" 12#include "base/sys_byteorder.h" 13#include "build/build_config.h" 14#include "net/server/http_connection.h" 15#include "net/server/http_server_request_info.h" 16#include "net/server/web_socket.h" 17#include "net/socket/tcp_listen_socket.h" 18 19namespace net { 20 21HttpServer::HttpServer(const StreamListenSocketFactory& factory, 22 HttpServer::Delegate* delegate) 23 : delegate_(delegate), 24 server_(factory.CreateAndListen(this)) { 25 DCHECK(server_.get()); 26} 27 28void HttpServer::AcceptWebSocket( 29 int connection_id, 30 const HttpServerRequestInfo& request) { 31 HttpConnection* connection = FindConnection(connection_id); 32 if (connection == NULL) 33 return; 34 35 DCHECK(connection->web_socket_.get()); 36 connection->web_socket_->Accept(request); 37} 38 39void HttpServer::SendOverWebSocket(int connection_id, 40 const std::string& data) { 41 HttpConnection* connection = FindConnection(connection_id); 42 if (connection == NULL) 43 return; 44 DCHECK(connection->web_socket_.get()); 45 connection->web_socket_->Send(data); 46} 47 48void HttpServer::Send(int connection_id, 49 HttpStatusCode status_code, 50 const std::string& data, 51 const std::string& content_type) { 52 HttpConnection* connection = FindConnection(connection_id); 53 if (connection == NULL) 54 return; 55 connection->Send(status_code, data, content_type); 56} 57 58void HttpServer::Send200(int connection_id, 59 const std::string& data, 60 const std::string& content_type) { 61 Send(connection_id, HTTP_OK, data, content_type); 62} 63 64void HttpServer::Send404(int connection_id) { 65 Send(connection_id, HTTP_NOT_FOUND, std::string(), "text/html"); 66} 67 68void HttpServer::Send500(int connection_id, const std::string& message) { 69 Send(connection_id, HTTP_INTERNAL_SERVER_ERROR, message, "text/html"); 70} 71 72void HttpServer::Close(int connection_id) { 73 HttpConnection* connection = FindConnection(connection_id); 74 if (connection == NULL) 75 return; 76 77 // Initiating close from server-side does not lead to the DidClose call. 78 // Do it manually here. 79 DidClose(connection->socket_.get()); 80} 81 82int HttpServer::GetLocalAddress(IPEndPoint* address) { 83 return server_->GetLocalAddress(address); 84} 85 86void HttpServer::DidAccept(StreamListenSocket* server, 87 StreamListenSocket* socket) { 88 HttpConnection* connection = new HttpConnection(this, socket); 89 id_to_connection_[connection->id()] = connection; 90 socket_to_connection_[socket] = connection; 91} 92 93void HttpServer::DidRead(StreamListenSocket* socket, 94 const char* data, 95 int len) { 96 HttpConnection* connection = FindConnection(socket); 97 DCHECK(connection != NULL); 98 if (connection == NULL) 99 return; 100 101 connection->recv_data_.append(data, len); 102 while (connection->recv_data_.length()) { 103 if (connection->web_socket_.get()) { 104 std::string message; 105 WebSocket::ParseResult result = connection->web_socket_->Read(&message); 106 if (result == WebSocket::FRAME_INCOMPLETE) 107 break; 108 109 if (result == WebSocket::FRAME_CLOSE || 110 result == WebSocket::FRAME_ERROR) { 111 Close(connection->id()); 112 break; 113 } 114 delegate_->OnWebSocketMessage(connection->id(), message); 115 continue; 116 } 117 118 HttpServerRequestInfo request; 119 size_t pos = 0; 120 if (!ParseHeaders(connection, &request, &pos)) 121 break; 122 123 std::string connection_header = request.GetHeaderValue("Connection"); 124 if (connection_header == "Upgrade") { 125 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection, 126 request, 127 &pos)); 128 129 if (!connection->web_socket_.get()) // Not enought data was received. 130 break; 131 delegate_->OnWebSocketRequest(connection->id(), request); 132 connection->Shift(pos); 133 continue; 134 } 135 // Request body is not supported. It is always empty. 136 delegate_->OnHttpRequest(connection->id(), request); 137 connection->Shift(pos); 138 } 139} 140 141void HttpServer::DidClose(StreamListenSocket* socket) { 142 HttpConnection* connection = FindConnection(socket); 143 DCHECK(connection != NULL); 144 id_to_connection_.erase(connection->id()); 145 socket_to_connection_.erase(connection->socket_.get()); 146 delete connection; 147} 148 149HttpServer::~HttpServer() { 150 STLDeleteContainerPairSecondPointers( 151 id_to_connection_.begin(), id_to_connection_.end()); 152 server_ = NULL; 153} 154 155// 156// HTTP Request Parser 157// This HTTP request parser uses a simple state machine to quickly parse 158// through the headers. The parser is not 100% complete, as it is designed 159// for use in this simple test driver. 160// 161// Known issues: 162// - does not handle whitespace on first HTTP line correctly. Expects 163// a single space between the method/url and url/protocol. 164 165// Input character types. 166enum header_parse_inputs { 167 INPUT_SPACE, 168 INPUT_CR, 169 INPUT_LF, 170 INPUT_COLON, 171 INPUT_DEFAULT, 172 MAX_INPUTS, 173}; 174 175// Parser states. 176enum header_parse_states { 177 ST_METHOD, // Receiving the method 178 ST_URL, // Receiving the URL 179 ST_PROTO, // Receiving the protocol 180 ST_HEADER, // Starting a Request Header 181 ST_NAME, // Receiving a request header name 182 ST_SEPARATOR, // Receiving the separator between header name and value 183 ST_VALUE, // Receiving a request header value 184 ST_DONE, // Parsing is complete and successful 185 ST_ERR, // Parsing encountered invalid syntax. 186 MAX_STATES 187}; 188 189// State transition table 190int parser_state[MAX_STATES][MAX_INPUTS] = { 191/* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD }, 192/* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL }, 193/* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO }, 194/* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR }, 195/* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_NAME }, 196/* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_VALUE }, 197/* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, 198/* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, 199/* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } 200}; 201 202// Convert an input character to the parser's input token. 203int charToInput(char ch) { 204 switch(ch) { 205 case ' ': 206 return INPUT_SPACE; 207 case '\r': 208 return INPUT_CR; 209 case '\n': 210 return INPUT_LF; 211 case ':': 212 return INPUT_COLON; 213 } 214 return INPUT_DEFAULT; 215} 216 217bool HttpServer::ParseHeaders(HttpConnection* connection, 218 HttpServerRequestInfo* info, 219 size_t* ppos) { 220 size_t& pos = *ppos; 221 size_t data_len = connection->recv_data_.length(); 222 int state = ST_METHOD; 223 std::string buffer; 224 std::string header_name; 225 std::string header_value; 226 while (pos < data_len) { 227 char ch = connection->recv_data_[pos++]; 228 int input = charToInput(ch); 229 int next_state = parser_state[state][input]; 230 231 bool transition = (next_state != state); 232 if (transition) { 233 // Do any actions based on state transitions. 234 switch (state) { 235 case ST_METHOD: 236 info->method = buffer; 237 buffer.clear(); 238 break; 239 case ST_URL: 240 info->path = buffer; 241 buffer.clear(); 242 break; 243 case ST_PROTO: 244 // TODO(mbelshe): Deal better with parsing protocol. 245 DCHECK(buffer == "HTTP/1.1"); 246 buffer.clear(); 247 break; 248 case ST_NAME: 249 header_name = buffer; 250 buffer.clear(); 251 break; 252 case ST_VALUE: 253 header_value = buffer; 254 // TODO(mbelshe): Deal better with duplicate headers 255 DCHECK(info->headers.find(header_name) == info->headers.end()); 256 info->headers[header_name] = header_value; 257 buffer.clear(); 258 break; 259 case ST_SEPARATOR: 260 buffer.append(&ch, 1); 261 break; 262 } 263 state = next_state; 264 } else { 265 // Do any actions based on current state 266 switch (state) { 267 case ST_METHOD: 268 case ST_URL: 269 case ST_PROTO: 270 case ST_VALUE: 271 case ST_NAME: 272 buffer.append(&ch, 1); 273 break; 274 case ST_DONE: 275 DCHECK(input == INPUT_LF); 276 return true; 277 case ST_ERR: 278 return false; 279 } 280 } 281 } 282 // No more characters, but we haven't finished parsing yet. 283 return false; 284} 285 286HttpConnection* HttpServer::FindConnection(int connection_id) { 287 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); 288 if (it == id_to_connection_.end()) 289 return NULL; 290 return it->second; 291} 292 293HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) { 294 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); 295 if (it == socket_to_connection_.end()) 296 return NULL; 297 return it->second; 298} 299 300} // namespace net 301