-
Notifications
You must be signed in to change notification settings - Fork 759
*: fix request body not rewindable when forwarding HTTP requests #10589
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
Open
iosmanthus
wants to merge
2
commits into
tikv:master
Choose a base branch
from
iosmanthus:iosmanthus/fix-cannot-rewind-body
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+156
−8
Open
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -484,7 +484,50 @@ func NewCustomReverseProxies(dialClient *http.Client, urls []url.URL) http.Handl | |
| return p | ||
| } | ||
|
|
||
| // EnsureRewindableBody makes r's body safe to be retried by net/http | ||
| // Transport on connection loss. It is a no-op when the body is nil, | ||
| // http.NoBody, or r.GetBody is already set. Otherwise it drains the body | ||
| // into memory and wires up GetBody so the transport can rewind. | ||
| // | ||
| // Callers should ensure the body fits in memory; this helper buffers the | ||
| // entire payload. It guards against the | ||
| // "net/http: cannot rewind body after connection loss" error that can | ||
| // occur when a server-side request (GetBody == nil) is forwarded via | ||
| // http.Client.Do and the underlying keep-alive connection goes stale. | ||
| func EnsureRewindableBody(r *http.Request) error { | ||
| if r.Body == nil || r.Body == http.NoBody || r.GetBody != nil { | ||
| return nil | ||
| } | ||
| buf, err := io.ReadAll(r.Body) | ||
| _ = r.Body.Close() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // Restore NoBody semantics for empty payloads so that Transport's | ||
| // outgoingLength returns 0 and no body probing happens. | ||
| if len(buf) == 0 { | ||
| r.Body = http.NoBody | ||
| r.GetBody = func() (io.ReadCloser, error) { return http.NoBody, nil } | ||
| r.ContentLength = 0 | ||
| return nil | ||
| } | ||
| r.Body = io.NopCloser(bytes.NewReader(buf)) | ||
| r.GetBody = func() (io.ReadCloser, error) { | ||
| return io.NopCloser(bytes.NewReader(buf)), nil | ||
| } | ||
| // We now know the exact length; set it so the transport can pick | ||
| // Content-Length framing over chunked encoding when forwarding. | ||
| r.ContentLength = int64(len(buf)) | ||
| return nil | ||
| } | ||
|
|
||
| func (p *customReverseProxies) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
| if err := EnsureRewindableBody(r); err != nil { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to move it before |
||
| log.Error("failed to read request body", zap.Error(err)) | ||
| http.Error(w, err.Error(), http.StatusInternalServerError) | ||
| return | ||
| } | ||
|
|
||
| for _, url := range p.urls { | ||
| r.RequestURI = "" | ||
| r.URL.Host = url.Host | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
🧩 Analysis chain
🏁 Script executed:
Repository: tikv/pd
Length of output: 425
🏁 Script executed:
Repository: tikv/pd
Length of output: 2553
🏁 Script executed:
Repository: tikv/pd
Length of output: 4467
Add a max body-size guard before buffering.
Line 501 reads the full request body into memory with no upper bound. When called in the
ServeHTTPreverse proxy handler (line 525), this creates a memory-exhaustion vector—an attacker can send large payloads to exhaust memory and trigger OOM without any server-side size limit configured.Additionally, line 528 exposes the raw error message to the client via
http.Error(w, err.Error(), ...), which should not leak internal details.🔧 Suggested fix
🤖 Prompt for AI Agents