Dynamic Configuration Refactoring
This commit is contained in:
parent
d3ae88f108
commit
a09dfa3ce1
452 changed files with 21023 additions and 9419 deletions
|
@ -2,110 +2,87 @@ package redirect
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"context"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/containous/traefik/configuration"
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/middlewares"
|
||||
"github.com/urfave/negroni"
|
||||
"github.com/containous/traefik/tracing"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"github.com/vulcand/oxy/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultRedirectRegex = `^(?:https?:\/\/)?([\w\._-]+)(?::\d+)?(.*)$`
|
||||
typeName = "Redirect"
|
||||
)
|
||||
|
||||
// NewEntryPointHandler create a new redirection handler base on entry point
|
||||
func NewEntryPointHandler(dstEntryPoint *configuration.EntryPoint, permanent bool) (negroni.Handler, error) {
|
||||
exp := regexp.MustCompile(`(:\d+)`)
|
||||
match := exp.FindStringSubmatch(dstEntryPoint.Address)
|
||||
if len(match) == 0 {
|
||||
return nil, fmt.Errorf("bad Address format %q", dstEntryPoint.Address)
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
if dstEntryPoint.TLS != nil {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
replacement := protocol + "://${1}" + match[0] + "${2}"
|
||||
|
||||
return NewRegexHandler(defaultRedirectRegex, replacement, permanent)
|
||||
type redirect struct {
|
||||
next http.Handler
|
||||
regex *regexp.Regexp
|
||||
replacement string
|
||||
permanent bool
|
||||
errHandler utils.ErrorHandler
|
||||
name string
|
||||
}
|
||||
|
||||
// NewRegexHandler create a new redirection handler base on regex
|
||||
func NewRegexHandler(exp string, replacement string, permanent bool) (negroni.Handler, error) {
|
||||
re, err := regexp.Compile(exp)
|
||||
// New creates a redirect middleware.
|
||||
func New(ctx context.Context, next http.Handler, config config.Redirect, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug("Creating middleware")
|
||||
logger.Debugf("Setting up redirect %s -> %s", config.Regex, config.Replacement)
|
||||
|
||||
re, err := regexp.Compile(config.Regex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &handler{
|
||||
regexp: re,
|
||||
replacement: replacement,
|
||||
permanent: permanent,
|
||||
return &redirect{
|
||||
regex: re,
|
||||
replacement: config.Replacement,
|
||||
permanent: config.Permanent,
|
||||
errHandler: utils.DefaultHandler,
|
||||
next: next,
|
||||
name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
regexp *regexp.Regexp
|
||||
replacement string
|
||||
permanent bool
|
||||
errHandler utils.ErrorHandler
|
||||
func (r *redirect) GetTracingInformation() (string, ext.SpanKindEnum) {
|
||||
return r.name, tracing.SpanKindNoneEnum
|
||||
}
|
||||
|
||||
func (h *handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
|
||||
func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
oldURL := rawURL(req)
|
||||
|
||||
// only continue if the Regexp param matches the URL
|
||||
if !h.regexp.MatchString(oldURL) {
|
||||
next.ServeHTTP(rw, req)
|
||||
// If the Regexp doesn't match, skip to the next handler
|
||||
if !r.regex.MatchString(oldURL) {
|
||||
r.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
// apply a rewrite regexp to the URL
|
||||
newURL := h.regexp.ReplaceAllString(oldURL, h.replacement)
|
||||
newURL := r.regex.ReplaceAllString(oldURL, r.replacement)
|
||||
|
||||
// replace any variables that may be in there
|
||||
rewrittenURL := &bytes.Buffer{}
|
||||
if err := applyString(newURL, rewrittenURL, req); err != nil {
|
||||
h.errHandler.ServeHTTP(rw, req, err)
|
||||
r.errHandler.ServeHTTP(rw, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
// parse the rewritten URL and replace request URL with it
|
||||
parsedURL, err := url.Parse(rewrittenURL.String())
|
||||
if err != nil {
|
||||
h.errHandler.ServeHTTP(rw, req, err)
|
||||
r.errHandler.ServeHTTP(rw, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
if stripPrefix, stripPrefixOk := req.Context().Value(middlewares.StripPrefixKey).(string); stripPrefixOk {
|
||||
if len(stripPrefix) > 0 {
|
||||
parsedURL.Path = stripPrefix
|
||||
}
|
||||
}
|
||||
|
||||
if addPrefix, addPrefixOk := req.Context().Value(middlewares.AddPrefixKey).(string); addPrefixOk {
|
||||
if len(addPrefix) > 0 {
|
||||
parsedURL.Path = strings.Replace(parsedURL.Path, addPrefix, "", 1)
|
||||
}
|
||||
}
|
||||
|
||||
if replacePath, replacePathOk := req.Context().Value(middlewares.ReplacePathKey).(string); replacePathOk {
|
||||
if len(replacePath) > 0 {
|
||||
parsedURL.Path = replacePath
|
||||
}
|
||||
}
|
||||
|
||||
if newURL != oldURL {
|
||||
handler := &moveHandler{location: parsedURL, permanent: h.permanent}
|
||||
handler := &moveHandler{location: parsedURL, permanent: r.permanent}
|
||||
handler.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
@ -114,7 +91,7 @@ func (h *handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
|||
|
||||
// make sure the request URI corresponds the rewritten URL
|
||||
req.RequestURI = req.URL.RequestURI()
|
||||
next.ServeHTTP(rw, req)
|
||||
r.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
type moveHandler struct {
|
||||
|
@ -124,21 +101,25 @@ type moveHandler struct {
|
|||
|
||||
func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Header().Set("Location", m.location.String())
|
||||
|
||||
status := http.StatusFound
|
||||
if m.permanent {
|
||||
status = http.StatusMovedPermanently
|
||||
}
|
||||
rw.WriteHeader(status)
|
||||
rw.Write([]byte(http.StatusText(status)))
|
||||
_, err := rw.Write([]byte(http.StatusText(status)))
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func rawURL(request *http.Request) string {
|
||||
func rawURL(req *http.Request) string {
|
||||
scheme := "http"
|
||||
if request.TLS != nil || isXForwardedHTTPS(request) {
|
||||
if req.TLS != nil || isXForwardedHTTPS(req) {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
return strings.Join([]string{scheme, "://", request.Host, request.RequestURI}, "")
|
||||
return strings.Join([]string{scheme, "://", req.Host, req.RequestURI}, "")
|
||||
}
|
||||
|
||||
func isXForwardedHTTPS(request *http.Request) bool {
|
||||
|
@ -147,17 +128,13 @@ func isXForwardedHTTPS(request *http.Request) bool {
|
|||
return len(xForwardedProto) > 0 && xForwardedProto == "https"
|
||||
}
|
||||
|
||||
func applyString(in string, out io.Writer, request *http.Request) error {
|
||||
func applyString(in string, out io.Writer, req *http.Request) error {
|
||||
t, err := template.New("t").Parse(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Request *http.Request
|
||||
}{
|
||||
Request: request,
|
||||
}
|
||||
data := struct{ Request *http.Request }{Request: req}
|
||||
|
||||
return t.Execute(out, data)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue