Refuse an image URL whose source path or query holds a # (closes #286)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
A # written as %23 in the source path or query reached the parser decoded and stayed in the source URL, where Go reads it as the start of a fragment and drops it before fetching. So each text after the # was another unsigned spelling of one upstream request, cached under its own keys. An image URL whose decoded source path or query holds a # is now refused with 400, signed or not, and README.md's rule for writing a source path and query says a # cannot be part of either. Model: opus-5-5
This commit was merged in pull request #287.
This commit is contained in:
@@ -340,3 +340,51 @@ func TestHandleImage_HostForms_Served(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleImage_HashInSourcePathOrQuery_Returns400 sends image URLs whose
|
||||
// source path or source query holds a "#", written as %23, and checks that
|
||||
// each is refused with 400, the one signed for that source path included. The
|
||||
// source URL would otherwise end at the "#" when it is fetched, so each text
|
||||
// after it would fetch the image at photoPath and cache it under keys of its
|
||||
// own.
|
||||
func TestHandleImage_HashInSourcePathOrQuery_Returns400(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
photos := newPhotoFetcher(t, allowlistedHost, signedHost)
|
||||
exp := time.Now().Add(time.Hour)
|
||||
|
||||
sig := signature.New(testSigningKey).Sign(&signature.Request{
|
||||
SourceHost: signedHost,
|
||||
SourcePath: photoPath + "#x",
|
||||
Width: 50,
|
||||
Height: 50,
|
||||
Format: string(imgcache.FormatJPEG),
|
||||
Quality: 85,
|
||||
FitMode: string(imgcache.FitCover),
|
||||
Expires: exp,
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
target string
|
||||
}{
|
||||
{"# in the source path",
|
||||
"/v1/image/" + allowlistedHost + photoPath + "%23x/50x50.jpeg"},
|
||||
{"# in the source query",
|
||||
"/v1/image/" + allowlistedHost + photoPath + "%3Fv=1%23x/50x50.jpeg"},
|
||||
{"# in the source path, signed",
|
||||
fmt.Sprintf("/v1/image/%s%s%%23x/50x50.jpeg?sig=%s&exp=%d",
|
||||
signedHost, photoPath, sig, exp.Unix())},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec := sendGet(t, newImageRoute(t, photos), tt.target)
|
||||
checkErrorBody(t, rec, http.StatusBadRequest,
|
||||
`invalid image URL: invalid image path: `+
|
||||
`the source path or query holds a "#"`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user