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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright 2015 Cloudius Systems
24 #include <seastar/http/matchrules.hh>
25 #include <seastar/http/handlers.hh>
26 #include <seastar/http/common.hh>
27 #include <seastar/http/reply.hh>
29 #include <boost/program_options/variables_map.hpp>
30 #include <unordered_map>
37 * The url helps defining a route.
47 * Construct with a url path as it's parameter
48 * @param path the url path to be used
50 url(const sstring& path)
55 * Adds a parameter that matches untill the end of the URL.
56 * @param param the parmaeter name
57 * @return the current url
59 url& remainder(const sstring& param) {
68 struct path_description;
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
80 * The destructor deletes the match rules and handlers
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
90 routes& put(operation_type type, const sstring& url, handler_base* handler);
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)
97 handler_base* drop(operation_type type, const sstring& url);
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
108 routes& add(match_rule* rule, operation_type type = GET) {
109 _rules[type][_rover++] = rule;
114 * Add a url match to a handler:
115 * Example routes.add(GET, url("/api").remainder("path"), handler);
121 routes& add(operation_type type, const url& url, handler_base* handler);
124 * Add a default handler - handles any HTTP Method and Path (/\*) combination:
125 * Example routes.add_default_handler(handler);
129 routes& add_default_handler(handler_base* handler);
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
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
141 future<std::unique_ptr<http::reply> > handle(const sstring& path, std::unique_ptr<http::request> req, std::unique_ptr<http::reply> rep);
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
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;
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
160 handler_base* get_handler(operation_type type, const sstring& url,
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 /
171 sstring normalize_url(const sstring& url);
173 std::unordered_map<sstring, handler_base*> _map[NUM_OPERATION];
175 using rule_cookie = uint64_t;
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;
182 using exception_handler_fun = std::function<std::unique_ptr<http::reply>(std::exception_ptr eptr)>;
183 using exception_handler_id = size_t;
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
190 exception_handler_fun _general_handler;
193 * The exception_handler_fun expect to call
194 * std::rethrow_exception(eptr);
195 * and catch only the exception it handles
197 exception_handler_id register_exeption_handler(exception_handler_fun fun) {
198 auto current = _exception_id++;
199 _exceptions[current] = fun;
203 void remove_exception_handler(exception_handler_id id) {
204 _exceptions.erase(id);
207 std::unique_ptr<http::reply> exception_reply(std::exception_ptr eptr);
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.
217 void add_alias(const path_description& old_path, const path_description& new_path);
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
225 rule_cookie add_cookie(match_rule* rule, operation_type type) {
227 _rules[type][pos] = rule;
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
237 match_rule* del_cookie(rule_cookie cookie, operation_type type);
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
246 void verify_param(const http::request& req, const sstring& param);
249 * The handler_registration object facilitates registration and auto
250 * unregistration of an exact-match handler_base into \ref routes "routes"
252 class handler_registration {
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)
265 handler_registration(routes& rs, handler_base& h, const sstring& url, operation_type op = GET);
268 * Unregisters the handler from routes with routes::drop
270 ~handler_registration();
274 * The rule_registration object facilitates registration and auto
275 * unregistration of a match_rule handler into \ref routes "routes"
277 class rule_registration {
280 routes::rule_cookie _cookie;
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)
289 rule_registration(routes& rs, match_rule& rule, operation_type op = GET);
292 * Unregisters the rule from routes with routes::del_cookie
294 ~rule_registration();