Start work on request log

This commit is contained in:
David Stotijn
2019-12-01 14:07:12 +01:00
parent 94363fe196
commit 1164837247
2 changed files with 100 additions and 7 deletions

View File

@ -1,15 +1,23 @@
package main package main
import ( import (
"bytes"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"flag" "flag"
"fmt"
"io/ioutil"
"log" "log"
"net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"net/url" "net/url"
"os"
"strings"
"github.com/dstotijn/gurp/pkg/proxy" "github.com/dstotijn/gurp/pkg/proxy"
"github.com/dstotijn/gurp/pkg/reqlog"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@ -33,6 +41,8 @@ func main() {
log.Fatalf("[FATAL] Could not parse CA: %v", err) log.Fatalf("[FATAL] Could not parse CA: %v", err)
} }
reqLog := reqlog.NewRequestLog()
p, err := proxy.NewProxy(caCert, tlsCA.PrivateKey) p, err := proxy.NewProxy(caCert, tlsCA.PrivateKey)
if err != nil { if err != nil {
log.Fatalf("[FATAL] Could not create Proxy: %v", err) log.Fatalf("[FATAL] Could not create Proxy: %v", err)
@ -40,34 +50,73 @@ func main() {
p.UseRequestModifier(func(next proxy.RequestModifyFunc) proxy.RequestModifyFunc { p.UseRequestModifier(func(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {
return func(req *http.Request) { return func(req *http.Request) {
log.Printf("[DEBUG] Incoming request: %v", req.URL)
next(req) next(req)
clone := req.Clone(req.Context())
var body []byte
if req.Body != nil {
// TODO: Use io.LimitReader.
body, err := ioutil.ReadAll(req.Body)
if err != nil {
log.Printf("[ERROR] Could not read request body for logging: %v", err)
return
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
reqLog.AddRequest(*clone, body)
} }
}) })
p.UseResponseModifier(func(next proxy.ResponseModifyFunc) proxy.ResponseModifyFunc { p.UseResponseModifier(func(next proxy.ResponseModifyFunc) proxy.ResponseModifyFunc {
return func(res *http.Response) error { return func(res *http.Response) error {
log.Printf("[DEBUG] Downstream response: %v %v %v", res.Proto, res.StatusCode, http.StatusText(res.StatusCode)) if err := next(res); err != nil {
return next(res) return err
}
clone := *res
var body []byte
if res.Body != nil {
// TODO: Use io.LimitReader.
var err error
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("could not read response body: %v", err)
}
res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
reqLog.AddResponse(clone, body)
return nil
} }
}) })
router := mux.NewRouter().SkipClean(true) var adminHandler http.Handler
adminRouter := router.Host("gurp.proxy")
if *dev { if *dev {
adminURL, err := url.Parse("http://localhost:3000") adminURL, err := url.Parse("http://localhost:3000")
if err != nil { if err != nil {
log.Fatalf("[FATAL] Invalid admin URL: %v", err) log.Fatalf("[FATAL] Invalid admin URL: %v", err)
} }
adminRouter.Handler(httputil.NewSingleHostReverseProxy(adminURL)) adminHandler = httputil.NewSingleHostReverseProxy(adminURL)
} else { } else {
if *adminPath == "" { if *adminPath == "" {
log.Fatal("[FATAL] `adminPath` must be set") log.Fatal("[FATAL] `adminPath` must be set")
} }
adminRouter.Handler(http.FileServer(http.Dir(*adminPath))) adminHandler = http.FileServer(http.Dir(*adminPath))
} }
router := mux.NewRouter().SkipClean(true)
adminRouter := router.MatcherFunc(func(req *http.Request, match *mux.RouteMatch) bool {
hostname, _ := os.Hostname()
host, _, _ := net.SplitHostPort(req.Host)
return strings.EqualFold(host, hostname) || req.Host == "gurp.proxy"
})
// GraphQL server.
// adminRouter.Path("/graphql").Handler(...)
// Admin interface.
adminRouter.Handler(adminHandler)
// Fallback (default) is the Proxy handler.
router.PathPrefix("").Handler(p) router.PathPrefix("").Handler(p)
s := &http.Server{ s := &http.Server{

44
pkg/reqlog/reqlog.go Normal file
View File

@ -0,0 +1,44 @@
package reqlog
import (
"net/http"
"sync"
)
type request struct {
req http.Request
body []byte
}
type response struct {
res http.Response
body []byte
}
type RequestLog struct {
reqStore []request
resStore []response
reqMu sync.Mutex
resMu sync.Mutex
}
func NewRequestLog() RequestLog {
return RequestLog{
reqStore: make([]request, 0),
resStore: make([]response, 0),
}
}
func (rl *RequestLog) AddRequest(req http.Request, body []byte) {
rl.reqMu.Lock()
defer rl.reqMu.Unlock()
rl.reqStore = append(rl.reqStore, request{req, body})
}
func (rl *RequestLog) AddResponse(res http.Response, body []byte) {
rl.resMu.Lock()
defer rl.resMu.Unlock()
rl.resStore = append(rl.resStore, response{res, body})
}