-
Notifications
You must be signed in to change notification settings - Fork 40k
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
Copy the request ContentLength and TransferEncoding field in proxy #16400
Copy the request ContentLength and TransferEncoding field in proxy #16400
Conversation
Labelling this PR as size/XS |
GCE e2e test build/test passed for commit 3289397. |
@@ -151,6 +151,8 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |||
} | |||
httpCode = http.StatusOK | |||
newReq.Header = req.Header | |||
newReq.ContentLength = req.ContentLength | |||
newReq.TransferEncoding = req.TransferEncoding |
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.
whatever we do here we also need to do in generic/rest/proxy.go (a refactor to make apiserver/proxy.go delegate to the generic proxy is overdue, but should be a separate PR)
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.
Looks like the reverse proxy strips the transfer encoding header.... isn't it a problem to send content length to the backend without transfer encoding?
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.
in any case, I'd want tests through the proxy to a backend using no transport encoding, gzip, and chunked, with and without content-length, to make sure the backend gets a correct content length in all cases
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.
hmm... this also gets set prior to the upgrade attempt... not sure if spdy or websockets would ever set a content length or transfer encoding, but we should at least check on that
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.
Thanks @liggitt. I'll take a look at the issues you mentioned tomorrow or Friday.
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.
After digging more, I'm pretty sure we should only be setting ContentLength. TransferEncoding is interpreted, and the request body wrapped in an interpreting reader before we get it (that's why a request sent as "chunked" comes in with no transfer encoding, and reading the body returns unchunked data).
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.
But we need to keep the new request being "chunked" when it hits wire, right? If so, I think we need to copy the Request.TransferEncoding
The transfer writer will set the transfer-encoding header field to "chunked" if Request.TransferEncoding contains "chunked:
https://golang.org/src/net/http/transfer.go#L177
Same for the Body, the body will be chunked if Request.TransferEncoding contains "chunked":
https://golang.org/src/net/http/transfer.go#L213
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.
hmm, I suppose so... I'm pretty sure the http package will always unwrap any transfer-encodings that are present, but in case they don't, it doesn't hurt to copy what remains to the new request
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.
tl;dr: we can keep this line, though it may not be useful.
After more digging, I found actually the http package is powerful enough deduce the outbound request should be "chunked" based on the fact that the content-length is left unset && there is content:
https://golang.org/src/net/http/transfer.go#L88
Well, it doesn't hurt to keep the copy in the PR, and perhaps it will save a broken request where "transfer-encoding:chunked" and "content-length: non-zero-value" are set at the same time.
Labelling this PR as size/M |
GCE e2e test build/test passed for commit 0940741481341fff406e39dae5865b332d1933e0. |
Labelling this PR as size/L |
} | ||
} | ||
|
||
// Help wanted: why is the transfer-encoding header field always empty? |
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 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.
Perhaps look at the header instead of the variable?
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, you are... hm
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.
For the record, in the received request, the struct field req.TranferEncoding = []string{"chunked"} for the last 2 test cases. I think go library deduced this somehow.
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 prints the content in the buffer in the conn struct and persistConn struct to understand what's written/read by the go standard library to/from the wire. The golang library only supports chuncked
as a transfer-encoding, more specifically,
- When a request is sent either by a default golang http client or by a golang server, the only possible value in the transfer-encoding field is
chunked
,
https://golang.org/src/net/http/transfer.go#L178 - When a golang server reads the next request, the standard library parses the transfer-encoding field, passes the result to
Request.TransferEncoding
, and deletes the transfer-encoding field in the header,
https://golang.org/src/net/http/transfer.go#L433,
The standard library actually considers it’s an error if the transfer-encoding field contains value other thanidentity
orchunked
,
https://golang.org/src/net/http/transfer.go#L447
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.
Asked the question in golang-nuts group:
https://groups.google.com/forum/#!topic/golang-nuts/g7xJk09xBxU
GCE e2e build/test failed for commit 34a863e65765a37768b1233f58accef2ecf84657. |
GCE e2e test build/test passed for commit 135b0b39c486081af26e9a00dbe049450fb10edb. |
} | ||
|
||
for _, item := range table { | ||
proxyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { |
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.
Suggest naming this "downstreamServer"-- it's not the proxy, it's the thing the proxy dials, right?
I think I found a couple bugs in the test, but I'm not sure if they'll actually fix your problem or not. Let me know. |
d3e3562
to
9690029
Compare
} | ||
} | ||
|
||
// The http library will strip the "Transfer-Encoding" field from request.Header. |
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.
As the comment reads, Go library strips the "Transfer-Encoding" field. It will stores the value in request.TransferEncodings after some processing, the only possible value will be either "" or "chunked".
People say usually "gzip" will be a "Content-Encoding", so hopefully we won't get bit for this.
The discussion in go-nuts group: https://groups.google.com/forum/#!topic/golang-nuts/g7xJk09xBxU
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.
Thanks for the investigation!
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, thanks... we should test with content-encoding: gzip, transfer-encoding:''
as well
GCE e2e test build/test passed for commit 9690029. |
GCE e2e build/test failed for commit 1fe49b6. |
After digging into the http DefaultClient/DefaultTransport more, it looks like there is no way to make it faithfully echo transfer-encoding/content-length headers to the server... it really wants to own the transfer. For low-level tests like this, I think we need to write headers and request bodies ourselves. Opened caesarxuchao#2 to do so |
That's true. I'll take a look at the PR. Thanks. |
597492b
to
32f2ec7
Compare
CLAs look good, thanks! |
Squashed. I kept liggitt in the commit message as an acknowledgement to his contribution. |
@lavalamp PTAL. Thanks. |
GCE e2e test build/test passed for commit e1e393ec1287fe5ca5f72e9a48c7b6c135f82bc1. |
GCE e2e build/test failed for commit 597492b845fb4dde54f5c82350391fc1a5debfc9. |
GCE e2e build/test failed for commit 32f2ec7. |
@k8s-bot test this please |
GCE e2e test build/test passed for commit 32f2ec7. |
LGTM, but the code duplication is unfortunate. I guess we already had that problem. :) |
@k8s-bot test this Tests are more than 48 hours old. Re-running tests. |
GCE e2e test build/test passed for commit 32f2ec7. |
@k8s-bot unit test this please |
1 similar comment
@k8s-bot unit test this please |
@k8s-bot test this Tests are more than 48 hours old. Re-running tests. |
GCE e2e test build/test passed for commit 32f2ec7. |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
GCE e2e build/test failed for commit 32f2ec7. |
Unrelated test failure:
|
@k8s-bot test this please |
GCE e2e build/test failed for commit 32f2ec7. |
unrelated e2e test failure:
|
@k8s-bot e2e test this please |
GCE e2e test build/test passed for commit 32f2ec7. |
@k8s-bot test this [submit-queue is verifying that this PR is safe to merge] |
GCE e2e test build/test passed for commit 32f2ec7. |
Automatic merge from submit-queue |
Auto commit by PR queue bot
Thanks to @tiran for identifying the problem and proposing the fix.
@lavalamp @liggitt
fix #16093