1 // Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey
2 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
3 
4 #ifndef TAO_PEGTL_CONTRIB_HTTP_HPP
5 #define TAO_PEGTL_CONTRIB_HTTP_HPP
6 
7 #include "../ascii.hpp"
8 #include "../config.hpp"
9 #include "../rules.hpp"
10 #include "../utf8.hpp"
11 
12 #include "abnf.hpp"
13 #include "uri.hpp"
14 
15 namespace tao
16 {
17    namespace TAO_PEGTL_NAMESPACE
18    {
19       namespace http
20       {
21          // HTTP 1.1 grammar according to RFC 7230.
22 
23          // This grammar is a direct PEG translation of the original HTTP grammar.
24          // It should be considered experimental -- in case of any issues, in particular
25          // missing rules for attached actions, please contact the developers.
26 
27          using OWS = star< abnf::WSP >;  // optional whitespace
28          using RWS = plus< abnf::WSP >;  // required whitespace
29          using BWS = OWS;                // "bad" whitespace
30 
31          // cppcheck-suppress constStatement
32          using obs_text = not_range< 0x00, 0x7F >;
33          using obs_fold = seq< abnf::CRLF, plus< abnf::WSP > >;
34 
35          // clang-format off
36          struct tchar : sor< abnf::ALPHA, abnf::DIGIT, one< '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~' > > {};
37          struct token : plus< tchar > {};
38 
39          struct field_name : token {};
40 
41          struct field_vchar : sor< abnf::VCHAR, obs_text > {};
42          struct field_content : list< field_vchar, plus< abnf::WSP > > {};
43          struct field_value : star< sor< field_content, obs_fold > > {};
44 
45          struct header_field : seq< field_name, one< ':' >, OWS, field_value, OWS > {};
46 
47          struct method : token {};
48 
49          struct absolute_path : plus< one< '/' >, uri::segment > {};
50 
51          struct origin_form : seq< absolute_path, uri::opt_query >  {};
52          struct absolute_form : uri::absolute_URI {};
53          struct authority_form : uri::authority {};
54          struct asterisk_form : one< '*' > {};
55 
56          struct request_target : sor< origin_form, absolute_form, authority_form, asterisk_form > {};
57 
58          struct status_code : rep< 3, abnf::DIGIT > {};
59          struct reason_phrase : star< sor< abnf::VCHAR, obs_text, abnf::WSP > > {};
60 
61          struct HTTP_version : if_must< string< 'H', 'T', 'T', 'P', '/' >, abnf::DIGIT, one< '.' >, abnf::DIGIT > {};
62 
63          struct request_line : if_must< method, abnf::SP, request_target, abnf::SP, HTTP_version, abnf::CRLF > {};
64          struct status_line : if_must< HTTP_version, abnf::SP, status_code, abnf::SP, reason_phrase, abnf::CRLF > {};
65          struct start_line : sor< status_line, request_line > {};
66 
67          struct message_body : star< abnf::OCTET > {};
68          struct HTTP_message : seq< start_line, star< header_field, abnf::CRLF >, abnf::CRLF, opt< message_body > > {};
69 
70          struct Content_Length : plus< abnf::DIGIT > {};
71 
72          struct uri_host : uri::host {};
73          struct port : uri::port {};
74 
75          struct Host : seq< uri_host, opt< one< ':' >, port > > {};
76 
77          // PEG are different from CFGs! (this replaces ctext and qdtext)
78          using text = sor< abnf::HTAB, range< 0x20, 0x7E >, obs_text >;
79 
80          struct quoted_pair : if_must< one< '\\' >, sor< abnf::VCHAR, obs_text, abnf::WSP > > {};
81          struct quoted_string : if_must< abnf::DQUOTE, until< abnf::DQUOTE, sor< quoted_pair, text > > > {};
82 
83          struct transfer_parameter : seq< token, BWS, one< '=' >, BWS, sor< token, quoted_string > > {};
84          struct transfer_extension : seq< token, star< OWS, one< ';' >, OWS, transfer_parameter > > {};
85          struct transfer_coding : sor< istring< 'c', 'h', 'u', 'n', 'k', 'e', 'd' >,
86                                        istring< 'c', 'o', 'm', 'p', 'r', 'e', 's', 's' >,
87                                        istring< 'd', 'e', 'f', 'l', 'a', 't', 'e' >,
88                                        istring< 'g', 'z', 'i', 'p' >,
89                                        transfer_extension > {};
90 
91          struct rank : sor< seq< one< '0' >, opt< one< '.' >, rep_opt< 3, abnf::DIGIT > > >,
92                             seq< one< '1' >, opt< one< '.' >, rep_opt< 3, one< '0' > > > > > {};
93 
94          struct t_ranking : seq< OWS, one< ';' >, OWS, one< 'q', 'Q' >, one< '=' >, rank > {};
95          struct t_codings : sor< istring< 't', 'r', 'a', 'i', 'l', 'e', 'r', 's' >, seq< transfer_coding, opt< t_ranking > > > {};
96 
97          struct TE : opt< sor< one< ',' >, t_codings >, star< OWS, one< ',' >, opt< OWS, t_codings > > > {};
98 
99          template< typename T >
100          using make_comma_list = seq< star< one< ',' >, OWS >, T, star< OWS, one< ',' >, opt< OWS, T > > >;
101 
102          struct connection_option : token {};
103          struct Connection : make_comma_list< connection_option > {};
104 
105          struct Trailer : make_comma_list< field_name > {};
106 
107          struct Transfer_Encoding : make_comma_list< transfer_coding > {};
108 
109          struct protocol_name : token {};
110          struct protocol_version : token {};
111          struct protocol : seq< protocol_name, opt< one< '/' >, protocol_version > > {};
112          struct Upgrade : make_comma_list< protocol > {};
113 
114          struct pseudonym : token {};
115 
116          struct received_protocol : seq< opt< protocol_name, one< '/' > >, protocol_version > {};
117          struct received_by : sor< seq< uri_host, opt< one< ':' >, port > >, pseudonym > {};
118 
119          struct comment : if_must< one< '(' >, until< one< ')' >, sor< comment, quoted_pair, text > > > {};
120 
121          struct Via : make_comma_list< seq< received_protocol, RWS, received_by, opt< RWS, comment > > > {};
122 
123          struct http_URI : if_must< istring< 'h', 't', 't', 'p', ':', '/', '/' >, uri::authority, uri::path_abempty, uri::opt_query, uri::opt_fragment > {};
124          struct https_URI : if_must< istring< 'h', 't', 't', 'p', 's', ':', '/', '/' >, uri::authority, uri::path_abempty, uri::opt_query, uri::opt_fragment > {};
125 
126          struct partial_URI : seq< uri::relative_part, uri::opt_query > {};
127 
128          struct chunk_size : plus< abnf::HEXDIG > {};
129 
130          struct chunk_ext_name : token {};
131          struct chunk_ext_val : sor< quoted_string, token > {};
132          struct chunk_ext : star_must< one< ';' >, chunk_ext_name, if_must< one< '=' >, chunk_ext_val > > {};
133 
134          struct chunk_data : until< at< abnf::CRLF >, abnf::OCTET > {};
135 
136          struct chunk : seq< chunk_size, opt< chunk_ext >, abnf::CRLF, chunk_data, abnf::CRLF > {};
137 
138          struct last_chunk : seq< plus< one< '0' > >, opt< chunk_ext >, abnf::CRLF > {};
139 
140          struct trailer_part : star< header_field, abnf::CRLF > {};
141 
142          struct chunked_body : seq< until< last_chunk, chunk >, trailer_part, abnf::CRLF > {};
143          // clang-format on
144 
145       }  // namespace http
146 
147    }  // namespace TAO_PEGTL_NAMESPACE
148 
149 }  // namespace tao
150 
151 #endif
152