Fix kiwix proxy 502ing on article links with non-ASCII titles
Sinatra decodes a route's splat before handing it to the block, so an article link like /kiwix/content/wikipedia/Dlhé_diely arrived as raw UTF-8, not percent-encoded. URI#path= rejects that outright (URI::InvalidComponentError) rather than escaping it, which .proxy's rescue turned into a silent nil -> every article link 502'd, while the search results page linking to them worked fine (its own path, /kiwix/search, is plain ASCII).
This commit is contained in:
1 parent
5ff9b113d9
commit
2b49eda7cb
2 files changed
+33
-1
No files matched your search
@@ -26,9 +26,16 @@ module Maptool
|
|||||||
# correct without this having to touch response bodies at all. Returns
|
# correct without this having to touch response bodies at all. Returns
|
||||||
# nil (halted as a 502 by the caller) rather than raising, same
|
# nil (halted as a 502 by the caller) rather than raising, same
|
||||||
# not-reachable-isn't-exceptional stance as .reachable? above.
|
# not-reachable-isn't-exceptional stance as .reachable? above.
|
||||||
|
#
|
||||||
|
# path arrives already URL-*decoded* — Sinatra decodes a route's splat
|
||||||
|
# before handing it over — so an article title with non-ASCII
|
||||||
|
# characters (e.g. "/kiwix/content/wikipedia/Dlhé_diely") has to be
|
||||||
|
# re-escaped before URI#path= will accept it at all; it raises
|
||||||
|
# URI::InvalidComponentError on raw UTF-8 bytes rather than escaping
|
||||||
|
# them itself. Article links otherwise 502'd for exactly this reason.
|
||||||
def self.proxy(base_url, path, query_string, open_timeout: 2, read_timeout: 10)
|
def self.proxy(base_url, path, query_string, open_timeout: 2, read_timeout: 10)
|
||||||
uri = URI(base_url)
|
uri = URI(base_url)
|
||||||
uri.path = path
|
uri.path = URI::RFC2396_PARSER.escape(path)
|
||||||
uri.query = query_string unless query_string.to_s.empty?
|
uri.query = query_string unless query_string.to_s.empty?
|
||||||
Net::HTTP.start(uri.host, uri.port, open_timeout: open_timeout, read_timeout: read_timeout) { |http| http.request(Net::HTTP::Get.new(uri)) }
|
Net::HTTP.start(uri.host, uri.port, open_timeout: open_timeout, read_timeout: read_timeout) { |http| http.request(Net::HTTP::Get.new(uri)) }
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
|
|||||||
@@ -45,4 +45,29 @@ class KiwixTest < Minitest::Test
|
|||||||
def test_proxy_returns_nil_when_nothing_is_listening
|
def test_proxy_returns_nil_when_nothing_is_listening
|
||||||
assert_nil Maptool::Kiwix.proxy("http://127.0.0.1:1", "/kiwix/search", "", open_timeout: 1)
|
assert_nil Maptool::Kiwix.proxy("http://127.0.0.1:1", "/kiwix/search", "", open_timeout: 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A path with non-ASCII characters, e.g. an article title like
|
||||||
|
# "/kiwix/content/wikipedia/Dlhé_diely" — exactly what Sinatra's splat
|
||||||
|
# hands .proxy for a real article link, already URL-*decoded*. Used to
|
||||||
|
# raise URI::InvalidComponentError (caught, so this returned nil — every
|
||||||
|
# article link 502'd) since URI#path= rejects raw UTF-8 bytes outright
|
||||||
|
# instead of escaping them.
|
||||||
|
def test_proxy_escapes_non_ascii_characters_in_the_path
|
||||||
|
server = TCPServer.new("127.0.0.1", 0)
|
||||||
|
port = server.addr[1]
|
||||||
|
request_line = nil
|
||||||
|
thread = Thread.new do
|
||||||
|
client = server.accept
|
||||||
|
request_line = client.gets
|
||||||
|
client.print("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\n")
|
||||||
|
client.close
|
||||||
|
end
|
||||||
|
|
||||||
|
response = Maptool::Kiwix.proxy("http://127.0.0.1:#{port}", "/kiwix/content/wikipedia/Dlhé_diely", "")
|
||||||
|
thread.join
|
||||||
|
server.close
|
||||||
|
|
||||||
|
assert_equal "GET /kiwix/content/wikipedia/Dlh%C3%A9_diely HTTP/1.1\r\n", request_line
|
||||||
|
assert_equal "200", response.code
|
||||||
|
end
|
||||||
end
|
end
|
||||||
Reference in new issue
Block a user