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