xref: /aosp_15_r20/external/perfetto/include/perfetto/ext/base/http/http_server.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 
17 #ifndef INCLUDE_PERFETTO_EXT_BASE_HTTP_HTTP_SERVER_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_HTTP_HTTP_SERVER_H_
19 
20 #include <array>
21 #include <cstddef>
22 #include <cstdint>
23 #include <initializer_list>
24 #include <list>
25 #include <memory>
26 #include <optional>
27 #include <string>
28 
29 #include "perfetto/base/task_runner.h"
30 #include "perfetto/ext/base/paged_memory.h"
31 #include "perfetto/ext/base/string_view.h"
32 #include "perfetto/ext/base/unix_socket.h"
33 
34 namespace perfetto::base {
35 
36 class HttpServerConnection;
37 
38 struct HttpRequest {
HttpRequestHttpRequest39   explicit HttpRequest(HttpServerConnection* c) : conn(c) {}
40 
41   std::optional<StringView> GetHeader(StringView name) const;
42 
43   HttpServerConnection* conn;
44 
45   // These StringViews point to memory in the rxbuf owned by |conn|. They are
46   // valid only within the OnHttpRequest() call.
47   StringView method;
48   StringView uri;
49   StringView origin;
50   StringView body;
51   bool is_websocket_handshake = false;
52 
53  private:
54   friend class HttpServer;
55   struct Header {
56     StringView name;
57     StringView value;
58   };
59 
60   static constexpr uint32_t kMaxHeaders = 32;
61   std::array<Header, kMaxHeaders> headers{};
62   size_t num_headers = 0;
63 };
64 
65 struct WebsocketMessage {
WebsocketMessageWebsocketMessage66   explicit WebsocketMessage(HttpServerConnection* c) : conn(c) {}
67 
68   HttpServerConnection* conn;
69 
70   // Note: message boundaries are not respected in case of fragmentation.
71   // This websocket implementation preserves only the byte stream, but not the
72   // atomicity of inbound messages (like SOCK_STREAM, unlike SOCK_DGRAM).
73   // Holds onto the connection's |rxbuf|. This is valid only within the scope
74   // of the OnWebsocketMessage() callback.
75   StringView data;
76 
77   // If false the payload contains binary data. If true it's supposed to contain
78   // text. Note that there is no guarantee this will be the case. This merely
79   // reflect the opcode that the client sets on each message.
80   bool is_text = false;
81 };
82 
83 class HttpServerConnection {
84  public:
85   static constexpr size_t kOmitContentLength = static_cast<size_t>(-1);
86 
87   explicit HttpServerConnection(std::unique_ptr<UnixSocket>);
88   ~HttpServerConnection();
89 
90   void SendResponseHeaders(const char* http_code,
91                            std::initializer_list<const char*> headers = {},
92                            size_t content_length = 0);
93 
94   // Works also for websockets.
95   void SendResponseBody(const void* content, size_t content_length);
96   void Close();
97 
98   // All the above in one shot.
99   void SendResponse(const char* http_code,
100                     std::initializer_list<const char*> headers = {},
101                     StringView content = {},
102                     bool force_close = false);
103   void SendResponseAndClose(const char* http_code,
104                             std::initializer_list<const char*> headers = {},
105                             StringView content = {}) {
106     SendResponse(http_code, headers, content, true);
107   }
108 
109   // The metods below are only valid for websocket connections.
110 
111   // Upgrade an existing connection to a websocket. This can be called only in
112   // the context of OnHttpRequest(req) if req.is_websocket_handshake == true.
113   // If the origin is not in the |allowed_origins_|, the request will fail with
114   // a 403 error (this is because there is no browser-side CORS support for
115   // websockets).
116   void UpgradeToWebsocket(const HttpRequest&);
117   void SendWebsocketMessage(const void* data, size_t len);
SendWebsocketMessage(StringView sv)118   void SendWebsocketMessage(StringView sv) {
119     SendWebsocketMessage(sv.data(), sv.size());
120   }
121   void SendWebsocketFrame(uint8_t opcode,
122                           const void* payload,
123                           size_t payload_len);
124 
is_websocket()125   bool is_websocket() const { return is_websocket_; }
126 
127  private:
128   friend class HttpServer;
129 
rxbuf_avail()130   size_t rxbuf_avail() { return rxbuf.size() - rxbuf_used; }
131 
132   std::unique_ptr<UnixSocket> sock;
133   PagedMemory rxbuf;
134   size_t rxbuf_used = 0;
135   bool is_websocket_ = false;
136   bool headers_sent_ = false;
137   size_t content_len_headers_ = 0;
138   size_t content_len_actual_ = 0;
139 
140   // If the origin is in the server's |allowed_origins_| this contains the
141   // origin itself. This is used to handle CORS headers.
142   std::string origin_allowed_;
143 
144   // By default treat connections as keep-alive unless the client says
145   // explicitly 'Connection: close'. This improves TraceProcessor's python API.
146   // This is consistent with that nginx does.
147   bool keepalive_ = true;
148 };
149 
150 class HttpRequestHandler {
151  public:
152   virtual ~HttpRequestHandler();
153   virtual void OnHttpRequest(const HttpRequest&) = 0;
154   virtual void OnWebsocketMessage(const WebsocketMessage&);
155   virtual void OnHttpConnectionClosed(HttpServerConnection*);
156 };
157 
158 class HttpServer : public UnixSocket::EventListener {
159  public:
160   HttpServer(TaskRunner*, HttpRequestHandler*);
161   ~HttpServer() override;
162   void Start(int port);
163   void AddAllowedOrigin(const std::string&);
164 
165  private:
166   size_t ParseOneHttpRequest(HttpServerConnection*);
167   size_t ParseOneWebsocketFrame(HttpServerConnection*);
168   void HandleCorsPreflightRequest(const HttpRequest&);
169   bool IsOriginAllowed(StringView);
170 
171   // UnixSocket::EventListener implementation.
172   void OnNewIncomingConnection(UnixSocket*,
173                                std::unique_ptr<UnixSocket>) override;
174   void OnConnect(UnixSocket* self, bool connected) override;
175   void OnDisconnect(UnixSocket* self) override;
176   void OnDataAvailable(UnixSocket* self) override;
177 
178   TaskRunner* const task_runner_;
179   HttpRequestHandler* req_handler_;
180   std::unique_ptr<UnixSocket> sock4_;
181   std::unique_ptr<UnixSocket> sock6_;
182   std::list<HttpServerConnection> clients_;
183   std::list<std::string> allowed_origins_;
184   bool origin_error_logged_ = false;
185 };
186 
187 }  // namespace perfetto::base
188 
189 #endif  // INCLUDE_PERFETTO_EXT_BASE_HTTP_HTTP_SERVER_H_
190