60
60
#include < boost/algorithm/string.hpp>
61
61
#include < fmt/core.h>
62
62
63
- using boost::fusion::make_cons;
64
- using boost::fusion::invoke;
65
-
66
- namespace al = boost::algorithm;
67
63
68
64
/* *
69
65
* maps router DSL expressions to constructors for handlers. this means it's
@@ -77,21 +73,11 @@ struct router {
77
73
virtual bool invoke_if (const std::vector<std::string> &, request &, handler_ptr_t &) = 0;
78
74
};
79
75
80
- using rule_ptr = std::unique_ptr<rule_base>;
81
-
82
76
// concrete rule match / constructor class
83
- template <typename rule_t , typename func_t >
77
+ template <typename Handler , typename Rule>
84
78
struct rule : public rule_base {
85
- // the DSL rule expression to match
86
- rule_t r;
87
-
88
- // the function to call (used later as constructor factory)
89
- func_t func;
90
-
91
- rule (rule_t r_, func_t f_) :
92
- r (std::move(r_)),
93
- func (f_)
94
- {}
79
+ explicit rule (Rule&& r) : r(std::move(r)) {}
80
+ ~rule () override = default ;
95
81
96
82
// try to match the expression. if it succeeds, call the provided function
97
83
// with the provided params and the matched DSL arguments.
@@ -101,15 +87,24 @@ struct router {
101
87
try {
102
88
auto begin = parts.begin ();
103
89
auto sequence = r.match (begin, parts.end ());
104
- if (begin!=parts.end ())
105
- throw match::error ();
90
+
91
+ if (begin != parts.end ())
92
+ return false ; // no match
93
+
94
+ // the function to call (used later as constructor factory)
95
+ boost::factory<Handler *> func{};
96
+
106
97
ptr.reset (
107
- invoke (func, make_cons (std::ref (params), sequence)));
108
- return true ;
98
+ boost::fusion::invoke (func, boost::fusion::make_cons (std::ref (params), sequence)));
109
99
} catch (const match::error &e) {
110
100
return false ;
111
101
}
102
+ return true ;
112
103
}
104
+
105
+ private:
106
+ // the DSL rule expression to match
107
+ Rule r;
113
108
};
114
109
115
110
/* add a match all methods rule (a DSL expression) which constructs the Handler
@@ -119,47 +114,36 @@ struct router {
119
114
*/
120
115
121
116
// add rule to match HTTP GET method only
122
- template <typename Handler, typename Rule> router& GET (Rule r) {
123
- // functor to create Handler instances
124
- boost::factory<Handler *> ctor;
117
+ template <typename Handler, typename Rule> router& GET (Rule&& r) {
125
118
126
119
static_assert (std::is_base_of<handler, Handler>::value, " GET rule requires handler subclass" );
127
120
static_assert (!std::is_base_of<payload_enabled_handler, Handler>::value, " GET rule cannot use payload enabled handler subclass" );
128
121
129
- rules_get.push_back (
130
- rule_ptr (new rule<Rule, boost::factory<Handler *> >(std::move (r), ctor)));
122
+ rules_get.push_back (std::make_unique<rule<Handler, Rule> >(std::move (r)));
131
123
return *this ;
132
124
}
133
125
134
126
// add rule to match HTTP POST method only
135
- template <typename Handler, typename Rule> router& POST (Rule r) {
136
- // functor to create Handler instances
137
- boost::factory<Handler *> ctor;
127
+ template <typename Handler, typename Rule> router& POST (Rule&& r) {
138
128
139
129
static_assert (std::is_base_of<payload_enabled_handler, Handler>::value, " POST rule requires payload enabled handler subclass" );
140
130
141
- rules_post.push_back (
142
- rule_ptr (new rule<Rule, boost::factory<Handler *> >(std::move (r), ctor)));
131
+ rules_post.push_back (std::make_unique<rule<Handler, Rule> >(std::move (r)));
143
132
return *this ;
144
133
}
145
134
146
-
147
135
// add rule to match HTTP PUT method only
148
- template <typename Handler, typename Rule> router& PUT (Rule r) {
149
- // functor to create Handler instances
150
- boost::factory<Handler *> ctor;
136
+ template <typename Handler, typename Rule> router& PUT (Rule&& r) {
151
137
152
138
static_assert (std::is_base_of<payload_enabled_handler, Handler>::value, " PUT rule requires payload enabled handler subclass" );
153
139
154
- rules_put.push_back (
155
- rule_ptr (new rule<Rule, boost::factory<Handler *> >(std::move (r), ctor)));
140
+ rules_put.push_back (std::make_unique<rule<Handler, Rule> >(std::move (r)));
156
141
return *this ;
157
142
}
158
143
159
144
/* match the list of path components given in p. if a match is found,
160
- * construct an
161
- * object of the handler type with the provided params and the matched
162
- * params.
145
+ * construct an object of the handler type with the provided params
146
+ * and the matched params.
163
147
*/
164
148
165
149
handler_ptr_t match (const std::vector<std::string> &p, request ¶ms) {
@@ -221,6 +205,8 @@ struct router {
221
205
}
222
206
223
207
private:
208
+ using rule_ptr = std::unique_ptr<rule_base>;
209
+
224
210
std::vector<rule_ptr> rules_get;
225
211
std::vector<rule_ptr> rules_post;
226
212
std::vector<rule_ptr> rules_put;
@@ -291,43 +277,44 @@ namespace {
291
277
std::pair<std::string, mime::type> resource_mime_type (const std::string &path) {
292
278
293
279
#if HAVE_YAJL
294
- {
295
- std::size_t json_found = path.rfind (" .json" );
296
280
297
- if (json_found != std::string::npos && json_found == path.length () - 5 ) {
298
- return std::make_pair (path.substr (0 , json_found), mime::type::application_json);
299
- }
300
- }
281
+ std::size_t json_found = path.rfind (" .json" );
282
+
283
+ if (json_found != std::string::npos && json_found == path.length () - 5 ) {
284
+ return {path.substr (0 , json_found), mime::type::application_json};
285
+ }
286
+
301
287
#endif
302
288
303
- {
304
- std::size_t xml_found = path.rfind (" .xml" );
289
+ std::size_t xml_found = path.rfind (" .xml" );
305
290
306
- if (xml_found != std::string::npos && xml_found == path.length () - 4 ) {
307
- return make_pair (path.substr (0 , xml_found), mime::type::application_xml);
308
- }
309
- }
291
+ if (xml_found != std::string::npos && xml_found == path.length () - 4 ) {
292
+ return {path.substr (0 , xml_found), mime::type::application_xml};
293
+ }
310
294
311
- return make_pair (path, mime::type::unspecified_type);
295
+ return make_pair (path, mime::type::unspecified_type);
312
296
}
313
297
314
298
handler_ptr_t route_resource (request &req, const std::string &path,
315
299
const std::unique_ptr<router> &r) {
300
+
301
+ namespace al = boost::algorithm;
302
+
316
303
// strip off the format-spec, if there is one
317
- std::pair<std::string, mime::type> resource = resource_mime_type (path);
304
+ auto [ resource, mime_type] = resource_mime_type (path);
318
305
319
306
// split the URL into bits to be matched.
320
307
std::vector<std::string> path_components;
321
- al::split (path_components, resource. first , al::is_any_of (" /" ));
308
+ al::split (path_components, resource, al::is_any_of (" /" ));
322
309
323
- handler_ptr_t hptr (r->match (path_components, req));
310
+ auto hptr (r->match (path_components, req));
324
311
325
312
// if the pointer points at something, then the path was found. otherwise,
326
313
// it must have exhausted all the possible routes.
327
314
if (hptr) {
328
315
// ugly hack - need this info later on to choose the output formatter,
329
316
// but don't want to parse the URI again...
330
- hptr->set_resource_type (resource. second );
317
+ hptr->set_resource_type (mime_type );
331
318
}
332
319
333
320
return hptr;
0 commit comments