github.com/rigado/snapd@v2.42.5-go-mod+incompatible/httputil/logger.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
    21  
    22  import (
    23  	"errors"
    24  	"net/http"
    25  	"net/http/httputil"
    26  	"os"
    27  	"strconv"
    28  
    29  	"github.com/snapcore/snapd/logger"
    30  )
    31  
    32  type debugflag uint
    33  
    34  // set these via the Key environ
    35  const (
    36  	DebugRequest = debugflag(1 << iota)
    37  	DebugResponse
    38  	DebugBody
    39  )
    40  
    41  func (f debugflag) debugRequest() bool {
    42  	return f&DebugRequest != 0
    43  }
    44  
    45  func (f debugflag) debugResponse() bool {
    46  	return f&DebugResponse != 0
    47  }
    48  
    49  func (f debugflag) debugBody() bool {
    50  	return f&DebugBody != 0
    51  }
    52  
    53  // LoggedTransport is an http.RoundTripper that can be used by
    54  // http.Client to log request/response roundtrips.
    55  type LoggedTransport struct {
    56  	Transport http.RoundTripper
    57  	Key       string
    58  	body      bool
    59  }
    60  
    61  // RoundTrip is from the http.RoundTripper interface.
    62  func (tr *LoggedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    63  	flags := tr.getFlags()
    64  
    65  	if flags.debugRequest() {
    66  		buf, _ := httputil.DumpRequestOut(req, tr.body && flags.debugBody())
    67  		logger.Debugf("> %q", buf)
    68  	}
    69  
    70  	rsp, err := tr.Transport.RoundTrip(req)
    71  
    72  	if err == nil && flags.debugResponse() {
    73  		buf, _ := httputil.DumpResponse(rsp, tr.body && flags.debugBody())
    74  		logger.Debugf("< %q", buf)
    75  	}
    76  
    77  	return rsp, err
    78  }
    79  
    80  func (tr *LoggedTransport) getFlags() debugflag {
    81  	flags, err := strconv.Atoi(os.Getenv(tr.Key))
    82  	if err != nil {
    83  		flags = 0
    84  	}
    85  
    86  	return debugflag(flags)
    87  }
    88  
    89  func checkRedirect(req *http.Request, via []*http.Request) error {
    90  	if len(via) > 10 {
    91  		return errors.New("stopped after 10 redirects")
    92  	}
    93  	// fixed in go 1.8
    94  	fixupHeadersForRedirect(req, via)
    95  
    96  	return nil
    97  }
    98  
    99  // BaseTransport returns the underlying http.Transport of a client created with NewHTTPClient. It panics if that's not the case. For tests.
   100  func BaseTransport(cli *http.Client) *http.Transport {
   101  	tr, ok := cli.Transport.(*LoggedTransport)
   102  	if !ok {
   103  		panic("client must have been created with httputil.NewHTTPClient")
   104  	}
   105  	return tr.Transport.(*http.Transport)
   106  }