github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/httputil/logger_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2017 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package httputil_test 21 22 import ( 23 "bytes" 24 "fmt" 25 "io/ioutil" 26 "net/http" 27 "net/http/httptest" 28 "os" 29 "strings" 30 "testing" 31 32 "gopkg.in/check.v1" 33 34 "github.com/snapcore/snapd/httputil" 35 "github.com/snapcore/snapd/logger" 36 "github.com/snapcore/snapd/testutil" 37 ) 38 39 func TestHTTPUtil(t *testing.T) { check.TestingT(t) } 40 41 type loggerSuite struct { 42 logbuf *bytes.Buffer 43 restoreLogger func() 44 } 45 46 var _ = check.Suite(&loggerSuite{}) 47 48 func (s *loggerSuite) TearDownTest(c *check.C) { 49 os.Unsetenv("SNAPD_DEBUG") 50 s.restoreLogger() 51 } 52 53 func (s *loggerSuite) SetUpTest(c *check.C) { 54 os.Setenv("SNAPD_DEBUG", "true") 55 s.logbuf = bytes.NewBuffer(nil) 56 s.logbuf, s.restoreLogger = logger.MockLogger() 57 } 58 59 func (loggerSuite) TestFlags(c *check.C) { 60 for _, f := range []interface{}{ 61 httputil.DebugRequest, 62 httputil.DebugResponse, 63 httputil.DebugBody, 64 httputil.DebugRequest | httputil.DebugResponse | httputil.DebugBody, 65 } { 66 os.Setenv("TEST_FOO", fmt.Sprintf("%d", f)) 67 tr := &httputil.LoggedTransport{ 68 Key: "TEST_FOO", 69 } 70 71 c.Check(httputil.GetFlags(tr), check.Equals, f) 72 } 73 } 74 75 type fakeTransport struct { 76 req *http.Request 77 rsp *http.Response 78 } 79 80 func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) { 81 t.req = req 82 return t.rsp, nil 83 } 84 85 func (s loggerSuite) TestLogging(c *check.C) { 86 req, err := http.NewRequest("WAT", "http://example.com/", nil) 87 c.Assert(err, check.IsNil) 88 rsp := &http.Response{ 89 Status: "999 WAT", 90 StatusCode: 999, 91 } 92 tr := &httputil.LoggedTransport{ 93 Transport: &fakeTransport{ 94 rsp: rsp, 95 }, 96 Key: "TEST_FOO", 97 } 98 99 os.Setenv("TEST_FOO", "7") 100 101 aRsp, err := tr.RoundTrip(req) 102 c.Assert(err, check.IsNil) 103 c.Check(aRsp, check.Equals, rsp) 104 c.Check(s.logbuf.String(), check.Matches, `(?ms).*> "WAT / HTTP/\S+.*`) 105 c.Check(s.logbuf.String(), check.Matches, `(?ms).*< "HTTP/\S+ 999 WAT.*`) 106 } 107 108 func (s loggerSuite) TestNotLoggingOctetStream(c *check.C) { 109 req, err := http.NewRequest("GET", "http://example.com/data", nil) 110 c.Assert(err, check.IsNil) 111 needle := "lots of binary data" 112 rsp := &http.Response{ 113 Status: "200 OK", 114 StatusCode: 200, 115 Header: http.Header{ 116 "Content-Type": []string{"application/octet-stream"}, 117 }, 118 Body: ioutil.NopCloser(strings.NewReader(needle)), 119 } 120 tr := &httputil.LoggedTransport{ 121 Transport: &fakeTransport{ 122 rsp: rsp, 123 }, 124 Key: "TEST_FOO", 125 } 126 127 os.Setenv("TEST_FOO", "7") 128 129 aRsp, err := tr.RoundTrip(req) 130 c.Assert(err, check.IsNil) 131 c.Check(aRsp, check.Equals, rsp) 132 c.Check(s.logbuf.String(), check.Matches, `(?ms).*> "GET /data HTTP/\S+.*`) 133 c.Check(s.logbuf.String(), check.Not(testutil.Contains), needle) 134 } 135 136 func (s loggerSuite) TestRedir(c *check.C) { 137 n := 0 138 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 139 switch n { 140 case 0: 141 c.Check(r.Method, check.Equals, "GET") 142 c.Check(r.URL.Path, check.Equals, "/") 143 c.Check(r.Header.Get("User-Agent"), check.Equals, "fancy-agent") 144 c.Check(r.Header.Get("Range"), check.Equals, "42") 145 c.Check(r.Header.Get("Authorization"), check.Equals, "please") 146 c.Check(r.Header.Get("Cookie"), check.Equals, "chocolate chip") 147 // go1.8 changes the policy for headers on redirect: 148 // https://golang.org/pkg/net/http/#Client 149 // sensitive headers are only cleaned if the redirect 150 // goes to a different domain, so we simulate this 151 // here 152 r.URL.Host = strings.Replace(r.Host, "127.0.0.1", "localhost", -1) 153 http.Redirect(w, r, r.URL.String(), 302) 154 case 1: 155 c.Check(r.Method, check.Equals, "GET") 156 c.Check(r.URL.Path, check.Equals, "/") 157 c.Check(r.Header.Get("User-Agent"), check.Equals, "fancy-agent") 158 c.Check(r.Header.Get("Range"), check.Equals, "42") 159 c.Check(r.Header.Get("Authorization"), check.Equals, "") 160 c.Check(r.Header.Get("Cookie"), check.Equals, "") 161 default: 162 c.Fatalf("expected to get 1 requests, now on %d", n+1) 163 } 164 n++ 165 })) 166 defer server.Close() 167 168 client := httputil.NewHTTPClient(nil) 169 req, err := http.NewRequest("GET", server.URL, nil) 170 c.Assert(err, check.IsNil) 171 // some headers that should be copied 172 req.Header.Set("User-Agent", "fancy-agent") 173 req.Header.Set("Range", "42") 174 175 // some headers that shouldn't 176 req.Header.Set("Authorization", "please") 177 req.Header.Set("Cookie", "chocolate chip") 178 179 _, err = client.Do(req) 180 c.Assert(err, check.IsNil) 181 c.Check(n, check.Equals, 2) 182 }