Use RequestURI when redirecting to canonical path. (#1331)

* Use RequestURI when redirecting to canonical path.

Caddy may trim a request's URL path when it starts with the path that's
associated with the virtual host. This change uses the path from the request's
RequestURI when performing a redirect.

Fix issue #1327.

* Rename redirurl to redirURL.

* Redirect to the full URL.

The scheme and host from the virtual host's site configuration is used
in order to redirect to the full URL.

* Add comment and remove redundant check.

* Store the original URL path in request context.

By storing the original URL path as a value in the request context,
middlewares can access both it and the sanitized path. The default
default FileServer handler will use the original URL on redirects.

* Replace contextKey type with CtxKey.

In addition to moving the CtxKey definition to the caddy package, this
change updates the CtxKey references in the httpserver, fastcgi, and
basicauth packages.

* httpserver: Fix reference to CtxKey
This commit is contained in:
ericdreeves
2017-02-28 06:54:12 -06:00
committed by Matt Holt
parent 50749b4e84
commit 0a0d2cc1cf
11 changed files with 142 additions and 45 deletions

View File

@ -14,6 +14,7 @@ import (
"os"
"github.com/mholt/caddy"
"github.com/russross/blackfriday"
)
@ -325,10 +326,8 @@ func (c Context) Files(name string) ([]string, error) {
// IsMITM returns true if it seems likely that the TLS connection
// is being intercepted.
func (c Context) IsMITM() bool {
if val, ok := c.Req.Context().Value(CtxKey("mitm")).(bool); ok {
if val, ok := c.Req.Context().Value(caddy.CtxKey("mitm")).(bool); ok {
return val
}
return false
}
type CtxKey string

View File

@ -9,6 +9,8 @@ import (
"net/http"
"strings"
"sync"
"github.com/mholt/caddy"
)
// tlsHandler is a http.Handler that will inject a value
@ -72,7 +74,7 @@ func (h *tlsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
if checked {
r = r.WithContext(context.WithValue(r.Context(), CtxKey("mitm"), mitm))
r = r.WithContext(context.WithValue(r.Context(), caddy.CtxKey("mitm"), mitm))
}
if mitm && h.closeOnMITM {

View File

@ -7,6 +7,8 @@ import (
"net/http/httptest"
"reflect"
"testing"
"github.com/mholt/caddy"
)
func TestParseClientHello(t *testing.T) {
@ -285,7 +287,7 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
want := ch.interception
handler := &tlsHandler{
next: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
got, checked = r.Context().Value(CtxKey("mitm")).(bool)
got, checked = r.Context().Value(caddy.CtxKey("mitm")).(bool)
}),
listener: newTLSListener(nil, nil),
}

View File

@ -13,6 +13,8 @@ import (
"strconv"
"strings"
"time"
"github.com/mholt/caddy"
)
// requestReplacer is a strings.Replacer which is used to
@ -299,7 +301,7 @@ func (r *replacer) getSubstitution(key string) string {
}
return requestReplacer.Replace(r.requestBody.String())
case "{mitm}":
if val, ok := r.request.Context().Value(CtxKey("mitm")).(bool); ok {
if val, ok := r.request.Context().Value(caddy.CtxKey("mitm")).(bool); ok {
if val {
return "likely"
} else {

View File

@ -9,6 +9,7 @@ import (
"log"
"net"
"net/http"
"net/url"
"os"
"runtime"
"strings"
@ -284,6 +285,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}()
w.Header().Set("Server", "Caddy")
c := context.WithValue(r.Context(), caddy.URLPathCtxKey, r.URL.Path)
r = r.WithContext(c)
sanitizePath(r)
@ -340,6 +343,14 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
}
}
// URL fields other than Path and RawQuery will be empty for most server
// requests. Hence, the request URL is updated with the scheme and host
// from the virtual host's site address.
if vhostURL, err := url.Parse(vhost.Addr.String()); err == nil {
r.URL.Scheme = vhostURL.Scheme
r.URL.Host = vhostURL.Host
}
// Apply the path-based request body size limit
// The error returned by MaxBytesReader is meant to be handled
// by whichever middleware/plugin that receives it when calling
@ -398,10 +409,10 @@ func (s *Server) Stop() error {
return nil
}
// sanitizePath collapses any ./ ../ /// madness
// which helps prevent path traversal attacks.
// Note to middleware: use URL.RawPath If you need
// the "original" URL.Path value.
// sanitizePath collapses any ./ ../ /// madness which helps prevent
// path traversal attacks. Note to middleware: use the value within the
// request's context at key caddy.URLPathContextKey to access the
// "original" URL.Path value.
func sanitizePath(r *http.Request) {
if r.URL.Path == "/" {
return