• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/server/http_server.h"
11 
12 #include <string_view>
13 #include <utility>
14 
15 #include "base/compiler_specific.h"
16 #include "base/functional/bind.h"
17 #include "base/location.h"
18 #include "base/logging.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/sys_byteorder.h"
22 #include "base/task/single_thread_task_runner.h"
23 #include "build/build_config.h"
24 #include "net/base/net_errors.h"
25 #include "net/server/http_connection.h"
26 #include "net/server/http_server_request_info.h"
27 #include "net/server/http_server_response_info.h"
28 #include "net/server/web_socket.h"
29 #include "net/server/web_socket_parse_result.h"
30 #include "net/socket/server_socket.h"
31 #include "net/socket/stream_socket.h"
32 #include "net/socket/tcp_server_socket.h"
33 #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
34 
35 namespace net {
36 
37 namespace {
38 
39 constexpr NetworkTrafficAnnotationTag
40     kHttpServerErrorResponseTrafficAnnotation =
41         DefineNetworkTrafficAnnotation("http_server_error_response",
42                                        R"(
43       semantics {
44         sender: "HTTP Server"
45         description: "Error response from the built-in HTTP server."
46         trigger: "Sending a request to the HTTP server that it can't handle."
47         data: "A 500 error code."
48         destination: OTHER
49         destination_other: "Any destination the consumer selects."
50       }
51       policy {
52         cookies_allowed: NO
53         setting:
54           "This request cannot be disabled in settings. However it will never "
55           "be made unless user activates an HTTP server."
56         policy_exception_justification:
57           "Not implemented, not used if HTTP Server is not activated."
58       })");
59 
60 }  // namespace
61 
HttpServer(std::unique_ptr<ServerSocket> server_socket,HttpServer::Delegate * delegate)62 HttpServer::HttpServer(std::unique_ptr<ServerSocket> server_socket,
63                        HttpServer::Delegate* delegate)
64     : server_socket_(std::move(server_socket)), delegate_(delegate) {
65   DCHECK(server_socket_);
66   // Start accepting connections in next run loop in case when delegate is not
67   // ready to get callbacks.
68   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
69       FROM_HERE, base::BindOnce(&HttpServer::DoAcceptLoop,
70                                 weak_ptr_factory_.GetWeakPtr()));
71 }
72 
73 HttpServer::~HttpServer() = default;
74 
75 void HttpServer::AcceptWebSocket(
76     int connection_id,
77     const HttpServerRequestInfo& request,
78     NetworkTrafficAnnotationTag traffic_annotation) {
79   HttpConnection* connection = FindConnection(connection_id);
80   if (connection == nullptr)
81     return;
82   DCHECK(connection->web_socket());
83   connection->web_socket()->Accept(request, traffic_annotation);
84 }
85 
86 void HttpServer::SendOverWebSocket(
87     int connection_id,
88     std::string_view data,
89     NetworkTrafficAnnotationTag traffic_annotation) {
90   HttpConnection* connection = FindConnection(connection_id);
91   if (connection == nullptr)
92     return;
93   DCHECK(connection->web_socket());
94   connection->web_socket()->Send(
95       data, WebSocketFrameHeader::OpCodeEnum::kOpCodeText, traffic_annotation);
96 }
97 
98 void HttpServer::SendRaw(int connection_id,
99                          const std::string& data,
100                          NetworkTrafficAnnotationTag traffic_annotation) {
101   HttpConnection* connection = FindConnection(connection_id);
102   if (connection == nullptr)
103     return;
104 
105   bool writing_in_progress = !connection->write_buf()->IsEmpty();
106   if (connection->write_buf()->Append(data) && !writing_in_progress)
107     DoWriteLoop(connection, traffic_annotation);
108 }
109 
110 void HttpServer::SendResponse(int connection_id,
111                               const HttpServerResponseInfo& response,
112                               NetworkTrafficAnnotationTag traffic_annotation) {
113   SendRaw(connection_id, response.Serialize(), traffic_annotation);
114 }
115 
116 void HttpServer::Send(int connection_id,
117                       HttpStatusCode status_code,
118                       const std::string& data,
119                       const std::string& content_type,
120                       NetworkTrafficAnnotationTag traffic_annotation) {
121   HttpServerResponseInfo response(status_code);
122   response.SetContentHeaders(data.size(), content_type);
123   SendResponse(connection_id, response, traffic_annotation);
124   SendRaw(connection_id, data, traffic_annotation);
125 }
126 
127 void HttpServer::Send200(int connection_id,
128                          const std::string& data,
129                          const std::string& content_type,
130                          NetworkTrafficAnnotationTag traffic_annotation) {
131   Send(connection_id, HTTP_OK, data, content_type, traffic_annotation);
132 }
133 
134 void HttpServer::Send404(int connection_id,
135                          NetworkTrafficAnnotationTag traffic_annotation) {
136   SendResponse(connection_id, HttpServerResponseInfo::CreateFor404(),
137                traffic_annotation);
138 }
139 
140 void HttpServer::Send500(int connection_id,
141                          const std::string& message,
142                          NetworkTrafficAnnotationTag traffic_annotation) {
143   SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message),
144                traffic_annotation);
145 }
146 
147 void HttpServer::Close(int connection_id) {
148   auto it = id_to_connection_.find(connection_id);
149   if (it == id_to_connection_.end())
150     return;
151 
152   closed_connections_.emplace_back(std::move(it->second));
153   id_to_connection_.erase(it);
154   delegate_->OnClose(connection_id);
155 
156   // The call stack might have callbacks which still have the pointer of
157   // connection. Instead of referencing connection with ID all the time,
158   // destroys the connection in next run loop to make sure any pending
159   // callbacks in the call stack return. List of closed Connections is owned
160   // by `this` in case `this` is destroyed before the task runs. Connections may
161   // not outlive `this`.
162   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
163       FROM_HERE, base::BindOnce(&HttpServer::DestroyClosedConnections,
164                                 weak_ptr_factory_.GetWeakPtr()));
165 }
166 
167 int HttpServer::GetLocalAddress(IPEndPoint* address) {
168   return server_socket_->GetLocalAddress(address);
169 }
170 
171 void HttpServer::SetReceiveBufferSize(int connection_id, int32_t size) {
172   HttpConnection* connection = FindConnection(connection_id);
173   if (connection)
174     connection->read_buf()->set_max_buffer_size(size);
175 }
176 
177 void HttpServer::SetSendBufferSize(int connection_id, int32_t size) {
178   HttpConnection* connection = FindConnection(connection_id);
179   if (connection)
180     connection->write_buf()->set_max_buffer_size(size);
181 }
182 
183 void HttpServer::DoAcceptLoop() {
184   int rv;
185   do {
186     rv = server_socket_->Accept(&accepted_socket_,
187                                 base::BindOnce(&HttpServer::OnAcceptCompleted,
188                                                weak_ptr_factory_.GetWeakPtr()));
189     if (rv == ERR_IO_PENDING)
190       return;
191     rv = HandleAcceptResult(rv);
192   } while (rv == OK);
193 }
194 
195 void HttpServer::OnAcceptCompleted(int rv) {
196   if (HandleAcceptResult(rv) == OK)
197     DoAcceptLoop();
198 }
199 
200 int HttpServer::HandleAcceptResult(int rv) {
201   if (rv < 0) {
202     LOG(ERROR) << "Accept error: rv=" << rv;
203     return rv;
204   }
205 
206   std::unique_ptr<HttpConnection> connection_ptr =
207       std::make_unique<HttpConnection>(++last_id_, std::move(accepted_socket_));
208   HttpConnection* connection = connection_ptr.get();
209   id_to_connection_[connection->id()] = std::move(connection_ptr);
210   delegate_->OnConnect(connection->id());
211   if (!HasClosedConnection(connection))
212     DoReadLoop(connection);
213   return OK;
214 }
215 
216 void HttpServer::DoReadLoop(HttpConnection* connection) {
217   int rv;
218   do {
219     HttpConnection::ReadIOBuffer* read_buf = connection->read_buf();
220     // Increases read buffer size if necessary.
221     if (read_buf->RemainingCapacity() == 0 && !read_buf->IncreaseCapacity()) {
222       Close(connection->id());
223       return;
224     }
225 
226     rv = connection->socket()->Read(
227         read_buf, read_buf->RemainingCapacity(),
228         base::BindOnce(&HttpServer::OnReadCompleted,
229                        weak_ptr_factory_.GetWeakPtr(), connection->id()));
230     if (rv == ERR_IO_PENDING)
231       return;
232     rv = HandleReadResult(connection, rv);
233   } while (rv == OK);
234 }
235 
236 void HttpServer::OnReadCompleted(int connection_id, int rv) {
237   HttpConnection* connection = FindConnection(connection_id);
238   if (!connection)  // It might be closed right before by write error.
239     return;
240 
241   if (HandleReadResult(connection, rv) == OK)
242     DoReadLoop(connection);
243 }
244 
245 int HttpServer::HandleReadResult(HttpConnection* connection, int rv) {
246   if (rv <= 0) {
247     Close(connection->id());
248     return rv == 0 ? ERR_CONNECTION_CLOSED : rv;
249   }
250 
251   HttpConnection::ReadIOBuffer* read_buf = connection->read_buf();
252   read_buf->DidRead(rv);
253 
254   // Handles http requests or websocket messages.
255   while (read_buf->GetSize() > 0) {
256     if (connection->web_socket()) {
257       std::string message;
258       WebSocketParseResult result = connection->web_socket()->Read(&message);
259       if (result == WebSocketParseResult::FRAME_INCOMPLETE) {
260         break;
261       }
262 
263       if (result == WebSocketParseResult::FRAME_CLOSE ||
264           result == WebSocketParseResult::FRAME_ERROR) {
265         Close(connection->id());
266         return ERR_CONNECTION_CLOSED;
267       }
268       if (result == WebSocketParseResult::FRAME_OK_FINAL) {
269         delegate_->OnWebSocketMessage(connection->id(), std::move(message));
270       }
271       if (HasClosedConnection(connection))
272         return ERR_CONNECTION_CLOSED;
273       continue;
274     }
275 
276     // The headers are reparsed from the beginning every time a packet is
277     // received. This only really matters if something tries to upload a large
278     // request body.
279     HttpServerRequestInfo request;
280     size_t pos = 0;
281     if (!ParseHeaders(read_buf->StartOfBuffer(), read_buf->GetSize(),
282                       &request, &pos)) {
283       // An error has occured. Close the connection.
284       Close(connection->id());
285       return ERR_CONNECTION_CLOSED;
286     } else if (!pos) {
287       // If pos is 0, all the data in read_buf has been consumed, but the
288       // headers have not been fully parsed yet. Continue parsing when more data
289       // rolls in.
290       break;
291     }
292 
293     // Sets peer address if exists.
294     connection->socket()->GetPeerAddress(&request.peer);
295 
296     if (request.HasHeaderValue("connection", "upgrade") &&
297         request.HasHeaderValue("upgrade", "websocket")) {
298       connection->SetWebSocket(std::make_unique<WebSocket>(this, connection));
299       read_buf->DidConsume(pos);
300       delegate_->OnWebSocketRequest(connection->id(), request);
301       if (HasClosedConnection(connection))
302         return ERR_CONNECTION_CLOSED;
303       continue;
304     }
305 
306     const char kContentLength[] = "content-length";
307     if (request.headers.count(kContentLength) > 0) {
308       size_t content_length = 0;
309       const size_t kMaxBodySize = 100 << 20;
310       if (!base::StringToSizeT(request.GetHeaderValue(kContentLength),
311                                &content_length) ||
312           content_length > kMaxBodySize) {
313         SendResponse(connection->id(),
314                      HttpServerResponseInfo::CreateFor500(
315                          "request content-length too big or unknown."),
316                      kHttpServerErrorResponseTrafficAnnotation);
317         Close(connection->id());
318         return ERR_CONNECTION_CLOSED;
319       }
320 
321       if (read_buf->GetSize() - pos < content_length)
322         break;  // Not enough data was received yet.
323       request.data.assign(read_buf->StartOfBuffer() + pos, content_length);
324       pos += content_length;
325     }
326 
327     read_buf->DidConsume(pos);
328     delegate_->OnHttpRequest(connection->id(), request);
329     if (HasClosedConnection(connection))
330       return ERR_CONNECTION_CLOSED;
331   }
332 
333   return OK;
334 }
335 
336 void HttpServer::DoWriteLoop(HttpConnection* connection,
337                              NetworkTrafficAnnotationTag traffic_annotation) {
338   int rv = OK;
339   HttpConnection::QueuedWriteIOBuffer* write_buf = connection->write_buf();
340   while (rv == OK && write_buf->GetSizeToWrite() > 0) {
341     rv = connection->socket()->Write(
342         write_buf, write_buf->GetSizeToWrite(),
343         base::BindOnce(&HttpServer::OnWriteCompleted,
344                        weak_ptr_factory_.GetWeakPtr(), connection->id(),
345                        traffic_annotation),
346         traffic_annotation);
347     if (rv == ERR_IO_PENDING || rv == OK)
348       return;
349     rv = HandleWriteResult(connection, rv);
350   }
351 }
352 
353 void HttpServer::OnWriteCompleted(
354     int connection_id,
355     NetworkTrafficAnnotationTag traffic_annotation,
356     int rv) {
357   HttpConnection* connection = FindConnection(connection_id);
358   if (!connection)  // It might be closed right before by read error.
359     return;
360 
361   if (HandleWriteResult(connection, rv) == OK)
362     DoWriteLoop(connection, traffic_annotation);
363 }
364 
365 int HttpServer::HandleWriteResult(HttpConnection* connection, int rv) {
366   if (rv < 0) {
367     Close(connection->id());
368     return rv;
369   }
370 
371   connection->write_buf()->DidConsume(rv);
372   return OK;
373 }
374 
375 namespace {
376 
377 //
378 // HTTP Request Parser
379 // This HTTP request parser uses a simple state machine to quickly parse
380 // through the headers.  The parser is not 100% complete, as it is designed
381 // for use in this simple test driver.
382 //
383 // Known issues:
384 //   - does not handle whitespace on first HTTP line correctly.  Expects
385 //     a single space between the method/url and url/protocol.
386 
387 // Input character types.
388 enum HeaderParseInputs {
389   INPUT_LWS,
390   INPUT_CR,
391   INPUT_LF,
392   INPUT_COLON,
393   INPUT_DEFAULT,
394   MAX_INPUTS,
395 };
396 
397 // Parser states.
398 enum HeaderParseStates {
399   ST_METHOD,     // Receiving the method
400   ST_URL,        // Receiving the URL
401   ST_PROTO,      // Receiving the protocol
402   ST_HEADER,     // Starting a Request Header
403   ST_NAME,       // Receiving a request header name
404   ST_SEPARATOR,  // Receiving the separator between header name and value
405   ST_VALUE,      // Receiving a request header value
406   ST_DONE,       // Parsing is complete and successful
407   ST_ERR,        // Parsing encountered invalid syntax.
408   MAX_STATES
409 };
410 
411 // This state machine has a number of bugs, for example it considers
412 // "HTTP/1.1 200 OK\r\n"
413 // "Foo\r\n"
414 // to be a correctly terminated set of request headers. It also accepts "\n"
415 // between header lines but requires "\r\n" at the end of the headers.
416 // TODO(crbug): Consider using a different request parser. Maybe balsa headers
417 // from QUICHE, if it doesn't increase the binary size too much.
418 
419 // State transition table
420 constexpr int kParserState[MAX_STATES][MAX_INPUTS] = {
421     /* METHOD    */ {ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD},
422     /* URL       */ {ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL},
423     /* PROTOCOL  */ {ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO},
424     /* HEADER    */ {ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR},
425     /* NAME      */ {ST_SEPARATOR, ST_DONE, ST_ERR, ST_VALUE, ST_NAME},
426     /* SEPARATOR */ {ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR},
427     /* VALUE     */ {ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE},
428     /* DONE      */ {ST_ERR, ST_ERR, ST_DONE, ST_ERR, ST_ERR},
429     /* ERR       */ {ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR}};
430 
431 // Convert an input character to the parser's input token.
CharToInputType(char ch)432 int CharToInputType(char ch) {
433   switch (ch) {
434     case ' ':
435     case '\t':
436       return INPUT_LWS;
437     case '\r':
438       return INPUT_CR;
439     case '\n':
440       return INPUT_LF;
441     case ':':
442       return INPUT_COLON;
443   }
444   return INPUT_DEFAULT;
445 }
446 
447 }  // namespace
448 
ParseHeaders(const char * data,size_t data_len,HttpServerRequestInfo * info,size_t * ppos)449 bool HttpServer::ParseHeaders(const char* data,
450                               size_t data_len,
451                               HttpServerRequestInfo* info,
452                               size_t* ppos) {
453   // Copy *ppos to avoid the compiler having to think about pointer aliasing.
454   size_t pos = *ppos;
455   // Make sure `pos` is always written back to `ppos` even if an extra return is
456   // added to the function.
457   absl::Cleanup set_ppos = [&pos, ppos]() { *ppos = pos; };
458   int state = ST_METHOD;
459   // Technically a base::span<const uint8_t> would be more correct, but using a
460   // std::string_view makes integration with the rest of the code easier.
461   const std::string_view data_view(data, data_len);
462   size_t token_start = pos;
463   std::string header_name;
464   for (; pos < data_len; ++pos) {
465     const char ch = data[pos];
466     if (ch == '\0') {
467       // Lots of code assumes strings don't contain null characters, so disallow
468       // them to be on the safe side.
469       return false;
470     }
471     const int input = CharToInputType(ch);
472     const int next_state = kParserState[state][input];
473     if (next_state == ST_ERR) {
474       // No point in continuing.
475       return false;
476     }
477 
478     const bool transition = (next_state != state);
479     if (transition) {
480       const std::string_view token =
481           data_view.substr(token_start, pos - token_start);
482       token_start = pos + 1;  // Skip the whitespace or separator.
483       // Do any actions based on state transitions.
484       switch (state) {
485         case ST_METHOD:
486           info->method = std::string(token);
487           break;
488         case ST_URL:
489           info->path = std::string(token);
490           break;
491         case ST_PROTO:
492           if (token != "HTTP/1.1") {
493             LOG(ERROR) << "Cannot handle request with protocol: " << token;
494             return false;
495           }
496           break;
497         case ST_NAME:
498           header_name = base::ToLowerASCII(token);
499           break;
500         case ST_VALUE: {
501           std::string_view header_value =
502               base::TrimWhitespaceASCII(token, base::TRIM_LEADING);
503           // See the second paragraph ("A sender MUST NOT generate multiple
504           // header fields...") of tools.ietf.org/html/rfc7230#section-3.2.2.
505           auto [it, inserted] = info->headers.try_emplace(
506               std::move(header_name), std::move(header_value));
507           header_name.clear();  // Avoid use-after-move lint error.
508           if (!inserted) {
509             // Since the insertion did not happen, try_emplace() did not move
510             // the contents of `header_value` and we can still use it.
511             std::string& value = it->second;
512             value.reserve(value.size() + 1 + header_value.size());
513             value.push_back(',');
514             value.append(header_value);
515           }
516           break;
517         }
518       }
519       state = next_state;
520     } else {
521       // Do any actions based on current state
522       if (state == ST_DONE) {
523         ++pos;  // Point to the first byte of the body.
524         return true;
525       }
526     }
527   }
528   // No more characters, but we haven't finished parsing yet. Signal this to
529   // the caller by setting |pos| to zero.
530   pos = 0;
531   return true;
532 }
533 
FindConnection(int connection_id)534 HttpConnection* HttpServer::FindConnection(int connection_id) {
535   auto it = id_to_connection_.find(connection_id);
536   if (it == id_to_connection_.end())
537     return nullptr;
538   return it->second.get();
539 }
540 
541 // This is called after any delegate callbacks are called to check if Close()
542 // has been called during callback processing. Using the pointer of connection,
543 // |connection| is safe here because Close() deletes the connection in next run
544 // loop.
HasClosedConnection(HttpConnection * connection)545 bool HttpServer::HasClosedConnection(HttpConnection* connection) {
546   return FindConnection(connection->id()) != connection;
547 }
548 
DestroyClosedConnections()549 void HttpServer::DestroyClosedConnections() {
550   closed_connections_.clear();
551 }
552 
553 }  // namespace net
554