mirror of
https://github.com/dstotijn/hetty.git
synced 2025-07-01 18:47:29 -04:00
Start work on request log
This commit is contained in:
63
cmd/main.go
63
cmd/main.go
@ -1,15 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dstotijn/gurp/pkg/proxy"
|
||||
"github.com/dstotijn/gurp/pkg/reqlog"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
@ -33,6 +41,8 @@ func main() {
|
||||
log.Fatalf("[FATAL] Could not parse CA: %v", err)
|
||||
}
|
||||
|
||||
reqLog := reqlog.NewRequestLog()
|
||||
|
||||
p, err := proxy.NewProxy(caCert, tlsCA.PrivateKey)
|
||||
if err != nil {
|
||||
log.Fatalf("[FATAL] Could not create Proxy: %v", err)
|
||||
@ -40,34 +50,73 @@ func main() {
|
||||
|
||||
p.UseRequestModifier(func(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {
|
||||
return func(req *http.Request) {
|
||||
log.Printf("[DEBUG] Incoming request: %v", req.URL)
|
||||
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 {
|
||||
return func(res *http.Response) error {
|
||||
log.Printf("[DEBUG] Downstream response: %v %v %v", res.Proto, res.StatusCode, http.StatusText(res.StatusCode))
|
||||
return next(res)
|
||||
if err := next(res); err != nil {
|
||||
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)
|
||||
adminRouter := router.Host("gurp.proxy")
|
||||
var adminHandler http.Handler
|
||||
|
||||
if *dev {
|
||||
adminURL, err := url.Parse("http://localhost:3000")
|
||||
if err != nil {
|
||||
log.Fatalf("[FATAL] Invalid admin URL: %v", err)
|
||||
}
|
||||
adminRouter.Handler(httputil.NewSingleHostReverseProxy(adminURL))
|
||||
adminHandler = httputil.NewSingleHostReverseProxy(adminURL)
|
||||
} else {
|
||||
if *adminPath == "" {
|
||||
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)
|
||||
|
||||
s := &http.Server{
|
||||
|
44
pkg/reqlog/reqlog.go
Normal file
44
pkg/reqlog/reqlog.go
Normal 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})
|
||||
}
|
Reference in New Issue
Block a user