3 machine unicorn_http_common;
5 #### HTTP PROTOCOL GRAMMAR
11 safe = ("$" | "-" | "_" | ".");
12 extra = ("!" | "*" | "'" | "(" | ")" | ",");
13 reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
14 sorta_safe = ("\"" | "<" | ">");
15 unsafe = (CTL | " " | "#" | "%" | sorta_safe);
16 national = any -- (alpha | digit | reserved | extra | safe | unsafe);
17 unreserved = (alpha | digit | safe | extra | national);
18 escape = ("%" xdigit xdigit);
19 uchar = (unreserved | escape | sorta_safe);
20 pchar = (uchar | ":" | "@" | "&" | "=" | "+");
21 tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
25 token = (ascii -- (CTL | tspecials));
27 # URI schemes and absolute paths
28 scheme = ( "http"i ("s"i)? ) $downcase_char >mark %scheme;
29 hostname = (alnum | "-" | "." | "_")+;
30 host_with_port = (hostname (":" digit*)?) >mark %host;
32 path = ( pchar+ ( "/" pchar* )* ) ;
33 query = ( uchar | reserved )* %query_string ;
34 param = ( pchar | "/" )* ;
35 params = ( param ( ";" param )* ) ;
36 rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
37 absolute_path = ( "/"+ rel_path );
38 path_uri = absolute_path > mark %request_uri;
39 Absolute_URI = (scheme "://" host_with_port path_uri);
41 Request_URI = ((absolute_path | "*") >mark %request_uri) | Absolute_URI;
42 Fragment = ( uchar | reserved )* >mark %fragment;
43 Method = (token){1,20} >mark %request_method;
44 GetOnly = "GET" >mark %request_method;
46 http_number = ( digit+ "." digit+ ) ;
47 HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
48 Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
50 field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
52 field_value = any* >start_value %write_value;
54 value_cont = lws+ any* >start_value %write_cont_value;
56 message_header = ((field_name ":" " "* field_value)|value_cont) :> CRLF;
57 chunk_ext_val = token*;
58 chunk_ext_name = token*;
59 chunk_extension = ( ";" " "* chunk_ext_name ("=" chunk_ext_val)? )*;
60 last_chunk = "0"+ chunk_extension CRLF;
61 chunk_size = (xdigit* [1-9a-fA-F] xdigit*) $add_to_chunk_size;
63 chunk_body = any >skip_chunk_data;
64 chunk_begin = chunk_size chunk_extension CRLF;
65 chunk = chunk_begin chunk_body chunk_end;
66 ChunkedBody := chunk* last_chunk @end_chunked_body;
67 Trailers := (message_header)* CRLF @end_trailers;
69 FullRequest = Request_Line (message_header)* CRLF @header_done;
70 SimpleRequest = GetOnly " " Request_URI ("#"Fragment){0,1} CRLF @header_done;
72 main := FullRequest | SimpleRequest;