From dd2b8f600d27e58a3e44d0bb85ee9487dc932e4c Mon Sep 17 00:00:00 2001 From: yusing Date: Tue, 21 Jan 2025 06:48:56 +0800 Subject: [PATCH] api: allow favicon endpoint to use url instead of alias --- internal/api/handler.go | 2 +- internal/api/v1/favicon/favicon.go | 81 ++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/internal/api/handler.go b/internal/api/handler.go index 09431e4a..32c54a1f 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -33,7 +33,7 @@ func NewHandler(cfg config.ConfigInstance) http.Handler { mux.HandleFunc("GET", "/v1/stats/ws", useCfg(cfg, v1.StatsWS)) mux.HandleFunc("GET", "/v1/health/ws", auth.RequireAuth(useCfg(cfg, v1.HealthWS))) mux.HandleFunc("GET", "/v1/logs/ws", auth.RequireAuth(useCfg(cfg, v1.LogsWS()))) - mux.HandleFunc("GET", "/v1/favicon/{alias}", auth.RequireAuth(favicon.GetFavIcon)) + mux.HandleFunc("GET", "/v1/favicon", auth.RequireAuth(favicon.GetFavIcon)) mux.HandleFunc("POST", "/v1/homepage/set", auth.RequireAuth(v1.SetHomePageOverrides)) defaultAuth := auth.GetDefaultAuth() diff --git a/internal/api/v1/favicon/favicon.go b/internal/api/v1/favicon/favicon.go index f2f50412..d44d8941 100644 --- a/internal/api/v1/favicon/favicon.go +++ b/internal/api/v1/favicon/favicon.go @@ -65,44 +65,71 @@ func (c *content) Hijack() (net.Conn, *bufio.ReadWriter, error) { // - 500 Internal Server Error: if internal error // - others: depends on route handler response func GetFavIcon(w http.ResponseWriter, req *http.Request) { - alias := req.PathValue("alias") - if alias == "" { - U.RespondError(w, U.ErrMissingKey("alias"), http.StatusBadRequest) + url, alias := req.FormValue("url"), req.FormValue("alias") + if url == "" && alias == "" { + U.RespondError(w, U.ErrMissingKey("url or alias"), http.StatusBadRequest) return } - r, ok := routes.GetHTTPRoutes().Load(alias) - if !ok { - http.NotFound(w, req) + if url != "" && alias != "" { + U.RespondError(w, U.ErrInvalidKey("url and alias are mutually exclusive"), http.StatusBadRequest) return } - switch r := r.(type) { - case route.HTTPRoute: - var icon []byte - var status int - var errMsg string - hp := r.RawEntry().Homepage.GetOverride() - if !hp.IsEmpty() && hp.Icon != nil { - switch hp.Icon.IconSource { - case homepage.IconSourceAbsolute: - icon, status, errMsg = fetchIconAbsolute(hp.Icon.Value) - case homepage.IconSourceRelative: - icon, status, errMsg = findIcon(r, req, hp.Icon.Value) - case homepage.IconSourceWalkXCode, homepage.IconSourceSelfhSt: - icon, status, errMsg = fetchKnownIcon(hp.Icon) - } - } else { - // try extract from "link[rel=icon]" - icon, status, errMsg = findIcon(r, req, "/") + // try with url + if url != "" { + var iconURL homepage.IconURL + if err := iconURL.Parse(url); err != nil { + U.RespondError(w, err, http.StatusBadRequest) + return } - if status != http.StatusOK { + icon, status, errMsg := getFavIconFromURL(&iconURL) + if icon == nil { http.Error(w, errMsg, status) return } U.WriteBody(w, icon) - default: - http.Error(w, "bad request", http.StatusBadRequest) + return } + + // try with route.Homepage.Icon + r, ok := routes.GetHTTPRoute(alias) + if !ok { + U.RespondError(w, errors.New("no such route"), http.StatusNotFound) + return + } + var icon []byte + var status int + var errMsg string + + hp := r.RawEntry().Homepage.GetOverride() + if !hp.IsEmpty() && hp.Icon != nil { + switch hp.Icon.IconSource { + case homepage.IconSourceRelative: + icon, status, errMsg = findIcon(r, req, hp.Icon.Value) + default: + icon, status, errMsg = getFavIconFromURL(hp.Icon) + } + } else { + // try extract from "link[rel=icon]" + icon, status, errMsg = findIcon(r, req, "/") + } + if status != http.StatusOK { + http.Error(w, errMsg, status) + return + } + U.WriteBody(w, icon) +} + +func getFavIconFromURL(iconURL *homepage.IconURL) ([]byte, int, string) { + switch iconURL.IconSource { + case homepage.IconSourceAbsolute: + return fetchIconAbsolute(iconURL.URL()) + case homepage.IconSourceRelative: + return nil, http.StatusBadRequest, "unexpected relative icon" + case homepage.IconSourceWalkXCode, homepage.IconSourceSelfhSt: + return fetchKnownIcon(iconURL) + } + return nil, http.StatusBadRequest, "invalid icon source" } // cache key can be absolute url or route name.