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