class Midori::Request
Request
class for midori @attr [String] ip client ip address @attr [Integer] port client port @attr [String] ip parsed ip address @attr [String] protocol protocol version of HTTP request @attr [Symbol] method HTTP method @attr [String] path request path @attr [Hash] query_params
parameter parsed from query string @attr [String | nil] query_string
request query string @attr [HTTPHeader] header request header @attr [String] body request body @attr [Hash] cookie cookie hash coming from request @attr [Boolean] parsed whether the request header parsed @attr [Boolean] body_parsed
whether the request body parsed @attr [Hash] params params in the url
Attributes
Public Class Methods
Init Request
# File lib/midori/request.rb, line 23 def initialize @header = HTTPHeader.new @parsed = false @body_parsed = false @is_websocket = false @is_eventsource = false @ip = '' @port = 0 @parser = Mizu::Parser.new @params = {} @query_params = Hash.new(Array.new) @cookie = {} @body = '' @parser.on_complete do @protocol = @parser.version @method = @parser.method @path = @parser.path # Turn header into case-insensitive due to RFC 2.6 Chapter 4.2 # https://www.ietf.org/rfc/rfc2616.txt @parser.headers.each { |key, value| @header[key] = value } @remote_ip = parse_ip || @ip # Detect client real IP with RFC 7239 @query_string = @path.match(/\?(.*?)$/) unless @query_string.nil? @query_string = @query_string[1] @query_params = CGI::parse(@query_string) end @cookie = CGI::Cookie.parse(@header['Cookie']) unless @header['Cookie'].nil? @path.gsub!(/\?(.*?)$/, '') @method = @method.to_sym @parsed = true end end
Public Instance Methods
Syntactic sugar for whether a request body is parsed @return [Boolean] parsed or not
# File lib/midori/request.rb, line 137 def body_parsed? @body_parsed end
Syntactic sugar for whether a request is an eventsource request @return [Boolean] eventsource or not
# File lib/midori/request.rb, line 149 def eventsource? @is_eventsource end
Init an request with String
data @param [String] data @return [nil] nil
# File lib/midori/request.rb, line 74 def parse(data) # Call parser if header not parsed if @parsed @body += data else return nil if data.nil? @parser << data @body += data[@parser.offset..-1] if @parsed end # Set body parsed if body reaches content length if @parsed && (@header['Content-Length'].to_i || 0) <= @body.bytesize @body_parsed = true pre_proceed end nil end
Get the real user IP from headers @return [String | nil] nil when not available, otherwise, return the real IP Modified from Rack
# File lib/midori/request.rb, line 95 def parse_ip # Do not parse anything if not behind proxy return nil unless Midori::Configure.proxy return @header['X-Real-IP'] if Midori::Configure.trust_real_ip # Not enough infomation return nil if @header['X-Forwarded-For'].nil? forwarded_ips = @header['X-Forwarded-For'].split(', ') # Spoofing check trusted = forwarded_ips.reject do |ip| ip =~ Midori::Configure.trusted_proxies end trusted.last end
Syntactic sugar for whether a request header is parsed @return [Boolean] parsed or not
# File lib/midori/request.rb, line 131 def parsed? @parsed end
Preproceed the request after parsed @return [nil] nil
# File lib/midori/request.rb, line 111 def pre_proceed # Deal with WebSocket upgrade = @header['Connection']&.split(', ')&.include?('Upgrade') if upgrade && @header['Upgrade'] == 'websocket' @method = :WEBSOCKET @is_websocket = true end # Deal with EventSource if @header['Accept'] == 'text/event-stream' @method = :EVENTSOURCE @is_eventsource = true end @method = @method.to_sym nil end
# File lib/midori/request.rb, line 58 def reset! @header = HTTPHeader.new @parsed = false @body_parsed = false @is_websocket = false @is_eventsource = false @parser.reset! @params = {} @query_params = Hash.new(Array.new) @cookie = {} @body = '' end
Syntactic sugar for whether a request is a websocket request @return [Boolean] websocket or not
# File lib/midori/request.rb, line 143 def websocket? @is_websocket end