89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
package mock
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"gitlab.com/inetmock/inetmock/pkg/audit"
|
|
details "gitlab.com/inetmock/inetmock/pkg/audit/details"
|
|
"gitlab.com/inetmock/inetmock/pkg/logging"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type route struct {
|
|
rule targetRule
|
|
handler http.Handler
|
|
}
|
|
|
|
type RegexpHandler struct {
|
|
handlerName string
|
|
logger logging.Logger
|
|
routes []*route
|
|
emitter audit.Emitter
|
|
}
|
|
|
|
func (h *RegexpHandler) Handler(rule targetRule, handler http.Handler) {
|
|
h.routes = append(h.routes, &route{rule, handler})
|
|
}
|
|
|
|
func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
timer := prometheus.NewTimer(requestDurationHistogram.WithLabelValues(h.handlerName))
|
|
defer timer.ObserveDuration()
|
|
|
|
for idx := range h.routes {
|
|
rule := h.routes[idx].rule
|
|
if h.routes[idx].rule.requestMatchTarget.Matches(r, rule.targetKey, rule.pattern) {
|
|
totalRequestCounter.WithLabelValues(h.handlerName, strconv.FormatBool(true)).Inc()
|
|
h.routes[idx].handler.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
}
|
|
// no pattern matched; send 404 response
|
|
totalRequestCounter.WithLabelValues(h.handlerName, strconv.FormatBool(false)).Inc()
|
|
http.NotFound(w, r)
|
|
}
|
|
|
|
func (h *RegexpHandler) setupRoute(rule targetRule) {
|
|
h.logger.Info(
|
|
"setup routing",
|
|
zap.String("route", rule.Pattern().String()),
|
|
zap.String("response", rule.Response()),
|
|
)
|
|
|
|
h.Handler(rule, emittingFileHandler{
|
|
emitter: h.emitter,
|
|
targetPath: rule.response,
|
|
})
|
|
}
|
|
|
|
type emittingFileHandler struct {
|
|
emitter audit.Emitter
|
|
targetPath string
|
|
}
|
|
|
|
func (f emittingFileHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|
f.emitter.Emit(eventFromRequest(request))
|
|
http.ServeFile(writer, request, f.targetPath)
|
|
}
|
|
|
|
func eventFromRequest(request *http.Request) audit.Event {
|
|
httpDetails := details.HTTP{
|
|
Method: request.Method,
|
|
Host: request.Host,
|
|
URI: request.RequestURI,
|
|
Proto: request.Proto,
|
|
Headers: request.Header,
|
|
}
|
|
|
|
ev := audit.Event{
|
|
Transport: audit.TransportProtocol_TCP,
|
|
Application: audit.AppProtocol_HTTP,
|
|
ProtocolDetails: httpDetails,
|
|
}
|
|
|
|
ev.SetDestinationIPFromAddr(LocalAddr(request.Context()))
|
|
ev.SetSourceIPFromAddr(RemoteAddr(request.Context()))
|
|
|
|
return ev
|
|
}
|