mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-23 09:18:51 +02:00
Feat/fileserver (#60)
* cleanup code for URL type * fix makefile for trace mode * refactor, merge Entry, RawEntry and Route into one. * Implement fileserver. * refactor: rename HTTPRoute to ReverseProxyRoute to avoid confusion * refactor: move metrics logger to middleware package - fix prometheus metrics for load balanced routes - route will now fail when health monitor fail to start * fix extra output of ls-* commands by defer initializaing stuff, speed up start time * add test for path traversal attack, small fix on FileServer.Start method * rename rule.on.bypass to pass * refactor and fixed map-to-map deserialization * updated route loading logic * schemas: add "add_prefix" option to modify_request middleware * updated route JSONMarshalling --------- Co-authored-by: yusing <yusing@6uo.me>
This commit is contained in:
@@ -23,12 +23,9 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/logging"
|
||||
"github.com/yusing/go-proxy/internal/metrics"
|
||||
gphttp "github.com/yusing/go-proxy/internal/net/http"
|
||||
"github.com/yusing/go-proxy/internal/net/http/accesslog"
|
||||
"github.com/yusing/go-proxy/internal/net/types"
|
||||
@@ -96,38 +93,7 @@ type ReverseProxy struct {
|
||||
HandlerFunc http.HandlerFunc
|
||||
|
||||
TargetName string
|
||||
TargetURL types.URL
|
||||
}
|
||||
|
||||
type httpMetricLogger struct {
|
||||
http.ResponseWriter
|
||||
timestamp time.Time
|
||||
labels *metrics.HTTPRouteMetricLabels
|
||||
}
|
||||
|
||||
// WriteHeader implements http.ResponseWriter.
|
||||
func (l *httpMetricLogger) WriteHeader(status int) {
|
||||
l.ResponseWriter.WriteHeader(status)
|
||||
duration := time.Since(l.timestamp)
|
||||
go func() {
|
||||
m := metrics.GetRouteMetrics()
|
||||
m.HTTPReqTotal.Inc()
|
||||
m.HTTPReqElapsed.With(l.labels).Set(float64(duration.Milliseconds()))
|
||||
|
||||
// ignore 1xx
|
||||
switch {
|
||||
case status >= 500:
|
||||
m.HTTP5xx.With(l.labels).Inc()
|
||||
case status >= 400:
|
||||
m.HTTP4xx.With(l.labels).Inc()
|
||||
case status >= 200:
|
||||
m.HTTP2xx3xx.With(l.labels).Inc()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (l *httpMetricLogger) Unwrap() http.ResponseWriter {
|
||||
return l.ResponseWriter
|
||||
TargetURL *types.URL
|
||||
}
|
||||
|
||||
func singleJoiningSlash(a, b string) string {
|
||||
@@ -167,7 +133,7 @@ func joinURLPath(a, b *url.URL) (path, rawpath string) {
|
||||
// URLs to the scheme, host, and base path provided in target. If the
|
||||
// target's path is "/base" and the incoming request was for "/dir",
|
||||
// the target request will be for /base/dir.
|
||||
func NewReverseProxy(name string, target types.URL, transport http.RoundTripper) *ReverseProxy {
|
||||
func NewReverseProxy(name string, target *types.URL, transport http.RoundTripper) *ReverseProxy {
|
||||
if transport == nil {
|
||||
panic("nil transport")
|
||||
}
|
||||
@@ -181,15 +147,11 @@ func NewReverseProxy(name string, target types.URL, transport http.RoundTripper)
|
||||
return rp
|
||||
}
|
||||
|
||||
func (p *ReverseProxy) UnregisterMetrics() {
|
||||
metrics.GetRouteMetrics().UnregisterService(p.TargetName)
|
||||
}
|
||||
|
||||
func (p *ReverseProxy) rewriteRequestURL(req *http.Request) {
|
||||
targetQuery := p.TargetURL.RawQuery
|
||||
req.URL.Scheme = p.TargetURL.Scheme
|
||||
req.URL.Host = p.TargetURL.Host
|
||||
req.URL.Path, req.URL.RawPath = joinURLPath(p.TargetURL.URL, req.URL)
|
||||
req.URL.Path, req.URL.RawPath = joinURLPath(&p.TargetURL.URL, req.URL)
|
||||
if targetQuery == "" || req.URL.RawQuery == "" {
|
||||
req.URL.RawQuery = targetQuery + req.URL.RawQuery
|
||||
} else {
|
||||
@@ -255,28 +217,6 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
||||
visitorIP, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err != nil {
|
||||
visitorIP = req.RemoteAddr
|
||||
}
|
||||
|
||||
if common.PrometheusEnabled {
|
||||
t := time.Now()
|
||||
// req.RemoteAddr had been modified by middleware (if any)
|
||||
lbls := &metrics.HTTPRouteMetricLabels{
|
||||
Service: p.TargetName,
|
||||
Method: req.Method,
|
||||
Host: req.Host,
|
||||
Visitor: visitorIP,
|
||||
Path: req.URL.Path,
|
||||
}
|
||||
rw = &httpMetricLogger{
|
||||
ResponseWriter: rw,
|
||||
timestamp: t,
|
||||
labels: lbls,
|
||||
}
|
||||
}
|
||||
|
||||
transport := p.Transport
|
||||
|
||||
ctx := req.Context()
|
||||
@@ -360,7 +300,11 @@ func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
||||
// separated list and fold multiple headers into one.
|
||||
prior, ok := outreq.Header[gphttp.HeaderXForwardedFor]
|
||||
omit := ok && prior == nil // Issue 38079: nil now means don't populate the header
|
||||
xff := visitorIP
|
||||
|
||||
xff, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err != nil {
|
||||
xff = req.RemoteAddr
|
||||
}
|
||||
if len(prior) > 0 {
|
||||
xff = strings.Join(prior, ", ") + ", " + xff
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user