]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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> | |
11fdf7f2 TL |
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 | */ | |
f67539c2 TL |
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); | |
11fdf7f2 TL |
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) { | |
f67539c2 | 109 | _rules[type][_rover++] = rule; |
11fdf7f2 TL |
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 | ||
20effc67 TL |
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 | ||
11fdf7f2 TL |
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 | */ | |
1e59de90 | 141 | future<std::unique_ptr<http::reply> > handle(const sstring& path, std::unique_ptr<http::request> req, std::unique_ptr<http::reply> rep); |
11fdf7f2 TL |
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 | */ | |
f67539c2 TL |
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; | |
11fdf7f2 TL |
151 | } |
152 | ||
11fdf7f2 TL |
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 | ||
f67539c2 | 163 | private: |
11fdf7f2 TL |
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]; | |
f67539c2 TL |
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]; | |
20effc67 TL |
179 | //default Handler -- for any HTTP Method and Path (/*) |
180 | handler_base* _default_handler = nullptr; | |
11fdf7f2 | 181 | public: |
1e59de90 | 182 | using exception_handler_fun = std::function<std::unique_ptr<http::reply>(std::exception_ptr eptr)>; |
11fdf7f2 TL |
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 | ||
1e59de90 | 207 | std::unique_ptr<http::reply> exception_reply(std::exception_ptr eptr); |
11fdf7f2 TL |
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); | |
f67539c2 TL |
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); | |
11fdf7f2 TL |
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 | */ | |
1e59de90 | 246 | void verify_param(const http::request& req, const sstring& param); |
11fdf7f2 | 247 | |
f67539c2 TL |
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 | ||
11fdf7f2 TL |
297 | } |
298 | ||
299 | } |