Redirect / to the main page instead of serving it in place
The served main page broke its own CSS and images when the entry point was a nested page. kage saves each page's asset links as mirror-relative paths (../_kage/...) computed for that page's own location, but the handler served the main page's bytes directly at /, so the browser resolved those relative URLs against / and 404ed every one of them. A developer.apple.com/documentation mirror landed at / with no styles. Redirect / to the main page's canonical content path, the way the archive's W/mainPage redirect already does, so the browser navigates to the page's real URL and resolves its relative assets correctly. Kiwix was unaffected because it follows that redirect itself.
This commit is contained in:
@@ -326,6 +326,24 @@ func TestHandler(t *testing.T) {
|
||||
if code, body := get("/"); code != 200 || !bytes.Contains([]byte(body), []byte("Example Home")) {
|
||||
t.Errorf("GET / = %d %.30q", code, body)
|
||||
}
|
||||
|
||||
// "/" must redirect to the main page's canonical content path, not serve its
|
||||
// bytes in place, so the page's mirror-relative asset URLs resolve against the
|
||||
// right base instead of 404ing.
|
||||
noFollow := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
}}
|
||||
resp, err := noFollow.Get(srv.URL + "/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
t.Errorf("GET / status = %d, want 302", resp.StatusCode)
|
||||
}
|
||||
if loc := resp.Header.Get("Location"); loc != "/index.html" {
|
||||
t.Errorf("GET / Location = %q, want %q", loc, "/index.html")
|
||||
}
|
||||
if code, _ := get("/about/index.html"); code != 200 {
|
||||
t.Errorf("GET /about/index.html = %d", code)
|
||||
}
|
||||
|
||||
+13
-3
@@ -8,14 +8,24 @@ import (
|
||||
"github.com/tamnd/kage/zim"
|
||||
)
|
||||
|
||||
// Handler serves a ZIM archive over HTTP. "/" maps to the archive's main page;
|
||||
// "/a/b.png" maps to the C/a/b.png content entry. Because the saved HTML's links
|
||||
// are mirror-relative paths, and those are exactly the C urls, a click in a
|
||||
// Handler serves a ZIM archive over HTTP. "/" redirects to the archive's main
|
||||
// page; "/a/b.png" maps to the C/a/b.png content entry. Because the saved HTML's
|
||||
// links are mirror-relative paths, and those are exactly the C urls, a click in a
|
||||
// served page hits the right entry with no rewriting. A miss is a plain 404.
|
||||
func Handler(r *zim.Reader) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
p := strings.TrimPrefix(req.URL.Path, "/")
|
||||
if p == "" {
|
||||
// The main page's saved HTML carries mirror-relative asset URLs
|
||||
// (../_kage/...) computed for its own nested location, so serving its
|
||||
// bytes at "/" would resolve them against the wrong base and 404 the
|
||||
// page's CSS and images. Redirect to the page's canonical content path
|
||||
// instead, the way the archive's W/mainPage redirect does, so the
|
||||
// browser resolves those relative URLs correctly.
|
||||
if ns, url, ok := r.MainPageRef(); ok && ns == zim.NamespaceContent {
|
||||
http.Redirect(w, req, "/"+url, http.StatusFound)
|
||||
return
|
||||
}
|
||||
blob, err := r.MainPage()
|
||||
if err != nil {
|
||||
http.NotFound(w, req)
|
||||
|
||||
Reference in New Issue
Block a user