2021-04-01 02:37:28 -05:00
|
|
|
package proxy
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-04-14 18:28:23 +02:00
|
|
|
"fmt"
|
2021-04-05 22:12:06 -05:00
|
|
|
"io"
|
2021-05-16 18:34:51 -05:00
|
|
|
"math/rand"
|
2021-04-04 02:57:34 -05:00
|
|
|
"net"
|
2021-04-01 02:37:28 -05:00
|
|
|
"net/http"
|
|
|
|
"net/http/httputil"
|
|
|
|
"net/url"
|
2021-04-03 01:20:24 -05:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2021-04-02 00:07:36 -05:00
|
|
|
"strings"
|
2021-04-01 02:37:28 -05:00
|
|
|
"time"
|
|
|
|
|
2021-04-02 03:13:49 -05:00
|
|
|
log "github.com/go-pkgz/lgr"
|
2021-04-03 00:22:54 -05:00
|
|
|
R "github.com/go-pkgz/rest"
|
2021-04-13 12:45:49 -05:00
|
|
|
"github.com/go-pkgz/rest/logger"
|
2021-04-05 22:12:06 -05:00
|
|
|
|
2021-04-05 03:37:28 -05:00
|
|
|
"github.com/umputun/reproxy/app/discovery"
|
2021-06-01 02:56:39 -05:00
|
|
|
"github.com/umputun/reproxy/app/plugin"
|
2021-04-01 02:37:28 -05:00
|
|
|
)
|
|
|
|
|
2021-04-03 01:20:24 -05:00
|
|
|
// Http is a proxy server for both http and https
|
2021-04-13 12:45:49 -05:00
|
|
|
type Http struct { // nolint golint
|
2021-04-01 02:37:28 -05:00
|
|
|
Matcher
|
2021-06-01 02:56:39 -05:00
|
|
|
Address string
|
|
|
|
AssetsLocation string
|
|
|
|
AssetsWebRoot string
|
2021-06-07 18:57:42 -05:00
|
|
|
AssetsSPA bool
|
2021-06-01 02:56:39 -05:00
|
|
|
MaxBodySize int64
|
|
|
|
GzEnabled bool
|
|
|
|
ProxyHeaders []string
|
|
|
|
SSLConfig SSLConfig
|
|
|
|
Version string
|
|
|
|
AccessLog io.Writer
|
|
|
|
StdOutEnabled bool
|
|
|
|
Signature bool
|
|
|
|
Timeouts Timeouts
|
|
|
|
CacheControl MiddlewareProvider
|
|
|
|
Metrics MiddlewareProvider
|
|
|
|
PluginConductor MiddlewareProvider
|
|
|
|
Reporter Reporter
|
|
|
|
LBSelector func(len int) int
|
2021-04-01 02:37:28 -05:00
|
|
|
}
|
|
|
|
|
2021-04-03 01:20:24 -05:00
|
|
|
// Matcher source info (server and route) to the destination url
|
|
|
|
// If no match found return ok=false
|
2021-04-01 02:37:28 -05:00
|
|
|
type Matcher interface {
|
2021-05-16 18:34:51 -05:00
|
|
|
Match(srv, src string) (res discovery.Matches)
|
2021-04-04 15:55:06 -05:00
|
|
|
Servers() (servers []string)
|
2021-04-09 15:05:22 -05:00
|
|
|
Mappers() (mappers []discovery.URLMapper)
|
2021-05-13 21:14:48 +02:00
|
|
|
CheckHealth() (pingResult map[string]error)
|
2021-04-01 02:37:28 -05:00
|
|
|
}
|
|
|
|
|
2021-04-26 18:51:48 -05:00
|
|
|
// MiddlewareProvider interface defines http middleware handler
|
|
|
|
type MiddlewareProvider interface {
|
2021-04-20 19:04:12 -05:00
|
|
|
Middleware(next http.Handler) http.Handler
|
|
|
|
}
|
|
|
|
|
2021-04-30 04:03:36 -05:00
|
|
|
// Reporter defines error reporting service
|
|
|
|
type Reporter interface {
|
|
|
|
Report(w http.ResponseWriter, code int)
|
|
|
|
}
|
|
|
|
|
2021-04-12 21:54:59 -05:00
|
|
|
// Timeouts consolidate timeouts for both server and transport
|
|
|
|
type Timeouts struct {
|
|
|
|
// server timeouts
|
|
|
|
ReadHeader time.Duration
|
|
|
|
Write time.Duration
|
|
|
|
Idle time.Duration
|
|
|
|
// transport timeouts
|
|
|
|
Dial time.Duration
|
|
|
|
KeepAlive time.Duration
|
|
|
|
IdleConn time.Duration
|
|
|
|
TLSHandshake time.Duration
|
|
|
|
ExpectContinue time.Duration
|
|
|
|
ResponseHeader time.Duration
|
|
|
|
}
|
|
|
|
|
2021-04-03 00:22:54 -05:00
|
|
|
// Run the lister and request's router, activate rest server
|
|
|
|
func (h *Http) Run(ctx context.Context) error {
|
2021-04-01 02:37:28 -05:00
|
|
|
|
2021-04-03 00:22:54 -05:00
|
|
|
if h.AssetsLocation != "" {
|
|
|
|
log.Printf("[DEBUG] assets file server enabled for %s, webroot %s", h.AssetsLocation, h.AssetsWebRoot)
|
2021-04-01 02:37:28 -05:00
|
|
|
}
|
|
|
|
|
2021-05-28 16:11:16 -05:00
|
|
|
if h.LBSelector == nil {
|
|
|
|
h.LBSelector = rand.Intn
|
|
|
|
}
|
|
|
|
|
2021-04-02 03:13:49 -05:00
|
|
|
var httpServer, httpsServer *http.Server
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-ctx.Done()
|
|
|
|
if httpServer != nil {
|
|
|
|
if err := httpServer.Close(); err != nil {
|
|
|
|
log.Printf("[ERROR] failed to close proxy http server, %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if httpsServer != nil {
|
|
|
|
if err := httpsServer.Close(); err != nil {
|
|
|
|
log.Printf("[ERROR] failed to close proxy https server, %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-04-03 00:22:54 -05:00
|
|
|
handler := R.Wrap(h.proxyHandler(),
|
2021-04-09 15:05:22 -05:00
|
|
|
R.Recoverer(log.Default()),
|
2021-06-01 02:56:39 -05:00
|
|
|
signatureHandler(h.Signature, h.Version),
|
2021-04-13 00:52:06 -05:00
|
|
|
h.pingHandler,
|
2021-04-05 03:37:28 -05:00
|
|
|
h.healthMiddleware,
|
2021-06-01 02:56:39 -05:00
|
|
|
h.matchHandler,
|
2021-05-22 10:44:21 -05:00
|
|
|
h.mgmtHandler(),
|
2021-06-01 02:56:39 -05:00
|
|
|
h.pluginHandler(),
|
|
|
|
headersHandler(h.ProxyHeaders),
|
|
|
|
accessLogHandler(h.AccessLog),
|
|
|
|
stdoutLogHandler(h.StdOutEnabled, logger.New(logger.Log(log.Default()), logger.Prefix("[INFO]")).Handler),
|
|
|
|
maxReqSizeHandler(h.MaxBodySize),
|
|
|
|
gzipHandler(h.GzEnabled),
|
2021-04-02 03:13:49 -05:00
|
|
|
)
|
|
|
|
|
2021-05-05 01:41:23 -05:00
|
|
|
if len(h.SSLConfig.FQDNs) == 0 && h.SSLConfig.SSLMode == SSLAuto {
|
|
|
|
// discovery async and may happen not right away. Try to get servers for some time
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
h.SSLConfig.FQDNs = h.Servers() // fill all discovered if nothing defined
|
|
|
|
if len(h.SSLConfig.FQDNs) > 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
}
|
2021-04-09 02:48:18 -05:00
|
|
|
}
|
|
|
|
|
2021-04-02 03:13:49 -05:00
|
|
|
switch h.SSLConfig.SSLMode {
|
2021-04-03 00:22:54 -05:00
|
|
|
case SSLNone:
|
2021-04-02 03:13:49 -05:00
|
|
|
log.Printf("[INFO] activate http proxy server on %s", h.Address)
|
|
|
|
httpServer = h.makeHTTPServer(h.Address, handler)
|
|
|
|
httpServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN")
|
2021-04-03 00:22:54 -05:00
|
|
|
return httpServer.ListenAndServe()
|
|
|
|
case SSLStatic:
|
2021-04-02 03:13:49 -05:00
|
|
|
log.Printf("[INFO] activate https server in 'static' mode on %s", h.Address)
|
|
|
|
|
|
|
|
httpsServer = h.makeHTTPSServer(h.Address, handler)
|
|
|
|
httpsServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN")
|
|
|
|
|
2021-04-09 15:05:22 -05:00
|
|
|
httpServer = h.makeHTTPServer(h.toHTTP(h.Address, h.SSLConfig.RedirHTTPPort), h.httpToHTTPSRouter())
|
2021-04-02 03:13:49 -05:00
|
|
|
httpServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN")
|
|
|
|
|
|
|
|
go func() {
|
2021-04-09 15:05:22 -05:00
|
|
|
log.Printf("[INFO] activate http redirect server on %s", h.toHTTP(h.Address, h.SSLConfig.RedirHTTPPort))
|
2021-04-02 03:13:49 -05:00
|
|
|
err := httpServer.ListenAndServe()
|
|
|
|
log.Printf("[WARN] http redirect server terminated, %s", err)
|
|
|
|
}()
|
2021-04-14 18:58:05 +04:00
|
|
|
return httpsServer.ListenAndServeTLS(h.SSLConfig.Cert, h.SSLConfig.Key)
|
2021-04-03 00:22:54 -05:00
|
|
|
case SSLAuto:
|
2021-04-02 03:13:49 -05:00
|
|
|
log.Printf("[INFO] activate https server in 'auto' mode on %s", h.Address)
|
2021-04-09 02:48:18 -05:00
|
|
|
log.Printf("[DEBUG] FQDNs %v", h.SSLConfig.FQDNs)
|
2021-04-02 03:13:49 -05:00
|
|
|
|
|
|
|
m := h.makeAutocertManager()
|
|
|
|
httpsServer = h.makeHTTPSAutocertServer(h.Address, handler, m)
|
|
|
|
httpsServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN")
|
|
|
|
|
2021-04-09 15:05:22 -05:00
|
|
|
httpServer = h.makeHTTPServer(h.toHTTP(h.Address, h.SSLConfig.RedirHTTPPort), h.httpChallengeRouter(m))
|
2021-04-02 03:13:49 -05:00
|
|
|
httpServer.ErrorLog = log.ToStdLogger(log.Default(), "WARN")
|
|
|
|
|
|
|
|
go func() {
|
2021-04-09 15:05:22 -05:00
|
|
|
log.Printf("[INFO] activate http challenge server on port %s", h.toHTTP(h.Address, h.SSLConfig.RedirHTTPPort))
|
2021-04-02 03:13:49 -05:00
|
|
|
err := httpServer.ListenAndServe()
|
|
|
|
log.Printf("[WARN] http challenge server terminated, %s", err)
|
|
|
|
}()
|
|
|
|
|
2021-04-03 00:22:54 -05:00
|
|
|
return httpsServer.ListenAndServeTLS("", "")
|
2021-04-02 03:13:49 -05:00
|
|
|
}
|
2021-04-14 18:28:23 +02:00
|
|
|
return fmt.Errorf("unknown SSL type %v", h.SSLConfig.SSLMode)
|
2021-04-02 03:13:49 -05:00
|
|
|
}
|
|
|
|
|
2021-06-01 02:56:39 -05:00
|
|
|
type contextKey string
|
|
|
|
|
|
|
|
const (
|
|
|
|
ctxURL = contextKey("url")
|
|
|
|
ctxMatchType = contextKey("type")
|
2021-06-01 03:59:23 -05:00
|
|
|
ctxMatch = contextKey("match")
|
2021-06-01 02:56:39 -05:00
|
|
|
)
|
|
|
|
|
2021-04-01 02:37:28 -05:00
|
|
|
func (h *Http) proxyHandler() http.HandlerFunc {
|
|
|
|
|
|
|
|
reverseProxy := &httputil.ReverseProxy{
|
|
|
|
Director: func(r *http.Request) {
|
|
|
|
ctx := r.Context()
|
2021-06-01 04:00:38 -05:00
|
|
|
uu := ctx.Value(ctxURL).(*url.URL)
|
2021-05-10 03:50:00 -05:00
|
|
|
r.Header.Add("X-Forwarded-Host", r.Host)
|
2021-04-01 02:37:28 -05:00
|
|
|
r.URL.Path = uu.Path
|
|
|
|
r.URL.Host = uu.Host
|
|
|
|
r.URL.Scheme = uu.Scheme
|
2021-04-17 13:11:10 -05:00
|
|
|
r.Host = uu.Host
|
2021-04-04 02:57:34 -05:00
|
|
|
h.setXRealIP(r)
|
2021-04-01 02:37:28 -05:00
|
|
|
},
|
2021-04-09 20:55:21 -05:00
|
|
|
Transport: &http.Transport{
|
2021-04-12 21:54:59 -05:00
|
|
|
ResponseHeaderTimeout: h.Timeouts.ResponseHeader,
|
2021-04-09 20:55:21 -05:00
|
|
|
DialContext: (&net.Dialer{
|
2021-04-12 21:54:59 -05:00
|
|
|
Timeout: h.Timeouts.Dial,
|
|
|
|
KeepAlive: h.Timeouts.KeepAlive,
|
2021-04-09 20:55:21 -05:00
|
|
|
}).DialContext,
|
|
|
|
ForceAttemptHTTP2: true,
|
|
|
|
MaxIdleConns: 100,
|
2021-04-12 21:54:59 -05:00
|
|
|
IdleConnTimeout: h.Timeouts.IdleConn,
|
|
|
|
TLSHandshakeTimeout: h.Timeouts.TLSHandshake,
|
|
|
|
ExpectContinueTimeout: h.Timeouts.ExpectContinue,
|
2021-04-09 20:55:21 -05:00
|
|
|
},
|
2021-04-13 14:03:25 -05:00
|
|
|
ErrorLog: log.ToStdLogger(log.Default(), "WARN"),
|
2021-04-09 20:54:02 -05:00
|
|
|
}
|
2021-04-30 04:03:36 -05:00
|
|
|
assetsHandler := h.assetsHandler()
|
2021-04-01 02:37:28 -05:00
|
|
|
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
2021-06-01 03:59:23 -05:00
|
|
|
if r.Context().Value(ctxMatch) == nil { // no route match detected by matchHandler
|
2021-04-30 04:03:36 -05:00
|
|
|
if h.isAssetRequest(r) {
|
|
|
|
assetsHandler.ServeHTTP(w, r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Printf("[WARN] no match for %s %s", r.URL.Hostname(), r.URL.Path)
|
|
|
|
h.Reporter.Report(w, http.StatusBadGateway)
|
2021-04-01 02:37:28 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-01 03:59:23 -05:00
|
|
|
match := r.Context().Value(ctxMatch).(discovery.MatchedRoute)
|
2021-06-01 02:56:39 -05:00
|
|
|
matchType := r.Context().Value(ctxMatchType).(discovery.MatchType)
|
|
|
|
|
|
|
|
switch matchType {
|
2021-04-16 02:49:00 -05:00
|
|
|
case discovery.MTProxy:
|
2021-06-06 18:13:59 -05:00
|
|
|
switch match.Mapper.RedirectType {
|
|
|
|
case discovery.RTNone:
|
|
|
|
uu := r.Context().Value(ctxURL).(*url.URL)
|
|
|
|
log.Printf("[DEBUG] proxy to %s", uu)
|
|
|
|
reverseProxy.ServeHTTP(w, r)
|
|
|
|
case discovery.RTPerm:
|
|
|
|
log.Printf("[DEBUG] redirect (301) to %s", match.Destination)
|
|
|
|
http.Redirect(w, r, match.Destination, http.StatusMovedPermanently)
|
|
|
|
case discovery.RTTemp:
|
|
|
|
log.Printf("[DEBUG] redirect (302) to %s", match.Destination)
|
|
|
|
http.Redirect(w, r, match.Destination, http.StatusFound)
|
|
|
|
}
|
|
|
|
|
2021-04-16 02:49:00 -05:00
|
|
|
case discovery.MTStatic:
|
2021-06-07 18:57:42 -05:00
|
|
|
// static match result has webroot:location:[spa:normal], i.e. /www:/var/somedir/:normal
|
2021-06-01 02:56:39 -05:00
|
|
|
ae := strings.Split(match.Destination, ":")
|
2021-06-07 18:57:42 -05:00
|
|
|
if len(ae) != 3 { // shouldn't happen
|
2021-06-01 03:25:35 -05:00
|
|
|
log.Printf("[WARN] unexpected static assets destination: %s", match.Destination)
|
2021-04-30 04:03:36 -05:00
|
|
|
h.Reporter.Report(w, http.StatusInternalServerError)
|
2021-04-16 02:49:00 -05:00
|
|
|
return
|
|
|
|
}
|
2021-06-07 18:57:42 -05:00
|
|
|
fs, err := h.fileServer(ae[0], ae[1], ae[2] == "spa")
|
2021-04-16 02:49:00 -05:00
|
|
|
if err != nil {
|
2021-06-01 03:25:35 -05:00
|
|
|
log.Printf("[WARN] file server error, %v", err)
|
2021-04-30 04:03:36 -05:00
|
|
|
h.Reporter.Report(w, http.StatusInternalServerError)
|
2021-04-16 02:49:00 -05:00
|
|
|
return
|
|
|
|
}
|
2021-04-26 18:51:48 -05:00
|
|
|
h.CacheControl.Middleware(fs).ServeHTTP(w, r)
|
2021-04-01 02:37:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-02 03:13:49 -05:00
|
|
|
|
2021-06-01 02:56:39 -05:00
|
|
|
// matchHandler is a part of middleware chain. Matches incoming request to one or more matched rules
|
|
|
|
// and if match found sets it to the request context. Context used by proxy handler as well as by plugin conductor
|
|
|
|
func (h *Http) matchHandler(next http.Handler) http.Handler {
|
2021-05-16 18:34:51 -05:00
|
|
|
|
2021-06-01 02:56:39 -05:00
|
|
|
getMatch := func(mm discovery.Matches, picker func(len int) int) (m discovery.MatchedRoute, ok bool) {
|
|
|
|
if len(mm.Routes) == 0 {
|
|
|
|
return m, false
|
2021-05-16 18:34:51 -05:00
|
|
|
}
|
2021-05-28 16:11:16 -05:00
|
|
|
|
2021-06-01 02:56:39 -05:00
|
|
|
var matches []discovery.MatchedRoute
|
|
|
|
for _, m := range mm.Routes {
|
|
|
|
if m.Alive {
|
|
|
|
matches = append(matches, m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch len(matches) {
|
|
|
|
case 0:
|
|
|
|
return m, false
|
|
|
|
case 1:
|
|
|
|
return matches[0], true
|
|
|
|
default:
|
|
|
|
return matches[picker(len(matches))], true
|
|
|
|
}
|
2021-05-16 18:34:51 -05:00
|
|
|
}
|
2021-06-01 02:56:39 -05:00
|
|
|
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
server := r.URL.Hostname()
|
|
|
|
if server == "" {
|
2021-06-07 18:57:42 -05:00
|
|
|
server = strings.Split(r.Host, ":")[0] // drop port
|
2021-06-01 02:56:39 -05:00
|
|
|
}
|
|
|
|
matches := h.Match(server, r.URL.Path) // get all matches for the server:path pair
|
|
|
|
match, ok := getMatch(matches, h.LBSelector)
|
|
|
|
if ok {
|
2021-06-01 03:59:23 -05:00
|
|
|
ctx := context.WithValue(r.Context(), ctxMatch, match) // set match info
|
|
|
|
ctx = context.WithValue(ctx, ctxMatchType, matches.MatchType) // set match type
|
|
|
|
ctx = context.WithValue(ctx, plugin.CtxMatch, match) // set match info for plugin conductor
|
2021-06-01 03:50:20 -05:00
|
|
|
|
|
|
|
if matches.MatchType == discovery.MTProxy {
|
|
|
|
uu, err := url.Parse(match.Destination)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[WARN] can't parse destination %s, %v", match.Destination, err)
|
|
|
|
h.Reporter.Report(w, http.StatusBadGateway)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, ctxURL, uu) // set destination url in request's context
|
2021-06-01 02:56:39 -05:00
|
|
|
}
|
|
|
|
r = r.WithContext(ctx)
|
|
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
})
|
2021-05-16 18:34:51 -05:00
|
|
|
}
|
|
|
|
|
2021-04-30 04:03:36 -05:00
|
|
|
func (h *Http) assetsHandler() http.HandlerFunc {
|
|
|
|
if h.AssetsLocation == "" || h.AssetsWebRoot == "" {
|
|
|
|
return func(writer http.ResponseWriter, request *http.Request) {}
|
|
|
|
}
|
2021-06-07 19:04:18 -05:00
|
|
|
log.Printf("[DEBUG] shared assets server enabled for %s %s, spa=%v", h.AssetsWebRoot, h.AssetsLocation, h.AssetsSPA)
|
2021-06-07 18:57:42 -05:00
|
|
|
fs, err := h.fileServer(h.AssetsWebRoot, h.AssetsLocation, h.AssetsSPA)
|
2021-04-30 04:03:36 -05:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("[WARN] can't initialize assets server, %v", err)
|
|
|
|
return func(writer http.ResponseWriter, request *http.Request) {}
|
|
|
|
}
|
|
|
|
return h.CacheControl.Middleware(fs).ServeHTTP
|
|
|
|
}
|
|
|
|
|
2021-06-07 18:57:42 -05:00
|
|
|
func (h *Http) fileServer(assetsWebRoot, assetsLocation string, spa bool) (http.Handler, error) {
|
|
|
|
if spa {
|
|
|
|
return R.FileServerSPA(assetsWebRoot, assetsLocation, nil)
|
|
|
|
}
|
|
|
|
return R.FileServer(assetsWebRoot, assetsLocation, nil)
|
|
|
|
}
|
|
|
|
|
2021-04-30 04:03:36 -05:00
|
|
|
func (h *Http) isAssetRequest(r *http.Request) bool {
|
|
|
|
if h.AssetsLocation == "" || h.AssetsWebRoot == "" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
root := strings.TrimSuffix(h.AssetsWebRoot, "/")
|
|
|
|
return r.URL.Path == root || strings.HasPrefix(r.URL.Path, root+"/")
|
|
|
|
}
|
|
|
|
|
2021-04-09 15:05:22 -05:00
|
|
|
func (h *Http) toHTTP(address string, httpPort int) string {
|
2021-04-05 22:12:06 -05:00
|
|
|
rx := regexp.MustCompile(`(.*):(\d*)`)
|
|
|
|
return rx.ReplaceAllString(address, "$1:") + strconv.Itoa(httpPort)
|
|
|
|
}
|
|
|
|
|
2021-06-01 02:56:39 -05:00
|
|
|
func (h *Http) pluginHandler() func(next http.Handler) http.Handler {
|
|
|
|
if h.PluginConductor != nil {
|
|
|
|
log.Printf("[INFO] plugin support enabled")
|
|
|
|
return h.PluginConductor.Middleware
|
2021-04-13 12:45:49 -05:00
|
|
|
}
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-22 10:44:21 -05:00
|
|
|
func (h *Http) mgmtHandler() func(next http.Handler) http.Handler {
|
2021-06-01 02:56:39 -05:00
|
|
|
if h.Metrics != nil {
|
2021-05-22 10:44:21 -05:00
|
|
|
log.Printf("[DEBUG] metrics enabled")
|
|
|
|
return h.Metrics.Middleware
|
|
|
|
}
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
}
|
2021-05-12 21:54:41 -05:00
|
|
|
}
|
|
|
|
|
2021-04-02 03:13:49 -05:00
|
|
|
func (h *Http) makeHTTPServer(addr string, router http.Handler) *http.Server {
|
|
|
|
return &http.Server{
|
|
|
|
Addr: addr,
|
|
|
|
Handler: router,
|
2021-04-12 21:54:59 -05:00
|
|
|
ReadHeaderTimeout: h.Timeouts.ReadHeader,
|
|
|
|
WriteTimeout: h.Timeouts.Write,
|
|
|
|
IdleTimeout: h.Timeouts.Idle,
|
2021-04-02 03:13:49 -05:00
|
|
|
}
|
|
|
|
}
|
2021-04-04 02:57:34 -05:00
|
|
|
|
|
|
|
func (h *Http) setXRealIP(r *http.Request) {
|
|
|
|
|
2021-04-06 23:17:50 -05:00
|
|
|
remoteIP := r.Header.Get("X-Forwarded-For")
|
|
|
|
if remoteIP == "" {
|
|
|
|
remoteIP = r.RemoteAddr
|
|
|
|
}
|
|
|
|
|
|
|
|
ip, _, err := net.SplitHostPort(remoteIP)
|
2021-04-04 02:57:34 -05:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
userIP := net.ParseIP(ip)
|
|
|
|
if userIP == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.Header.Add("X-Real-IP", ip)
|
|
|
|
}
|