Line data Source code
1 : // Copyright (c) 2015-present 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 0 : void WriteReply(int nStatus, std::string_view reply = "")
142 : {
143 0 : WriteReply(nStatus, std::as_bytes(std::span{reply}));
144 0 : }
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 class. This can be used either as a cross-thread trigger or as a timer.
163 : */
164 : class HTTPEvent
165 : {
166 : public:
167 : /** Create a new event.
168 : * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called)
169 : * handler is the handler to call when the event is triggered.
170 : */
171 : HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void()>& handler);
172 : ~HTTPEvent();
173 :
174 : /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
175 : * the given time has elapsed.
176 : */
177 : void trigger(struct timeval* tv);
178 :
179 : bool deleteWhenTriggered;
180 : std::function<void()> handler;
181 : private:
182 : struct event* ev;
183 : };
184 :
185 : #endif // BITCOIN_HTTPSERVER_H
|