Cleanup request api and simplify creating a logging transport (#657)
This commit is contained in:
parent
85d1aa322a
commit
f01ed0dc1c
9 changed files with 45 additions and 114 deletions
|
|
@ -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
50
util/request/roundtrip.go
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue