marky

Lightweight bookmarking + plaintext archive
Log | Files | Refs | README | LICENSE

commit ed33b91b16ef728d05014fb51c6dc44abc2c0652
parent fdaf61bd91edf8b5ac90448203c7ad3b92b9a8c6
Author: David Eisinger <[email protected]>
Date:   Tue,  1 Sep 2026 10:58:21 -0400

Fix issue w/ text/plain

Diffstat:
Minternal/archiver.go | 6++++++
Minternal/archiver_test.go | 18++++++++++++++++++
2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/internal/archiver.go b/internal/archiver.go @@ -64,6 +64,12 @@ func IsHTMLURL(ctx context.Context, rawURL string) bool { return true } defer resp.Body.Close() + // A denial or other error response describes the error document, not the + // resource. Treat it as inconclusive so the archive path can still try its + // renderer fallback (for example, w3m may be allowed by the origin). + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { + return true + } ct := strings.ToLower(resp.Header.Get("Content-Type")) if ct == "" { return true diff --git a/internal/archiver_test.go b/internal/archiver_test.go @@ -29,6 +29,24 @@ func TestTitleAndText(t *testing.T) { } } +func TestIsHTMLURL_ErrorHEADResponseIsInconclusive(t *testing.T) { + t.Parallel() + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodHead { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusForbidden) + return + } + t.Fatalf("unexpected %s request", r.Method) + })) + defer srv.Close() + + if !IsHTMLURL(t.Context(), srv.URL) { + t.Fatal("expected a failed HEAD request to be treated as inconclusive") + } +} + func containsFold(s, sub string) bool { return len(s) >= len(sub) && (stringFold(s, sub) || containsFold(s[1:], sub)) }