mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
Add a SNAP_CLIENT_DEBUG_HTTP bitfield environment variable that allows logging requests, responses and bodies that the client receives from the REST API. Bodies are never logged in local installs because, since they contain packaged snaps, their size would make the log unreadable. Signed-off-by: Miguel Pires <miguel.pires@canonical.com>
105 lines
2.5 KiB
Go
105 lines
2.5 KiB
Go
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|
|
|
/*
|
|
* Copyright (C) 2016-2017 Canonical Ltd
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
package httputil
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"os"
|
|
"strconv"
|
|
|
|
"github.com/snapcore/snapd/logger"
|
|
)
|
|
|
|
type debugflag uint
|
|
|
|
// set these via the Key environ
|
|
const (
|
|
DebugRequest = debugflag(1 << iota)
|
|
DebugResponse
|
|
DebugBody
|
|
)
|
|
|
|
func (f debugflag) debugRequest() bool {
|
|
return f&DebugRequest != 0
|
|
}
|
|
|
|
func (f debugflag) debugResponse() bool {
|
|
return f&DebugResponse != 0
|
|
}
|
|
|
|
func (f debugflag) debugBody() bool {
|
|
return f&DebugBody != 0
|
|
}
|
|
|
|
// LoggedTransport is an http.RoundTripper that can be used by
|
|
// http.Client to log request/response roundtrips.
|
|
type LoggedTransport struct {
|
|
Transport http.RoundTripper
|
|
Key string
|
|
MayLogBody bool
|
|
}
|
|
|
|
// RoundTrip is from the http.RoundTripper interface.
|
|
func (tr *LoggedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
flags := tr.getFlags()
|
|
|
|
if flags.debugRequest() {
|
|
buf, _ := httputil.DumpRequestOut(req, tr.MayLogBody && flags.debugBody())
|
|
logger.NoGuardDebugf("> %q", buf)
|
|
}
|
|
|
|
rsp, err := tr.Transport.RoundTrip(req)
|
|
|
|
if err == nil && flags.debugResponse() {
|
|
buf, _ := httputil.DumpResponse(rsp, tr.MayLogBody && flags.debugBody())
|
|
logger.NoGuardDebugf("< %q", buf)
|
|
}
|
|
|
|
return rsp, err
|
|
}
|
|
|
|
func (tr *LoggedTransport) getFlags() debugflag {
|
|
flags, err := strconv.Atoi(os.Getenv(tr.Key))
|
|
if err != nil {
|
|
flags = 0
|
|
}
|
|
|
|
return debugflag(flags)
|
|
}
|
|
|
|
func checkRedirect(req *http.Request, via []*http.Request) error {
|
|
if len(via) > 10 {
|
|
return errors.New("stopped after 10 redirects")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// BaseTransport returns the underlying http.Transport of a client created with NewHTTPClient. It panics if that's not the case. For tests.
|
|
func BaseTransport(cli *http.Client) *http.Transport {
|
|
tr, ok := cli.Transport.(*LoggedTransport)
|
|
if !ok {
|
|
panic("client must have been created with httputil.NewHTTPClient")
|
|
}
|
|
return tr.Transport.(*http.Transport)
|
|
}
|