diff --git a/core/router/router_subdomain_redirect.go b/core/router/router_subdomain_redirect.go index 90e292a8..59014fa1 100644 --- a/core/router/router_subdomain_redirect.go +++ b/core/router/router_subdomain_redirect.go @@ -3,8 +3,10 @@ package router import ( "fmt" "net/http" + "strconv" "strings" "text/template" + "unicode/utf8" "github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/core/netutil" @@ -217,7 +219,7 @@ func RedirectAbsolute(w http.ResponseWriter, r *http.Request, url string, code i // Do it only if the request didn't already have a Content-Type header. _, hadCT := h[context.ContentTypeHeaderKey] - h.Set("Location", url) + h.Set("Location", hexEscapeNonASCII(url)) if !hadCT && (r.Method == http.MethodGet || r.Method == http.MethodHead) { h.Set(context.ContentTypeHeaderKey, "text/html; charset=utf-8") } @@ -229,3 +231,27 @@ func RedirectAbsolute(w http.ResponseWriter, r *http.Request, url string, code i fmt.Fprintln(w, body) } } + +func hexEscapeNonASCII(s string) string { // part of the standard library. + newLen := 0 + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + newLen += 3 + } else { + newLen++ + } + } + if newLen == len(s) { + return s + } + b := make([]byte, 0, newLen) + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + b = append(b, '%') + b = strconv.AppendInt(b, int64(s[i]), 16) + } else { + b = append(b, s[i]) + } + } + return string(b) +} diff --git a/middleware/rewrite/rewrite.go b/middleware/rewrite/rewrite.go index 0edf6345..1b14e3e2 100644 --- a/middleware/rewrite/rewrite.go +++ b/middleware/rewrite/rewrite.go @@ -8,7 +8,6 @@ import ( "regexp" "strconv" "strings" - "text/template" "github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/core/router" @@ -244,7 +243,7 @@ func (e *Engine) Rewrite(w http.ResponseWriter, r *http.Request, routeHandler ht // this performs better, no need to check query or host, // the uri already built. e.debugf("Full redirect: from: %s to: %s\n", src, target) - redirectAbs(w, r, target, rd.code) + router.RedirectAbsolute(w, r, target, rd.code) } else { e.debugf("Path redirect: from: %s to: %s\n", src, target) http.Redirect(w, r, target, rd.code) @@ -324,22 +323,3 @@ func getPort(hostport string) string { // returns :port, note that this is only return "" } - -func redirectAbs(w http.ResponseWriter, r *http.Request, url string, code int) { - // part of net/http std library. - h := w.Header() - - _, hadCT := h[context.ContentTypeHeaderKey] - - h.Set("Location", url) - if !hadCT && (r.Method == http.MethodGet || r.Method == http.MethodHead) { - h.Set(context.ContentTypeHeaderKey, "text/html; charset=utf-8") - } - w.WriteHeader(code) - - // Shouldn't send the body for POST or HEAD; that leaves GET. - if !hadCT && r.Method == "GET" { - body := "" + http.StatusText(code) + ".\n" - fmt.Fprintln(w, body) - } -}