forked from scylladb/seastar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathroutes.hh
211 lines (185 loc) · 6.09 KB
/
routes.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright 2015 Cloudius Systems
*/
#ifndef ROUTES_HH_
#define ROUTES_HH_
#include "matchrules.hh"
#include "handlers.hh"
#include "common.hh"
#include "reply.hh"
#include <boost/program_options/variables_map.hpp>
#include <unordered_map>
#include <vector>
#include "core/future-util.hh"
namespace seastar {
namespace httpd {
/**
* The url helps defining a route.
*/
class url {
public:
/**
* Move constructor
*/
url(url&&) = default;
/**
* Construct with a url path as it's parameter
* @param path the url path to be used
*/
url(const sstring& path)
: _path(path) {
}
/**
* Adds a parameter that matches untill the end of the URL.
* @param param the parmaeter name
* @return the current url
*/
url& remainder(const sstring& param) {
this->_param = param;
return *this;
}
sstring _path;
sstring _param;
};
/**
* routes object do the request dispatching according to the url.
* It uses two decision mechanism exact match, if a url matches exactly
* (an optional leading slash is permitted) it is choosen
* If not, the matching rules are used.
* matching rules are evaluated by their insertion order
*/
class routes {
public:
/**
* The destructor deletes the match rules and handlers
*/
~routes();
/**
* adding a handler as an exact match
* @param url the url to match (note that url should start with /)
* @param handler the desire handler
* @return it self
*/
routes& put(operation_type type, const sstring& url,
handler_base* handler) {
//FIXME if a handler is already exists, it need to be
// deleted to prevent memory leak
_map[type][url] = handler;
return *this;
}
/**
* add a rule to be used.
* rules are search only if an exact match was not found.
* rules are search by the order they were added.
* First in higher priority
* @param rule a rule to add
* @param type the operation type
* @return it self
*/
routes& add(match_rule* rule, operation_type type = GET) {
_rules[type].push_back(rule);
return *this;
}
/**
* Add a url match to a handler:
* Example routes.add(GET, url("/api").remainder("path"), handler);
* @param type
* @param url
* @param handler
* @return
*/
routes& add(operation_type type, const url& url, handler_base* handler);
/**
* the main entry point.
* the general handler calls this method with the request
* the method takes the headers from the request and find the
* right handler.
* It then call the handler with the parameters (if they exists) found in the url
* @param path the url path found
* @param req the http request
* @param rep the http reply
*/
future<std::unique_ptr<reply> > handle(const sstring& path, std::unique_ptr<request> req, std::unique_ptr<reply> rep);
/**
* Search and return an exact match
* @param url the request url
* @return the handler if exists or nullptr if it does not
*/
handler_base* get_exact_match(operation_type type, const sstring& url) {
return (_map[type].find(url) == _map[type].end()) ?
nullptr : _map[type][url];
}
private:
/**
* Search and return a handler by the operation type and url
* @param type the http operation type
* @param url the request url
* @param params a parameter object that will be filled during the match
* @return a handler based on the type/url match
*/
handler_base* get_handler(operation_type type, const sstring& url,
parameters& params);
/**
* Normalize the url to remove the last / if exists
* and get the parameter part
* @param url the full url path
* @param param_part will hold the string with the parameters
* @return the url from the request without the last /
*/
sstring normalize_url(const sstring& url);
std::unordered_map<sstring, handler_base*> _map[NUM_OPERATION];
std::vector<match_rule*> _rules[NUM_OPERATION];
public:
using exception_handler_fun = std::function<std::unique_ptr<reply>(std::exception_ptr eptr)>;
using exception_handler_id = size_t;
private:
std::map<exception_handler_id, exception_handler_fun> _exceptions;
exception_handler_id _exception_id = 0;
// for optimization reason, the lambda function
// that calls the exception_reply of the current object
// is stored
exception_handler_fun _general_handler;
public:
/**
* The exception_handler_fun expect to call
* std::rethrow_exception(eptr);
* and catch only the exception it handles
*/
exception_handler_id register_exeption_handler(exception_handler_fun fun) {
auto current = _exception_id++;
_exceptions[current] = fun;
return current;
}
void remove_exception_handler(exception_handler_id id) {
_exceptions.erase(id);
}
std::unique_ptr<reply> exception_reply(std::exception_ptr eptr);
routes();
};
/**
* A helper function that check if a parameter is found in the params object
* if it does not the function would throw a parameter not found exception
* @param params the parameters object
* @param param the parameter to look for
*/
void verify_param(const httpd::request& req, const sstring& param);
}
}
#endif /* ROUTES_HH_ */