Mercurial > maze-src
comparison 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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1eef88068f9f |
|---|---|
| 1 require 'net/protocol' | |
| 2 require 'parslet' | |
| 3 | |
| 4 module Net | |
| 5 class HTTP < Protocol | |
| 6 module Server | |
| 7 # | |
| 8 # Inspired by: | |
| 9 # | |
| 10 # * [Thin](https://github.com/macournoyer/thin/blob/master/ext/thin_parser/common.rl) | |
| 11 # * [Unicorn](https://github.com/defunkt/unicorn/blob/master/ext/unicorn_http/unicorn_http_common.rl) | |
| 12 # * [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616.html) | |
| 13 # | |
| 14 class Parser < Parslet::Parser | |
| 15 | |
| 16 # | |
| 17 # Character Classes | |
| 18 # | |
| 19 rule(:digit) { match['0-9'] } | |
| 20 rule(:digits) { digit.repeat(1) } | |
| 21 rule(:xdigit) { digit | match['a-fA-F'] } | |
| 22 rule(:upper) { match['A-Z'] } | |
| 23 rule(:lower) { match['a-z'] } | |
| 24 rule(:alpha) { upper | lower } | |
| 25 rule(:alnum) { alpha | digit } | |
| 26 rule(:cntrl) { match['\x00-\x1f'] } | |
| 27 rule(:ascii) { match['\x00-\x7f'] } | |
| 28 | |
| 29 rule(:lws) { match[" \t"] } | |
| 30 rule(:crlf) { str("\r\n") } | |
| 31 | |
| 32 rule(:ctl) { cntrl | str("\x7f") } | |
| 33 rule(:text) { lws | (ctl.absnt? >> ascii) } | |
| 34 | |
| 35 rule(:safe) { charset('$', '-', '_', '.') } | |
| 36 rule(:extra) { charset('!', '*', "'", '(', ')', ',') } | |
| 37 rule(:reserved) { charset(';', '/', '?', ':', '@', '&', '=', '+') } | |
| 38 rule(:sorta_safe) { charset('"', '<', '>') } | |
| 39 | |
| 40 rule(:unsafe) { ctl | charset(' ', '#', '%') | sorta_safe } | |
| 41 rule(:national) { | |
| 42 (alpha | digit | reserved | extra | safe | unsafe).absnt? >> any | |
| 43 } | |
| 44 | |
| 45 rule(:unreserved) { alpha | digit | safe | extra | national } | |
| 46 rule(:uescape) { str("%u") >> xdigit >> xdigit >> xdigit >> xdigit } | |
| 47 rule(:escape) { str("%") >> xdigit >> xdigit } | |
| 48 rule(:uchar) { unreserved | uescape | escape | sorta_safe } | |
| 49 rule(:pchar) { uchar | charset(':', '@', '&', '=', '+') } | |
| 50 rule(:separators) { | |
| 51 lws | charset( | |
| 52 '(', ')', '<', '>', '@', ',', ';', ':', "\\", '"', '/', '[', ']', | |
| 53 '?', '=', '{', '}' | |
| 54 ) | |
| 55 } | |
| 56 | |
| 57 # | |
| 58 # Elements | |
| 59 # | |
| 60 rule(:token) { (ctl | separators).absnt? >> ascii } | |
| 61 | |
| 62 rule(:comment_text) { (str('(') | str(')')).absnt? >> text } | |
| 63 rule(:comment) { str('(') >> comment_text.repeat >> str(')') } | |
| 64 | |
| 65 rule(:quoted_pair) { str("\\") >> ascii } | |
| 66 rule(:quoted_text) { quoted_pair | str('"').absnt? >> text } | |
| 67 rule(:quoted_string) { str('"') >> quoted_text >> str('"') } | |
| 68 | |
| 69 # | |
| 70 # URI Elements | |
| 71 # | |
| 72 rule(:scheme) { | |
| 73 (alpha | digit | charset('+', '-', '.')).repeat | |
| 74 } | |
| 75 rule(:host_name) { | |
| 76 (alnum | charset('-', '_', '.')).repeat(1) | |
| 77 } | |
| 78 rule(:user_info) { | |
| 79 ( | |
| 80 unreserved | escape | charset(';', ':', '&', '=', '+') | |
| 81 ).repeat(1) | |
| 82 } | |
| 83 | |
| 84 rule(:path) { pchar.repeat(1) >> (str('/') >> pchar.repeat).repeat } | |
| 85 rule(:query_string) { (uchar | reserved).repeat } | |
| 86 rule(:param) { (pchar | str('/')).repeat } | |
| 87 rule(:params) { param >> (str(';') >> param).repeat } | |
| 88 rule(:frag) { (uchar | reserved).repeat } | |
| 89 | |
| 90 rule(:uri_path) { | |
| 91 (str('/').maybe >> path.maybe).as(:path) >> | |
| 92 (str(';') >> params.as(:params)).maybe >> | |
| 93 (str('?') >> query_string.as(:query)).maybe >> | |
| 94 (str('#') >> frag.as(:fragment)).maybe | |
| 95 } | |
| 96 | |
| 97 rule(:uri) { | |
| 98 scheme.as(:scheme) >> str(':') >> str('//').maybe >> | |
| 99 (user_info.as(:user_info) >> str('@')).maybe >> | |
| 100 host_name.as(:host) >> | |
| 101 (str(':') >> digits.as(:port)).maybe >> | |
| 102 uri_path | |
| 103 } | |
| 104 | |
| 105 rule(:request_uri) { str('*') | uri | uri_path } | |
| 106 | |
| 107 # | |
| 108 # HTTP Elements | |
| 109 # | |
| 110 rule(:request_method) { upper.repeat(1,20) | token.repeat(1) } | |
| 111 | |
| 112 rule(:version_number) { digits >> str('.') >> digits } | |
| 113 rule(:http_version) { str('HTTP/') >> version_number.as(:version) } | |
| 114 rule(:request_line) { | |
| 115 request_method.as(:method) >> str(' ') >> | |
| 116 request_uri.as(:uri) >> str(' ') >> | |
| 117 http_version | |
| 118 } | |
| 119 | |
| 120 rule(:header_name) { (str(':').absnt? >> token).repeat(1) } | |
| 121 rule(:header_value) { | |
| 122 (text | token | separators | quoted_string).repeat(1) | |
| 123 } | |
| 124 | |
| 125 rule(:header) { | |
| 126 header_name.as(:name) >> str(':') >> lws.repeat(1) >> | |
| 127 header_value.as(:value) >> crlf | |
| 128 } | |
| 129 rule(:request) { | |
| 130 request_line >> crlf >> | |
| 131 header.repeat.as(:headers) >> crlf | |
| 132 } | |
| 133 | |
| 134 root :request | |
| 135 | |
| 136 protected | |
| 137 | |
| 138 # | |
| 139 # Creates a matcher for the given characters. | |
| 140 # | |
| 141 # @param [Array<String>] chars | |
| 142 # The characters to match. | |
| 143 # | |
| 144 def charset(*chars) | |
| 145 match[chars.map { |c| Regexp.escape(c) }.join] | |
| 146 end | |
| 147 | |
| 148 end | |
| 149 end | |
| 150 end | |
| 151 end |
