Skip to content

Commit ffdf0b2

Browse files
Fix NewResponse writing HTTP/0.0 status lines in MITM mode (#749)
* Set HTTP/1.1 proto version in NewResponse NewResponse left ProtoMajor/ProtoMinor at zero, which produced HTTP/0.0 status lines when written via resp.Write() in the MITM path (introduced in #734). Clients like npm reset the connection on seeing HTTP/0.0, causing repeated 'Cannot read request from mitm'd client' errors. Set Proto, ProtoMajor, and ProtoMinor to HTTP/1.1 so resp.Write() emits a valid status line. Fixes #745 * Fix linter issues --------- Co-authored-by: Erik Pellizzon <erikpelli@tutamail.com>
1 parent b343a9a commit ffdf0b2

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

proxy_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,49 @@ func TestMITMRequestCancel(t *testing.T) {
12641264
}
12651265
}
12661266

1267+
func TestNewResponseProtoVersion(t *testing.T) {
1268+
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://example.com/", nil)
1269+
require.NoError(t, err)
1270+
1271+
resp := goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusForbidden, "blocked")
1272+
1273+
assert.Equal(t, "HTTP/1.1", resp.Proto)
1274+
assert.Equal(t, 1, resp.ProtoMajor)
1275+
assert.Equal(t, 1, resp.ProtoMinor)
1276+
1277+
var buf bytes.Buffer
1278+
err = resp.Write(&buf)
1279+
require.NoError(t, err)
1280+
1281+
line, err := buf.ReadString('\n')
1282+
require.NoError(t, err)
1283+
assert.True(t, strings.HasPrefix(line, "HTTP/1.1 403"), "expected HTTP/1.1 status line, got: %s", line)
1284+
}
1285+
1286+
func TestNewResponseMitmWrite(t *testing.T) {
1287+
proxy := goproxy.NewProxyHttpServer()
1288+
proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
1289+
proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
1290+
return nil, goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusForbidden, "blocked")
1291+
})
1292+
1293+
client, l := oneShotProxy(proxy)
1294+
defer l.Close()
1295+
1296+
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, https.URL+"/anything", nil)
1297+
require.NoError(t, err)
1298+
1299+
resp, err := client.Do(req)
1300+
require.NoError(t, err)
1301+
defer resp.Body.Close()
1302+
1303+
body, err := io.ReadAll(resp.Body)
1304+
require.NoError(t, err)
1305+
1306+
assert.Equal(t, http.StatusForbidden, resp.StatusCode)
1307+
assert.Equal(t, "blocked", string(body))
1308+
}
1309+
12671310
func TestPersistentMitmRequest(t *testing.T) {
12681311
requestCount := 0
12691312
backend := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

responses.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ func NewResponse(r *http.Request, contentType string, status int, body string) *
2222
resp.Header.Add("Content-Type", contentType)
2323
resp.StatusCode = status
2424
resp.Status = http.StatusText(status)
25+
resp.Proto = "HTTP/1.1"
26+
resp.ProtoMajor = 1
27+
resp.ProtoMinor = 1
2528
buf := bytes.NewBufferString(body)
2629
resp.ContentLength = int64(buf.Len())
2730
resp.Body = io.NopCloser(buf)

0 commit comments

Comments
 (0)