1
#pragma once
2

            
3
#include <functional>
4
#include <string>
5

            
6
#include "envoy/buffer/buffer.h"
7
#include "envoy/common/pure.h"
8
#include "envoy/http/codes.h"
9
#include "envoy/http/filter.h"
10
#include "envoy/http/header_map.h"
11
#include "envoy/http/query_params.h"
12
#include "envoy/network/listen_socket.h"
13
#include "envoy/server/config_tracker.h"
14

            
15
#include "absl/strings/string_view.h"
16

            
17
namespace Envoy {
18
namespace Server {
19

            
20
class AdminStream {
21
public:
22
612
  virtual ~AdminStream() = default;
23

            
24
  /**
25
   * @param end_stream set to false for streaming response. Default is true, which will
26
   * end the response when the initial handler completes.
27
   */
28
  virtual void setEndStreamOnComplete(bool end_stream) PURE;
29

            
30
  /**
31
   * @param cb callback to be added to the list of callbacks invoked by onDestroy() when stream
32
   * is closed.
33
   */
34
  virtual void addOnDestroyCallback(std::function<void()> cb) PURE;
35

            
36
  /**
37
   * @return Http::StreamDecoderFilterCallbacks& to be used by the handler to get HTTP request data
38
   * for streaming.
39
   */
40
  virtual Http::StreamDecoderFilterCallbacks& getDecoderFilterCallbacks() const PURE;
41

            
42
  /**
43
   * @return const Buffer::Instance* the fully buffered admin request if applicable.
44
   */
45
  virtual const Buffer::Instance* getRequestBody() const PURE;
46

            
47
  /**
48
   * @return Http::HeaderMap& to be used by handler to parse header information sent with the
49
   * request.
50
   */
51
  virtual const Http::RequestHeaderMap& getRequestHeaders() const PURE;
52

            
53
  /**
54
   * Return the HTTP/1 stream encoder options if applicable. If the stream is not HTTP/1 returns
55
   * absl::nullopt.
56
   */
57
  virtual Http::Http1StreamEncoderOptionsOptRef http1StreamEncoderOptions() PURE;
58

            
59
  /**
60
   * Construct query-param map for the stream, using the URL-specified params,
61
   * or the request data if that is url-form-encoded.
62
   *
63
   * @param The query name/value map.
64
   */
65
  virtual Http::Utility::QueryParamsMulti queryParams() const PURE;
66
};
67

            
68
/**
69
 * This macro is used to add handlers to the Admin HTTP Endpoint. It builds
70
 * a callback that executes X when the specified admin handler is hit. This macro can be
71
 * used to add static handlers as in source/server/admin/admin.cc and also dynamic handlers as
72
 * done in the RouteConfigProviderManagerImpl constructor in source/common/router/rds_impl.cc.
73
 */
74
#define MAKE_ADMIN_HANDLER(X)                                                                      \
75
332823
  [this](Http::ResponseHeaderMap& response_headers, Buffer::Instance& data,                        \
76
332823
         Server::AdminStream& admin_stream) -> Http::Code {                                        \
77
512
    return X(response_headers, data, admin_stream);                                                \
78
512
  }
79

            
80
/**
81
 * Global admin HTTP endpoint for the server, holding a map from URL prefixes to
82
 * handlers. When an HTTP request arrives at the admin port, the URL is linearly
83
 * prefixed-matched against an ordered list of handlers. When a match is found,
84
 * the handler is used to generate a Request.
85
 *
86
 * Requests are capable of streaming out content to the client, however, most
87
 * requests are delivered all at once. The implementation supplies adapters for
88
 * simplifying the creation of streaming requests based on a simple callback
89
 * that takes a URL and generates response headers and response body.
90
 *
91
 * A Taxonomy of the major types involved may help clarify:
92
 *   Request     a class holding state for streaming admin content to clients.
93
 *               These are re-created for each request.
94
 *   Handler     a class that holds context for a family of admin requests,
95
 *               supplying one-shot callbacks for non-streamed responses, and
96
 *               for generating Request objects directly for streamed responses.
97
 *               These have the same lifetime as Admin objects.
98
 *   Admin       Holds the ordered list of handlers to be prefix-matched.
99
 */
100
class Admin {
101
public:
102
50762
  virtual ~Admin() = default;
103

            
104
  // Describes a parameter for an endpoint. This structure is used when
105
  // admin-html has not been disabled to populate an HTML form to enable a
106
  // visitor to the admin console to intuitively specify query-parameters for
107
  // each endpoint. The parameter descriptions also appear in the /help
108
  // endpoint, independent of how Envoy is compiled.
109
  struct ParamDescriptor {
110
    enum class Type { Boolean, String, Enum };
111
    Type type_;
112
    std::string id_;   // HTML form ID and query-param name (JS var name rules).
113
    std::string help_; // Rendered into home-page HTML and /help text.
114
    std::vector<absl::string_view> enum_choices_{};
115
  };
116
  using ParamDescriptorVec = std::vector<ParamDescriptor>;
117

            
118
  // Represents a request for admin endpoints, enabling streamed responses.
119
  class Request {
120
  public:
121
911
    virtual ~Request() = default;
122

            
123
    /**
124
     * Initiates a handler. The URL can be supplied to the constructor if needed.
125
     *
126
     * @param response_headers successful text responses don't need to modify this,
127
     *        but if we want to respond with (e.g.) JSON or HTML we can can set
128
     *        those here.
129
     * @return the HTTP status of the response.
130
     */
131
    virtual Http::Code start(Http::ResponseHeaderMap& response_headers) PURE;
132

            
133
    /**
134
     * Adds the next chunk of data to the response. Note that nextChunk can
135
     * return 'true' but not add any data to the response, in which case a chunk
136
     * is not sent, and a subsequent call to nextChunk can be made later,
137
     * possibly after a post() or low-watermark callback on the http filter.
138
     *
139
     * It is not necessary for the caller to drain the response after each call;
140
     * it can leave the data in response if it's necessary to buffer the entire
141
     * response prior to sending it to the network. It is preferable to stream
142
     * the data out, draining the response buffer on each call, but not
143
     * required.
144
     *
145
     * @param response a buffer in which to write the chunk
146
     * @return whether or not any chunks follow this one.
147
     */
148
    virtual bool nextChunk(Buffer::Instance& response) PURE;
149
  };
150
  using RequestPtr = std::unique_ptr<Request>;
151

            
152
  /**
153
   * Lambda to generate a Request.
154
   */
155
  using GenRequestFn = std::function<RequestPtr(AdminStream&)>;
156

            
157
  /**
158
   * Individual admin handler including prefix, help text, and callback.
159
   */
160
  struct UrlHandler {
161
    const std::string prefix_;
162
    const std::string help_text_;
163
    const GenRequestFn handler_;
164
    const bool removable_;
165
    const bool mutates_server_state_;
166
    const ParamDescriptorVec params_{};
167
  };
168

            
169
  /**
170
   * Callback for admin URL handlers.
171
   * @param path_and_query supplies the path and query of the request URL.
172
   * @param response_headers enables setting of http headers (e.g., content-type, cache-control) in
173
   * the handler.
174
   * @param response supplies the buffer to fill in with the response body.
175
   * @param admin_stream supplies the filter which invoked the handler, enables the handler to use
176
   * its data.
177
   * @return Http::Code the response code.
178
   */
179
  using HandlerCb =
180
      std::function<Http::Code(Http::ResponseHeaderMap& response_headers,
181
                               Buffer::Instance& response, AdminStream& admin_stream)>;
182

            
183
  /**
184
   * Add a legacy admin handler where the entire response is written in
185
   * one chunk.
186
   *
187
   * @param prefix supplies the URL prefix to handle.
188
   * @param help_text supplies the help text for the handler.
189
   * @param callback supplies the callback to invoke when the prefix matches.
190
   * @param removable if true allows the handler to be removed via removeHandler.
191
   * @param mutates_server_state indicates whether callback will mutate server state.
192
   * @param params command parameter descriptors.
193
   * @return bool true if the handler was added, false if it was not added.
194
   */
195
  virtual bool addHandler(const std::string& prefix, const std::string& help_text,
196
                          HandlerCb callback, bool removable, bool mutates_server_state,
197
                          const ParamDescriptorVec& params = {}) PURE;
198

            
199
  /**
200
   * Adds a an chunked admin handler.
201
   *
202
   * @param prefix supplies the URL prefix to handle.
203
   * @param help_text supplies the help text for the handler.
204
   * @param gen_request supplies the callback to generate a Request.
205
   * @param removable if true allows the handler to be removed via removeHandler.
206
   * @param mutates_server_state indicates whether callback will mutate server state.
207
   * @param params command parameter descriptors.
208
   * @return bool true if the handler was added, false if it was not added.
209
   */
210
  virtual bool addStreamingHandler(const std::string& prefix, const std::string& help_text,
211
                                   GenRequestFn gen_request, bool removable,
212
                                   bool mutates_server_state,
213
                                   const ParamDescriptorVec& params = {}) PURE;
214

            
215
  /**
216
   * Remove an admin handler if it is removable.
217
   * @param prefix supplies the URL prefix of the handler to delete.
218
   * @return bool true if the handler was removed, false if it was not removed.
219
   */
220
  virtual bool removeHandler(const std::string& prefix) PURE;
221

            
222
  /**
223
   * Obtain socket the admin endpoint is bound to.
224
   * @return Network::Socket& socket reference.
225
   */
226
  virtual const Network::Socket& socket() PURE;
227

            
228
  /**
229
   * @return ConfigTracker& tracker for /config_dump endpoint.
230
   */
231
  virtual ConfigTracker& getConfigTracker() PURE;
232

            
233
  /**
234
   * Expose this Admin console as an HTTP server.
235
   * @param access_logs access_logs list of file loggers to write the HTTP request log to.
236
   * @param address network address to bind and listen on.
237
   * @param socket_options socket options to apply to the listening socket.
238
   */
239
  virtual void startHttpListener(AccessLog::InstanceSharedPtrVector access_logs,
240
                                 Network::Address::InstanceConstSharedPtr address,
241
                                 Network::Socket::OptionsSharedPtr socket_options) PURE;
242

            
243
  /**
244
   * Executes an admin request with the specified query params. Note: this must
245
   * be called from Envoy's main thread.
246
   *
247
   * @param path_and_query the path and query of the admin URL.
248
   * @param method the HTTP method (POST or GET).
249
   * @param response_headers populated the response headers from executing the request,
250
   *     most notably content-type.
251
   * @param body populated with the response-body from the admin request.
252
   * @return Http::Code The HTTP response code from the admin request.
253
   */
254
  virtual Http::Code request(absl::string_view path_and_query, absl::string_view method,
255
                             Http::ResponseHeaderMap& response_headers, std::string& body) PURE;
256

            
257
  /**
258
   * Add this Admin's listener to the provided handler, if the listener exists.
259
   * Throws an exception if the listener does not exist.
260
   * @param handler the handler that will receive this Admin's listener.
261
   */
262
  virtual void addListenerToHandler(Network::ConnectionHandler* handler) PURE;
263

            
264
  /**
265
   * @return the number of worker threads to run in the server.
266
   */
267
  virtual uint32_t concurrency() const PURE;
268

            
269
  /**
270
   * Makes a request for streamed static text. The version that takes the
271
   * Buffer::Instance& transfers the content from the passed-in buffer.
272
   *
273
   * @param response_text the text to populate response with
274
   * @param code the Http::Code for the response
275
   * @return the request
276
   */
277
  static RequestPtr makeStaticTextRequest(absl::string_view response_text, Http::Code code);
278
  static RequestPtr makeStaticTextRequest(Buffer::Instance& response_text, Http::Code code);
279

            
280
  /**
281
   * Closes the listening socket for the admin.
282
   */
283
  virtual void closeSocket() PURE;
284

            
285
  /**
286
   * Creates a streaming request context from the url path in the admin stream.
287
   */
288
  virtual RequestPtr makeRequest(AdminStream& admin_stream) const PURE;
289
};
290

            
291
} // namespace Server
292
} // namespace Envoy