2018-01-31 18:10:04 +00:00
|
|
|
package redirect
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"regexp"
|
|
|
|
|
2022-11-21 17:36:05 +00:00
|
|
|
"github.com/vulcand/oxy/v2/utils"
|
2024-01-08 08:10:06 +00:00
|
|
|
"go.opentelemetry.io/otel/trace"
|
2018-01-31 18:10:04 +00:00
|
|
|
)
|
|
|
|
|
2021-08-11 15:10:12 +00:00
|
|
|
const (
|
|
|
|
schemeHTTP = "http"
|
|
|
|
schemeHTTPS = "https"
|
|
|
|
)
|
|
|
|
|
2024-01-08 08:10:06 +00:00
|
|
|
const typeName = "Redirect"
|
|
|
|
|
2022-04-15 15:24:08 +00:00
|
|
|
var uriRegexp = regexp.MustCompile(`^(https?):\/\/(\[[\w:.]+\]|[\w\._-]+)?(:\d+)?(.*)$`)
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
type redirect struct {
|
|
|
|
next http.Handler
|
|
|
|
regex *regexp.Regexp
|
|
|
|
replacement string
|
|
|
|
permanent bool
|
|
|
|
errHandler utils.ErrorHandler
|
|
|
|
name string
|
2021-08-11 15:10:12 +00:00
|
|
|
rawURL func(*http.Request) string
|
2018-01-31 18:10:04 +00:00
|
|
|
}
|
|
|
|
|
2019-01-22 07:30:04 +00:00
|
|
|
// New creates a Redirect middleware.
|
2021-08-11 15:10:12 +00:00
|
|
|
func newRedirect(next http.Handler, regex, replacement string, permanent bool, rawURL func(*http.Request) string, name string) (http.Handler, error) {
|
2019-01-22 07:30:04 +00:00
|
|
|
re, err := regexp.Compile(regex)
|
2018-01-31 18:10:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
return &redirect{
|
|
|
|
regex: re,
|
2019-01-22 07:30:04 +00:00
|
|
|
replacement: replacement,
|
|
|
|
permanent: permanent,
|
2018-01-31 18:10:04 +00:00
|
|
|
errHandler: utils.DefaultHandler,
|
2018-11-14 09:18:03 +00:00
|
|
|
next: next,
|
|
|
|
name: name,
|
2021-08-11 15:10:12 +00:00
|
|
|
rawURL: rawURL,
|
2018-01-31 18:10:04 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2024-01-08 08:10:06 +00:00
|
|
|
func (r *redirect) GetTracingInformation() (string, string, trace.SpanKind) {
|
|
|
|
return r.name, typeName, trace.SpanKindInternal
|
2018-01-31 18:10:04 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
2021-08-11 15:10:12 +00:00
|
|
|
oldURL := r.rawURL(req)
|
2018-01-31 18:10:04 +00:00
|
|
|
|
2020-11-24 13:16:03 +00:00
|
|
|
// If the Regexp doesn't match, skip to the next handler.
|
2018-11-14 09:18:03 +00:00
|
|
|
if !r.regex.MatchString(oldURL) {
|
|
|
|
r.next.ServeHTTP(rw, req)
|
2018-01-31 18:10:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-24 13:16:03 +00:00
|
|
|
// Apply a rewrite regexp to the URL.
|
2018-11-14 09:18:03 +00:00
|
|
|
newURL := r.regex.ReplaceAllString(oldURL, r.replacement)
|
2018-01-31 18:10:04 +00:00
|
|
|
|
2020-11-24 13:16:03 +00:00
|
|
|
// Parse the rewritten URL and replace request URL with it.
|
|
|
|
parsedURL, err := url.Parse(newURL)
|
2018-01-31 18:10:04 +00:00
|
|
|
if err != nil {
|
2018-11-14 09:18:03 +00:00
|
|
|
r.errHandler.ServeHTTP(rw, req, err)
|
2018-01-31 18:10:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if newURL != oldURL {
|
2018-11-14 09:18:03 +00:00
|
|
|
handler := &moveHandler{location: parsedURL, permanent: r.permanent}
|
2018-01-31 18:10:04 +00:00
|
|
|
handler.ServeHTTP(rw, req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
req.URL = parsedURL
|
|
|
|
|
2020-11-24 13:16:03 +00:00
|
|
|
// Make sure the request URI corresponds the rewritten URL.
|
2018-01-31 18:10:04 +00:00
|
|
|
req.RequestURI = req.URL.RequestURI()
|
2018-11-14 09:18:03 +00:00
|
|
|
r.next.ServeHTTP(rw, req)
|
2018-01-31 18:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type moveHandler struct {
|
|
|
|
location *url.URL
|
|
|
|
permanent bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
rw.Header().Set("Location", m.location.String())
|
2018-11-14 09:18:03 +00:00
|
|
|
|
2018-01-31 18:10:04 +00:00
|
|
|
status := http.StatusFound
|
2019-01-07 16:56:04 +00:00
|
|
|
if req.Method != http.MethodGet {
|
|
|
|
status = http.StatusTemporaryRedirect
|
|
|
|
}
|
|
|
|
|
2018-01-31 18:10:04 +00:00
|
|
|
if m.permanent {
|
|
|
|
status = http.StatusMovedPermanently
|
2019-01-07 16:56:04 +00:00
|
|
|
if req.Method != http.MethodGet {
|
|
|
|
status = http.StatusPermanentRedirect
|
|
|
|
}
|
2018-01-31 18:10:04 +00:00
|
|
|
}
|
|
|
|
rw.WriteHeader(status)
|
2018-11-14 09:18:03 +00:00
|
|
|
_, err := rw.Write([]byte(http.StatusText(status)))
|
|
|
|
if err != nil {
|
|
|
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
|
|
|
}
|
2018-01-31 18:10:04 +00:00
|
|
|
}
|