Skip to content

Commit fb8f70e

Browse files
committed
martian(h2): fix half-close propagation downstream
Use http2.Response.Close() to send RST_STREAM frame. Reimplement writeFlusher as h2Writer. This is to be tested in Sauce Connect due to lack of testing infrastructure for http2 at the moment. I added #869 to fix that.
1 parent 7816067 commit fb8f70e

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

internal/martian/proxy_handler.go

+20-11
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ func (p proxyHandler) tunnel(name string, rw http.ResponseWriter, req *http.Requ
236236

237237
cc = []copier{
238238
{"outbound " + name, crw, req.Body},
239-
{"inbound " + name, writeFlusher{rw, rc}, crw},
239+
{"inbound " + name, makeH2Writer(rw, rc, req), crw},
240240
}
241241
default:
242242
err := fmt.Errorf("unsupported protocol version: %d", req.ProtoMajor)
@@ -337,27 +337,36 @@ func (p proxyHandler) handleRequest(rw http.ResponseWriter, req *http.Request) {
337337
}
338338
}
339339

340-
type writeFlusher struct {
341-
rw io.Writer
342-
rc *http.ResponseController
340+
type h2Writer struct {
341+
w io.Writer
342+
flush func() error
343+
close func() error
343344
}
344345

345-
func (w writeFlusher) Write(p []byte) (n int, err error) {
346-
n, err = w.rw.Write(p)
346+
func makeH2Writer(rw http.ResponseWriter, rc *http.ResponseController, req *http.Request) *h2Writer {
347+
return &h2Writer{
348+
w: rw,
349+
flush: rc.Flush,
350+
close: req.Body.Close,
351+
}
352+
}
353+
354+
func (w h2Writer) Write(p []byte) (n int, err error) {
355+
n, err = w.w.Write(p)
347356

348357
if n > 0 {
349-
if err := w.rc.Flush(); err != nil {
358+
if err := w.flush(); err != nil {
350359
log.Errorf(context.TODO(), "got error while flushing response back to client: %v", err)
351360
}
352361
}
353362

354363
return
355364
}
356365

357-
func (w writeFlusher) CloseWrite() error {
358-
// This is a nop implementation of closeWriter.
359-
// It avoids printing the error log "cannot close write side of inbound CONNECT tunnel".
360-
return nil
366+
func (w h2Writer) CloseWrite() error {
367+
// Close request body to signal the end of the request.
368+
// This results RST_STREAM frame with error code NO_ERROR to be sent to the other side.
369+
return w.close()
361370
}
362371

363372
func (p proxyHandler) writeErrorResponse(rw http.ResponseWriter, req *http.Request, err error) {

0 commit comments

Comments
 (0)