-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Prevention of Hijack() runtime panics #4295
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
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4295 +/- ##
==========================================
- Coverage 99.21% 98.92% -0.29%
==========================================
Files 42 44 +2
Lines 3182 3440 +258
==========================================
+ Hits 3157 3403 +246
- Misses 17 26 +9
- Partials 8 11 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
All lines introduced in this PR are covered by tests. The reported -0.29% decrease in coverage is not caused by these changes, |
|
Hi! Just following up to see if there's anything I can improve in this PR 🙇 |
|
Thank you for your review, I have corrected the points you pointed out. 1. Memory Management:Opinion: This point is correct as a general reminder, but it is not a problem in this code. mockHijacker is created as a local variable in the TestResponseWriterHijackAfterWrite function. 2. Concurrency Considerations:Opinion: In the current test code, mockHijacker is not used in concurrency, 3. Error Handling in Hijack Method:Opinion: mockHijacker is a mock for testing, and since the return value is not used in the current test, an implementation that returns nil is fine. hijacked bool
}
// response_writer_test.go
++ // Hijack implements the http.Hijacker interface. It just records that it was called.
func (m *mockHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
m.hijacked = true
return nil, nil, nil4. Testing Edge Cases:Opinion: It is important for the robustness of the code to test that Hijack works as expected even if responseWriter.Write fails. Looking at the implementation of responseWriter.Write, 5. Remove Duplicate Type Definition:Opinion:Looking at the code in response_writer_test.go, there is only one definition of mockHijacker. 6. Group Related Assertions:Describe the text in place of documentation in the name field of the test. 7. Assertion Messages:Fixed style consistency. 8. Consider Logging:Adding logging to a simple mock like this one may be excessive. 9. Enhance Test Case Comments:Describe the text in place of documentation in the name field of the test. 10. Parameterize Test Cases:Fixed. 11. Documentation:This is related to “9. Enhanced test case comments” and “10. Parameterization of test cases”. We believe that the name field (e.g., “hijack before write should succeed”) that is attached to each entry in a table-driven test serves as documentation as it is. |
|
Hi maintainers 👋 |
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.
Pull Request Overview
This PR prevents runtime panics by adding a safety check to the Hijack() method to ensure it cannot be called after the response has already been written, aligning with Go's standard HTTP server behavior.
- Adds a pre-write check in
Hijack()method that returns an error if the response has already been written - Introduces a specific error type
errHijackAlreadyWrittenfor this failure scenario - Includes comprehensive test coverage for both valid and invalid hijack scenarios
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| response_writer.go | Adds error check and error variable to prevent hijacking after response is written |
| response_writer_test.go | Adds test cases and mock hijacker to verify the new safety behavior |
Comments suppressed due to low confidence (2)
response_writer_test.go:152
- The test expects
expectWritten: truefor the "hijack before write" case, but according to the comment, this is because "Hijack itself marks the writer as written". However, the new implementation returns early if already written, so it's unclear if hijacking actually marks the writer as written when it succeeds. This test case should verify the actual behavior rather than assume it.
expectWritten: true, // Hijack itself marks the writer as written
response_writer_test.go:174
- The test should verify the
Written()state before callingHijack()to ensure the test setup is correct. Currently, it only checks the state after hijacking, which doesn't validate that the pre-conditions are properly established.
require.NoError(t, tc.action(w), "unexpected error during pre-hijack action")
|
Thanks for the feedback! I've updated the tests to:
Let me know if there's anything else I should update. 🙌 |
Proposal
The current implementation of the Hijack() method allows it to be called even after the response body has already been written to the client;
Go's internal implementation of http.Server is designed so that calling
Hijack ()afterWrite()orWriteHeader()has been called is designed to return an error,and the current Gin implementation differs from this.
Because of this difference,
some implementations of the underlying http.ResponseWriter may experience unexpected panics if Hijack() is called at an unintended time.
Therefore, we suggest changing the Hijack() method to check at the beginning of the method to see if the response has already been written
and return a clear and descriptive error if it has.
Changes
Definition of
errHijackAlreadyWritten:Hijack()fails.Update
Hijack()method:w.Written()to see if the response has already been written.errHijackAlreadyWrittenerror and stop further execution.