
نواصل تطوير خادم RESTinio HTTP المجاني والمفتوح المضمن في تطبيقات C ++ . تستخدم قوالب C ++ بنشاط في تنفيذ RESTinio ، والتي نتحدث عنها بانتظام هنا ( المثال الأخير ).
كانت إحدى نقاط التطبيق لسحر قالب C ++ easy_parser ، وهو تطبيق صغير لمحلل تكراري تنازلي يعتمد على PEG . تمت إضافة Easy_parser إلى RESTinio العام الماضي لتبسيط العمل باستخدام رؤوس HTTP.
لقد تحدثنا بالفعل قليلاً عن easy_parser في مقال سابق . واليوم أريد أن أبين كيف يتم استخدام easy_parser في تطوير RESTinio. عن طريق تحليل محتويات رأس HTTP المصادقة. دعونا نحاول ، إذا جاز التعبير ، النظر في أحشاء RESTinio.
تفويض قواعد
يتم تعريف بنية رأس التفويض في RFC7235 كما يلي:
authorization-field = "Authorization" ":" OWS credentials
credentials = auth-scheme [ 1*SP ( token68 / [ #auth-param ] ) ]
auth-scheme = token
auth-param = token BWS "=" BWS ( token / quoted-string )
token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
أولئك. يجب أن تتضمن قيمة رأس التفويض الاسم المطلوب لنظام المصادقة والمعلمات الاختيارية لهذا النظام.
, token68 ( , base64), "=".
Authorization easy_parser?
?
easy_parser , , .
, , :
struct authorization_value_t
{
enum class value_form_t { token, quoted_string };
struct param_value_t
{
std::string value;
value_form_t form;
};
struct param_t
{
std::string name;
param_value_t value;
};
using param_container_t = std::vector< param_t >;
struct token68_t
{
std::string value;
};
using auth_param_t = variant_t< token68_t, param_container_t >;
std::string auth_scheme;
auth_param_t auth_param;
};
authorization_value_t
: auth_scheme
auth_params
. auth_params
— token68_t
, , param_t
.
Authorization
producer
, , . ( ) , , :
auto make_parser()
{
...
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
)
);
}
make_parser
-, authorization_value_t
. produce
, . produce
, C++ DSL.
:
- token ( RFC7230). token-
auth_scheme
authorization_value_t
; - , , ,
maybe
; - ;
- token68, . ,
auth_param
authorization_value_t
auth_param_t
.
- . , , easy_parser DSL.
, - , , token68_seq
params_seq
. , ;)
token68_seq?
token68_seq
— , make_parser
:
auto token68_seq = sequence(
token68_p() >> as_result(),
not_clause( any_symbol_p() >> skip() ) );
, token68_seq
— . token68 , , .
, , token68 . PEG, not-predicate. Not-pedicate , , . , not-predicate, .
, RFC7617 , token68, . , token68 . , .
token68_seq
, token68_p
. :
struct is_token68_char_predicate_t
: protected hfp_impl::is_alphanum_predicate_t
{
using base_type_t = hfp_impl::is_alphanum_predicate_t;
bool operator()( const char actual ) const noexcept
{
return base_type_t::operator()(actual)
|| '-' == actual
|| '.' == actual
|| '_' == actual
|| '~' == actual
|| '+' == actual
|| '/' == actual
;
}
};
inline auto token68_symbol_p()
{
return restinio::easy_parser::impl::symbol_producer_template_t<
is_token68_char_predicate_t >{};
}
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
);
}
, token68_p
. is_token68_char_predicate_t
token68_symbol_p
— . , easy_parser , - , : digit_p
, space_p
, hexdigit_p
, alpha_symbol_p
, alphanum_symbol_p
.. , , token68, . is_token68_char_predicate_t
token68_symbol_p
.
token68_p
token68 -- : token68, =
. .
params_seq?
, params_seq
. , , make_parser
, :
auto make_parser()
{
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 };
};
auto token68_seq = sequence(
token68_p() >> as_result(),
not_clause( any_symbol_p() >> skip() ) );
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
)
);
}
, lambda- token_to_v
qstring_to_v
. , std::string
param_value_t
, : token quoted-string.
- , name=value
std::string
, param_value_t
, std::string
.
params_seq
:
auto params_seq = maybe_empty_comma_separated_list_p< param_container_t >(
...
) >> as_result();
params_seq
, param_container_t
. , .
maybe_empty_comma_separated_list_p
easy_parser- , RFC HTTP #auth-param
, #
:
[ ( "," / auth-param ) *( OWS "," [ OWS auth-param ] ) ]
params_seq
, . auth-param
. , -, :
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
)
, param_t
, :
- token,
param_t::name
; - (
ows
OWS
(.. optional whitespace) RFC7230); =
;- ;
- (..
param_value_t
), : token, quoted-string. token, , token_to_v
( ) . quoted-string, , qstring_to_v
; param_value_t
param_t::value
.
, , .
" ?" .
, , , , RESTinio , . , , RESTinio.
, . , RESTinio, , , C++ . , .
easy_parser RESTinio , RESTinio HTTP-.
, - , - . ( , ), - .
, - ( bison, coco/r, ragel .) . RESTinio header-only ( libhttp-parser). - header-only . , : , - RESTinio, , - ( , RESTinio)? ragel coco/r? , .
, C++ DSL. , RESTinio - Boost- - PEGTL , .. . , (Boost.Spirit PEGTL) , . , show stopper-. easy_parser.
C HTTP- RESTinio easy_parser-. .
...
, easy_parser, . . , a) RFC, b) , , , c) d) . , , - 4-6 , easy_parser- — 15-20 .
, easy_parser- RESTinio , - RESTinio .
RESTinio
الجواب الثاني على السؤال "لماذا وماذا كتب هذا المقال؟" مجرد تافه وواضح: أردت أن أذكر مرة أخرى أن المشروع يعيش ويتطور. يمكنك أخذه وتجربته ثم مشاركة مشاعرك معنا: ما أعجبك وما لم يعجبك وما لم يكن مفقودًا وما لم يتم فعله بالطريقة التي تريدها ... نستمع إلى جميع التعليقات والاقتراحات البناءة (أعتقد أن بعض القراء سيتمكنون من تأكيد ذلك )