1 /*
2  * Copyright (C) 2019 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 #pragma once
18 
19 #include <https/ServerSocket.h>
20 #include <https/WebSocketHandler.h>
21 
22 #include <functional>
23 #include <mutex>
24 #include <optional>
25 #include <string>
26 #include <unordered_map>
27 #include <variant>
28 #include <vector>
29 
30 struct HTTPRequest;
31 
32 struct HTTPServer {
33     explicit HTTPServer(
34             std::shared_ptr<RunLoop> runLoop,
35             const char *iface = nullptr, // defaults to 0.0.0.0, i.e. INADDR_ANY
36             uint16_t port = 8443,
37             ServerSocket::TransportType transportType =
38                     ServerSocket::TransportType::TLS,
39             const std::optional<std::string> &certificate_pem_path =
40                     std::nullopt,
41             const std::optional<std::string> &private_key_pem_path =
42                     std::nullopt);
43 
44     HTTPServer(const HTTPServer &) = delete;
45     HTTPServer &operator=(const HTTPServer &) = delete;
46 
47     uint16_t getLocalPort() const;
48 
49     void run();
50 
51     // Returns true iff the client should close the connection.
52     bool handleSingleRequest(
53             ClientSocket *client, const uint8_t *data, size_t size, bool isEOS);
54 
55     void addStaticFile(
56             const char *at,
57             const char *path,
58             std::optional<std::string> mimeType = std::nullopt);
59 
60     void addStaticContent(
61             const char *at,
62             const void *data,
63             size_t size,
64             std::optional<std::string> mimeType = std::nullopt);
65 
66     using WebSocketHandlerFactory =
67         std::function<std::pair<int32_t, std::shared_ptr<WebSocketHandler>>()>;
68 
69     void addWebSocketHandlerFactory(
70             const char *at, WebSocketHandlerFactory factory);
71 
72     std::optional<std::string> certificate_pem_path() const;
73     std::optional<std::string> private_key_pem_path() const;
74 
75 private:
76     struct StaticFileInfo {
77         std::variant<std::string, std::vector<uint8_t>> mPathOrContent;
78         std::optional<std::string> mMimeType;
79     };
80 
81     std::shared_ptr<RunLoop> mRunLoop;
82     uint16_t mLocalPort;
83 
84     std::shared_ptr<ServerSocket> mSocketTLS;
85 
86     // Protects mStaticFiles and mWebSocketHandlerFactories below.
87     std::mutex mContentLock;
88 
89     std::unordered_map<std::string, StaticFileInfo> mStaticFiles;
90 
91     std::unordered_map<std::string, WebSocketHandlerFactory>
92         mWebSocketHandlerFactories;
93 
94     void handleWebSocketRequest(
95             ClientSocket *clientSocket,
96             WebSocketHandlerFactory factory,
97             const HTTPRequest &request,
98             int32_t *httpResultCode,
99             std::unordered_map<std::string, std::string> *responseHeaders,
100             std::string *body);
101 
102     void handleStaticFileRequest(
103             const StaticFileInfo &info,
104             const HTTPRequest &request,
105             int32_t *httpResultCode,
106             std::unordered_map<std::string, std::string> *responseHeaders,
107             std::string *body);
108 
109     static std::string GuessMimeType(const std::string &path);
110 };
111