Class | WEBrick::HTTPRequest |
In: |
lib/webrick/https.rb
lib/webrick/httprequest.rb |
Parent: | Object |
BODY_CONTAINABLE_METHODS | = | [ "POST", "PUT" ] |
BUFSIZE | = | 1024*4 |
parse | -> | orig_parse |
parse_uri | -> | orig_parse_uri |
meta_vars | -> | orig_meta_vars |
accept | [R] | |
accept_charset | [R] | |
accept_encoding | [R] | |
accept_language | [R] | |
addr | [R] | |
attributes | [R] | |
cipher | [R] | |
client_cert | [R] | |
cookies | [R] | Header and entity body |
header | [R] | Header and entity body |
host | [R] | Request-URI |
http_version | [R] | |
keep_alive | [R] | |
path | [R] | Request-URI |
path_info | [RW] | |
peeraddr | [R] | |
port | [R] | Request-URI |
query_string | [RW] | |
raw_header | [R] | Header and entity body |
request_line | [R] | Request line |
request_method | [R] | |
request_time | [R] | |
request_uri | [R] | Request-URI |
script_name | [RW] | |
server_cert | [R] | |
unparsed_uri | [R] | |
user | [RW] | Misc |
# File lib/webrick/httprequest.rb, line 45 45: def initialize(config) 46: @config = config 47: @logger = config[:Logger] 48: 49: @request_line = @request_method = 50: @unparsed_uri = @http_version = nil 51: 52: @request_uri = @host = @port = @path = nil 53: @script_name = @path_info = nil 54: @query_string = nil 55: @query = nil 56: @form_data = nil 57: 58: @raw_header = Array.new 59: @header = nil 60: @cookies = [] 61: @accept = [] 62: @accept_charset = [] 63: @accept_encoding = [] 64: @accept_language = [] 65: @body = "" 66: 67: @addr = @peeraddr = nil 68: @attributes = {} 69: @user = nil 70: @keep_alive = false 71: @request_time = nil 72: 73: @remaining_size = nil 74: @socket = nil 75: end
# File lib/webrick/httprequest.rb, line 145 145: def [](header_name) 146: if @header 147: value = @header[header_name.downcase] 148: value.empty? ? nil : value.join(", ") 149: end 150: end
# File lib/webrick/httprequest.rb, line 124 124: def body(&block) 125: block ||= Proc.new{|chunk| @body << chunk } 126: read_body(@socket, block) 127: @body.empty? ? nil : @body 128: end
# File lib/webrick/httprequest.rb, line 137 137: def content_length 138: return Integer(self['content-length']) 139: end
# File lib/webrick/httprequest.rb, line 141 141: def content_type 142: return self['content-type'] 143: end
# File lib/webrick/httprequest.rb, line 152 152: def each 153: @header.each{|k, v| 154: value = @header[k] 155: yield(k, value.empty? ? nil : value.join(", ")) 156: } 157: end
# File lib/webrick/httprequest.rb, line 171 171: def fixup() 172: begin 173: body{|chunk| } # read remaining body 174: rescue HTTPStatus::Error => ex 175: @logger.error("HTTPRequest#fixup: #{ex.class} occured.") 176: @keep_alive = false 177: rescue => ex 178: @logger.error(ex) 179: @keep_alive = false 180: end 181: end
# File lib/webrick/https.rb, line 45 45: def meta_vars 46: meta = orig_meta_vars 47: if @server_cert 48: meta["HTTPS"] = "on" 49: meta["SSL_SERVER_CERT"] = @server_cert.to_pem 50: meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : "" 51: if @client_cert_chain 52: @client_cert_chain.each_with_index{|cert, i| 53: meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem 54: } 55: end 56: meta["SSL_CIPHER"] = @cipher[0] 57: meta["SSL_PROTOCOL"] = @cipher[1] 58: meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s 59: meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s 60: end 61: meta 62: end
# File lib/webrick/httprequest.rb, line 183 183: def meta_vars 184: # This method provides the metavariables defined by the revision 3 185: # of ``The WWW Common Gateway Interface Version 1.1''. 186: # (http://Web.Golux.Com/coar/cgi/) 187: 188: meta = Hash.new 189: 190: cl = self["Content-Length"] 191: ct = self["Content-Type"] 192: meta["CONTENT_LENGTH"] = cl if cl.to_i > 0 193: meta["CONTENT_TYPE"] = ct.dup if ct 194: meta["GATEWAY_INTERFACE"] = "CGI/1.1" 195: meta["PATH_INFO"] = @path_info ? @path_info.dup : "" 196: #meta["PATH_TRANSLATED"] = nil # no plan to be provided 197: meta["QUERY_STRING"] = @query_string ? @query_string.dup : "" 198: meta["REMOTE_ADDR"] = @peeraddr[3] 199: meta["REMOTE_HOST"] = @peeraddr[2] 200: #meta["REMOTE_IDENT"] = nil # no plan to be provided 201: meta["REMOTE_USER"] = @user 202: meta["REQUEST_METHOD"] = @request_method.dup 203: meta["REQUEST_URI"] = @request_uri.to_s 204: meta["SCRIPT_NAME"] = @script_name.dup 205: meta["SERVER_NAME"] = @host 206: meta["SERVER_PORT"] = @port.to_s 207: meta["SERVER_PROTOCOL"] = "HTTP/" + @config[:HTTPVersion].to_s 208: meta["SERVER_SOFTWARE"] = @config[:ServerSoftware].dup 209: 210: self.each{|key, val| 211: next if /^content-type$/i =~ key 212: next if /^content-length$/i =~ key 213: name = "HTTP_" + key 214: name.gsub!(/-/o, "_") 215: name.upcase! 216: meta[name] = val 217: } 218: 219: meta 220: end
# File lib/webrick/httprequest.rb, line 77 77: def parse(socket=nil) 78: @socket = socket 79: begin 80: @peeraddr = socket.respond_to?(:peeraddr) ? socket.peeraddr : [] 81: @addr = socket.respond_to?(:addr) ? socket.addr : [] 82: rescue Errno::ENOTCONN 83: raise HTTPStatus::EOFError 84: end 85: 86: read_request_line(socket) 87: if @http_version.major > 0 88: read_header(socket) 89: @header['cookie'].each{|cookie| 90: @cookies += Cookie::parse(cookie) 91: } 92: @accept = HTTPUtils.parse_qvalues(self['accept']) 93: @accept_charset = HTTPUtils.parse_qvalues(self['accept-charset']) 94: @accept_encoding = HTTPUtils.parse_qvalues(self['accept-encoding']) 95: @accept_language = HTTPUtils.parse_qvalues(self['accept-language']) 96: end 97: return if @request_method == "CONNECT" 98: return if @unparsed_uri == "*" 99: 100: begin 101: @request_uri = parse_uri(@unparsed_uri) 102: @path = HTTPUtils::unescape(@request_uri.path) 103: @path = HTTPUtils::normalize_path(@path) 104: @host = @request_uri.host 105: @port = @request_uri.port 106: @query_string = @request_uri.query 107: @script_name = "" 108: @path_info = @path.dup 109: rescue 110: raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'." 111: end 112: 113: if /close/io =~ self["connection"] 114: @keep_alive = false 115: elsif /keep-alive/io =~ self["connection"] 116: @keep_alive = true 117: elsif @http_version < "1.1" 118: @keep_alive = false 119: else 120: @keep_alive = true 121: end 122: end
# File lib/webrick/https.rb, line 23 23: def parse(socket=nil) 24: @cipher = @server_cert = @client_cert = nil 25: if socket.respond_to?(:cert) 26: @server_cert = socket.cert || @config[:SSLCertificate] 27: @client_cert = socket.peer_cert 28: @client_cert_chain = socket.peer_cert_chain 29: @cipher = socket.cipher 30: end 31: orig_parse(socket) 32: end
# File lib/webrick/https.rb, line 36 36: def parse_uri(str, scheme="https") 37: if @server_cert 38: return orig_parse_uri(str, scheme) 39: end 40: return orig_parse_uri(str) 41: end
# File lib/webrick/httprequest.rb, line 130 130: def query 131: unless @query 132: parse_query() 133: end 134: @query 135: end
# File lib/webrick/httprequest.rb, line 163 163: def to_s 164: ret = @request_line.dup 165: @raw_header.each{|line| ret << line } 166: ret << CRLF 167: ret << body if body 168: ret 169: end
# File lib/webrick/httprequest.rb, line 325 325: def _read_data(io, method, arg) 326: begin 327: timeout(@config[:RequestTimeout]){ 328: return io.__send__(method, arg) 329: } 330: rescue Errno::ECONNRESET 331: return nil 332: rescue TimeoutError 333: raise HTTPStatus::RequestTimeout 334: end 335: end
# File lib/webrick/httprequest.rb, line 345 345: def parse_query() 346: begin 347: if @request_method == "GET" || @request_method == "HEAD" 348: @query = HTTPUtils::parse_query(@query_string) 349: elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/ 350: @query = HTTPUtils::parse_query(body) 351: elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/ 352: boundary = HTTPUtils::dequote($1) 353: @query = HTTPUtils::parse_form_data(body, boundary) 354: else 355: @query = Hash.new 356: end 357: rescue => ex 358: raise HTTPStatus::BadRequest, ex.message 359: end 360: end
# File lib/webrick/httprequest.rb, line 248 248: def parse_uri(str, scheme="http") 249: if @config[:Escape8bitURI] 250: str = HTTPUtils::escape8bit(str) 251: end 252: str.sub!(%r{\A/+}o, '/') 253: uri = URI::parse(str) 254: return uri if uri.absolute? 255: if self["host"] 256: pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n 257: host, port = *self['host'].scan(pattern)[0] 258: elsif @addr.size > 0 259: host, port = @addr[2], @addr[1] 260: else 261: host, port = @config[:ServerName], @config[:Port] 262: end 263: uri.scheme = scheme 264: uri.host = host 265: uri.port = port ? port.to_i : nil 266: return URI::parse(uri.to_s) 267: end
# File lib/webrick/httprequest.rb, line 269 269: def read_body(socket, block) 270: return unless socket 271: if tc = self['transfer-encoding'] 272: case tc 273: when /chunked/io then read_chunked(socket, block) 274: else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." 275: end 276: elsif self['content-length'] || @remaining_size 277: @remaining_size ||= self['content-length'].to_i 278: while @remaining_size > 0 279: sz = BUFSIZE < @remaining_size ? BUFSIZE : @remaining_size 280: break unless buf = read_data(socket, sz) 281: @remaining_size -= buf.size 282: block.call(buf) 283: end 284: if @remaining_size > 0 && @socket.eof? 285: raise HTTPStatus::BadRequest, "invalid body size." 286: end 287: elsif BODY_CONTAINABLE_METHODS.member?(@request_method) 288: raise HTTPStatus::LengthRequired 289: end 290: return @body 291: end
# File lib/webrick/httprequest.rb, line 293 293: def read_chunk_size(socket) 294: line = read_line(socket) 295: if /^([0-9a-fA-F]+)(?:;(\S+))?/ =~ line 296: chunk_size = $1.hex 297: chunk_ext = $2 298: [ chunk_size, chunk_ext ] 299: else 300: raise HTTPStatus::BadRequest, "bad chunk `#{line}'." 301: end 302: end
# File lib/webrick/httprequest.rb, line 304 304: def read_chunked(socket, block) 305: chunk_size, = read_chunk_size(socket) 306: while chunk_size > 0 307: data = "" 308: while data.size < chunk_size 309: tmp = read_data(socket, chunk_size-data.size) # read chunk-data 310: break unless tmp 311: data << tmp 312: end 313: if data.nil? || data.size != chunk_size 314: raise BadRequest, "bad chunk data size." 315: end 316: read_line(socket) # skip CRLF 317: block.call(data) 318: chunk_size, = read_chunk_size(socket) 319: end 320: read_header(socket) # trailer + CRLF 321: @header.delete("transfer-encoding") 322: @remaining_size = 0 323: end
# File lib/webrick/httprequest.rb, line 341 341: def read_data(io, size) 342: _read_data(io, :read, size) 343: end
# File lib/webrick/httprequest.rb, line 238 238: def read_header(socket) 239: if socket 240: while line = read_line(socket) 241: break if /\A(#{CRLF}|#{LF})\z/om =~ line 242: @raw_header << line 243: end 244: end 245: @header = HTTPUtils::parse_header(@raw_header.join) 246: end
# File lib/webrick/httprequest.rb, line 337 337: def read_line(io) 338: _read_data(io, :gets, LF) 339: end
# File lib/webrick/httprequest.rb, line 224 224: def read_request_line(socket) 225: @request_line = read_line(socket) if socket 226: @request_time = Time.now 227: raise HTTPStatus::EOFError unless @request_line 228: if /^(\S+)\s+(\S+?)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line 229: @request_method = $1 230: @unparsed_uri = $2 231: @http_version = HTTPVersion.new($3 ? $3 : "0.9") 232: else 233: rl = @request_line.sub(/\x0d?\x0a\z/o, '') 234: raise HTTPStatus::BadRequest, "bad Request-Line `#{rl}'." 235: end 236: end