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