Cleanup request api and simplify creating a logging transport (#657)

This commit is contained in:
andig 2021-02-11 16:52:17 +01:00 • committed by GitHub
parent 85d1aa322a
commit f01ed0dc1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 45 additions and 114 deletions

View file

@ -1,95 +1,30 @@
package request
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"strings"
"time"
"github.com/andig/evcc/util"
)
// Timeout is the default request timeout used by the Helper
var Timeout = 10 * time.Second
// Helper provides utility primitives
type Helper struct {
*http.Client
log *log.Logger
last *http.Response // last response
}
// NewHelper creates http helper for simplified PUT GET logic
func NewHelper(log *util.Logger) *Helper {
r := &Helper{
Client: &http.Client{Timeout: 10 * time.Second},
log: log.TRACE,
}
// intercept for logging
r.Transport(http.DefaultTransport)
return r
}
// LastResponse returns last http.Response that was read without error
func (r *Helper) LastResponse() *http.Response {
return r.last
}
type helperTransport struct {
log *log.Logger
detailed bool
lastResponse func(*http.Response)
roundTripper http.RoundTripper
}
func (r *helperTransport) RoundTrip(req *http.Request) (*http.Response, error) {
msg := fmt.Sprintf("%s %s", req.Method, req.URL)
if r.detailed {
if body, err := httputil.DumpRequest(req, true); err == nil {
msg += "\n" + strings.TrimSpace(string(body)) + "\n"
}
}
resp, err := r.roundTripper.RoundTrip(req)
r.lastResponse(resp)
if r.log != nil {
if resp != nil {
if r.detailed {
if body, err := httputil.DumpResponse(resp, true); err == nil {
msg += "\n" + strings.TrimSpace(string(body))
}
} else {
msg += "\n" + resp.Status
if body, _ := ReadBody(resp); len(body) > 0 {
const max = 2048
str := string(body)
if len(str) >= max {
str = str[:max]
}
msg += "\n" + strings.TrimSpace(str)
}
}
}
r.log.Println(msg)
}
return resp, err
}
// Transport wraps the provided transport with logging and sets it as client transport
func (r *Helper) Transport(roundTripper http.RoundTripper) {
r.Client.Transport = &helperTransport{
log: r.log,
roundTripper: roundTripper,
lastResponse: func(resp *http.Response) {
r.last = resp
Client: &http.Client{
Timeout: Timeout,
Transport: NewTripper(log, http.DefaultTransport),
},
}
return r
}
// DoBody executes HTTP request and returns the response body

50
util/request/roundtrip.go Normal file
View file

@ -0,0 +1,50 @@
package request
import (
"net/http"
"net/http/httputil"
"strings"
"github.com/andig/evcc/util"
)
type roundTripper struct {
log *util.Logger
transport http.RoundTripper
}
const max = 2048
// NewTripper creates a logging roundtrip handler
func NewTripper(log *util.Logger, transport http.RoundTripper) http.RoundTripper {
tripper := &roundTripper{
log: log,
transport: transport,
}
return tripper
}
func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if body, err := httputil.DumpRequest(req, true); err == nil {
s := strings.TrimSpace(string(body))
if len(s) > max {
s = s[:max]
}
r.log.TRACE.Println(s)
}
resp, err := r.transport.RoundTrip(req)
if resp != nil {
if body, err := httputil.DumpResponse(resp, true); err == nil {
s := strings.TrimSpace(string(body))
if len(s) > max {
s = s[:max]
}
r.log.TRACE.Println(s)
}
}
return resp, err
}

View file

@ -5,27 +5,18 @@ import (
"net/http"
)
// Transport decorates http.Transport with fluent style
type Transport struct {
*http.Transport
}
// NewDefaultTransport creates a clone of the http.DefaultTransport
func NewDefaultTransport() *http.Transport {
return http.DefaultTransport.(*http.Transport).Clone()
}
// NewTransport creates an HTTP transport
func NewTransport() *Transport {
t := &Transport{
Transport: NewDefaultTransport(),
// DefaultTransport returns http.DefaultTransport as http.Transport instead of http.RoundTripper
func DefaultTransport() *http.Transport {
t, ok := http.DefaultTransport.(*http.Transport)
if !ok {
panic("http.DefaultTransport is not an http.Transport")
}
return t
}
// WithTLSConfig sets the transports TLS configuration
func (t *Transport) WithTLSConfig(tls *tls.Config) *Transport {
t.Transport.TLSClientConfig = tls
// InsecureTransport is an http.Transport with TLSClientConfig.InsecureSkipVerify enabled
func InsecureTransport() *http.Transport {
t := DefaultTransport()
t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
return t
}