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 44 44: def meta_vars 45: meta = orig_meta_vars 46: if @server_cert 47: meta["HTTPS"] = "on" 48: meta["SSL_SERVER_CERT"] = @server_cert.to_pem 49: meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : "" 50: if @client_cert_chain 51: @client_cert_chain.each_with_index{|cert, i| 52: meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem 53: } 54: end 55: meta["SSL_CIPHER"] = @cipher[0] 56: meta["SSL_PROTOCOL"] = @cipher[1] 57: meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s 58: meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s 59: end 60: meta 61: 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: if socket.respond_to?(:cert) 25: @server_cert = socket.cert || @config[:SSLCertificate] 26: @client_cert = socket.peer_cert 27: @client_cert_chain = socket.peer_cert_chain 28: @cipher = socket.cipher 29: end 30: orig_parse(socket) 31: end
# File lib/webrick/https.rb, line 35 35: def parse_uri(str, scheme="https") 36: if @server_cert 37: return orig_parse_uri(str, scheme) 38: end 39: return orig_parse_uri(str) 40: 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 324 324: def _read_data(io, method, arg) 325: begin 326: timeout(@config[:RequestTimeout]){ 327: return io.__send__(method, arg) 328: } 329: rescue Errno::ECONNRESET 330: return nil 331: rescue TimeoutError 332: raise HTTPStatus::RequestTimeout 333: end 334: end
# File lib/webrick/httprequest.rb, line 344 344: def parse_query() 345: begin 346: if @request_method == "GET" || @request_method == "HEAD" 347: @query = HTTPUtils::parse_query(@query_string) 348: elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/ 349: @query = HTTPUtils::parse_query(body) 350: elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/ 351: boundary = HTTPUtils::dequote($1) 352: @query = HTTPUtils::parse_form_data(body, boundary) 353: else 354: @query = Hash.new 355: end 356: rescue => ex 357: raise HTTPStatus::BadRequest, ex.message 358: end 359: 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: uri = URI::parse(str) 253: return uri if uri.absolute? 254: if self["host"] 255: pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n 256: host, port = *self['host'].scan(pattern)[0] 257: elsif @addr.size > 0 258: host, port = @addr[2], @addr[1] 259: else 260: host, port = @config[:ServerName], @config[:Port] 261: end 262: uri.scheme = scheme 263: uri.host = host 264: uri.port = port ? port.to_i : nil 265: return URI::parse(uri.to_s) 266: end
# File lib/webrick/httprequest.rb, line 268 268: def read_body(socket, block) 269: return unless socket 270: if tc = self['transfer-encoding'] 271: case tc 272: when /chunked/io then read_chunked(socket, block) 273: else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." 274: end 275: elsif self['content-length'] || @remaining_size 276: @remaining_size ||= self['content-length'].to_i 277: while @remaining_size > 0 278: sz = BUFSIZE < @remaining_size ? BUFSIZE : @remaining_size 279: break unless buf = read_data(socket, sz) 280: @remaining_size -= buf.size 281: block.call(buf) 282: end 283: if @remaining_size > 0 && @socket.eof? 284: raise HTTPStatus::BadRequest, "invalid body size." 285: end 286: elsif BODY_CONTAINABLE_METHODS.member?(@request_method) 287: raise HTTPStatus::LengthRequired 288: end 289: return @body 290: end
# File lib/webrick/httprequest.rb, line 292 292: def read_chunk_size(socket) 293: line = read_line(socket) 294: if /^([0-9a-fA-F]+)(?:;(\S+))?/ =~ line 295: chunk_size = $1.hex 296: chunk_ext = $2 297: [ chunk_size, chunk_ext ] 298: else 299: raise HTTPStatus::BadRequest, "bad chunk `#{line}'." 300: end 301: end
# File lib/webrick/httprequest.rb, line 303 303: def read_chunked(socket, block) 304: chunk_size, = read_chunk_size(socket) 305: while chunk_size > 0 306: data = "" 307: while data.size < chunk_size 308: tmp = read_data(socket, chunk_size-data.size) # read chunk-data 309: break unless tmp 310: data << tmp 311: end 312: if data.nil? || data.size != chunk_size 313: raise BadRequest, "bad chunk data size." 314: end 315: read_line(socket) # skip CRLF 316: block.call(data) 317: chunk_size, = read_chunk_size(socket) 318: end 319: read_header(socket) # trailer + CRLF 320: @header.delete("transfer-encoding") 321: @remaining_size = 0 322: end
# File lib/webrick/httprequest.rb, line 340 340: def read_data(io, size) 341: _read_data(io, :read, size) 342: 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 336 336: def read_line(io) 337: _read_data(io, :gets, LF) 338: 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