New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"GET %2Ffavicon.ico HTTP/1.1" in log #11816
Comments
I can confirm that this happens with Unicorn and Puma. It doesn't even seem to show up with |
With Unicorn I could reproduce the bug. However it shows up on the first request with curl http://localhost:8080. Afterwards, only after server restart it shows up again (but not always, looks like Unicorn is somehow caching the logger output...) |
So the issue in here is not on unicorn or puma. We only can see the symptoms of it happening on those because they enable the |
This is a bug in AD::Static. It's wrongly escaping the PATH_INFO:
|
Indeed, From 2012: rack/rack#265 (comment) |
Rack diff --git a/lib/rack/file.rb b/lib/rack/file.rb
index c8f8d0d..e1bf12b 100644
--- a/lib/rack/file.rb
+++ b/lib/rack/file.rb
@@ -38,7 +38,8 @@ module Rack
return fail(405, "Method Not Allowed", {'Allow' => ALLOW_HEADER})
end
- path_info = Utils.unescape(env["PATH_INFO"])
+ # FIXME: unescape as URI path, not as query component
+ path_info = env['rack.file.unescaped_path_info'] || Utils.unescape(env["PATH_INFO"])
clean_path_info = Utils.clean_path_info(path_info)
@path = F.join(@root, clean_path_info) Rails diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index e66c21e..03ce68f 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -21,14 +21,11 @@ module ActionDispatch
end
def match?(path)
- path = URI.parser.unescape(path)
+ path = Journey::Router::Utils.unescape_uri(path)
return false unless path.valid_encoding?
paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"]
-
- if match = paths.detect {|p| File.file?(File.join(@root, p)) }
- return ::Rack::Utils.escape(match)
- end
+ paths.detect {|p| File.file?(File.join(@root, p)) }
end
def call(env)
@@ -36,7 +33,8 @@ module ActionDispatch
gzip_path = gzip_file_path(path)
if gzip_path && gzip_encoding_accepted?(env)
- env['PATH_INFO'] = gzip_path
+ env["rack.file.unescaped_path_info"] = gzip_path
+ env["PATH_INFO"] = Journey::Router::Utils.escape_path(gzip_path)
status, headers, body = @file_server.call(env)
headers['Content-Encoding'] = 'gzip'
headers['Content-Type'] = content_type(path)
@@ -67,7 +65,7 @@ module ActionDispatch
def gzip_file_path(path)
can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
gzip_path = "#{path}.gz"
- if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape(gzip_path)))
+ if can_gzip_mime && File.exist?(File.join(@root, Journey::Router::Utils.unescape_uri(gzip_path)))
gzip_path
else
false
@@ -95,7 +93,8 @@ module ActionDispatch
when 'GET', 'HEAD'
path = env['PATH_INFO'].chomp('/')
if match = @file_handler.match?(path)
- env["PATH_INFO"] = match
+ env["rack.file.unescaped_path_info"] = match
+ env["PATH_INFO"] = Journey::Router::Utils.escape_path(match)
return @file_handler.call(env)
end
end |
This issue has been automatically marked as stale because it has not been commented on for at least The resources of the Rails team are limited, and so we are asking for your help. If you can still reproduce this error on the Thank you for all your contributions. |
@jeremy the ruby-lang bug you linked to in rack/rack#265 is broken. Are you able to find the right URL? Since Rack master is 2.0, I'd like to fix this The Right Way™ |
@tenderlove see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/24014 and surrounds. AFAICS, it's a bug report complaining that That matches my understanding too:
(emphasis mine, but the heading's hardly subtle in the original) RFC 3986 ascribes no special interpretation to |
@matthewd So we should really only be dealing with Shouldn't we just change Rack to use URI unescape vs form unescape? It looks like Rack is using form unescape rather than URI escape:
As a side note, this comment seems dubious / wrong. It seems like we have an diff --git a/lib/rack/file.rb b/lib/rack/file.rb
index 1efa15a..5b755f5 100644
--- a/lib/rack/file.rb
+++ b/lib/rack/file.rb
@@ -30,7 +30,7 @@ module Rack
return fail(405, "Method Not Allowed", {'Allow' => ALLOW_HEADER})
end
- path_info = Utils.unescape request.path_info
+ path_info = Utils.unescape_path request.path_info
clean_path_info = Utils.clean_path_info(path_info)
path = ::File.join(@root, clean_path_info)
diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb
index 184bf5a..8911445 100644
--- a/lib/rack/utils.rb
+++ b/lib/rack/utils.rb
@@ -19,6 +19,8 @@ module Rack
COMMON_SEP = QueryParser::COMMON_SEP
KeySpaceConstrainedParams = QueryParser::Params
+ URI_PARSER = URI::Parser.new
+
class << self
attr_accessor :default_query_parser
end
@@ -35,10 +37,17 @@ module Rack
# Like URI escaping, but with %20 instead of +. Strictly speaking this is
# true URI escaping.
def escape_path(s)
- escape(s).gsub('+', '%20')
+ URI_PARSER.escape s
end
module_function :escape_path
+ # Unescapes the **path** component of a URI. See Rack::Utils.unescape for
+ # unescaping query parameters or form components.
+ def unescape_path(s)
+ URI_PARSER.unescape s
+ end
+ module_function :unescape_path
+
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
# target encoding of the string returned, and it defaults to UTF-8
def unescape(s, encoding = Encoding::UTF_8) /cc @jeremy |
directories that have + in the name should be served up if the browser puts a + in the path. + is a valid path character, so it should not be translated to a space (like you do in query parameters). references #265 rails/rails#11816
Unescaping paths is different from unescaping query parameters. This commit changes the unescape to use the URI parser to unescape the path, which leaves `+` as `+`. Fixes #265 References rails/rails#11816
Fixed in e25fdad |
Escaping and unescaping paths is different than query parameters, and we need to respect that. This commit uses the new method in Rack to escape and unescape paths. Fixes #11816
How to reproduce:
rails new foo
(I use rails 4.0.0)Gemfile
and enableunicorn
gembundle exec unicorn
http://localhost:8080/
with browser.then I found
"GET %2Ffavicon.ico HTTP/1.1"
in log messages.I expected
"GET /favicon.ico HTTP/1.1"
.In
actionpack-4.0.0/lib/action_dispatch/middleware/static.rb
,match = @file_handler.match?(path)
returns escaped path,and overwrite
env["PATH_INFO"]
.It seems to affect logger.
The text was updated successfully, but these errors were encountered: