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  }