-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
transport: Discard the buffer when empty after http connect handshake #7424
Conversation
57074b6
to
b0e2b5d
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #7424 +/- ##
========================================
Coverage 81.50% 81.50%
========================================
Files 350 354 +4
Lines 26877 27078 +201
========================================
+ Hits 21906 22071 +165
- Misses 3776 3813 +37
+ Partials 1195 1194 -1
|
internal/transport/proxy_test.go
Outdated
c.SetReadDeadline(time.Now().Add(20 * time.Millisecond)) | ||
|
||
gotServerMessage := make([]byte, len(serverMessage)) | ||
// This call will return a deadline exceeded error if the server has nothing | ||
// to send. This is expected. | ||
if _, err := c.Read(gotServerMessage); err != nil { | ||
t.Logf("Got error while reading message from server: %v", err) | ||
} |
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.
Similar; I don't really like adding a magic deadline to things that we know will timeout sometimes.
Probably we should only do this read if len(serverMessage) != 0
, and then we can apply a longer deadline while not impacting code that doesn't use it?
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.
Changed, now the proxy is configured to wait for server hello.
internal/transport/proxy_test.go
Outdated
@@ -100,7 +118,7 @@ func (p *proxyServer) stop() { | |||
} | |||
} | |||
|
|||
func testHTTPConnect(t *testing.T, proxyURLModify func(*url.URL) *url.URL, proxyReqCheck func(*http.Request) error) { | |||
func testHTTPConnect(t *testing.T, proxyURLModify func(*url.URL) *url.URL, proxyReqCheck func(*http.Request) error, serverMessage []byte) { |
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 probably should add a struct about now to hold all the parameters (unless we decide to test this code differently per the above comment).
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.
Done.
internal/transport/proxy_test.go
Outdated
@@ -157,33 +181,62 @@ func testHTTPConnect(t *testing.T, proxyURLModify func(*url.URL) *url.URL, proxy | |||
if string(recvBuf) != string(msg) { | |||
t.Fatalf("received msg: %v, want %v", recvBuf, msg) | |||
} | |||
|
|||
if len(args.serverMessage) > 0 { | |||
c.SetReadDeadline(time.Now().Add(defaultTestTimeout)) |
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's now 3 places where we're setting this deadline.
Maybe instead when the conn is created in proxyDial
we should just do c.SetDeadline(....defaultTestTimeout)
(note Deadline
not Read
to also abort writes)?
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.
During testing, I noticed that the test can hang in proxyDial
if the proxy server waits for a server hello
when the server doesn't intend to send one. This was due to a logical error on my part which I fixed.
To be safe, I added read deadlines in both the places where reads could hang.
Maybe instead when the conn is created in proxyDial we should just do c.SetDeadline(....defaultTestTimeout) (note Deadline not Read to also abort writes)?
Do you mean adding a deadline in the actual proxyDial()
implementation by introducing a timeout that only the tests use?
Or are you referring to adding a deadline on the conn returned by proxyDial
in the test code?
The latter would not prevent proxyDial
from hanging when the proxy server is stuck reading the server hello
. The former would work but it involves changing non-test code, which I was trying to avoid.
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.
Sorry, I didn't mean in proxyDial
... I meant the connection it returns, we could immediately, always, do a SetDeadline(...)
, instead of doing it later and conditionally.
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.
Changed SetReadDeadline
to SetDeadline
. Moved the SetDeadline immediately after the proxyDial
call. The SetDeadline
in proxyServer.run()
is still present to avoid proxyDial from hanging indefinitely in case of test failures.
…grpc#7424) * Discard the buffer when empty after http connect handshake * configure the proxy to wait for server hello * Extract test args to a struct * Change deadline sets
Fixes: #7327
The buffer used to read the http connect response could contain extra bytes from the target server, so we can't discard it. However, in many cases where the server waits for the client to send the first message (e.g. when TLS is being used), the buffer will be empty, so we can avoid the overhead of reading through this buffer.
This PR also adds a unit test to ensure the buffer is not discarded when it has unread data.
RELEASE NOTES: