• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "perfetto/ext/base/http/http_server.h"
17 
18 #include <cinttypes>
19 
20 #include <vector>
21 
22 #include "perfetto/ext/base/base64.h"
23 #include "perfetto/ext/base/endian.h"
24 #include "perfetto/ext/base/http/sha1.h"
25 #include "perfetto/ext/base/string_utils.h"
26 #include "perfetto/ext/base/string_view.h"
27 
28 namespace perfetto {
29 namespace base {
30 
31 namespace {
32 constexpr size_t kMaxPayloadSize = 64 * 1024 * 1024;
33 constexpr size_t kMaxRequestSize = kMaxPayloadSize + 4096;
34 
35 enum WebsocketOpcode : uint8_t {
36   kOpcodeContinuation = 0x0,
37   kOpcodeText = 0x1,
38   kOpcodeBinary = 0x2,
39   kOpcodeDataUnused = 0x3,
40   kOpcodeClose = 0x8,
41   kOpcodePing = 0x9,
42   kOpcodePong = 0xA,
43   kOpcodeControlUnused = 0xB,
44 };
45 
46 // From https://datatracker.ietf.org/doc/html/rfc6455#section-1.3.
47 constexpr char kWebsocketGuid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
48 
49 }  // namespace
50 
HttpServer(TaskRunner * task_runner,HttpRequestHandler * req_handler)51 HttpServer::HttpServer(TaskRunner* task_runner, HttpRequestHandler* req_handler)
52     : task_runner_(task_runner), req_handler_(req_handler) {}
53 HttpServer::~HttpServer() = default;
54 
Start(int port)55 void HttpServer::Start(int port) {
56   std::string ipv4_addr = "127.0.0.1:" + std::to_string(port);
57   std::string ipv6_addr = "[::1]:" + std::to_string(port);
58 
59   sock4_ = UnixSocket::Listen(ipv4_addr, this, task_runner_, SockFamily::kInet,
60                               SockType::kStream);
61   bool ipv4_listening = sock4_ && sock4_->is_listening();
62   if (!ipv4_listening) {
63     PERFETTO_PLOG("Failed to listen on IPv4 socket");
64     sock4_.reset();
65   }
66 
67   sock6_ = UnixSocket::Listen(ipv6_addr, this, task_runner_, SockFamily::kInet6,
68                               SockType::kStream);
69   bool ipv6_listening = sock6_ && sock6_->is_listening();
70   if (!ipv6_listening) {
71     PERFETTO_PLOG("Failed to listen on IPv6 socket");
72     sock6_.reset();
73   }
74 }
75 
AddAllowedOrigin(const std::string & origin)76 void HttpServer::AddAllowedOrigin(const std::string& origin) {
77   allowed_origins_.emplace_back(origin);
78 }
79 
OnNewIncomingConnection(UnixSocket *,std::unique_ptr<UnixSocket> sock)80 void HttpServer::OnNewIncomingConnection(
81     UnixSocket*,  // The listening socket, irrelevant here.
82     std::unique_ptr<UnixSocket> sock) {
83   PERFETTO_LOG("[HTTP] New connection");
84   clients_.emplace_back(std::move(sock));
85 }
86 
OnConnect(UnixSocket *,bool)87 void HttpServer::OnConnect(UnixSocket*, bool) {}
88 
OnDisconnect(UnixSocket * sock)89 void HttpServer::OnDisconnect(UnixSocket* sock) {
90   PERFETTO_LOG("[HTTP] Client disconnected");
91   for (auto it = clients_.begin(); it != clients_.end(); ++it) {
92     if (it->sock.get() == sock) {
93       req_handler_->OnHttpConnectionClosed(&*it);
94       clients_.erase(it);
95       return;
96     }
97   }
98   PERFETTO_DFATAL("[HTTP] Untracked client in OnDisconnect()");
99 }
100 
OnDataAvailable(UnixSocket * sock)101 void HttpServer::OnDataAvailable(UnixSocket* sock) {
102   HttpServerConnection* conn = nullptr;
103   for (auto it = clients_.begin(); it != clients_.end() && !conn; ++it)
104     conn = (it->sock.get() == sock) ? &*it : nullptr;
105   PERFETTO_CHECK(conn);
106 
107   char* rxbuf = reinterpret_cast<char*>(conn->rxbuf.Get());
108   for (;;) {
109     size_t avail = conn->rxbuf_avail();
110     PERFETTO_CHECK(avail <= kMaxRequestSize);
111     if (avail == 0) {
112       conn->SendResponseAndClose("413 Payload Too Large");
113       return;
114     }
115     size_t rsize = sock->Receive(&rxbuf[conn->rxbuf_used], avail);
116     conn->rxbuf_used += rsize;
117     if (rsize == 0 || conn->rxbuf_avail() == 0)
118       break;
119   }
120 
121   // At this point |rxbuf| can contain a partial HTTP request, a full one or
122   // more (in case of HTTP Keepalive pipelining).
123   for (;;) {
124     size_t bytes_consumed;
125 
126     if (conn->is_websocket()) {
127       bytes_consumed = ParseOneWebsocketFrame(conn);
128     } else {
129       bytes_consumed = ParseOneHttpRequest(conn);
130     }
131 
132     if (bytes_consumed == 0)
133       break;
134     memmove(rxbuf, &rxbuf[bytes_consumed], conn->rxbuf_used - bytes_consumed);
135     conn->rxbuf_used -= bytes_consumed;
136   }
137 }
138 
139 // Parses the HTTP request and invokes HandleRequest(). It returns the size of
140 // the HTTP header + body that has been processed or 0 if there isn't enough
141 // data for a full HTTP request in the buffer.
ParseOneHttpRequest(HttpServerConnection * conn)142 size_t HttpServer::ParseOneHttpRequest(HttpServerConnection* conn) {
143   auto* rxbuf = reinterpret_cast<char*>(conn->rxbuf.Get());
144   StringView buf_view(rxbuf, conn->rxbuf_used);
145   bool has_parsed_first_line = false;
146   bool all_headers_received = false;
147   HttpRequest http_req(conn);
148   size_t body_size = 0;
149 
150   // This loop parses the HTTP request headers and sets the |body_offset|.
151   while (!buf_view.empty()) {
152     size_t next = buf_view.find('\n');
153     if (next == StringView::npos)
154       break;
155     StringView line = buf_view.substr(0, next);
156     buf_view = buf_view.substr(next + 1);  // Eat the current line.
157     while (!line.empty() && (line.at(line.size() - 1) == '\r' ||
158                              line.at(line.size() - 1) == '\n')) {
159       line = line.substr(0, line.size() - 1);
160     }
161 
162     if (!has_parsed_first_line) {
163       // Parse the "GET /xxx HTTP/1.1" line.
164       has_parsed_first_line = true;
165       size_t space = line.find(' ');
166       if (space == std::string::npos || space + 2 >= line.size()) {
167         conn->SendResponseAndClose("400 Bad Request");
168         return 0;
169       }
170       http_req.method = line.substr(0, space);
171       size_t uri_size = line.find(' ', space + 1) - (space + 1);
172       http_req.uri = line.substr(space + 1, uri_size);
173     } else if (line.empty()) {
174       all_headers_received = true;
175       // The CR-LF marker that separates headers from body.
176       break;
177     } else {
178       // Parse HTTP headers, e.g. "Content-Length: 1234".
179       size_t col = line.find(':');
180       if (col == StringView::npos) {
181         PERFETTO_DLOG("[HTTP] Malformed HTTP header: \"%s\"",
182                       line.ToStdString().c_str());
183         conn->SendResponseAndClose("400 Bad Request", {}, "Bad HTTP header");
184         return 0;
185       }
186       auto hdr_name = line.substr(0, col);
187       auto hdr_value = line.substr(col + 2);
188       if (http_req.num_headers < http_req.headers.size()) {
189         http_req.headers[http_req.num_headers++] = {hdr_name, hdr_value};
190       } else {
191         conn->SendResponseAndClose("400 Bad Request", {},
192                                    "Too many HTTP headers");
193       }
194 
195       if (hdr_name.CaseInsensitiveEq("content-length")) {
196         body_size = static_cast<size_t>(atoi(hdr_value.ToStdString().c_str()));
197       } else if (hdr_name.CaseInsensitiveEq("origin")) {
198         http_req.origin = hdr_value;
199         if (IsOriginAllowed(hdr_value))
200           conn->origin_allowed_ = hdr_value.ToStdString();
201       } else if (hdr_name.CaseInsensitiveEq("connection")) {
202         conn->keepalive_ = hdr_value.CaseInsensitiveEq("keep-alive");
203         http_req.is_websocket_handshake =
204             hdr_value.CaseInsensitiveEq("upgrade");
205       }
206     }
207   }
208 
209   // At this point |buf_view| has been stripped of the header and contains the
210   // request body. We don't know yet if we have all the bytes for it or not.
211   PERFETTO_CHECK(buf_view.size() <= conn->rxbuf_used);
212   const size_t headers_size = conn->rxbuf_used - buf_view.size();
213 
214   if (body_size + headers_size >= kMaxRequestSize ||
215       body_size > kMaxPayloadSize) {
216     conn->SendResponseAndClose("413 Payload Too Large");
217     return 0;
218   }
219 
220   // If we can't read the full request return and try again next time with more
221   // data.
222   if (!all_headers_received || buf_view.size() < body_size)
223     return 0;
224 
225   http_req.body = buf_view.substr(0, body_size);
226 
227   PERFETTO_LOG("[HTTP] %.*s %.*s [body=%zuB, origin=\"%.*s\"]",
228                static_cast<int>(http_req.method.size()), http_req.method.data(),
229                static_cast<int>(http_req.uri.size()), http_req.uri.data(),
230                http_req.body.size(), static_cast<int>(http_req.origin.size()),
231                http_req.origin.data());
232 
233   if (http_req.method == "OPTIONS") {
234     HandleCorsPreflightRequest(http_req);
235   } else {
236     // Let the HttpHandler handle the request.
237     req_handler_->OnHttpRequest(http_req);
238   }
239 
240   // The handler is expected to send a response. If not, bail with a HTTP 500.
241   if (!conn->headers_sent_)
242     conn->SendResponseAndClose("500 Internal Server Error");
243 
244   // Allow chaining multiple responses in the same HTTP-Keepalive connection.
245   conn->headers_sent_ = false;
246 
247   return headers_size + body_size;
248 }
249 
HandleCorsPreflightRequest(const HttpRequest & req)250 void HttpServer::HandleCorsPreflightRequest(const HttpRequest& req) {
251   req.conn->SendResponseAndClose(
252       "204 No Content",
253       {
254           "Access-Control-Allow-Methods: POST, GET, OPTIONS",  //
255           "Access-Control-Allow-Headers: *",                   //
256           "Access-Control-Max-Age: 86400",                     //
257       });
258 }
259 
IsOriginAllowed(StringView origin)260 bool HttpServer::IsOriginAllowed(StringView origin) {
261   for (const std::string& allowed_origin : allowed_origins_) {
262     if (origin.CaseInsensitiveEq(StringView(allowed_origin))) {
263       return true;
264     }
265   }
266   if (!origin_error_logged_ && !origin.empty()) {
267     origin_error_logged_ = true;
268     PERFETTO_ELOG(
269         "[HTTP] The origin \"%.*s\" is not allowed, Access-Control-Allow-Origin"
270         " won't be emitted. If this request comes from a browser it will fail.",
271         static_cast<int>(origin.size()), origin.data());
272   }
273   return false;
274 }
275 
UpgradeToWebsocket(const HttpRequest & req)276 void HttpServerConnection::UpgradeToWebsocket(const HttpRequest& req) {
277   PERFETTO_CHECK(req.is_websocket_handshake);
278 
279   // |origin_allowed_| is set to the req.origin only if it's in the allowlist.
280   if (origin_allowed_.empty())
281     return SendResponseAndClose("403 Forbidden", {}, "Origin not allowed");
282 
283   auto ws_ver = req.GetHeader("sec-webSocket-version").value_or(StringView());
284   auto ws_key = req.GetHeader("sec-webSocket-key").value_or(StringView());
285 
286   if (!ws_ver.CaseInsensitiveEq("13"))
287     return SendResponseAndClose("505 HTTP Version Not Supported", {});
288 
289   if (ws_key.size() != 24) {
290     // The nonce must be a base64 encoded 16 bytes value (24 after base64).
291     return SendResponseAndClose("400 Bad Request", {});
292   }
293 
294   // From https://datatracker.ietf.org/doc/html/rfc6455#section-1.3 :
295   // For this header field, the server has to take the value (as present
296   // in the header field, e.g., the base64-encoded [RFC4648] version minus
297   // any leading and trailing whitespace) and concatenate this with the
298   // Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA-
299   // 95CA-C5AB0DC85B11" in string form, which is unlikely to be used by
300   // network endpoints that do not understand the WebSocket Protocol.  A
301   // SHA-1 hash (160 bits) [FIPS.180-3], base64-encoded (see Section 4 of
302   // [RFC4648]), of this concatenation is then returned in the server's
303   // handshake.
304   StackString<128> signed_nonce("%.*s%s", static_cast<int>(ws_key.size()),
305                                 ws_key.data(), kWebsocketGuid);
306   auto digest = SHA1Hash(signed_nonce.c_str(), signed_nonce.len());
307   std::string digest_b64 = Base64Encode(digest.data(), digest.size());
308 
309   StackString<128> accept_hdr("Sec-WebSocket-Accept: %s", digest_b64.c_str());
310 
311   std::initializer_list<const char*> headers = {
312       "Upgrade: websocket",   //
313       "Connection: Upgrade",  //
314       accept_hdr.c_str(),     //
315   };
316   PERFETTO_DLOG("[HTTP] Handshaking WebSocket for %.*s",
317                 static_cast<int>(req.uri.size()), req.uri.data());
318   for (const char* hdr : headers)
319     PERFETTO_DLOG("> %s", hdr);
320 
321   SendResponseHeaders("101 Switching Protocols", headers,
322                       HttpServerConnection::kOmitContentLength);
323 
324   is_websocket_ = true;
325 }
326 
ParseOneWebsocketFrame(HttpServerConnection * conn)327 size_t HttpServer::ParseOneWebsocketFrame(HttpServerConnection* conn) {
328   auto* rxbuf = reinterpret_cast<uint8_t*>(conn->rxbuf.Get());
329   const size_t frame_size = conn->rxbuf_used;
330   uint8_t* rd = rxbuf;
331   uint8_t* const end = rxbuf + frame_size;
332 
333   auto avail = [&] {
334     PERFETTO_CHECK(rd <= end);
335     return static_cast<size_t>(end - rd);
336   };
337 
338   // From https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 :
339   //   0                   1                   2                   3
340   //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
341   //  +-+-+-+-+-------+-+-------------+-------------------------------+
342   //  |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
343   //  |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
344   //  |N|V|V|V|       |S|             |   (if payload len==126/127)   |
345   //  | |1|2|3|       |K|             |                               |
346   //  +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
347   //  |     Extended payload length continued, if payload len == 127  |
348   //  + - - - - - - - - - - - - - - - +-------------------------------+
349   //  |                               |Masking-key, if MASK set to 1  |
350   //  +-------------------------------+-------------------------------+
351   //  | Masking-key (continued)       |          Payload Data         |
352   //  +-------------------------------- - - - - - - - - - - - - - - - +
353   //  :                     Payload Data continued ...                :
354   //  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
355   //  |                     Payload Data continued ...                |
356   //  +---------------------------------------------------------------+
357 
358   if (avail() < 2)
359     return 0;  // Can't even decode the frame header. Wait for more data.
360 
361   uint8_t h0 = *(rd++);
362   uint8_t h1 = *(rd++);
363   const bool fin = !!(h0 & 0x80);  // This bit is set if this frame is the last
364                                    // data to complete this message.
365   const uint8_t opcode = h0 & 0x0F;
366 
367   const bool has_mask = !!(h1 & 0x80);
368   uint64_t payload_len_u64 = (h1 & 0x7F);
369   uint8_t extended_payload_size = 0;
370   if (payload_len_u64 == 126) {
371     extended_payload_size = 2;
372   } else if (payload_len_u64 == 127) {
373     extended_payload_size = 8;
374   }
375 
376   if (extended_payload_size > 0) {
377     if (avail() < extended_payload_size)
378       return 0;  // Not enough data to read the extended header.
379     payload_len_u64 = 0;
380     for (uint8_t i = 0; i < extended_payload_size; ++i) {
381       payload_len_u64 <<= 8;
382       payload_len_u64 |= *(rd++);
383     }
384   }
385 
386   if (payload_len_u64 >= kMaxPayloadSize) {
387     PERFETTO_ELOG("[HTTP] Websocket payload too big (%" PRIu64 " > %zu)",
388                   payload_len_u64, kMaxPayloadSize);
389     conn->Close();
390     return 0;
391   }
392   const size_t payload_len = static_cast<size_t>(payload_len_u64);
393 
394   if (!has_mask) {
395     // https://datatracker.ietf.org/doc/html/rfc6455#section-5.1
396     // The server MUST close the connection upon receiving a frame that is
397     // not masked.
398     PERFETTO_ELOG("[HTTP] Websocket inbound frames must be masked");
399     conn->Close();
400     return 0;
401   }
402 
403   uint8_t mask[4];
404   if (avail() < sizeof(mask))
405     return 0;  // Not enough data to read the masking key.
406   memcpy(mask, rd, sizeof(mask));
407   rd += sizeof(mask);
408 
409   PERFETTO_DLOG(
410       "[HTTP] Websocket fin=%d opcode=%u, payload_len=%zu (avail=%zu), "
411       "mask=%02x%02x%02x%02x",
412       fin, opcode, payload_len, avail(), mask[0], mask[1], mask[2], mask[3]);
413 
414   if (avail() < payload_len)
415     return 0;  // Not enouh data to read the payload.
416   uint8_t* const payload_start = rd;
417 
418   // Unmask the payload.
419   for (uint32_t i = 0; i < payload_len; ++i)
420     payload_start[i] ^= mask[i % sizeof(mask)];
421 
422   if (opcode == kOpcodePing) {
423     PERFETTO_DLOG("[HTTP] Websocket PING");
424     conn->SendWebsocketFrame(kOpcodePong, payload_start, payload_len);
425   } else if (opcode == kOpcodeBinary || opcode == kOpcodeText ||
426              opcode == kOpcodeContinuation) {
427     // We do NOT handle fragmentation. We propagate all fragments as individual
428     // messages, breaking the message-oriented nature of websockets. We do this
429     // because in all our use cases we need only a byte stream without caring
430     // about message boundaries.
431     // If we wanted to support fragmentation, we'd have to stash
432     // kOpcodeContinuation messages in a buffer, until we FIN bit is set.
433     // When loading traces with trace processor, the messages can be up to
434     // 32MB big (SLICE_SIZE in trace_stream.ts). The double-buffering would
435     // slow down significantly trace loading with no benefits.
436     WebsocketMessage msg(conn);
437     msg.data =
438         StringView(reinterpret_cast<const char*>(payload_start), payload_len);
439     msg.is_text = opcode == kOpcodeText;
440     req_handler_->OnWebsocketMessage(msg);
441   } else if (opcode == kOpcodeClose) {
442     conn->Close();
443   } else {
444     PERFETTO_LOG("Unsupported WebSocket opcode: %d", opcode);
445   }
446   return static_cast<size_t>(rd - rxbuf) + payload_len;
447 }
448 
SendResponseHeaders(const char * http_code,std::initializer_list<const char * > headers,size_t content_length)449 void HttpServerConnection::SendResponseHeaders(
450     const char* http_code,
451     std::initializer_list<const char*> headers,
452     size_t content_length) {
453   PERFETTO_CHECK(!headers_sent_);
454   PERFETTO_CHECK(!is_websocket_);
455   headers_sent_ = true;
456   std::vector<char> resp_hdr;
457   resp_hdr.reserve(512);
458   bool has_connection_header = false;
459 
460   auto append = [&resp_hdr](const char* str) {
461     resp_hdr.insert(resp_hdr.end(), str, str + strlen(str));
462   };
463 
464   append("HTTP/1.1 ");
465   append(http_code);
466   append("\r\n");
467   for (const char* hdr_cstr : headers) {
468     StringView hdr = (hdr_cstr);
469     if (hdr.empty())
470       continue;
471     has_connection_header |= hdr.substr(0, 11).CaseInsensitiveEq("connection:");
472     append(hdr_cstr);
473     append("\r\n");
474   }
475   content_len_actual_ = 0;
476   content_len_headers_ = content_length;
477   if (content_length != kOmitContentLength) {
478     append("Content-Length: ");
479     append(std::to_string(content_length).c_str());
480     append("\r\n");
481   }
482   if (!has_connection_header) {
483     // Various clients (e.g., python's http.client) assume that a HTTP
484     // connection is keep-alive if the server says nothing, even when they do
485     // NOT ask for it. Hence we must be explicit. If we are about to close the
486     // connection, we must say so.
487     append(keepalive_ ? "Connection: keep-alive\r\n" : "Connection: close\r\n");
488   }
489   if (!origin_allowed_.empty()) {
490     append("Access-Control-Allow-Origin: ");
491     append(origin_allowed_.c_str());
492     append("\r\n");
493     append("Vary: Origin\r\n");
494   }
495   append("\r\n");  // End-of-headers marker.
496   sock->Send(resp_hdr.data(),
497              resp_hdr.size());  // Send response headers.
498 }
499 
SendResponseBody(const void * data,size_t len)500 void HttpServerConnection::SendResponseBody(const void* data, size_t len) {
501   PERFETTO_CHECK(!is_websocket_);
502   if (data == nullptr) {
503     PERFETTO_DCHECK(len == 0);
504     return;
505   }
506   content_len_actual_ += len;
507   PERFETTO_CHECK(content_len_actual_ <= content_len_headers_ ||
508                  content_len_headers_ == kOmitContentLength);
509   sock->Send(data, len);
510 }
511 
Close()512 void HttpServerConnection::Close() {
513   sock->Shutdown(/*notify=*/true);
514 }
515 
SendResponse(const char * http_code,std::initializer_list<const char * > headers,StringView content,bool force_close)516 void HttpServerConnection::SendResponse(
517     const char* http_code,
518     std::initializer_list<const char*> headers,
519     StringView content,
520     bool force_close) {
521   if (force_close)
522     keepalive_ = false;
523   SendResponseHeaders(http_code, headers, content.size());
524   SendResponseBody(content.data(), content.size());
525   if (!keepalive_)
526     Close();
527 }
528 
SendWebsocketMessage(const void * data,size_t len)529 void HttpServerConnection::SendWebsocketMessage(const void* data, size_t len) {
530   SendWebsocketFrame(kOpcodeBinary, data, len);
531 }
532 
SendWebsocketFrame(uint8_t opcode,const void * payload,size_t payload_len)533 void HttpServerConnection::SendWebsocketFrame(uint8_t opcode,
534                                               const void* payload,
535                                               size_t payload_len) {
536   PERFETTO_CHECK(is_websocket_);
537 
538   uint8_t hdr[10]{};
539   uint32_t hdr_len = 0;
540 
541   hdr[0] = opcode | 0x80 /* FIN=1, no fragmentation */;
542   if (payload_len < 126) {
543     hdr_len = 2;
544     hdr[1] = static_cast<uint8_t>(payload_len);
545   } else if (payload_len < 0xffff) {
546     hdr_len = 4;
547     hdr[1] = 126;  // Special value: Header extends for 2 bytes.
548     uint16_t len_be = HostToBE16(static_cast<uint16_t>(payload_len));
549     memcpy(&hdr[2], &len_be, sizeof(len_be));
550   } else {
551     hdr_len = 10;
552     hdr[1] = 127;  // Special value: Header extends for 4 bytes.
553     uint64_t len_be = HostToBE64(payload_len);
554     memcpy(&hdr[2], &len_be, sizeof(len_be));
555   }
556 
557   sock->Send(hdr, hdr_len);
558   if (payload && payload_len > 0)
559     sock->Send(payload, payload_len);
560 }
561 
HttpServerConnection(std::unique_ptr<UnixSocket> s)562 HttpServerConnection::HttpServerConnection(std::unique_ptr<UnixSocket> s)
563     : sock(std::move(s)), rxbuf(PagedMemory::Allocate(kMaxRequestSize)) {}
564 
565 HttpServerConnection::~HttpServerConnection() = default;
566 
GetHeader(StringView name) const567 Optional<StringView> HttpRequest::GetHeader(StringView name) const {
568   for (size_t i = 0; i < num_headers; i++) {
569     if (headers[i].name.CaseInsensitiveEq(name))
570       return headers[i].value;
571   }
572   return nullopt;
573 }
574 
575 HttpRequestHandler::~HttpRequestHandler() = default;
OnWebsocketMessage(const WebsocketMessage &)576 void HttpRequestHandler::OnWebsocketMessage(const WebsocketMessage&) {}
OnHttpConnectionClosed(HttpServerConnection *)577 void HttpRequestHandler::OnHttpConnectionClosed(HttpServerConnection*) {}
578 
579 }  // namespace base
580 }  // namespace perfetto
581