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
improvement: include response body on fetch_http error #7148
improvement: include response body on fetch_http error #7148
Conversation
Thanks for opening a pull request and helping make RubyGems and Bundler better! Someone from the RubyGems team will take a look at your pull request shortly and leave any feedback. Please make sure that your pull request has tests for any changes or added functionality. We use GitHub Actions to test and make sure your change works functionally and uses acceptable conventions, you can review the current progress of GitHub Actions in the PR status window below. If you have any questions or concerns that you wish to ask, feel free to leave a comment in this PR or join our #rubygems or #bundler channel on Slack. For more information about contributing to the RubyGems project feel free to review our CONTRIBUTING guide |
@duckinator does this look good? |
At a glance, this looks good. I'll test it locally when I'm at my computer later today (mainly to see what errors from rubygems.org look like with it), but don't expect any problems. 👍 |
Thank you! We appreciate it! |
The test failures don't seem to be related to this PR; I asked the other maintainers if they know what's up. I'll get back to you when I have more info. 🙂 |
Looks like that issue is resolved by #7156. Merging master back into this branch to get the latest changes. CI should in theory pass now. |
Thanks for the PR, @Paul-Bob! |
@@ -234,7 +234,7 @@ def fetch_http(uri, last_modified = nil, head = false, depth = 0) | |||
|
|||
fetch_http(location, last_modified, head, depth + 1) | |||
else | |||
raise FetchError.new("bad response #{response.message} #{response.code}", uri) | |||
raise FetchError.new("bad response #{response.message} #{response.code} #{response.body.strip}", uri) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be suuuuuuuuuuuuper messy IMHO when remote provides like 404 HTML page. Would it make sense to limit this to first X characters at least or scan for friendly response and report back only when recognized format is returned? What's returned by RubyGems.org in here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referencing a gem that doesn't exist doesn't result in this message being displayed.
I'm not opposed to adding a character limit, though.
puppy@orthrus:~/test$ ls -a
./ ../ Gemfile
puppy@orthrus:~/test$ cat Gemfile
source 'https://rubygems.org'
gem 'asdfasdfsadfihgjklsadkjfhakljfhsaf-this-gem-does-not-exist'
puppy@orthrus:~/test$ bundle install
Fetching gem metadata from https://rubygems.org/.
Could not find gem 'asdfasdfsadfihgjklsadkjfhakljfhsaf-this-gem-does-not-exist' in rubygems repository
https://rubygems.org/ or installed locally.
puppy@orthrus:~/test$
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are other gem servers which can return super long 500 HTML page for example. I would suggest to revert this and instead build some kind of "protocol" to let the error message propagate to client. IMHO it is not good idea to propagate licensing error back to clients using HTTP message on gem install. There is no guarantee how RubyGems handles HTTP errors and IMHO it should not be mis-used to handing over messages to client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be happy to keep this output, but only in kind of "verbose" mode and that is most likely against the original need of @adrianthedev.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have also sometimes needed this in Bundler, for example when rate-limiting certain requests. I like the idea of this being officially supported, but I agree that an unlimited message size is messy and unhelpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, sorry, I misunderstood! I thought you were saying only responses not 4xx or 5xx. 🙃 Sounds good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adrianthedev would that work for you? ^ Are you in control of returned HTTP headers for 403 on your gemserver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes @simi, we are in control of the returned HTTP headers. Our gem server is operated by a sinatra app.
Not completely sure how to send the message.
Is it something like this?
halt 403, {'Content-Type' => 'application/vnd.rubygems.text'}, { message: 'some text' }.to_json
Our message is something like this. That's 164 characters. We might play around with it so the number of chars might increase.
It seems that you don't have a valid GEM_SERVER_TOKEN for Avo (https://bundler.dev/). Please read this for more information
https://docs.avohq.io/3.0/some-path-here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did I understand correctly that we'd rather revert this PR and go with the cleaner solution that @simi proposed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if possible, don't release this. 🙏
Thanks for the help! |
What was the end-user or developer problem that led to this PR?
We would like to show custom error messages on our private rubygems server (https://packager.dev) that serves private Avo gems.
Right now the error message looks like (using local-host for testing purposes):
Bundler::HTTPError: Could not download gem from http://localhost:4567/avo-hq/ due to underlying error <bad response Forbidden 403 (http://localhost:4567/avo-hq/gems/avo-menu-0.1.18.gem)>
It would be helpful to us to make this message more customized so we can inform our users about the reason that download failed.
@adrianthedev opened this issue and @duckinator pointed us in the right direction in this comment.
Here is where we can fully customize the message lib/bundler/rubygems_integration.rb L519 but I noticed that the error that is rescued on that line it's already pre-processed here (remote_fetcher.rb L237) and it passes only the
response.message
and theresponse.code
.What is your fix for the problem, implemented in this PR?
With this PR the error message also includes the response's body and looks like:
Bundler::HTTPError: Could not download gem from http://localhost:4567/avo-hq/ due to underlying error <bad response Forbidden 403 Invalid License tier for 'avo-menu'. (http://localhost:4567/avo-hq/gems/avo-menu-0.1.18.gem)>
Notice that the error now includes the response's body
Invalid License tier for 'avo-menu'.
.Not sure if is the best approach, open for any kind of improvement.
Make sure the following tasks are checked
PS:
Alternative approach
What if we add an attribute on
FetchError
that will store the originalresponse
and we would be able to manipulate it on lib/bundler/rubygems_integration.rb L519 ?This way the error message can be fully customizable.