Skip to content
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

Make sure low level error response is sent to the client #3094

Merged

Conversation

Vuta
Copy link
Contributor

@Vuta Vuta commented Mar 12, 2023

Closes #2341

Description

Currently, when Client I/O operations raise any exceptions, we build a fallback rack response (either by lowlevel_error_handler or by default puma's hard-coded response), but doesn't do anything with it. This commit ensures that this response is sent back to client.

To verify:

  1. bundle exec puma -C test/config/lowlevel_error_handler.rb test/rackup/hello.ru
  2. curl -i GET localhost:9292
HTTP/1.1 500 Internal Server Error
Content-Length: 24

something wrong happened

Your checklist for this pull request

  • I have reviewed the guidelines for contributing to this repository.
  • I have added (or updated) appropriate tests if this PR fixes a bug or adds a feature.
  • My pull request is 100 lines added/removed or less so that it can be easily reviewed.
  • If this PR doesn't need tests (docs change), I added [ci skip] to the title of the PR.
  • If this closes any issues, I have added "Closes #issue" to the PR description or my commit messages.
  • I have updated the documentation accordingly.
  • All new and existing tests passed, including Rubocop.

@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch 3 times, most recently from e83e5ad to a90b6b3 Compare March 12, 2023 17:38
@Vuta Vuta changed the title Closes #2341 - Make sure fallback Rack response are sent to the client Closes #2341 - Make sure fallback Rack response is sent to the client Mar 12, 2023
@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch from a90b6b3 to 7c8fa70 Compare March 13, 2023 11:29
@dentarg dentarg changed the title Closes #2341 - Make sure fallback Rack response is sent to the client Make sure low level error response is sent to the client Mar 13, 2023
@@ -49,15 +49,15 @@ def test_integer_key
server_run app: ->(env) { [200, { 1 => 'Boo'}, []] }
data = send_http_and_read "GET / HTTP/1.0\r\n\r\n"

assert_match(/HTTP\/1.1 500 Internal Server Error/, data)
assert_match(/HTTP\/1.0 500 Internal Server Error/, data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Huh?

Copy link
Contributor Author

@Vuta Vuta Mar 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously it failed on some platforms (non MRI or windows I think). This is the full data

HTTP/1.0 500 Internal Server Error\r\nContent-Length: 659\r\n\r\nPuma caught this error: undefined method `downcase' for 1:Integer (NoMethodError)\n/Users/vutran/learning/puma/lib/puma/request.rb:610:in `block in str_headers'\n/Users/vutran/learning/puma/lib/puma/request.rb:607:in `each'\n/Users/vutran/learning/puma/lib/puma/request.rb:607:in `str_headers'\n/Users/vutran/learning/puma/lib/puma/request.rb:170:in `prepare_response'\n/Users/vutran/learning/puma/lib/puma/request.rb:131:in `handle_request'\n/Users/vutran/learning/puma/lib/puma/server.rb:431:in `process_client'\n/Users/vutran/learning/puma/lib/puma/server.rb:233:in `block in run'\n/Users/vutran/learning/puma/lib/puma/thread_pool.rb:147:in `block in spawn_thread'HTTP/1.1 500 Internal Server Error\r\n\r\n

I guess matching against "Puma caught this error: undefined method `downcase' for 1:Integer" would be better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nateberkopec I commented on the same thing with the previous attempt: https://github.com/puma/puma/pull/2731/files#diff-732bb402028f0495d2e1bbcdf2abd9deef82f19e1b5f45711e5e32d450656563

We should understand why this is changing, not just change it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the full data

Why does it say HTTP/1.1 500 Internal Server Error\r\n\r\n at the end?

What does it say in master?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it say HTTP/1.1 500 Internal Server Error\r\n\r\n at the end?

That comes from the client.write_error(500). We can either

  1. keep that line and change the regex to make the test pass
  2. remove that line completely

I went with (1) because I wasn't sure if (2) has any other implications

lib/puma/server.rb Outdated Show resolved Hide resolved
@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch 2 times, most recently from ad437a7 to 70ce137 Compare March 15, 2023 11:24
@nateberkopec
Copy link
Member

Leaving unmerged to give other maintainers some time to look but LGTM

lib/puma/server.rb Outdated Show resolved Hide resolved
@MSP-Greg
Copy link
Member

I need to look at the code more, but is this optional? I'm not sure if everyone wants backtrace info sent to a client? Options for logging it, but not to the client, unless development mode? Sorry, busy with other things (reliable CI)...

@Vuta
Copy link
Contributor Author

Vuta commented Mar 16, 2023

I need to look at the code more, but is this optional? I'm not sure if everyone wants backtrace info sent to a client? Options for logging it, but not to the client, unless development mode? Sorry, busy with other things (reliable CI)...

I think it's optional. If user sets the environment to something other than development and test, the general message An unhandled lowlevel error occurred. The application logs may have details. will be sent instead.

@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch from 70ce137 to 8a49366 Compare March 17, 2023 07:41
@nateberkopec nateberkopec added the waiting-for-review Waiting on review from anyone label Mar 29, 2023
@nateberkopec
Copy link
Member

Marking as waiting for review as @Vuta has responded to maintainer concerns but we don't have an approve yet.

@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch from 8a49366 to 864665a Compare May 22, 2023 05:29
@Vuta Vuta requested a review from dentarg May 22, 2023 05:52
@nateberkopec nateberkopec added waiting-for-changes Waiting on changes from the requestor and removed waiting-for-review Waiting on review from anyone labels May 25, 2023
@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch from 864665a to 175334d Compare June 17, 2023 15:00
@MSP-Greg
Copy link
Member

I'll defer to others, but I'm not sure about any responses that might 'fingerprint' Puma's use to clients.

@dentarg
Copy link
Member

dentarg commented Jun 19, 2023

I'll defer to others, but I'm not sure about any responses that might 'fingerprint' Puma's use to clients.

Fair point considering the recent Server header discussions.

It is set here

[status, {}, ["An unhandled lowlevel error occurred. The application logs may have details.\n"]]

I guess it is meant to be helpful in cases where you haven't configured the low level handler and something unexpected happens in production... but I agree it is sharing unnecessary details to the end user.

@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch from 175334d to db7df2c Compare June 22, 2023 11:17
@Vuta
Copy link
Contributor Author

Vuta commented Jun 22, 2023

@dentarg thanks. I agree that end users don't need to know about "unhandled lowlevel error" or "application logs". So I removed them altogether.

@@ -541,10 +541,17 @@ def lowlevel_error(e, env, status=500)
backtrace = e.backtrace.nil? ? '<no backtrace available>' : e.backtrace.join("\n")
[status, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{backtrace}"]]
else
[status, {}, ["An unhandled lowlevel error occurred. The application logs may have details.\n"]]
[status, {}, ["An error occurred\n"]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is that much better than the previous message, it is probably still somewhat unique to Puma.

I checked what pitchfork does in the 500 Internal Server Error case, and it doesn't respond with any body (RACK_ENV=development and RACK_ENV=production behaves the same).

$ curl -s -v http://127.0.0.1:8080/raise
*   Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /raise HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.84.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0

$ curl -s -v http://127.0.0.1:8080/nil
*   Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /nil HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.84.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0

…lient

Currently, when Client I/O operations raise any exceptions, we build a fallback rack response (either by lowlevel_error_handler or by default puma's hard-coded response), but doesn't do anything with it.
This commit ensures that this response is sent back to client.
@Vuta Vuta force-pushed the make_sure_lowlevel_error_handler_are_returned branch from db7df2c to d56e8cb Compare June 24, 2023 18:40
@Vuta Vuta requested a review from dentarg June 27, 2023 19:08
# Swallow, do not log
return if [ConnectionError, EOFError].include?(e.class)

lowlevel_error(e, client.env)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does MiniSSL::SSLError get slightly different handling now? If I'm reading it right, this branch still has the "bug" of never responding to the client actually?

Copy link
Contributor Author

@Vuta Vuta Jun 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding lowlevel_error to MiniSSL::SSLError so that the handler code can be run, and we don't send anything back to client because there is nothing to send back right (the connection isn't established)? If I understand your previous comment correctly

@nateberkopec nateberkopec merged commit 99ae85b into puma:master Jul 23, 2023
64 checks passed
maxlazio pushed a commit to gitlabhq/omnibus-gitlab that referenced this pull request Oct 5, 2023
Because of puma/puma#3094, Puma v6.4.0 now
returns the status code sent from the low-level handler instead of
Puma's recommended status code.

Previously we hard-coded low-level errors to return a 500 error, but
now we should adapt this to return the status code recommended by
Puma.

Relates to
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/16417

Changelog: fixed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature waiting-for-changes Waiting on changes from the requestor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Puma sends empty response bodies even when low-level handler is specified
4 participants