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