mirror of
https://github.com/willnorris/imageproxy.git
synced 2024-12-16 21:56:43 -05:00
Add MaxRedirects option
Add `MaxRedirects` option to set maximum redirection-followings allowed. The option is only valid when `FollowRedirects` is `true`. Being able to limit the amount of redirections is helpful in order to avoid possible loops of redirections or just too long round trips.
This commit is contained in:
parent
8fd838a5cc
commit
13bafdbf9e
2 changed files with 54 additions and 4 deletions
|
@ -31,6 +31,9 @@ import (
|
|||
tphttp "willnorris.com/go/imageproxy/third_party/http"
|
||||
)
|
||||
|
||||
// Maximum number of redirection-followings allowed.
|
||||
const maxRedirects = 10
|
||||
|
||||
// Proxy serves image requests.
|
||||
type Proxy struct {
|
||||
Client *http.Client // client used to fetch remote URLs
|
||||
|
@ -189,6 +192,12 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
|
|||
if p.FollowRedirects {
|
||||
// FollowRedirects is true (default), ensure that the redirected host is allowed
|
||||
p.Client.CheckRedirect = func(newreq *http.Request, via []*http.Request) error {
|
||||
if len(via) > maxRedirects {
|
||||
if p.Verbose {
|
||||
p.logf("followed too many redirects (%d).", len(via))
|
||||
}
|
||||
return errTooManyRedirects
|
||||
}
|
||||
if hostMatches(p.DenyHosts, newreq.URL) || (len(p.AllowHosts) > 0 && !hostMatches(p.AllowHosts, newreq.URL)) {
|
||||
http.Error(w, msgNotAllowedInRedirect, http.StatusForbidden)
|
||||
return errNotAllowed
|
||||
|
@ -288,6 +297,7 @@ var (
|
|||
errReferrer = errors.New("request does not contain an allowed referrer")
|
||||
errDeniedHost = errors.New("request contains a denied host")
|
||||
errNotAllowed = errors.New("request does not contain an allowed host or valid signature")
|
||||
errTooManyRedirects = errors.New("too many redirects")
|
||||
|
||||
msgNotAllowed = "requested URL is not allowed"
|
||||
msgNotAllowedInRedirect = "requested URL in redirect is not allowed"
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
@ -349,8 +351,18 @@ func (t testTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
|
||||
raw = fmt.Sprintf("HTTP/1.1 200 OK\nContent-Length: %d\nContent-Type: image/png\n\n%s", len(img.Bytes()), img.Bytes())
|
||||
default:
|
||||
redirectRegexp := regexp.MustCompile(`/redirects-(\d+)`)
|
||||
if redirectRegexp.MatchString(req.URL.Path) {
|
||||
redirectsLeft, _ := strconv.ParseUint(redirectRegexp.FindStringSubmatch(req.URL.Path)[1], 10, 8)
|
||||
if redirectsLeft == 0 {
|
||||
raw = "HTTP/1.1 200 OK\n\n"
|
||||
} else {
|
||||
raw = fmt.Sprintf("HTTP/1.1 302\nLocation: /http://redirect.test/redirects-%d\n\n", redirectsLeft-1)
|
||||
}
|
||||
} else {
|
||||
raw = "HTTP/1.1 404 Not Found\n\n"
|
||||
}
|
||||
}
|
||||
|
||||
buf := bufio.NewReader(bytes.NewBufferString(raw))
|
||||
return http.ReadResponse(buf, req)
|
||||
|
@ -414,6 +426,34 @@ func TestProxy_ServeHTTP_is304(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProxy_ServeHTTP_maxRedirects(t *testing.T) {
|
||||
p := &Proxy{
|
||||
Client: &http.Client{
|
||||
Transport: testTransport{},
|
||||
},
|
||||
FollowRedirects: true,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
url string
|
||||
code int
|
||||
}{
|
||||
{"/http://redirect.test/redirects-0", http.StatusOK},
|
||||
{"/http://redirect.test/redirects-2", http.StatusOK},
|
||||
{"/http://redirect.test/redirects-11", http.StatusInternalServerError}, // too many redirects
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
req, _ := http.NewRequest("GET", "http://localhost"+tt.url, nil)
|
||||
resp := httptest.NewRecorder()
|
||||
p.ServeHTTP(resp, req)
|
||||
|
||||
if got, want := resp.Code, tt.code; got != want {
|
||||
t.Errorf("ServeHTTP(%v) returned status %d, want %d", req, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy_log(t *testing.T) {
|
||||
var b strings.Builder
|
||||
|
||||
|
|
Loading…
Reference in a new issue