-
Notifications
You must be signed in to change notification settings - Fork 983
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
Some API providers cannot interpret encoded colons in the path #1567
Comments
Hi @ykrods and thank you for the thorough investigation! The underlying issue was described in this comment, so I want to make sure we don’t fall back into that. To check your proposed solution, I’ve run the following: base = URI.parse('https://service.com/')
url = 'service:search?limit=50&offset=400'
uri = url ? URI.parse(base.to_s + url) : base # this is your proposed solution, which works!
=> #<URI::HTTPS https://service.com/service:search?limit=50&offset=400> Thank you also for pointing out pros/cons of the proposed solution.
Benchmark.bm do |x|
x.report do
10_000.times do
url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque
uri = url ? base + url : base
end
end
x.report { 10_000.times { URI.parse(base.to_s + url) } }
end
user system total real
0.184706 0.021542 0.206248 ( 0.206335)
0.040563 0.001414 0.041977 ( 0.041988)
|
Thanks for benchmarking and very good news!
I know this might not be a common use case, but I concerned about like a below case. base = URI.parse("https://example.com/search?limit=100")
url = "additional_path"
p URI.parse(base.to_s + url) # ==> <URI::HTTPS https://example.com/search?limit=100additional_path> However, I found query is removed in url_prefix= method, so it's disadvantage has been resolved. faraday/lib/faraday/connection.rb Lines 356 to 362 in 4abafa5
For example, the following code, if patched as is, would result in an extra slash. con = Faraday.new(url: "http://example.com/v1")
p con.build_exclusive_url("/search")
# ==> <URI::HTTP http://example.com/v1//search> It seems to me that we could simply remove the leading slash from the non-base url, but I'm concerned that there may be use cases that I'm not recognizing. |
Sorry for changing my mind, but I came up with another, better idea. As mentioned in #1237, the point of problem is caused by string before the colon (like p URI.parse("service:search").scheme # ==> "service"
Here, quoting from rfc3986 4.2, is
and url can be parsed as a relative path reference by prepending a dot segment as noted above. base = URI.parse("http://example.com/v1/")
p base + "service:search" # ==> #<URI::Generic service:search>
p base + "./service:search" # ==> #<URI::HTTP http://example.com/v1/service:search> Applying this to the current - url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque
+ url = "./#{url}" if url.respond_to?(:start_with?) && !url.start_with?("http://", "https://", "/", "./")
uri = url ? base + url : base This seems to be a smaller change than string joins. references |
Thank you for pointing that out! I agree with your take that it's probably best to keep Could you re-run the benchmark I shared above just to make sure this is also in line (or faster) than the current implementation? |
Thanks for your response! Below are the benchmark results: require "uri"
require "benchmark"
base = URI.parse("https://example.com/")
def t1(base, url)
url = url.to_s.gsub(":", "%3A") if URI.parse(url.to_s).opaque
uri = url ? base + url : base
end
def t2(base, url)
url = "./#{url}" if url.respond_to?(:start_with?) && !url.start_with?("http://", "https://", "/", "./")
uri = url ? base + url : base
end
Benchmark.bm do |x|
p "case 1: with colon"
x.report { 10_000.times { t1 base, "service:search" } }
x.report { 10_000.times { t2 base, "service:search" } }
p "case 2: without colon"
x.report { 10_000.times { t1 base, "service/search" } }
x.report { 10_000.times { t2 base, "service/search" } }
end output:
And I create a new PR: #1569 |
The new solution is faster in both cases, this is great 🎉 ! |
Hi and thank you very much for this project at first.
Basic Info
Issue description
By the #1237 improvements, colons in path are now encoded as %3A. However, it is up to the server implementation to accept encoded colons, and in fact Firebase's fcm v1 api responds 404 status for encoded
messages%3Asend
.https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send
Currently, encoding occurs only in limited cases like a below reproduction code.
And no error occurs in the following situations.
Faraday.initialize()
orpost()
methodpost()
(like:client.post("/v1/projects/#{project_id}/messages:send")
)Steps to reproduce
(using ENV for secret values)
Execution log
My thoughts
faraday/lib/faraday/connection.rb
Lines 470 to 483 in 4abafa5
How about replace URL + string merge to string + string merge
This has the following advantages and disadvantages.
Advantages.
Disadvantages.
The text was updated successfully, but these errors were encountered: