Add RespectForwardedHeaders option to handlers
When activated, X-Forwarded-* and Forwarded headers will be checked for a hostname and protocol used for generating absolute URLs. Addresses #38
This commit is contained in:
parent
cecccf4162
commit
27d6ade187
74
post_test.go
74
post_test.go
|
@ -66,4 +66,78 @@ func TestPost(t *testing.T) {
|
||||||
},
|
},
|
||||||
Code: http.StatusRequestEntityTooLarge,
|
Code: http.StatusRequestEntityTooLarge,
|
||||||
}).Run(handler, t)
|
}).Run(handler, t)
|
||||||
|
|
||||||
|
(&httpTest{
|
||||||
|
Name: "Ignore Forwarded headers",
|
||||||
|
Method: "POST",
|
||||||
|
ReqHeader: map[string]string{
|
||||||
|
"Tus-Resumable": "1.0.0",
|
||||||
|
"Upload-Length": "300",
|
||||||
|
"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
|
||||||
|
"X-Forwarded-Host": "foo.com",
|
||||||
|
"X-Forwarded-Proto": "https",
|
||||||
|
},
|
||||||
|
Code: http.StatusCreated,
|
||||||
|
ResHeader: map[string]string{
|
||||||
|
"Location": "http://tus.io/files/foo",
|
||||||
|
},
|
||||||
|
}).Run(handler, t)
|
||||||
|
|
||||||
|
handler, _ = NewHandler(Config{
|
||||||
|
MaxSize: 400,
|
||||||
|
BasePath: "files",
|
||||||
|
DataStore: postStore{
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
|
RespectForwardedHeaders: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
(&httpTest{
|
||||||
|
Name: "Respect X-Forwarded-* headers",
|
||||||
|
Method: "POST",
|
||||||
|
ReqHeader: map[string]string{
|
||||||
|
"Tus-Resumable": "1.0.0",
|
||||||
|
"Upload-Length": "300",
|
||||||
|
"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
|
||||||
|
"X-Forwarded-Host": "foo.com",
|
||||||
|
"X-Forwarded-Proto": "https",
|
||||||
|
},
|
||||||
|
Code: http.StatusCreated,
|
||||||
|
ResHeader: map[string]string{
|
||||||
|
"Location": "https://foo.com/files/foo",
|
||||||
|
},
|
||||||
|
}).Run(handler, t)
|
||||||
|
|
||||||
|
(&httpTest{
|
||||||
|
Name: "Respect Forwarded headers",
|
||||||
|
Method: "POST",
|
||||||
|
ReqHeader: map[string]string{
|
||||||
|
"Tus-Resumable": "1.0.0",
|
||||||
|
"Upload-Length": "300",
|
||||||
|
"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
|
||||||
|
"X-Forwarded-Host": "bar.com",
|
||||||
|
"X-Forwarded-Proto": "http",
|
||||||
|
"Forwarded": "proto=https,host=foo.com",
|
||||||
|
},
|
||||||
|
Code: http.StatusCreated,
|
||||||
|
ResHeader: map[string]string{
|
||||||
|
"Location": "https://foo.com/files/foo",
|
||||||
|
},
|
||||||
|
}).Run(handler, t)
|
||||||
|
|
||||||
|
(&httpTest{
|
||||||
|
Name: "Filter forwarded protocol",
|
||||||
|
Method: "POST",
|
||||||
|
ReqHeader: map[string]string{
|
||||||
|
"Tus-Resumable": "1.0.0",
|
||||||
|
"Upload-Length": "300",
|
||||||
|
"Upload-Metadata": "foo aGVsbG8=, bar d29ybGQ=",
|
||||||
|
"X-Forwarded-Proto": "aaa",
|
||||||
|
"Forwarded": "proto=bbb",
|
||||||
|
},
|
||||||
|
Code: http.StatusCreated,
|
||||||
|
ResHeader: map[string]string{
|
||||||
|
"Location": "http://tus.io/files/foo",
|
||||||
|
},
|
||||||
|
}).Run(handler, t)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var reExtractFileID = regexp.MustCompile(`([^/]+)\/?$`)
|
var (
|
||||||
|
reExtractFileID = regexp.MustCompile(`([^/]+)\/?$`)
|
||||||
|
reForwardedHost = regexp.MustCompile(`host=([^,]+)`)
|
||||||
|
reForwardedProto = regexp.MustCompile(`proto=(https?)`)
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrUnsupportedVersion = errors.New("unsupported version")
|
ErrUnsupportedVersion = errors.New("unsupported version")
|
||||||
|
@ -65,6 +69,10 @@ type Config struct {
|
||||||
NotifyCompleteUploads bool
|
NotifyCompleteUploads bool
|
||||||
// Logger the logger to use internally
|
// Logger the logger to use internally
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
|
// Respect the X-Forwarded-Host, X-Forwarded-Proto and Forwarded headers
|
||||||
|
// potentially set by proxies when generating an absolute URL in the
|
||||||
|
// reponse to POST requests.
|
||||||
|
RespectForwardedHeaders bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnroutedHandler exposes methods to handle requests as part of the tus protocol,
|
// UnroutedHandler exposes methods to handle requests as part of the tus protocol,
|
||||||
|
@ -500,16 +508,51 @@ func (handler *UnroutedHandler) absFileURL(r *http.Request, id string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read origin and protocol from request
|
// Read origin and protocol from request
|
||||||
url := "http://"
|
host, proto := getHostAndProtocol(r, handler.config.RespectForwardedHeaders)
|
||||||
if r.TLS != nil {
|
|
||||||
url = "https://"
|
|
||||||
}
|
|
||||||
|
|
||||||
url += r.Host + handler.basePath + id
|
url := proto + "://" + host + handler.basePath + id
|
||||||
|
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getHostAndProtocol extracts the host and used protocol (either HTTP or HTTPS)
|
||||||
|
// from the given request. If `allowForwarded` is set, the X-Forwarded-Host,
|
||||||
|
// X-Forwarded-Proto and Forwarded headers will also be checked to
|
||||||
|
// support proxies.
|
||||||
|
func getHostAndProtocol(r *http.Request, allowForwarded bool) (host, proto string) {
|
||||||
|
if r.TLS != nil {
|
||||||
|
proto = "https"
|
||||||
|
} else {
|
||||||
|
proto = "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
host = r.Host
|
||||||
|
|
||||||
|
if !allowForwarded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if h := r.Header.Get("X-Forwarded-Host"); h != "" {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
|
||||||
|
if h := r.Header.Get("X-Forwarded-Proto"); h == "http" || h == "https" {
|
||||||
|
proto = h
|
||||||
|
}
|
||||||
|
|
||||||
|
if h := r.Header.Get("Forwarded"); h != "" {
|
||||||
|
if r := reForwardedHost.FindStringSubmatch(h); len(r) == 2 {
|
||||||
|
host = r[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if r := reForwardedProto.FindStringSubmatch(h); len(r) == 2 {
|
||||||
|
proto = r[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// The get sum of all sizes for a list of upload ids while checking whether
|
// The get sum of all sizes for a list of upload ids while checking whether
|
||||||
// all of these uploads are finished yet. This is used to calculate the size
|
// all of these uploads are finished yet. This is used to calculate the size
|
||||||
// of a final resource.
|
// of a final resource.
|
||||||
|
|
Loading…
Reference in New Issue