| OLD | NEW |
| (Empty) |
| 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/bind.h" | |
| 8 #include "base/compiler_specific.h" | |
| 9 #include "base/location.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/message_loop/message_loop_proxy.h" | |
| 12 #include "base/stl_util.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/strings/stringprintf.h" | |
| 16 #include "base/sys_byteorder.h" | |
| 17 #include "build/build_config.h" | |
| 18 #include "net/base/net_errors.h" | |
| 19 #include "net/server/http_connection.h" | |
| 20 #include "net/server/http_server_request_info.h" | |
| 21 #include "net/server/http_server_response_info.h" | |
| 22 #include "net/server/web_socket.h" | |
| 23 #include "net/socket/server_socket.h" | |
| 24 #include "net/socket/stream_socket.h" | |
| 25 #include "net/socket/tcp_server_socket.h" | |
| 26 | |
| 27 namespace net { | |
| 28 | |
| 29 HttpServer::HttpServer(scoped_ptr<ServerSocket> server_socket, | |
| 30 HttpServer::Delegate* delegate) | |
| 31 : server_socket_(server_socket.Pass()), | |
| 32 delegate_(delegate), | |
| 33 last_id_(0), | |
| 34 weak_ptr_factory_(this) { | |
| 35 DCHECK(server_socket_); | |
| 36 // Start accepting connections in next run loop in case when delegate is not | |
| 37 // ready to get callbacks. | |
| 38 base::MessageLoopProxy::current()->PostTask( | |
| 39 FROM_HERE, | |
| 40 base::Bind(&HttpServer::DoAcceptLoop, weak_ptr_factory_.GetWeakPtr())); | |
| 41 } | |
| 42 | |
| 43 HttpServer::~HttpServer() { | |
| 44 STLDeleteContainerPairSecondPointers( | |
| 45 id_to_connection_.begin(), id_to_connection_.end()); | |
| 46 } | |
| 47 | |
| 48 void HttpServer::AcceptWebSocket( | |
| 49 int connection_id, | |
| 50 const HttpServerRequestInfo& request) { | |
| 51 HttpConnection* connection = FindConnection(connection_id); | |
| 52 if (connection == NULL) | |
| 53 return; | |
| 54 DCHECK(connection->web_socket()); | |
| 55 connection->web_socket()->Accept(request); | |
| 56 } | |
| 57 | |
| 58 void HttpServer::SendOverWebSocket(int connection_id, | |
| 59 const std::string& data) { | |
| 60 HttpConnection* connection = FindConnection(connection_id); | |
| 61 if (connection == NULL) | |
| 62 return; | |
| 63 DCHECK(connection->web_socket()); | |
| 64 connection->web_socket()->Send(data); | |
| 65 } | |
| 66 | |
| 67 void HttpServer::SendRaw(int connection_id, const std::string& data) { | |
| 68 HttpConnection* connection = FindConnection(connection_id); | |
| 69 if (connection == NULL) | |
| 70 return; | |
| 71 | |
| 72 bool writing_in_progress = !connection->write_buf()->IsEmpty(); | |
| 73 if (connection->write_buf()->Append(data) && !writing_in_progress) | |
| 74 DoWriteLoop(connection); | |
| 75 } | |
| 76 | |
| 77 void HttpServer::SendResponse(int connection_id, | |
| 78 const HttpServerResponseInfo& response) { | |
| 79 SendRaw(connection_id, response.Serialize()); | |
| 80 } | |
| 81 | |
| 82 void HttpServer::Send(int connection_id, | |
| 83 HttpStatusCode status_code, | |
| 84 const std::string& data, | |
| 85 const std::string& content_type) { | |
| 86 HttpServerResponseInfo response(status_code); | |
| 87 response.SetContentHeaders(data.size(), content_type); | |
| 88 SendResponse(connection_id, response); | |
| 89 SendRaw(connection_id, data); | |
| 90 } | |
| 91 | |
| 92 void HttpServer::Send200(int connection_id, | |
| 93 const std::string& data, | |
| 94 const std::string& content_type) { | |
| 95 Send(connection_id, HTTP_OK, data, content_type); | |
| 96 } | |
| 97 | |
| 98 void HttpServer::Send404(int connection_id) { | |
| 99 SendResponse(connection_id, HttpServerResponseInfo::CreateFor404()); | |
| 100 } | |
| 101 | |
| 102 void HttpServer::Send500(int connection_id, const std::string& message) { | |
| 103 SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message)); | |
| 104 } | |
| 105 | |
| 106 void HttpServer::Close(int connection_id) { | |
| 107 HttpConnection* connection = FindConnection(connection_id); | |
| 108 if (connection == NULL) | |
| 109 return; | |
| 110 | |
| 111 id_to_connection_.erase(connection_id); | |
| 112 delegate_->OnClose(connection_id); | |
| 113 | |
| 114 // The call stack might have callbacks which still have the pointer of | |
| 115 // connection. Instead of referencing connection with ID all the time, | |
| 116 // destroys the connection in next run loop to make sure any pending | |
| 117 // callbacks in the call stack return. | |
| 118 base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, connection); | |
| 119 } | |
| 120 | |
| 121 int HttpServer::GetLocalAddress(IPEndPoint* address) { | |
| 122 return server_socket_->GetLocalAddress(address); | |
| 123 } | |
| 124 | |
| 125 void HttpServer::SetReceiveBufferSize(int connection_id, int32 size) { | |
| 126 HttpConnection* connection = FindConnection(connection_id); | |
| 127 DCHECK(connection); | |
| 128 connection->read_buf()->set_max_buffer_size(size); | |
| 129 } | |
| 130 | |
| 131 void HttpServer::SetSendBufferSize(int connection_id, int32 size) { | |
| 132 HttpConnection* connection = FindConnection(connection_id); | |
| 133 DCHECK(connection); | |
| 134 connection->write_buf()->set_max_buffer_size(size); | |
| 135 } | |
| 136 | |
| 137 void HttpServer::DoAcceptLoop() { | |
| 138 int rv; | |
| 139 do { | |
| 140 rv = server_socket_->Accept(&accepted_socket_, | |
| 141 base::Bind(&HttpServer::OnAcceptCompleted, | |
| 142 weak_ptr_factory_.GetWeakPtr())); | |
| 143 if (rv == ERR_IO_PENDING) | |
| 144 return; | |
| 145 rv = HandleAcceptResult(rv); | |
| 146 } while (rv == OK); | |
| 147 } | |
| 148 | |
| 149 void HttpServer::OnAcceptCompleted(int rv) { | |
| 150 if (HandleAcceptResult(rv) == OK) | |
| 151 DoAcceptLoop(); | |
| 152 } | |
| 153 | |
| 154 int HttpServer::HandleAcceptResult(int rv) { | |
| 155 if (rv < 0) { | |
| 156 LOG(ERROR) << "Accept error: rv=" << rv; | |
| 157 return rv; | |
| 158 } | |
| 159 | |
| 160 HttpConnection* connection = | |
| 161 new HttpConnection(++last_id_, accepted_socket_.Pass()); | |
| 162 id_to_connection_[connection->id()] = connection; | |
| 163 delegate_->OnConnect(connection->id()); | |
| 164 if (!HasClosedConnection(connection)) | |
| 165 DoReadLoop(connection); | |
| 166 return OK; | |
| 167 } | |
| 168 | |
| 169 void HttpServer::DoReadLoop(HttpConnection* connection) { | |
| 170 int rv; | |
| 171 do { | |
| 172 HttpConnection::ReadIOBuffer* read_buf = connection->read_buf(); | |
| 173 // Increases read buffer size if necessary. | |
| 174 if (read_buf->RemainingCapacity() == 0 && !read_buf->IncreaseCapacity()) { | |
| 175 Close(connection->id()); | |
| 176 return; | |
| 177 } | |
| 178 | |
| 179 rv = connection->socket()->Read( | |
| 180 read_buf, | |
| 181 read_buf->RemainingCapacity(), | |
| 182 base::Bind(&HttpServer::OnReadCompleted, | |
| 183 weak_ptr_factory_.GetWeakPtr(), connection->id())); | |
| 184 if (rv == ERR_IO_PENDING) | |
| 185 return; | |
| 186 rv = HandleReadResult(connection, rv); | |
| 187 } while (rv == OK); | |
| 188 } | |
| 189 | |
| 190 void HttpServer::OnReadCompleted(int connection_id, int rv) { | |
| 191 HttpConnection* connection = FindConnection(connection_id); | |
| 192 if (!connection) // It might be closed right before by write error. | |
| 193 return; | |
| 194 | |
| 195 if (HandleReadResult(connection, rv) == OK) | |
| 196 DoReadLoop(connection); | |
| 197 } | |
| 198 | |
| 199 int HttpServer::HandleReadResult(HttpConnection* connection, int rv) { | |
| 200 if (rv <= 0) { | |
| 201 Close(connection->id()); | |
| 202 return rv == 0 ? ERR_CONNECTION_CLOSED : rv; | |
| 203 } | |
| 204 | |
| 205 HttpConnection::ReadIOBuffer* read_buf = connection->read_buf(); | |
| 206 read_buf->DidRead(rv); | |
| 207 | |
| 208 // Handles http requests or websocket messages. | |
| 209 while (read_buf->GetSize() > 0) { | |
| 210 if (connection->web_socket()) { | |
| 211 std::string message; | |
| 212 WebSocket::ParseResult result = connection->web_socket()->Read(&message); | |
| 213 if (result == WebSocket::FRAME_INCOMPLETE) | |
| 214 break; | |
| 215 | |
| 216 if (result == WebSocket::FRAME_CLOSE || | |
| 217 result == WebSocket::FRAME_ERROR) { | |
| 218 Close(connection->id()); | |
| 219 return ERR_CONNECTION_CLOSED; | |
| 220 } | |
| 221 delegate_->OnWebSocketMessage(connection->id(), message); | |
| 222 if (HasClosedConnection(connection)) | |
| 223 return ERR_CONNECTION_CLOSED; | |
| 224 continue; | |
| 225 } | |
| 226 | |
| 227 HttpServerRequestInfo request; | |
| 228 size_t pos = 0; | |
| 229 if (!ParseHeaders(read_buf->StartOfBuffer(), read_buf->GetSize(), | |
| 230 &request, &pos)) { | |
| 231 break; | |
| 232 } | |
| 233 | |
| 234 // Sets peer address if exists. | |
| 235 connection->socket()->GetPeerAddress(&request.peer); | |
| 236 | |
| 237 if (request.HasHeaderValue("connection", "upgrade")) { | |
| 238 scoped_ptr<WebSocket> websocket( | |
| 239 WebSocket::CreateWebSocket(this, connection, request, &pos)); | |
| 240 if (!websocket) // Not enough data was received. | |
| 241 break; | |
| 242 connection->SetWebSocket(websocket.Pass()); | |
| 243 read_buf->DidConsume(pos); | |
| 244 delegate_->OnWebSocketRequest(connection->id(), request); | |
| 245 if (HasClosedConnection(connection)) | |
| 246 return ERR_CONNECTION_CLOSED; | |
| 247 continue; | |
| 248 } | |
| 249 | |
| 250 const char kContentLength[] = "content-length"; | |
| 251 if (request.headers.count(kContentLength) > 0) { | |
| 252 size_t content_length = 0; | |
| 253 const size_t kMaxBodySize = 100 << 20; | |
| 254 if (!base::StringToSizeT(request.GetHeaderValue(kContentLength), | |
| 255 &content_length) || | |
| 256 content_length > kMaxBodySize) { | |
| 257 SendResponse(connection->id(), | |
| 258 HttpServerResponseInfo::CreateFor500( | |
| 259 "request content-length too big or unknown: " + | |
| 260 request.GetHeaderValue(kContentLength))); | |
| 261 Close(connection->id()); | |
| 262 return ERR_CONNECTION_CLOSED; | |
| 263 } | |
| 264 | |
| 265 if (read_buf->GetSize() - pos < content_length) | |
| 266 break; // Not enough data was received yet. | |
| 267 request.data.assign(read_buf->StartOfBuffer() + pos, content_length); | |
| 268 pos += content_length; | |
| 269 } | |
| 270 | |
| 271 read_buf->DidConsume(pos); | |
| 272 delegate_->OnHttpRequest(connection->id(), request); | |
| 273 if (HasClosedConnection(connection)) | |
| 274 return ERR_CONNECTION_CLOSED; | |
| 275 } | |
| 276 | |
| 277 return OK; | |
| 278 } | |
| 279 | |
| 280 void HttpServer::DoWriteLoop(HttpConnection* connection) { | |
| 281 int rv = OK; | |
| 282 HttpConnection::QueuedWriteIOBuffer* write_buf = connection->write_buf(); | |
| 283 while (rv == OK && write_buf->GetSizeToWrite() > 0) { | |
| 284 rv = connection->socket()->Write( | |
| 285 write_buf, | |
| 286 write_buf->GetSizeToWrite(), | |
| 287 base::Bind(&HttpServer::OnWriteCompleted, | |
| 288 weak_ptr_factory_.GetWeakPtr(), connection->id())); | |
| 289 if (rv == ERR_IO_PENDING || rv == OK) | |
| 290 return; | |
| 291 rv = HandleWriteResult(connection, rv); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 void HttpServer::OnWriteCompleted(int connection_id, int rv) { | |
| 296 HttpConnection* connection = FindConnection(connection_id); | |
| 297 if (!connection) // It might be closed right before by read error. | |
| 298 return; | |
| 299 | |
| 300 if (HandleWriteResult(connection, rv) == OK) | |
| 301 DoWriteLoop(connection); | |
| 302 } | |
| 303 | |
| 304 int HttpServer::HandleWriteResult(HttpConnection* connection, int rv) { | |
| 305 if (rv < 0) { | |
| 306 Close(connection->id()); | |
| 307 return rv; | |
| 308 } | |
| 309 | |
| 310 connection->write_buf()->DidConsume(rv); | |
| 311 return OK; | |
| 312 } | |
| 313 | |
| 314 namespace { | |
| 315 | |
| 316 // | |
| 317 // HTTP Request Parser | |
| 318 // This HTTP request parser uses a simple state machine to quickly parse | |
| 319 // through the headers. The parser is not 100% complete, as it is designed | |
| 320 // for use in this simple test driver. | |
| 321 // | |
| 322 // Known issues: | |
| 323 // - does not handle whitespace on first HTTP line correctly. Expects | |
| 324 // a single space between the method/url and url/protocol. | |
| 325 | |
| 326 // Input character types. | |
| 327 enum header_parse_inputs { | |
| 328 INPUT_LWS, | |
| 329 INPUT_CR, | |
| 330 INPUT_LF, | |
| 331 INPUT_COLON, | |
| 332 INPUT_DEFAULT, | |
| 333 MAX_INPUTS, | |
| 334 }; | |
| 335 | |
| 336 // Parser states. | |
| 337 enum header_parse_states { | |
| 338 ST_METHOD, // Receiving the method | |
| 339 ST_URL, // Receiving the URL | |
| 340 ST_PROTO, // Receiving the protocol | |
| 341 ST_HEADER, // Starting a Request Header | |
| 342 ST_NAME, // Receiving a request header name | |
| 343 ST_SEPARATOR, // Receiving the separator between header name and value | |
| 344 ST_VALUE, // Receiving a request header value | |
| 345 ST_DONE, // Parsing is complete and successful | |
| 346 ST_ERR, // Parsing encountered invalid syntax. | |
| 347 MAX_STATES | |
| 348 }; | |
| 349 | |
| 350 // State transition table | |
| 351 int parser_state[MAX_STATES][MAX_INPUTS] = { | |
| 352 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD }, | |
| 353 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL }, | |
| 354 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO }, | |
| 355 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR }, | |
| 356 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_VALUE, ST_NAME }, | |
| 357 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR }, | |
| 358 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, | |
| 359 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, | |
| 360 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } | |
| 361 }; | |
| 362 | |
| 363 // Convert an input character to the parser's input token. | |
| 364 int charToInput(char ch) { | |
| 365 switch(ch) { | |
| 366 case ' ': | |
| 367 case '\t': | |
| 368 return INPUT_LWS; | |
| 369 case '\r': | |
| 370 return INPUT_CR; | |
| 371 case '\n': | |
| 372 return INPUT_LF; | |
| 373 case ':': | |
| 374 return INPUT_COLON; | |
| 375 } | |
| 376 return INPUT_DEFAULT; | |
| 377 } | |
| 378 | |
| 379 } // namespace | |
| 380 | |
| 381 bool HttpServer::ParseHeaders(const char* data, | |
| 382 size_t data_len, | |
| 383 HttpServerRequestInfo* info, | |
| 384 size_t* ppos) { | |
| 385 size_t& pos = *ppos; | |
| 386 int state = ST_METHOD; | |
| 387 std::string buffer; | |
| 388 std::string header_name; | |
| 389 std::string header_value; | |
| 390 while (pos < data_len) { | |
| 391 char ch = data[pos++]; | |
| 392 int input = charToInput(ch); | |
| 393 int next_state = parser_state[state][input]; | |
| 394 | |
| 395 bool transition = (next_state != state); | |
| 396 HttpServerRequestInfo::HeadersMap::iterator it; | |
| 397 if (transition) { | |
| 398 // Do any actions based on state transitions. | |
| 399 switch (state) { | |
| 400 case ST_METHOD: | |
| 401 info->method = buffer; | |
| 402 buffer.clear(); | |
| 403 break; | |
| 404 case ST_URL: | |
| 405 info->path = buffer; | |
| 406 buffer.clear(); | |
| 407 break; | |
| 408 case ST_PROTO: | |
| 409 // TODO(mbelshe): Deal better with parsing protocol. | |
| 410 DCHECK(buffer == "HTTP/1.1"); | |
| 411 buffer.clear(); | |
| 412 break; | |
| 413 case ST_NAME: | |
| 414 header_name = base::StringToLowerASCII(buffer); | |
| 415 buffer.clear(); | |
| 416 break; | |
| 417 case ST_VALUE: | |
| 418 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value); | |
| 419 it = info->headers.find(header_name); | |
| 420 // See last paragraph ("Multiple message-header fields...") | |
| 421 // of www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 | |
| 422 if (it == info->headers.end()) { | |
| 423 info->headers[header_name] = header_value; | |
| 424 } else { | |
| 425 it->second.append(","); | |
| 426 it->second.append(header_value); | |
| 427 } | |
| 428 buffer.clear(); | |
| 429 break; | |
| 430 case ST_SEPARATOR: | |
| 431 break; | |
| 432 } | |
| 433 state = next_state; | |
| 434 } else { | |
| 435 // Do any actions based on current state | |
| 436 switch (state) { | |
| 437 case ST_METHOD: | |
| 438 case ST_URL: | |
| 439 case ST_PROTO: | |
| 440 case ST_VALUE: | |
| 441 case ST_NAME: | |
| 442 buffer.append(&ch, 1); | |
| 443 break; | |
| 444 case ST_DONE: | |
| 445 DCHECK(input == INPUT_LF); | |
| 446 return true; | |
| 447 case ST_ERR: | |
| 448 return false; | |
| 449 } | |
| 450 } | |
| 451 } | |
| 452 // No more characters, but we haven't finished parsing yet. | |
| 453 return false; | |
| 454 } | |
| 455 | |
| 456 HttpConnection* HttpServer::FindConnection(int connection_id) { | |
| 457 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); | |
| 458 if (it == id_to_connection_.end()) | |
| 459 return NULL; | |
| 460 return it->second; | |
| 461 } | |
| 462 | |
| 463 // This is called after any delegate callbacks are called to check if Close() | |
| 464 // has been called during callback processing. Using the pointer of connection, | |
| 465 // |connection| is safe here because Close() deletes the connection in next run | |
| 466 // loop. | |
| 467 bool HttpServer::HasClosedConnection(HttpConnection* connection) { | |
| 468 return FindConnection(connection->id()) != connection; | |
| 469 } | |
| 470 | |
| 471 } // namespace net | |
| OLD | NEW |