/bitcoin/src/httpserver.h
Line | Count | Source |
1 | | // Copyright (c) 2015-2022 The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #ifndef BITCOIN_HTTPSERVER_H |
6 | | #define BITCOIN_HTTPSERVER_H |
7 | | |
8 | | #include <functional> |
9 | | #include <optional> |
10 | | #include <span> |
11 | | #include <string> |
12 | | |
13 | | namespace util { |
14 | | class SignalInterrupt; |
15 | | } // namespace util |
16 | | |
17 | | /** |
18 | | * The default value for `-rpcthreads`. This number of threads will be created at startup. |
19 | | */ |
20 | | static const int DEFAULT_HTTP_THREADS=16; |
21 | | |
22 | | /** |
23 | | * The default value for `-rpcworkqueue`. This is the maximum depth of the work queue, |
24 | | * we don't allocate this number of work queue items upfront. |
25 | | */ |
26 | | static const int DEFAULT_HTTP_WORKQUEUE=64; |
27 | | |
28 | | static const int DEFAULT_HTTP_SERVER_TIMEOUT=30; |
29 | | |
30 | | struct evhttp_request; |
31 | | struct event_base; |
32 | | class CService; |
33 | | class HTTPRequest; |
34 | | |
35 | | /** Initialize HTTP server. |
36 | | * Call this before RegisterHTTPHandler or EventBase(). |
37 | | */ |
38 | | bool InitHTTPServer(const util::SignalInterrupt& interrupt); |
39 | | /** Start HTTP server. |
40 | | * This is separate from InitHTTPServer to give users race-condition-free time |
41 | | * to register their handlers between InitHTTPServer and StartHTTPServer. |
42 | | */ |
43 | | void StartHTTPServer(); |
44 | | /** Interrupt HTTP server threads */ |
45 | | void InterruptHTTPServer(); |
46 | | /** Stop HTTP server */ |
47 | | void StopHTTPServer(); |
48 | | |
49 | | /** Change logging level for libevent. */ |
50 | | void UpdateHTTPServerLogging(bool enable); |
51 | | |
52 | | /** Handler for requests to a certain HTTP path */ |
53 | | typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler; |
54 | | /** Register handler for prefix. |
55 | | * If multiple handlers match a prefix, the first-registered one will |
56 | | * be invoked. |
57 | | */ |
58 | | void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler); |
59 | | /** Unregister handler for prefix */ |
60 | | void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch); |
61 | | |
62 | | /** Return evhttp event base. This can be used by submodules to |
63 | | * queue timers or custom events. |
64 | | */ |
65 | | struct event_base* EventBase(); |
66 | | |
67 | | /** In-flight HTTP request. |
68 | | * Thin C++ wrapper around evhttp_request. |
69 | | */ |
70 | | class HTTPRequest |
71 | | { |
72 | | private: |
73 | | struct evhttp_request* req; |
74 | | const util::SignalInterrupt& m_interrupt; |
75 | | bool replySent; |
76 | | |
77 | | public: |
78 | | explicit HTTPRequest(struct evhttp_request* req, const util::SignalInterrupt& interrupt, bool replySent = false); |
79 | | ~HTTPRequest(); |
80 | | |
81 | | enum RequestMethod { |
82 | | UNKNOWN, |
83 | | GET, |
84 | | POST, |
85 | | HEAD, |
86 | | PUT |
87 | | }; |
88 | | |
89 | | /** Get requested URI. |
90 | | */ |
91 | | std::string GetURI() const; |
92 | | |
93 | | /** Get CService (address:ip) for the origin of the http request. |
94 | | */ |
95 | | CService GetPeer() const; |
96 | | |
97 | | /** Get request method. |
98 | | */ |
99 | | RequestMethod GetRequestMethod() const; |
100 | | |
101 | | /** Get the query parameter value from request uri for a specified key, or std::nullopt if the |
102 | | * key is not found. |
103 | | * |
104 | | * If the query string contains duplicate keys, the first value is returned. Many web frameworks |
105 | | * would instead parse this as an array of values, but this is not (yet) implemented as it is |
106 | | * currently not needed in any of the endpoints. |
107 | | * |
108 | | * @param[in] key represents the query parameter of which the value is returned |
109 | | */ |
110 | | std::optional<std::string> GetQueryParameter(const std::string& key) const; |
111 | | |
112 | | /** |
113 | | * Get the request header specified by hdr, or an empty string. |
114 | | * Return a pair (isPresent,string). |
115 | | */ |
116 | | std::pair<bool, std::string> GetHeader(const std::string& hdr) const; |
117 | | |
118 | | /** |
119 | | * Read request body. |
120 | | * |
121 | | * @note As this consumes the underlying buffer, call this only once. |
122 | | * Repeated calls will return an empty string. |
123 | | */ |
124 | | std::string ReadBody(); |
125 | | |
126 | | /** |
127 | | * Write output header. |
128 | | * |
129 | | * @note call this before calling WriteErrorReply or Reply. |
130 | | */ |
131 | | void WriteHeader(const std::string& hdr, const std::string& value); |
132 | | |
133 | | /** |
134 | | * Write HTTP reply. |
135 | | * nStatus is the HTTP status code to send. |
136 | | * reply is the body of the reply. Keep it empty to send a standard message. |
137 | | * |
138 | | * @note Can be called only once. As this will give the request back to the |
139 | | * main thread, do not call any other HTTPRequest methods after calling this. |
140 | | */ |
141 | | void WriteReply(int nStatus, std::string_view reply = "") |
142 | 2.35M | { |
143 | 2.35M | WriteReply(nStatus, std::as_bytes(std::span{reply})); |
144 | 2.35M | } |
145 | | void WriteReply(int nStatus, std::span<const std::byte> reply); |
146 | | }; |
147 | | |
148 | | /** Get the query parameter value from request uri for a specified key, or std::nullopt if the key |
149 | | * is not found. |
150 | | * |
151 | | * If the query string contains duplicate keys, the first value is returned. Many web frameworks |
152 | | * would instead parse this as an array of values, but this is not (yet) implemented as it is |
153 | | * currently not needed in any of the endpoints. |
154 | | * |
155 | | * Helper function for HTTPRequest::GetQueryParameter. |
156 | | * |
157 | | * @param[in] uri is the entire request uri |
158 | | * @param[in] key represents the query parameter of which the value is returned |
159 | | */ |
160 | | std::optional<std::string> GetQueryParameterFromUri(const char* uri, const std::string& key); |
161 | | |
162 | | /** Event handler closure. |
163 | | */ |
164 | | class HTTPClosure |
165 | | { |
166 | | public: |
167 | | virtual void operator()() = 0; |
168 | 2.35M | virtual ~HTTPClosure() = default; |
169 | | }; |
170 | | |
171 | | /** Event class. This can be used either as a cross-thread trigger or as a timer. |
172 | | */ |
173 | | class HTTPEvent |
174 | | { |
175 | | public: |
176 | | /** Create a new event. |
177 | | * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called) |
178 | | * handler is the handler to call when the event is triggered. |
179 | | */ |
180 | | HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void()>& handler); |
181 | | ~HTTPEvent(); |
182 | | |
183 | | /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after |
184 | | * the given time has elapsed. |
185 | | */ |
186 | | void trigger(struct timeval* tv); |
187 | | |
188 | | bool deleteWhenTriggered; |
189 | | std::function<void()> handler; |
190 | | private: |
191 | | struct event* ev; |
192 | | }; |
193 | | |
194 | | #endif // BITCOIN_HTTPSERVER_H |