lib/rack/request.rb in rack-1.4.7 vs lib/rack/request.rb in rack-1.5.0.beta.1

- old
+ new

@@ -96,14 +96,12 @@ def port if port = host_with_port.split(/:/)[1] port.to_i elsif port = @env['HTTP_X_FORWARDED_PORT'] port.to_i - elsif ssl? - 443 elsif @env.has_key?("HTTP_X_FORWARDED_HOST") - 80 + DEFAULT_PORTS[scheme] else @env["SERVER_PORT"].to_i end end @@ -116,29 +114,29 @@ def path_info=(s); @env["PATH_INFO"] = s.to_s end # Checks the HTTP request method (or verb) to see if it was of type DELETE def delete?; request_method == "DELETE" end - + # Checks the HTTP request method (or verb) to see if it was of type GET def get?; request_method == "GET" end - + # Checks the HTTP request method (or verb) to see if it was of type HEAD def head?; request_method == "HEAD" end - + # Checks the HTTP request method (or verb) to see if it was of type OPTIONS def options?; request_method == "OPTIONS" end - + # Checks the HTTP request method (or verb) to see if it was of type PATCH def patch?; request_method == "PATCH" end - + # Checks the HTTP request method (or verb) to see if it was of type POST def post?; request_method == "POST" end - + # Checks the HTTP request method (or verb) to see if it was of type PUT def put?; request_method == "PUT" end - + # Checks the HTTP request method (or verb) to see if it was of type TRACE def trace?; request_method == "TRACE" end # The set of form-data media-types. Requests that do not indicate @@ -155,10 +153,14 @@ PARSEABLE_DATA_MEDIA_TYPES = [ 'multipart/related', 'multipart/mixed' ] + # Default ports depending on scheme. Used to decide whether or not + # to include the port in a generated URI. + DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 } + # Determine whether the request body contains form-data by checking # the request Content-Type for one of the media-types: # "application/x-www-form-urlencoded" or "multipart/form-data". The # list of form-data media types can be modified through the # +FORM_DATA_MEDIA_TYPES+ array. @@ -215,22 +217,59 @@ {} end end # The union of GET and POST data. + # + # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params. def params @params ||= self.GET.merge(self.POST) rescue EOFError - self.GET + self.GET.dup end + # Destructively update a parameter, whether it's in GET and/or POST. Returns nil. + # + # The parameter is updated wherever it was previous defined, so GET, POST, or both. If it wasn't previously defined, it's inserted into GET. + # + # env['rack.input'] is not touched. + def update_param(k, v) + found = false + if self.GET.has_key?(k) + found = true + self.GET[k] = v + end + if self.POST.has_key?(k) + found = true + self.POST[k] = v + end + unless found + self.GET[k] = v + end + @params = nil + nil + end + + # Destructively delete a parameter, whether it's in GET or POST. Returns the value of the deleted parameter. + # + # If the parameter is in both GET and POST, the POST value takes precedence since that's how #params works. + # + # env['rack.input'] is not touched. + def delete_param(k) + v = [ self.POST.delete(k), self.GET.delete(k) ].compact.first + @params = nil + v + end + # shortcut for request.params[key] def [](key) params[key.to_s] end # shortcut for request.params[key] = value + # + # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params. def []=(key, value) params[key.to_s] = value end # like Hash#values_at @@ -269,18 +308,12 @@ def xhr? @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" end def base_url - url = scheme + "://" - url << host - - if scheme == "https" && port != 443 || - scheme == "http" && port != 80 - url << ":#{port}" - end - + url = "#{scheme}://#{host}" + url << ":#{port}" if port != DEFAULT_PORTS[scheme] url end # Tries to return a remake of the original request URL as a string. def url @@ -305,30 +338,38 @@ [encoding, quality] end end def trusted_proxy?(ip) - ip =~ /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|^::1$|^fd[0-9a-f]{2}:.+|^localhost$/i + ip =~ /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|^::1$|^fd[0-9a-f]{2}:.+|^localhost$|^unix$|^unix:/i end def ip - remote_addrs = @env['REMOTE_ADDR'] ? @env['REMOTE_ADDR'].split(/[,\s]+/) : [] - remote_addrs.reject! { |addr| trusted_proxy?(addr) } - + remote_addrs = split_ip_addresses(@env['REMOTE_ADDR']) + remote_addrs = reject_trusted_ip_addresses(remote_addrs) + return remote_addrs.first if remote_addrs.any? - forwarded_ips = @env['HTTP_X_FORWARDED_FOR'] ? @env['HTTP_X_FORWARDED_FOR'].strip.split(/[,\s]+/) : [] + forwarded_ips = split_ip_addresses(@env['HTTP_X_FORWARDED_FOR']) if client_ip = @env['HTTP_CLIENT_IP'] # If forwarded_ips doesn't include the client_ip, it might be an # ip spoofing attempt, so we ignore HTTP_CLIENT_IP return client_ip if forwarded_ips.include?(client_ip) end - return forwarded_ips.reject { |ip| trusted_proxy?(ip) }.last || @env["REMOTE_ADDR"] + return reject_trusted_ip_addresses(forwarded_ips).last || @env["REMOTE_ADDR"] end protected + def split_ip_addresses(ip_addresses) + ip_addresses ? ip_addresses.strip.split(/[,\s]+/) : [] + end + + def reject_trusted_ip_addresses(ip_addresses) + ip_addresses.reject { |ip| trusted_proxy?(ip) } + end + def parse_query(qs) Utils.parse_nested_query(qs) end def parse_multipart(env)