Merge PR #1495 latest head: infer extension for opaque URLs

This commit is contained in:
Levi committed 2026-09-10 00:26:00 +08:00
commit 22db46c68a
3 files changed
+48

No files matched your search

+1
View File
@@ -459,6 +459,7 @@ func (f *Fetcher) Resolve(req *base.Request, opts *base.Options) error {
if file.Name == "" || file.Name == "/" || file.Name == "." {
file.Name = httpReq.URL.Hostname()
}
file.Name = appendFilenameExtension(file.Name, resp.Header.Get("Content-Type"))
res.Files = append(res.Files, file)
f.meta.Res = res
+24
View File
@@ -221,6 +221,30 @@ func TestFetcher_Resolve(t *testing.T) {
})
}
func TestFetcher_ResolveFilenameFromContentType(t *testing.T) {
server := httptest.NewServer(gohttp.HandlerFunc(func(w gohttp.ResponseWriter, r *gohttp.Request) {
w.Header().Set("Content-Type", "image/webp")
w.WriteHeader(gohttp.StatusOK)
}))
defer server.Close()
fetcher := buildFetcher()
defer fetcher.Pause()
const opaqueName = "OIP-C.u5nEXTXND3PJF0gNTgw5YgHaFP"
err := fetcher.Resolve(&base.Request{URL: server.URL + "/" + opaqueName}, &base.Options{
Name: test.DownloadName,
Path: test.Dir,
})
if err != nil {
t.Fatal(err)
}
if got := fetcher.meta.Res.Files[0].Name; got != opaqueName+".webp" {
t.Fatalf("resolved filename = %q, want %q", got, opaqueName+".webp")
}
}
func TestFetcher_ResolveWithHostHeader(t *testing.T) {
listener := test.StartTestHostHeaderServer()
defer listener.Close()
+23
View File
@@ -12,6 +12,7 @@ import (
"net/http"
"net/http/cookiejar"
"net/url"
"path"
"strings"
"time"
"unicode/utf8"
@@ -314,6 +315,28 @@ func parseFilename(contentDisposition string) string {
return parseFilenameFallback(contentDisposition)
}
// appendFilenameExtension adds a MIME-derived extension when the resolved
// filename has no usable extension. Some image hosts use opaque path segments
// that look like extensions, even though the response Content-Type is the
// only reliable source for the file type.
func appendFilenameExtension(filename, contentType string) string {
mediaType, _, err := mime.ParseMediaType(contentType)
if err != nil {
return filename
}
extensions, err := mime.ExtensionsByType(mediaType)
if err != nil || len(extensions) == 0 {
return filename
}
ext := path.Ext(filename)
if len(ext) > 1 && len(ext) <= 20 {
return filename
}
return filename + extensions[0]
}
// parseFilenameExtended handles RFC 5987 extended notation (filename*=)
// Format: filename*=charset'language'value (e.g., UTF-8”%E6%B5%8B%E8%AF%95.zip)
func parseFilenameExtended(cd string) string {