Class: WEBrick::HTTPRequest
Relationships & Source Files | |
Inherits: | Object |
Defined in: | lib/webrick/https.rb, lib/webrick/httprequest.rb |
Constant Summary
-
BODY_CONTAINABLE_METHODS =
Internal use only
# File 'lib/webrick/httprequest.rb', line 26[ "POST", "PUT" ]
-
MAX_HEADER_LENGTH =
Internal use only
same as Mongrel, Thin and Puma
(112 * 1024)
-
MAX_URI_LENGTH =
Internal use only
# File 'lib/webrick/httprequest.rb', line 4152083
-
PrivateNetworkRegexp =
Internal use only
# File 'lib/webrick/httprequest.rb', line 566/ ^unknown$| ^((::ffff:)?127.0.0.1|::1)$| ^(::ffff:)?(10|172\.(1[6-9]|2[0-9]|3[01])|192\.168)\. /ixo
Request line
-
#http_version
readonly
The HTTP version of the request.
-
#request_line
readonly
The complete request line such as:
-
#request_method
readonly
The request method, GET, POST, PUT, etc.
-
#unparsed_uri
readonly
The unparsed URI of the request.
Request-URI
-
#path
readonly
The request path.
-
#path_info
rw
The path info (CGI variable).
-
#query_string
rw
The query from the URI of the request.
-
#request_uri
readonly
The parsed URI of the request.
-
#script_name
rw
The script name (CGI variable).
Header and entity body
-
#accept
readonly
The Accept header value.
-
#accept_charset
readonly
The Accept-Charset header value.
-
#accept_encoding
readonly
The Accept-Encoding header value.
-
#accept_language
readonly
The Accept-Language header value.
-
#cookies
readonly
The parsed request cookies.
-
#header
readonly
The parsed header of the request.
-
#raw_header
readonly
The raw header of the request.
Class Method Summary
-
.new(config) ⇒ HTTPRequest
constructor
Creates a new HTTP request.
Instance Attribute Summary
-
#addr
readonly
The socket address of the server.
-
#attributes
readonly
Hash of request attributes.
-
#cipher
readonly
HTTP request SSL cipher.
-
#client_cert
readonly
HTTP request client certificate.
-
#keep_alive
readonly
Is this a keep-alive connection?
-
#keep_alive? ⇒ Boolean
readonly
Should the connection this request was made on be kept alive?
-
#peeraddr
readonly
The socket address of the client.
-
#request_time
readonly
The local time this request was received.
-
#server_cert
readonly
HTTP request server certificate.
-
#ssl? ⇒ Boolean
readonly
Is this an SSL request?
-
#user
rw
The remote user (CGI variable).
Instance Method Summary
-
#[](header_name)
Retrieves
header_name
-
#body(&block)
Returns the request body.
-
#content_length
The content-length header.
-
#content_type
The content-type header.
-
#each
Iterates over the request headers.
-
#host
The host this request is for.
-
#port
The port this request is for.
-
#query
Request query as a Hash.
-
#remote_ip
The client's IP address.
-
#server_name
The server name this request is for.
-
#continue
Internal use only
Generate HTTP/1.1 100 continue response if the client expects it, otherwise does nothing.
-
#fixup
Internal use only
Consumes any remaining body and updates keep-alive status.
-
#meta_vars
Internal use only
This method provides the metavariables defined by the revision 3 of “The WWW Common Gateway Interface Version 1.1” To browse the current document of CGI Version 1.1, see below: tools.ietf.org/html/rfc3875.
- #orig_meta_vars Internal use only
- #orig_parse Internal use only
- #orig_parse_uri Internal use only
-
#parse(socket = nil)
Internal use only
Parses a request from
socket
. - #to_s Internal use only
- #_read_data(io, method, *arg) private Internal use only
- #parse_query private Internal use only
-
#parse_uri(str, scheme = "http")
private
Internal use only
See additional method definition at file lib/webrick/https.rb line 57.
- #read_body(socket, block) private Internal use only
- #read_chunk_size(socket) private Internal use only
- #read_chunked(socket, block) private Internal use only
- #read_data(io, size) private Internal use only
- #read_header(socket) private Internal use only
- #read_line(io, size = 4096) private Internal use only
- #read_request_line(socket) private Internal use only
-
#setup_forwarded_info
private
Internal use only
It's said that all X-Forwarded-* headers will contain more than one (comma-separated) value if the original request already contained one of these headers.
Constructor Details
.new(config) ⇒ HTTPRequest
Creates a new HTTP request. Config::HTTP is the default configuration.
# File 'lib/webrick/httprequest.rb', line 152
def initialize(config) @config = config @buffer_size = @config[:InputBufferSize] @logger = config[:Logger] @request_line = @request_method = @unparsed_uri = @http_version = nil @request_uri = @host = @port = @path = nil @script_name = @path_info = nil @query_string = nil @query = nil @form_data = nil @raw_header = Array.new @header = nil @cookies = [] @accept = [] @accept_charset = [] @accept_encoding = [] @accept_language = [] @body = "" @addr = @peeraddr = nil @attributes = {} @user = nil @keep_alive = false @request_time = nil @remaining_size = nil @socket = nil @forwarded_proto = @forwarded_host = @forwarded_port = @forwarded_server = @forwarded_for = nil end
Instance Attribute Details
#accept (readonly)
The Accept header value
# File 'lib/webrick/httprequest.rb', line 99
attr_reader :accept
#accept_charset (readonly)
The Accept-Charset header value
# File 'lib/webrick/httprequest.rb', line 104
attr_reader :accept_charset
#accept_encoding (readonly)
The Accept-Encoding header value
# File 'lib/webrick/httprequest.rb', line 109
attr_reader :accept_encoding
#accept_language (readonly)
The Accept-Language header value
# File 'lib/webrick/httprequest.rb', line 114
attr_reader :accept_language
#addr (readonly)
The socket address of the server
# File 'lib/webrick/httprequest.rb', line 126
attr_reader :addr
#attributes (readonly)
Hash of request attributes
# File 'lib/webrick/httprequest.rb', line 136
attr_reader :attributes
#cipher (readonly)
HTTP request SSL cipher
# File 'lib/webrick/https.rb', line 29
attr_reader :cipher
#client_cert (readonly)
HTTP request client certificate
# File 'lib/webrick/https.rb', line 39
attr_reader :client_cert
#cookies (readonly)
The parsed request cookies
# File 'lib/webrick/httprequest.rb', line 94
attr_reader :
#header (readonly)
The parsed header of the request
# File 'lib/webrick/httprequest.rb', line 89
attr_reader :header
#http_version (readonly)
The HTTP version of the request
# File 'lib/webrick/httprequest.rb', line 50
attr_reader :http_version
#keep_alive (readonly)
Is this a keep-alive connection?
# File 'lib/webrick/httprequest.rb', line 141
attr_reader :keep_alive
#keep_alive? ⇒ Boolean
(readonly)
Should the connection this request was made on be kept alive?
# File 'lib/webrick/httprequest.rb', line 344
def keep_alive? @keep_alive end
#path (readonly)
The request path
# File 'lib/webrick/httprequest.rb', line 62
attr_reader :path
#path_info (rw)
The path info (CGI variable)
# File 'lib/webrick/httprequest.rb', line 72
attr_accessor :path_info
#peeraddr (readonly)
The socket address of the client
# File 'lib/webrick/httprequest.rb', line 131
attr_reader :peeraddr
#query_string (rw)
The query from the URI of the request
# File 'lib/webrick/httprequest.rb', line 77
attr_accessor :query_string
#raw_header (readonly)
The raw header of the request
# File 'lib/webrick/httprequest.rb', line 84
attr_reader :raw_header
#request_line (readonly)
The complete request line such as:
GET / HTTP/1.1
# File 'lib/webrick/httprequest.rb', line 35
attr_reader :request_line
#request_method (readonly)
The request method, GET, POST, PUT, etc.
# File 'lib/webrick/httprequest.rb', line 40
attr_reader :request_method
#request_time (readonly)
The local time this request was received
# File 'lib/webrick/httprequest.rb', line 146
attr_reader :request_time
#request_uri (readonly)
The parsed URI of the request
# File 'lib/webrick/httprequest.rb', line 57
attr_reader :request_uri
#script_name (rw)
The script name (CGI variable)
# File 'lib/webrick/httprequest.rb', line 67
attr_accessor :script_name
#server_cert (readonly)
HTTP request server certificate
# File 'lib/webrick/https.rb', line 34
attr_reader :server_cert
#ssl? ⇒ Boolean
(readonly)
Is this an SSL request?
# File 'lib/webrick/httprequest.rb', line 337
def ssl? return @request_uri.scheme == "https" end
#unparsed_uri (readonly)
The unparsed URI of the request
# File 'lib/webrick/httprequest.rb', line 45
attr_reader :unparsed_uri
#user (rw)
The remote user (CGI variable)
# File 'lib/webrick/httprequest.rb', line 121
attr_accessor :user
Instance Method Details
#[](header_name)
Retrieves header_name
# File 'lib/webrick/httprequest.rb', line 287
def [](header_name) if @header value = @header[header_name.downcase] value.empty? ? nil : value.join(", ") end end
#_read_data(io, method, *arg) (private)
# File 'lib/webrick/httprequest.rb', line 529
def _read_data(io, method, *arg) begin WEBrick::Utils.timeout(@config[:RequestTimeout]){ return io.__send__(method, *arg) } rescue Errno::ECONNRESET return nil rescue Timeout::Error raise HTTPStatus::RequestTimeout end end
#body(&block)
Returns the request body.
#content_length
The content-length header
# File 'lib/webrick/httprequest.rb', line 273
def content_length return Integer(self['content-length']) end
#content_type
The content-type header
# File 'lib/webrick/httprequest.rb', line 280
def content_type return self['content-type'] end
#continue
Generate HTTP/1.1 100 continue response if the client expects it, otherwise does nothing.
# File 'lib/webrick/httprequest.rb', line 244
def continue # :nodoc: if self['expect'] == '100-continue' && @config[:HTTPVersion] >= "1.1" @socket << "HTTP/#{@config[:HTTPVersion]} 100 continue#{CRLF}#{CRLF}" @header.delete('expect') end end
#each
Iterates over the request headers
# File 'lib/webrick/httprequest.rb', line 297
def each if @header @header.each{|k, v| value = @header[k] yield(k, value.empty? ? nil : value.join(", ")) } end end
#fixup
Consumes any remaining body and updates keep-alive status
# File 'lib/webrick/httprequest.rb', line 359
def fixup() # :nodoc: begin body{|chunk| } # read remaining body rescue HTTPStatus::Error => ex @logger.error("HTTPRequest#fixup: #{ex.class} occurred.") @keep_alive = false rescue => ex @logger.error(ex) @keep_alive = false end end
#host
The host this request is for
# File 'lib/webrick/httprequest.rb', line 309
def host return @forwarded_host || @host end
#meta_vars
This method provides the metavariables defined by the revision 3 of “The WWW Common Gateway Interface Version 1.1” To browse the current document of CGI Version 1.1, see below: tools.ietf.org/html/rfc3875
# File 'lib/webrick/httprequest.rb', line 376
def = if server_cert ["HTTPS"] = "on" ["SSL_SERVER_CERT"] = @server_cert.to_pem ["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : "" if @client_cert_chain @client_cert_chain.each_with_index{|cert, i| ["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem } end ["SSL_CIPHER"] = @cipher[0] ["SSL_PROTOCOL"] = @cipher[1] ["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s ["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s end end
#orig_meta_vars
# File 'lib/webrick/https.rb', line 65
alias
#orig_parse
# File 'lib/webrick/https.rb', line 43
alias orig_parse parse
#orig_parse_uri
# File 'lib/webrick/https.rb', line 55
alias orig_parse_uri parse_uri
#parse(socket = nil)
Parses a request from socket
. This is called internally by HTTPServer.
# File 'lib/webrick/httprequest.rb', line 192
def parse(socket=nil) if socket.respond_to?(:cert) @server_cert = socket.cert || @config[:SSLCertificate] @client_cert = socket.peer_cert @client_cert_chain = socket.peer_cert_chain @cipher = socket.cipher end orig_parse(socket) end
#parse_query (private)
# File 'lib/webrick/httprequest.rb', line 549
def parse_query() begin if @request_method == "GET" || @request_method == "HEAD" @query = HTTPUtils::parse_query(@query_string) elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/ @query = HTTPUtils::parse_query(body) elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/ boundary = HTTPUtils::dequote($1) @query = HTTPUtils::parse_form_data(body, boundary) else @query = Hash.new end rescue => ex raise HTTPStatus::BadRequest, ex. end end
#parse_uri(str, scheme = "http") (private)
See additional method definition at file lib/webrick/https.rb line 57.
# File 'lib/webrick/httprequest.rb', line 451
def parse_uri(str, scheme="https") if server_cert return orig_parse_uri(str, scheme) end return orig_parse_uri(str) end
#port
The port this request is for
# File 'lib/webrick/httprequest.rb', line 316
def port return @forwarded_port || @port end
#query
Request query as a Hash
# File 'lib/webrick/httprequest.rb', line 263
def query unless @query parse_query() end @query end
#read_body(socket, block) (private)
# File 'lib/webrick/httprequest.rb', line 474
def read_body(socket, block) return unless socket if tc = self['transfer-encoding'] case tc when /\Achunked\z/io then read_chunked(socket, block) else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." end elsif self['content-length'] || @remaining_size @remaining_size ||= self['content-length'].to_i while @remaining_size > 0 sz = [@buffer_size, @remaining_size].min break unless buf = read_data(socket, sz) @remaining_size -= buf.bytesize block.call(buf) end if @remaining_size > 0 && @socket.eof? raise HTTPStatus::BadRequest, "invalid body size." end elsif BODY_CONTAINABLE_METHODS.member?(@request_method) raise HTTPStatus::LengthRequired end return @body end
#read_chunk_size(socket) (private)
# File 'lib/webrick/httprequest.rb', line 498
def read_chunk_size(socket) line = read_line(socket) if /^([0-9a-fA-F])(?:;(\S))?/ =~ line chunk_size = $1.hex chunk_ext = $2 [ chunk_size, chunk_ext ] else raise HTTPStatus::BadRequest, "bad chunk `#{line}'." end end
#read_chunked(socket, block) (private)
# File 'lib/webrick/httprequest.rb', line 509
def read_chunked(socket, block) chunk_size, = read_chunk_size(socket) while chunk_size > 0 begin sz = [ chunk_size, @buffer_size ].min data = read_data(socket, sz) # read chunk-data if data.nil? || data.bytesize != sz raise HTTPStatus::BadRequest, "bad chunk data size." end block.call(data) end while (chunk_size -= sz) > 0 read_line(socket) # skip CRLF chunk_size, = read_chunk_size(socket) end read_header(socket) # trailer + CRLF @header.delete("transfer-encoding") @remaining_size = 0 end
#read_data(io, size) (private)
# File 'lib/webrick/httprequest.rb', line 545
def read_data(io, size) _read_data(io, :read, size) end
#read_header(socket) (private)
# File 'lib/webrick/httprequest.rb', line 438
def read_header(socket) if socket while line = read_line(socket) break if /\A(#{CRLF}|#{LF})\z/om =~ line if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH raise HTTPStatus::RequestEntityTooLarge, 'headers too large' end @raw_header << line end end @header = HTTPUtils::parse_header(@raw_header.join) end
#read_line(io, size = 4096) (private)
# File 'lib/webrick/httprequest.rb', line 541
def read_line(io, size=4096) _read_data(io, :gets, LF, size) end
#read_request_line(socket) (private)
# File 'lib/webrick/httprequest.rb', line 420
def read_request_line(socket) @request_line = read_line(socket, MAX_URI_LENGTH) if socket @request_bytes = @request_line.bytesize if @request_bytes >= MAX_URI_LENGTH and @request_line[-1, 1] != LF raise HTTPStatus::RequestURITooLarge end @request_time = Time.now raise HTTPStatus::EOFError unless @request_line if /^(\S)\s(\S)(?:\sHTTP\/(\d\.\d))?\r?\n/mo =~ @request_line @request_method = $1 @unparsed_uri = $2 @http_version = HTTPVersion.new($3 ? $3 : "0.9") else rl = @request_line.sub(/\x0d?\x0a\z/o, '') raise HTTPStatus::BadRequest, "bad Request-Line `#{rl}'." end end
#remote_ip
The client's IP address
# File 'lib/webrick/httprequest.rb', line 330
def remote_ip return self["client-ip"] || @forwarded_for || @peeraddr[3] end
#server_name
The server name this request is for
# File 'lib/webrick/httprequest.rb', line 323
def server_name return @forwarded_server || @config[:ServerName] end
#setup_forwarded_info (private)
It's said that all X-Forwarded-* headers will contain more than one (comma-separated) value if the original request already contained one of these headers. Since we could use these values as Host header, we choose the initial(first) value. (apr_table_mergen() adds new value after the existing value with “, ” prefix)
# File 'lib/webrick/httprequest.rb', line 577
def setup_forwarded_info if @forwarded_server = self["x-forwarded-server"] @forwarded_server = @forwarded_server.split(",", 2).first end if @forwarded_proto = self["x-forwarded-proto"] @forwarded_proto = @forwarded_proto.split(",", 2).first end if host_port = self["x-forwarded-host"] host_port = host_port.split(",", 2).first @forwarded_host, tmp = host_port.split(":", 2) @forwarded_port = (tmp || (@forwarded_proto == "https" ? 443 : 80)).to_i end if addrs = self["x-forwarded-for"] addrs = addrs.split(",").collect(&:strip) addrs.reject!{|ip| PrivateNetworkRegexp =~ ip } @forwarded_for = addrs.first end end