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