Make http servers obey --dump headers,bodies

This commit is contained in:
Nick Craig-Wood
2023-07-30 13:22:28 +01:00
parent 982f76b4df
commit 444a6e6d2d
5 changed files with 188 additions and 77 deletions

View File

@@ -1,15 +1,18 @@
package http
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"net/http"
"strings"
"sync"
goauth "github.com/abbot/go-http-auth"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/fshttp/fshttpdump"
)
// parseAuthorization parses the Authorization header into user, pass
@@ -195,3 +198,79 @@ func MiddlewareStripPrefix(prefix string) Middleware {
return http.StripPrefix(prefix, next)
}
}
type dumpWriter struct {
w http.ResponseWriter
resp http.Response
buf bytes.Buffer
out io.Writer
dump fs.DumpFlags
dumpBody bool
}
func newDumpWriter(w http.ResponseWriter, req *http.Request, dump fs.DumpFlags) *dumpWriter {
d := &dumpWriter{
w: w,
resp: http.Response{
Status: "200 probably OK",
StatusCode: 200,
Proto: req.Proto,
ProtoMajor: req.ProtoMajor,
ProtoMinor: req.ProtoMinor,
},
dump: dump,
dumpBody: dump&(fs.DumpBodies|fs.DumpResponses) != 0,
}
if d.dumpBody {
d.out = io.MultiWriter(w, &d.buf)
}
return d
}
// Header returns the header map that will be sent by WriteHeader.
func (d *dumpWriter) Header() http.Header {
return d.w.Header()
}
// Write writes the data to the connection as part of an HTTP reply.
func (d *dumpWriter) Write(buf []byte) (int, error) {
if d.dumpBody {
return d.out.Write(buf)
}
return d.w.Write(buf)
}
// WriteHeader sends an HTTP response header with the provided status
// code.
func (d *dumpWriter) WriteHeader(statusCode int) {
d.resp.StatusCode = statusCode
d.w.WriteHeader(statusCode)
}
// dump the recorded contents.
func (d *dumpWriter) dumpResponse(req *http.Request) {
d.resp.Header = d.w.Header()
if d.dumpBody {
d.resp.Body = io.NopCloser(bytes.NewBuffer(d.buf.Bytes()))
}
fshttpdump.DumpResponse(&d.resp, req, nil, d.dump)
}
// MiddlewareDump dumps requests and responses to the log
func MiddlewareDump(dump fs.DumpFlags) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// First dump the incoming request
fshttpdump.DumpRequest(r, dump, false)
// Now intercept the body write
d := newDumpWriter(w, r, dump)
// Do the request
next.ServeHTTP(d, r)
// Now dump the contents
d.dumpResponse(r)
})
}
}