github.com/gofiber/fiber/v2@v2.47.0/middleware/favicon/favicon.go (about)

     1  package favicon
     2  
     3  import (
     4  	"io"
     5  	"net/http"
     6  	"os"
     7  	"strconv"
     8  
     9  	"github.com/gofiber/fiber/v2"
    10  )
    11  
    12  // Config defines the config for middleware.
    13  type Config struct {
    14  	// Next defines a function to skip this middleware when returned true.
    15  	//
    16  	// Optional. Default: nil
    17  	Next func(c *fiber.Ctx) bool
    18  
    19  	// File holds the path to an actual favicon that will be cached
    20  	//
    21  	// Optional. Default: ""
    22  	File string `json:"file"`
    23  
    24  	// URL for favicon handler
    25  	//
    26  	// Optional. Default: "/favicon.ico"
    27  	URL string `json:"url"`
    28  
    29  	// FileSystem is an optional alternate filesystem to search for the favicon in.
    30  	// An example of this could be an embedded or network filesystem
    31  	//
    32  	// Optional. Default: nil
    33  	FileSystem http.FileSystem `json:"-"`
    34  
    35  	// CacheControl defines how the Cache-Control header in the response should be set
    36  	//
    37  	// Optional. Default: "public, max-age=31536000"
    38  	CacheControl string `json:"cache_control"`
    39  }
    40  
    41  // ConfigDefault is the default config
    42  var ConfigDefault = Config{
    43  	Next:         nil,
    44  	File:         "",
    45  	URL:          fPath,
    46  	CacheControl: "public, max-age=31536000",
    47  }
    48  
    49  const (
    50  	fPath  = "/favicon.ico"
    51  	hType  = "image/x-icon"
    52  	hAllow = "GET, HEAD, OPTIONS"
    53  	hZero  = "0"
    54  )
    55  
    56  // New creates a new middleware handler
    57  func New(config ...Config) fiber.Handler {
    58  	// Set default config
    59  	cfg := ConfigDefault
    60  
    61  	// Override config if provided
    62  	if len(config) > 0 {
    63  		cfg = config[0]
    64  
    65  		// Set default values
    66  		if cfg.Next == nil {
    67  			cfg.Next = ConfigDefault.Next
    68  		}
    69  		if cfg.URL == "" {
    70  			cfg.URL = ConfigDefault.URL
    71  		}
    72  		if cfg.File == "" {
    73  			cfg.File = ConfigDefault.File
    74  		}
    75  		if cfg.CacheControl == "" {
    76  			cfg.CacheControl = ConfigDefault.CacheControl
    77  		}
    78  	}
    79  
    80  	// Load icon if provided
    81  	var (
    82  		err     error
    83  		icon    []byte
    84  		iconLen string
    85  	)
    86  	if cfg.File != "" {
    87  		// read from configured filesystem if present
    88  		if cfg.FileSystem != nil {
    89  			f, err := cfg.FileSystem.Open(cfg.File)
    90  			if err != nil {
    91  				panic(err)
    92  			}
    93  			if icon, err = io.ReadAll(f); err != nil {
    94  				panic(err)
    95  			}
    96  		} else if icon, err = os.ReadFile(cfg.File); err != nil {
    97  			panic(err)
    98  		}
    99  
   100  		iconLen = strconv.Itoa(len(icon))
   101  	}
   102  
   103  	// Return new handler
   104  	return func(c *fiber.Ctx) error {
   105  		// Don't execute middleware if Next returns true
   106  		if cfg.Next != nil && cfg.Next(c) {
   107  			return c.Next()
   108  		}
   109  
   110  		// Only respond to favicon requests
   111  		if c.Path() != cfg.URL {
   112  			return c.Next()
   113  		}
   114  
   115  		// Only allow GET, HEAD and OPTIONS requests
   116  		if c.Method() != fiber.MethodGet && c.Method() != fiber.MethodHead {
   117  			if c.Method() != fiber.MethodOptions {
   118  				c.Status(fiber.StatusMethodNotAllowed)
   119  			} else {
   120  				c.Status(fiber.StatusOK)
   121  			}
   122  			c.Set(fiber.HeaderAllow, hAllow)
   123  			c.Set(fiber.HeaderContentLength, hZero)
   124  			return nil
   125  		}
   126  
   127  		// Serve cached favicon
   128  		if len(icon) > 0 {
   129  			c.Set(fiber.HeaderContentLength, iconLen)
   130  			c.Set(fiber.HeaderContentType, hType)
   131  			c.Set(fiber.HeaderCacheControl, cfg.CacheControl)
   132  			return c.Status(fiber.StatusOK).Send(icon)
   133  		}
   134  
   135  		return c.SendStatus(fiber.StatusNoContent)
   136  	}
   137  }