From dd03346d05afe2f53f1935313826d3c1c7e29264 Mon Sep 17 00:00:00 2001 From: Anatoly Zherdev Date: Sat, 4 Dec 2021 21:30:36 +0300 Subject: [PATCH 1/4] Allow to set Host header for Client --- http.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/http.go b/http.go index c8c2eb439e..2fa7805522 100644 --- a/http.go +++ b/http.go @@ -1360,7 +1360,9 @@ func (req *Request) Write(w *bufio.Writer) error { if len(host) == 0 { return errRequestHostRequired } - req.Header.SetHostBytes(host) + if len(req.Header.Host()) == 0 { + req.Header.SetHostBytes(host) + } req.Header.SetRequestURIBytes(uri.RequestURI()) if len(uri.username) > 0 { From e5a0b2103ef6e70a833766ecaa7b0fc82a706102 Mon Sep 17 00:00:00 2001 From: Anatoly Zherdev Date: Sun, 5 Dec 2021 17:02:21 +0300 Subject: [PATCH 2/4] Allow to change Host header without tests violation --- http.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/http.go b/http.go index 2fa7805522..2a1bc55367 100644 --- a/http.go +++ b/http.go @@ -56,6 +56,9 @@ type Request struct { // Request timeout. Usually set by DoDeadline or DoTimeout // if <= 0, means not set timeout time.Duration + + // Allow to change Host header with parsedURI == true (E.g. Client for type). + AllowToChangeHostHeader bool } // Response represents HTTP response. @@ -1360,7 +1363,7 @@ func (req *Request) Write(w *bufio.Writer) error { if len(host) == 0 { return errRequestHostRequired } - if len(req.Header.Host()) == 0 { + if len(req.Header.Host()) == 0 || !req.AllowToChangeHostHeader { req.Header.SetHostBytes(host) } req.Header.SetRequestURIBytes(uri.RequestURI()) From 9644d8aae689b219c9925e6441b7daac7f63bd4b Mon Sep 17 00:00:00 2001 From: Anatoly Zherdev Date: Mon, 6 Dec 2021 10:50:38 +0300 Subject: [PATCH 3/4] Rename AllowToChangeHostHeader and add tests. --- http.go | 6 +++--- http_test.go | 31 ++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/http.go b/http.go index 2a1bc55367..871480a6a7 100644 --- a/http.go +++ b/http.go @@ -57,8 +57,8 @@ type Request struct { // if <= 0, means not set timeout time.Duration - // Allow to change Host header with parsedURI == true (E.g. Client for type). - AllowToChangeHostHeader bool + // Use Host header (request.Header.SetHost) instead of the host from SetRequestURI, SetHost, or URI().SetHost + UseHostHeader bool } // Response represents HTTP response. @@ -1363,7 +1363,7 @@ func (req *Request) Write(w *bufio.Writer) error { if len(host) == 0 { return errRequestHostRequired } - if len(req.Header.Host()) == 0 || !req.AllowToChangeHostHeader { + if len(req.Header.Host()) == 0 || !req.UseHostHeader { req.Header.SetHostBytes(host) } req.Header.SetRequestURIBytes(uri.RequestURI()) diff --git a/http_test.go b/http_test.go index 8bd050b98e..2259611ebf 100644 --- a/http_test.go +++ b/http_test.go @@ -58,7 +58,7 @@ func TestIssue875(t *testing.T) { expectedLocation string } - var testcases = []testcase{ + testcases := []testcase{ { uri: `http://localhost:3000/?redirect=foo%0d%0aSet-Cookie:%20SESSIONID=MaliciousValue%0d%0a`, expectedRedirect: "foo\r\nSet-Cookie: SESSIONID=MaliciousValue\r\n", @@ -117,7 +117,6 @@ func TestRequestCopyTo(t *testing.T) { t.Fatalf("unexpected error: %s", err) } testRequestCopyTo(t, &req) - } func TestResponseCopyTo(t *testing.T) { @@ -134,7 +133,6 @@ func TestResponseCopyTo(t *testing.T) { resp.Header.SetStatusCode(200) resp.SetBodyString("test") testResponseCopyTo(t, &resp) - } func testRequestCopyTo(t *testing.T, src *Request) { @@ -594,6 +592,31 @@ func TestRequestUpdateURI(t *testing.T) { } } +func TestUseHostHeader(t *testing.T) { + t.Parallel() + + var r Request + r.UseHostHeader = true + r.Header.SetHost("aaa.bbb") + r.SetRequestURI("/lkjkl/kjl") + + // Modify request uri and host via URI() object and make sure + // the requestURI and Host header are properly updated + u := r.URI() + u.SetPath("/123/432.html") + u.SetHost("foobar.com") + a := u.QueryArgs() + a.Set("aaa", "bcse") + + s := r.String() + if !strings.HasPrefix(s, "GET /123/432.html?aaa=bcse") { + t.Fatalf("cannot find %q in %q", "GET /123/432.html?aaa=bcse", s) + } + if !strings.Contains(s, "\r\nHost: aaa.bbb\r\n") { + t.Fatalf("cannot find %q in %q", "\r\nHost: aaa.bbb\r\n", s) + } +} + func TestRequestBodyStreamMultipleBodyCalls(t *testing.T) { t.Parallel() @@ -1053,7 +1076,6 @@ func TestRequestContinueReadBodyDisablePrereadMultipartForm(t *testing.T) { if string(formData) != string(r.Body()) { t.Fatalf("The body given must equal the body in the Request") } - } func TestRequestMayContinue(t *testing.T) { @@ -2183,7 +2205,6 @@ Content-Type: application/json `, "\n", "\r\n", -1) mr := multipart.NewReader(strings.NewReader(s), "foo") form, err := mr.ReadForm(1024) - if err != nil { t.Fatalf("unexpected error: %s", err) } From 25a4937ca92bec4353207c6c2f1c68f3ffd2d623 Mon Sep 17 00:00:00 2001 From: Anatoly Zherdev Date: Tue, 14 Dec 2021 00:22:07 +0300 Subject: [PATCH 4/4] Allow to use empty uri.Host() when req.Header.Host() does not empty --- http.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/http.go b/http.go index 871480a6a7..6102f65757 100644 --- a/http.go +++ b/http.go @@ -1360,10 +1360,13 @@ func (req *Request) Write(w *bufio.Writer) error { if len(req.Header.Host()) == 0 || req.parsedURI { uri := req.URI() host := uri.Host() - if len(host) == 0 { - return errRequestHostRequired - } - if len(req.Header.Host()) == 0 || !req.UseHostHeader { + if len(req.Header.Host()) == 0 { + if len(host) == 0 { + return errRequestHostRequired + } else { + req.Header.SetHostBytes(host) + } + } else if !req.UseHostHeader { req.Header.SetHostBytes(host) } req.Header.SetRequestURIBytes(uri.RequestURI())