%%{

    machine puma_parser_common;

#### HTTP PROTOCOL GRAMMAR # line endings

    CRLF = "\r\n";

# character types

    CTL = (cntrl | 127);
    safe = ("$" | "-" | "_" | ".");
    extra = ("!" | "*" | "'" | "(" | ")" | ",");
    reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
    unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">");
    national = any -- (alpha | digit | reserved | extra | safe | unsafe);
    unreserved = (alpha | digit | safe | extra | national);
    escape = ("%" xdigit xdigit);
    uchar = (unreserved | escape | "%");
    pchar = (uchar | ":" | "@" | "&" | "=" | "+");
    tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");

# elements

    token = (ascii -- (CTL | tspecials));

# URI schemes and absolute paths

    scheme = ( alpha | digit | "+" | "-" | "." )* ;
    absolute_uri = (scheme ":" (uchar | reserved )*);

    path = ( pchar+ ( "/" pchar* )* ) ;
    query = ( uchar | reserved )* %query_string ;
    param = ( pchar | "/" )* ;
    params = ( param ( ";" param )* ) ;
    rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
    absolute_path = ( "/"+ rel_path );

    Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
    Fragment = ( uchar | reserved )* >mark %fragment;
    Method = ( upper | digit | safe ){1,20} >mark %request_method;

    http_number = ( digit+ "." digit+ ) ;
    HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
    Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;

    field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;

    field_value = any* >start_value %write_value;

    message_header = field_name ":" " "* field_value :> CRLF;

    Request = Request_Line ( message_header )* ( CRLF @done );

main := Request;

}%%