diff --git a/httpdebug.go b/httpdebug.go index fb7daab..6c1a529 100644 --- a/httpdebug.go +++ b/httpdebug.go @@ -7,57 +7,111 @@ import ( "io/ioutil" "log" "net/http" + "strings" "unicode" ) -// Wrap returns an http handler that serves h while logging requests and responses to stderr. +type Mode int + +const ( + ModeOneline Mode = iota + ModeTrimmed + ModeFull +) + +var ModeDefault = ModeOneline + +// Wrap returns an http handler that serves h while logging requests and responses to stderr. It uses ModeDefault. func Wrap(h http.Handler) http.Handler { + return WrapMode(h, ModeDefault) +} + +// WrapMode returns an http handler that serves h while logging requests and responses to stderr. +func WrapMode(h http.Handler, m Mode) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Println(r.Method, r.URL.Path, r.Proto) + switch m { + case ModeTrimmed: + serveTrimmed(h, w, r, 1024, 128) + case ModeFull: + serveTrimmed(h, w, r, 0, 0) + case ModeOneline: + buf := &bytes.Buffer{} + rw := &rw{ + ResponseWriter: w, + w: buf, + } + + h.ServeHTTP(rw, r) + log.Println(r.Method, r.URL.Path, strings.Repeat("\t", 5-((len(r.Method)+len(r.URL.Path))/12)+1), rw.status, http.StatusText(rw.status), buf.Len(), "bytes", "\t", "("+w.Header().Get("Content-Type")+")") + } + }) +} - hBuf := &bytes.Buffer{} - r.Header.Write(hBuf) - log.Println(hBuf.String()) +func serveTrimmed(h http.Handler, w http.ResponseWriter, r *http.Request, trimAt, trimTo int64) { + log.Println(r.Method, r.URL.Path, r.Proto) - requestBuf := &bytes.Buffer{} - responseBuf := &bytes.Buffer{} + hBuf := &bytes.Buffer{} + r.Header.Write(hBuf) + log.Println(hBuf.String()) - defer r.Body.Close() + requestBuf := &bytes.Buffer{} + responseBuf := &bytes.Buffer{} - r.Body = ioutil.NopCloser(io.TeeReader(r.Body, requestBuf)) + defer r.Body.Close() - h.ServeHTTP(rw{ - ResponseWriter: w, - w: responseBuf, - }, r) + r.Body = ioutil.NopCloser(io.TeeReader(r.Body, requestBuf)) + + rw := &rw{ + ResponseWriter: w, + w: responseBuf, + } - if requestBuf.Len() > 1024 { + h.ServeHTTP(rw, r) + + if trimAt > 0 && trimTo > 0 { + if int64(requestBuf.Len()) > trimAt { trimmed := &bytes.Buffer{} - io.CopyN(trimmed, requestBuf, 128) + io.CopyN(trimmed, requestBuf, trimTo) requestBuf = trimmed } + } - log.Println() - log.Println(logsafe(requestBuf.String())) + log.Println() + log.Println(logsafe(requestBuf.String())) - hBuf.Reset() - w.Header().Write(hBuf) - log.Println(hBuf.String()) + log.Println(rw.status) - responseBuf = trim(responseBuf, 128) + hBuf.Reset() + w.Header().Write(hBuf) + log.Println(hBuf.String()) - log.Println() - log.Println(logsafe(responseBuf.String())) - }) + if trimTo > 0 { + responseBuf = trim(responseBuf, int(trimTo)) + } + + log.Println() + log.Println(logsafe(responseBuf.String())) } type rw struct { http.ResponseWriter - w io.Writer + w io.Writer + status int } -func (rw rw) Write(b []byte) (int, error) { - rw.w.Write(b) +func (rw *rw) WriteHeader(s int) { + rw.status = s + rw.ResponseWriter.WriteHeader(s) +} + +func (rw *rw) Write(b []byte) (int, error) { + if rw.status == 0 { + rw.WriteHeader(http.StatusOK) + } + + if rw.w != nil { + rw.w.Write(b) + } return rw.ResponseWriter.Write(b) }