Add some tolerance (RFC2616 sec. 19.3)
[unicorn.git] / ext / unicorn_http / unicorn_http_common.rl
blob0988b54c754c3ce0b962d380f87bfb76d0e45be3
1 %%{
3   machine unicorn_http_common;
5 #### HTTP PROTOCOL GRAMMAR
6 # line endings
7   CRLF = ("\r\n" | "\n");
9 # character types
10   CTL = (cntrl | 127);
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");
22   lws = (" " | "\t");
23   content = ((any -- CTL) | lws);
25 # elements
26   token = (ascii -- (CTL | tspecials));
28 # URI schemes and absolute paths
29   scheme = ( "http"i ("s"i)? ) $downcase_char >mark %scheme;
30   hostname = ((alnum | "-" | "." | "_")+ | ("[" (":" | xdigit)+ "]"));
31   host_with_port = (hostname (":" digit*)?) >mark %host;
32   userinfo = ((unreserved | escape | ";" | ":" | "&" | "=" | "+")+ "@")*;
34   path = ( pchar+ ( "/" pchar* )* ) ;
35   query = ( uchar | reserved )* %query_string ;
36   param = ( pchar | "/" )* ;
37   params = ( param ( ";" param )* ) ;
38   rel_path = (path? (";" params)? %request_path) ("?" %start_query query)?;
39   absolute_path = ( "/"+ rel_path );
40   path_uri = absolute_path > mark %request_uri;
41   Absolute_URI = (scheme "://" userinfo host_with_port path_uri);
43   Request_URI = ((absolute_path | "*") >mark %request_uri) | Absolute_URI;
44   Fragment = ( uchar | reserved )* >mark %fragment;
45   Method = (token){1,20} >mark %request_method;
46   GetOnly = "GET" >mark %request_method;
48   http_number = ( digit+ "." digit+ ) ;
49   HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
50   Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
52   field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
54   field_value = content* >start_value %write_value;
56   value_cont = lws+ content* >start_value %write_cont_value;
58   message_header = ((field_name ":" lws* field_value)|value_cont) :> CRLF;
59   chunk_ext_val = token*;
60   chunk_ext_name = token*;
61   chunk_extension = ( ";" " "* chunk_ext_name ("=" chunk_ext_val)? )*;
62   last_chunk = "0"+ chunk_extension CRLF;
63   chunk_size = (xdigit* [1-9a-fA-F] xdigit*) $add_to_chunk_size;
64   chunk_end = CRLF;
65   chunk_body = any >skip_chunk_data;
66   chunk_begin = chunk_size chunk_extension CRLF;
67   chunk = chunk_begin chunk_body chunk_end;
68   ChunkedBody := chunk* last_chunk @end_chunked_body;
69   Trailers := (message_header)* CRLF @end_trailers;
71   FullRequest = Request_Line (message_header)* CRLF @header_done;
72   SimpleRequest = GetOnly " " Request_URI ("#"Fragment){0,1} CRLF @header_done;
74 main := FullRequest | SimpleRequest;
76 }%%