Mercurial > maze-src
diff net/http/server/parser.rb @ 0:1eef88068f9f tip
initial commit of maze game source
| author | ferencd |
|---|---|
| date | Sun, 15 Sep 2019 11:46:47 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/http/server/parser.rb Sun Sep 15 11:46:47 2019 +0200 @@ -0,0 +1,151 @@ +require 'net/protocol' +require 'parslet' + +module Net + class HTTP < Protocol + module Server + # + # Inspired by: + # + # * [Thin](https://github.com/macournoyer/thin/blob/master/ext/thin_parser/common.rl) + # * [Unicorn](https://github.com/defunkt/unicorn/blob/master/ext/unicorn_http/unicorn_http_common.rl) + # * [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616.html) + # + class Parser < Parslet::Parser + + # + # Character Classes + # + rule(:digit) { match['0-9'] } + rule(:digits) { digit.repeat(1) } + rule(:xdigit) { digit | match['a-fA-F'] } + rule(:upper) { match['A-Z'] } + rule(:lower) { match['a-z'] } + rule(:alpha) { upper | lower } + rule(:alnum) { alpha | digit } + rule(:cntrl) { match['\x00-\x1f'] } + rule(:ascii) { match['\x00-\x7f'] } + + rule(:lws) { match[" \t"] } + rule(:crlf) { str("\r\n") } + + rule(:ctl) { cntrl | str("\x7f") } + rule(:text) { lws | (ctl.absnt? >> ascii) } + + rule(:safe) { charset('$', '-', '_', '.') } + rule(:extra) { charset('!', '*', "'", '(', ')', ',') } + rule(:reserved) { charset(';', '/', '?', ':', '@', '&', '=', '+') } + rule(:sorta_safe) { charset('"', '<', '>') } + + rule(:unsafe) { ctl | charset(' ', '#', '%') | sorta_safe } + rule(:national) { + (alpha | digit | reserved | extra | safe | unsafe).absnt? >> any + } + + rule(:unreserved) { alpha | digit | safe | extra | national } + rule(:uescape) { str("%u") >> xdigit >> xdigit >> xdigit >> xdigit } + rule(:escape) { str("%") >> xdigit >> xdigit } + rule(:uchar) { unreserved | uescape | escape | sorta_safe } + rule(:pchar) { uchar | charset(':', '@', '&', '=', '+') } + rule(:separators) { + lws | charset( + '(', ')', '<', '>', '@', ',', ';', ':', "\\", '"', '/', '[', ']', + '?', '=', '{', '}' + ) + } + + # + # Elements + # + rule(:token) { (ctl | separators).absnt? >> ascii } + + rule(:comment_text) { (str('(') | str(')')).absnt? >> text } + rule(:comment) { str('(') >> comment_text.repeat >> str(')') } + + rule(:quoted_pair) { str("\\") >> ascii } + rule(:quoted_text) { quoted_pair | str('"').absnt? >> text } + rule(:quoted_string) { str('"') >> quoted_text >> str('"') } + + # + # URI Elements + # + rule(:scheme) { + (alpha | digit | charset('+', '-', '.')).repeat + } + rule(:host_name) { + (alnum | charset('-', '_', '.')).repeat(1) + } + rule(:user_info) { + ( + unreserved | escape | charset(';', ':', '&', '=', '+') + ).repeat(1) + } + + rule(:path) { pchar.repeat(1) >> (str('/') >> pchar.repeat).repeat } + rule(:query_string) { (uchar | reserved).repeat } + rule(:param) { (pchar | str('/')).repeat } + rule(:params) { param >> (str(';') >> param).repeat } + rule(:frag) { (uchar | reserved).repeat } + + rule(:uri_path) { + (str('/').maybe >> path.maybe).as(:path) >> + (str(';') >> params.as(:params)).maybe >> + (str('?') >> query_string.as(:query)).maybe >> + (str('#') >> frag.as(:fragment)).maybe + } + + rule(:uri) { + scheme.as(:scheme) >> str(':') >> str('//').maybe >> + (user_info.as(:user_info) >> str('@')).maybe >> + host_name.as(:host) >> + (str(':') >> digits.as(:port)).maybe >> + uri_path + } + + rule(:request_uri) { str('*') | uri | uri_path } + + # + # HTTP Elements + # + rule(:request_method) { upper.repeat(1,20) | token.repeat(1) } + + rule(:version_number) { digits >> str('.') >> digits } + rule(:http_version) { str('HTTP/') >> version_number.as(:version) } + rule(:request_line) { + request_method.as(:method) >> str(' ') >> + request_uri.as(:uri) >> str(' ') >> + http_version + } + + rule(:header_name) { (str(':').absnt? >> token).repeat(1) } + rule(:header_value) { + (text | token | separators | quoted_string).repeat(1) + } + + rule(:header) { + header_name.as(:name) >> str(':') >> lws.repeat(1) >> + header_value.as(:value) >> crlf + } + rule(:request) { + request_line >> crlf >> + header.repeat.as(:headers) >> crlf + } + + root :request + + protected + + # + # Creates a matcher for the given characters. + # + # @param [Array<String>] chars + # The characters to match. + # + def charset(*chars) + match[chars.map { |c| Regexp.escape(c) }.join] + end + + end + end + end +end
