Enhance favicon handling with content type detection

- Added a new variable to store the content type for the favicon.
- Updated the favicon loading mechanism to determine the content type based on the file extension.
- Adjusted the default fallback to use an embedded favicon.ico instead of orly.png.
- Modified the favicon handler to set the appropriate content type when serving the favicon.
This commit is contained in:
2025-10-10 10:19:49 +01:00
parent 81fbc9b2a4
commit 456a0ce108

32
main.go
View File

@@ -41,6 +41,9 @@ var orlyFavicon []byte
// faviconData holds the favicon data to serve
var faviconData []byte
// faviconContentType holds the content type for the favicon
var faviconContentType string
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
@@ -60,7 +63,7 @@ type C struct {
WTo time.Duration `env:"REVERSE_WTO" usage:"maximum duration before timing out write of the response" default:"5m"`
Idle time.Duration `env:"REVERSE_IDLE" usage:"how long idle connection is kept before closing (set rto, wto to 0 to use this)"`
Certs []string `env:"REVERSE_CERTS" usage:"certificates and the domain they match: eg: mleku.dev:/path/to/cert - this will indicate to load two, one with extension .key and one with .crt, each expected to be PEM encoded TLS private and public keys, respectively"`
Favicon string `env:"REVERSE_FAVICON" usage:"path to custom favicon file to serve as favicon.ico (overrides default orly.png)"`
Favicon string `env:"REVERSE_FAVICON" usage:"path to custom favicon file to serve as favicon.ico (overrides default favicon.ico)"`
}
// GetEnv checks if the first command line argument is "env" and returns
@@ -855,8 +858,9 @@ func NostrDNS(hn, ba string, mux *http.ServeMux) (err error) {
// loadFavicon loads the favicon data from the configured file or uses the default
func loadFavicon(faviconPath string) error {
if faviconPath == "" {
// Use default orly.png
faviconData = orlyFavicon
// Use default embedded favicon.ico
faviconData = defaultFavicon
faviconContentType = "image/x-icon"
return nil
}
@@ -870,18 +874,36 @@ func loadFavicon(faviconPath string) error {
}
faviconData = data
// Determine content type based on file extension
ext := strings.ToLower(filepath.Ext(faviconPath))
switch ext {
case ".ico":
faviconContentType = "image/x-icon"
case ".png":
faviconContentType = "image/png"
case ".gif":
faviconContentType = "image/gif"
case ".jpg", ".jpeg":
faviconContentType = "image/jpeg"
case ".svg":
faviconContentType = "image/svg+xml"
default:
faviconContentType = "image/x-icon" // default fallback
}
log.I.Ln("loaded custom favicon from", faviconPath)
return nil
}
// addFaviconHandler adds a favicon handler for the given hostname that serves
// the configured favicon as favicon.ico
// the configured favicon (default favicon.ico or custom file) as favicon.ico
func addFaviconHandler(hostname string, mux *http.ServeMux) {
mux.HandleFunc(
hostname+"/favicon.ico",
func(w http.ResponseWriter, r *http.Request) {
log.I.Ln("serving favicon for", hostname)
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Content-Type", faviconContentType)
w.Header().Set("Content-Length", fmt.Sprint(len(faviconData)))
w.Header().Set("Cache-Control", "public, max-age=31536000") // 1 year cache
if _, err := w.Write(faviconData); err != nil {