]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/http/routes.hh
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / include / seastar / http / routes.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright 2015 Cloudius Systems
20 */
21
22 #pragma once
23
24 #include <seastar/http/matchrules.hh>
25 #include <seastar/http/handlers.hh>
26 #include <seastar/http/common.hh>
27 #include <seastar/http/reply.hh>
28
29 #include <boost/program_options/variables_map.hpp>
30 #include <unordered_map>
31
32 namespace seastar {
33
34 namespace httpd {
35
36 /**
37 * The url helps defining a route.
38 */
39 class url {
40 public:
41 /**
42 * Move constructor
43 */
44 url(url&&) = default;
45
46 /**
47 * Construct with a url path as it's parameter
48 * @param path the url path to be used
49 */
50 url(const sstring& path)
51 : _path(path) {
52 }
53
54 /**
55 * Adds a parameter that matches untill the end of the URL.
56 * @param param the parmaeter name
57 * @return the current url
58 */
59 url& remainder(const sstring& param) {
60 this->_param = param;
61 return *this;
62 }
63
64 sstring _path;
65 sstring _param;
66 };
67
68 struct path_description;
69
70 /**
71 * routes object do the request dispatching according to the url.
72 * It uses two decision mechanism exact match, if a url matches exactly
73 * (an optional leading slash is permitted) it is choosen
74 * If not, the matching rules are used.
75 * matching rules are evaluated by their insertion order
76 */
77 class routes {
78 public:
79 /**
80 * The destructor deletes the match rules and handlers
81 */
82 ~routes();
83
84 /**
85 * adding a handler as an exact match
86 * @param url the url to match (note that url should start with /)
87 * @param handler the desire handler
88 * @return it self
89 */
90 routes& put(operation_type type, const sstring& url, handler_base* handler);
91
92 /**
93 * removing a handler from exact match
94 * @param url the url to match (note that url should start with /)
95 * @return the current handler (to be removed by caller)
96 */
97 handler_base* drop(operation_type type, const sstring& url);
98
99 /**
100 * add a rule to be used.
101 * rules are search only if an exact match was not found.
102 * rules are search by the order they were added.
103 * First in higher priority
104 * @param rule a rule to add
105 * @param type the operation type
106 * @return it self
107 */
108 routes& add(match_rule* rule, operation_type type = GET) {
109 _rules[type][_rover++] = rule;
110 return *this;
111 }
112
113 /**
114 * Add a url match to a handler:
115 * Example routes.add(GET, url("/api").remainder("path"), handler);
116 * @param type
117 * @param url
118 * @param handler
119 * @return
120 */
121 routes& add(operation_type type, const url& url, handler_base* handler);
122
123 /**
124 * Add a default handler - handles any HTTP Method and Path (/\*) combination:
125 * Example routes.add_default_handler(handler);
126 * @param handler
127 * @return
128 */
129 routes& add_default_handler(handler_base* handler);
130
131 /**
132 * the main entry point.
133 * the general handler calls this method with the request
134 * the method takes the headers from the request and find the
135 * right handler.
136 * It then call the handler with the parameters (if they exists) found in the url
137 * @param path the url path found
138 * @param req the http request
139 * @param rep the http reply
140 */
141 future<std::unique_ptr<http::reply> > handle(const sstring& path, std::unique_ptr<http::request> req, std::unique_ptr<http::reply> rep);
142
143 /**
144 * Search and return an exact match
145 * @param url the request url
146 * @return the handler if exists or nullptr if it does not
147 */
148 handler_base* get_exact_match(operation_type type, const sstring& url) const {
149 auto i = _map[type].find(url);
150 return (i == _map[type].end()) ? nullptr : i->second;
151 }
152
153 /**
154 * Search and return a handler by the operation type and url
155 * @param type the http operation type
156 * @param url the request url
157 * @param params a parameter object that will be filled during the match
158 * @return a handler based on the type/url match
159 */
160 handler_base* get_handler(operation_type type, const sstring& url,
161 parameters& params);
162
163 private:
164 /**
165 * Normalize the url to remove the last / if exists
166 * and get the parameter part
167 * @param url the full url path
168 * @param param_part will hold the string with the parameters
169 * @return the url from the request without the last /
170 */
171 sstring normalize_url(const sstring& url);
172
173 std::unordered_map<sstring, handler_base*> _map[NUM_OPERATION];
174 public:
175 using rule_cookie = uint64_t;
176 private:
177 rule_cookie _rover = 0;
178 std::map<rule_cookie, match_rule*> _rules[NUM_OPERATION];
179 //default Handler -- for any HTTP Method and Path (/*)
180 handler_base* _default_handler = nullptr;
181 public:
182 using exception_handler_fun = std::function<std::unique_ptr<http::reply>(std::exception_ptr eptr)>;
183 using exception_handler_id = size_t;
184 private:
185 std::map<exception_handler_id, exception_handler_fun> _exceptions;
186 exception_handler_id _exception_id = 0;
187 // for optimization reason, the lambda function
188 // that calls the exception_reply of the current object
189 // is stored
190 exception_handler_fun _general_handler;
191 public:
192 /**
193 * The exception_handler_fun expect to call
194 * std::rethrow_exception(eptr);
195 * and catch only the exception it handles
196 */
197 exception_handler_id register_exeption_handler(exception_handler_fun fun) {
198 auto current = _exception_id++;
199 _exceptions[current] = fun;
200 return current;
201 }
202
203 void remove_exception_handler(exception_handler_id id) {
204 _exceptions.erase(id);
205 }
206
207 std::unique_ptr<http::reply> exception_reply(std::exception_ptr eptr);
208
209 routes();
210
211 /*!
212 * \brief add an alias to an already registered path.
213 * After registering a handler to a path, use this method
214 * to add an alias to that handler.
215 *
216 */
217 void add_alias(const path_description& old_path, const path_description& new_path);
218
219 /**
220 * Add a rule to be used.
221 * @param rule a rule to add
222 * @param type the operation type
223 * @return a cookie using which the rule can be removed
224 */
225 rule_cookie add_cookie(match_rule* rule, operation_type type) {
226 auto pos = _rover++;
227 _rules[type][pos] = rule;
228 return pos;
229 }
230
231 /**
232 * Del a rule by cookie
233 * @param cookie a cookie returned previously by add_cookie
234 * @param type the operation type
235 * @return the pointer to the rule
236 */
237 match_rule* del_cookie(rule_cookie cookie, operation_type type);
238 };
239
240 /**
241 * A helper function that check if a parameter is found in the params object
242 * if it does not the function would throw a parameter not found exception
243 * @param params the parameters object
244 * @param param the parameter to look for
245 */
246 void verify_param(const http::request& req, const sstring& param);
247
248 /**
249 * The handler_registration object facilitates registration and auto
250 * unregistration of an exact-match handler_base into \ref routes "routes"
251 */
252 class handler_registration {
253 routes& _routes;
254 const sstring _url;
255 operation_type _op;
256
257 public:
258 /**
259 * Registers the handler_base into routes with routes::put
260 * @param rs the routes object reference
261 * @param h the desire handler
262 * @param url the url to match
263 * @param op the operation type (`GET` by default)
264 */
265 handler_registration(routes& rs, handler_base& h, const sstring& url, operation_type op = GET);
266
267 /**
268 * Unregisters the handler from routes with routes::drop
269 */
270 ~handler_registration();
271 };
272
273 /**
274 * The rule_registration object facilitates registration and auto
275 * unregistration of a match_rule handler into \ref routes "routes"
276 */
277 class rule_registration {
278 routes& _routes;
279 operation_type _op;
280 routes::rule_cookie _cookie;
281
282 public:
283 /**
284 * Registers the match_rule into routes with routes::add_cookie
285 * @param rs the routes object reference
286 * @param rule a rule to add
287 * @param op the operation type (`GET` by default)
288 */
289 rule_registration(routes& rs, match_rule& rule, operation_type op = GET);
290
291 /**
292 * Unregisters the rule from routes with routes::del_cookie
293 */
294 ~rule_registration();
295 };
296
297 }
298
299 }