/
authorization.hpp
317 lines (273 loc) · 6.26 KB
/
authorization.hpp
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
* RESTinio
*/
/*!
* @file
* @brief Stuff related to value of Authorization HTTP-field.
*
* @since v.0.6.7
*/
#pragma once
#include <restinio/helpers/http_field_parsers/basics.hpp>
#include <restinio/variant.hpp>
#include <iostream>
namespace restinio
{
namespace http_field_parsers
{
namespace authorization_details
{
namespace hfp_impl = restinio::http_field_parsers::impl;
//
// is_token68_char_predicate_t
//
/*!
* @brief A preducate for symbol_producer_template that checks that
* a symbol can be used inside token68 from RFC7235.
*
* @since v.0.6.7
*/
struct is_token68_char_predicate_t
: protected hfp_impl::is_alphanum_predicate_t
{
using base_type_t = hfp_impl::is_alphanum_predicate_t;
RESTINIO_NODISCARD
bool
operator()( const char actual ) const noexcept
{
return base_type_t::operator()(actual)
|| '-' == actual
|| '.' == actual
|| '_' == actual
|| '~' == actual
|| '+' == actual
|| '/' == actual
;
}
};
//
// token68_symbol_p
//
RESTINIO_NODISCARD
inline auto
token68_symbol_p()
{
return restinio::easy_parser::impl::symbol_producer_template_t<
is_token68_char_predicate_t >{};
}
//
// token68_t
//
/*!
* @brief A structure for holding a value of token68 from RFC7235.
*
* The actual value of token68 is stored as `std::string` inside that
* struct.
*
* @since v.0.6.7
*/
struct token68_t
{
std::string value;
};
inline std::ostream &
operator<<( std::ostream & to, const token68_t & v )
{
return (to << v.value);
}
//
// token68_p
//
RESTINIO_NODISCARD
inline auto
token68_p()
{
return produce< token68_t >(
produce< std::string >(
repeat( 1, N, token68_symbol_p() >> to_container() ),
repeat( 0, N, symbol_p('=') >> to_container() )
) >> &token68_t::value
);
}
} /* authorization_details */
//
// authorization_value_t
//
/*!
* @brief Tools for working with the value of Authorization HTTP-field.
*
* This struct represents parsed value of HTTP-field Authorization
* (see https://tools.ietf.org/html/rfc7235):
@verbatim
Authorization = credentials
credentials = auth-scheme [ 1*SP ( token68 / [ #auth-param ] ) ]
auth-scheme = token
auth-param = token BWS "=" BWS ( token / quoted-string )
token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
@endverbatim
*
* @since v.0.6.7
*/
struct authorization_value_t
{
//! An indicator of the source form of the value of a parameter.
enum class value_form_t
{
//! The value of a parameter was specified as token.
token,
//! The value of a parameter was specified as quoted_string.
quoted_string
};
//! A storage for the value of a parameter.
struct param_value_t
{
//! The value of a parameter.
std::string value;
//! How this value was represented: as a token, or a quoted string?
value_form_t form;
};
//! A storage for a parameter with a name and a value.
struct param_t
{
//! The name of a parameter.
std::string name;
//! The value of a parameter.
param_value_t value;
};
//! Type of container for holding parameters.
using param_container_t = std::vector< param_t >;
//! Type for holding a value of token68 from RFC7235.
using token68_t = authorization_details::token68_t;
//! Type for holding a parameter for authorization.
using auth_param_t = variant_t< token68_t, param_container_t >;
//! A value of auth-scheme.
std::string auth_scheme;
//! A parameter for authorization.
/*!
* @note
* It can be empty.
*/
auth_param_t auth_param;
/*!
* @brief A factory function for a parser of Authorization value.
*
* @since v.0.6.7
*/
RESTINIO_NODISCARD
static auto
make_parser()
{
using namespace authorization_details;
auto token_to_v = []( std::string v ) -> param_value_t {
return { std::move(v), value_form_t::token };
};
auto qstring_to_v = []( std::string v ) -> param_value_t {
return { std::move(v), value_form_t::quoted_string };
};
// NOTE: token68 should consume all input.
// So there should not be any symbols after the value.
auto token68_seq = sequence(
token68_p() >> as_result(),
not_clause( any_symbol_p() >> skip() ) );
// Parameters list can be empty.
auto params_seq = maybe_empty_comma_separated_list_p< param_container_t >(
produce< param_t >(
token_p() >> to_lower() >> ¶m_t::name,
ows(),
symbol('='),
ows(),
produce< param_value_t >(
alternatives(
token_p() >> convert( token_to_v ) >> as_result(),
quoted_string_p() >> convert( qstring_to_v )
>> as_result()
)
) >> ¶m_t::value
)
) >> as_result();
return produce< authorization_value_t >(
token_p() >> to_lower() >> &authorization_value_t::auth_scheme,
maybe(
repeat( 1, N, space() ),
produce< auth_param_t >(
alternatives( token68_seq, params_seq )
) >> &authorization_value_t::auth_param
)
);
}
/*!
* @brief An attempt to parse Authorization HTTP-field.
*
* @since v.0.6.7
*/
RESTINIO_NODISCARD
static expected_t<
authorization_value_t,
restinio::easy_parser::parse_error_t >
try_parse( string_view_t what )
{
return restinio::easy_parser::try_parse( what, make_parser() );
}
};
//
// Various helpers for dumping values to std::ostream.
//
inline std::ostream &
operator<<(
std::ostream & to,
const authorization_value_t::param_value_t & v )
{
if(authorization_value_t::value_form_t::token == v.form)
to << v.value;
else
to << '"' << v.value << '"';
return to;
}
inline std::ostream &
operator<<(
std::ostream & to,
const authorization_value_t::param_t & v )
{
return (to << v.name << '=' << v.value);
}
inline std::ostream &
operator<<(
std::ostream & to,
const authorization_value_t::auth_param_t & p )
{
struct printer_t
{
std::ostream & to;
void
operator()( const authorization_value_t::token68_t & t ) const
{
to << t;
}
void
operator()( const authorization_value_t::param_container_t & c ) const
{
bool first = true;
to << '{';
for( const auto & param : c )
{
if( !first )
to << ", ";
else
first = false;
to << param;
}
to << '}';
}
};
restinio::visit( printer_t{ to }, p );
return to;
}
inline std::ostream &
operator<<(
std::ostream & to,
const authorization_value_t & v )
{
return (to << v.auth_scheme << ' ' << v.auth_param);
}
} /* namespace http_field_parsers */
} /* namespace restinio */