etag

package
v0.91.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package etag provides ETag generation and validation middleware.

ETags enable HTTP conditional requests, allowing clients to cache responses and avoid re-downloading unchanged content.

Usage

import "github.com/alexferl/zerohttp/middleware/etag"

// Use defaults (MD5-based ETags)
app.Use(etag.New())

// Custom configuration
app.Use(etag.New(etag.Config{
    Weak: true, // Use weak ETags (prefixed with W/)
}))

The middleware automatically handles If-None-Match and If-Match headers, returning 304 Not Modified when content hasn't changed.

Index

Constants

This section is empty.

Variables

View Source
var DefaultConfig = Config{
	Algorithm:     FNV,
	Weak:          config.Bool(false),
	MaxBufferSize: 1024 * 1024,
	SkipStatusCodes: map[int]struct{}{
		http.StatusNoContent:           {},
		http.StatusPartialContent:      {},
		http.StatusMovedPermanently:    {},
		http.StatusFound:               {},
		http.StatusNotModified:         {},
		http.StatusTemporaryRedirect:   {},
		http.StatusPermanentRedirect:   {},
		http.StatusBadRequest:          {},
		http.StatusUnauthorized:        {},
		http.StatusForbidden:           {},
		http.StatusNotFound:            {},
		http.StatusMethodNotAllowed:    {},
		http.StatusInternalServerError: {},
		http.StatusBadGateway:          {},
		http.StatusServiceUnavailable:  {},
	},
	SkipContentTypes: map[string]struct{}{
		httpx.MIMETextEventStream: {},
	},
	ExcludedPaths: []string{},
	IncludedPaths: []string{},
	ExcludedFunc:  nil,
}

DefaultConfig contains the default values for ETag configuration

Functions

func GenerateFromFile

func GenerateFromFile(modTime int64, size int64, weak bool) string

GenerateFromFile generates an etag for a file based on its modification time and size. This is much more efficient than hashing the file content, especially for large files. The format is: W/"mtime-size" (weak etag) or "mtime-size" (strong etag) Example: W/"1709999999-1024"

Usage:

file, _ := os.Open("largefile.zip")
stat, _ := file.Stat()
etag := etag.GenerateFromFile(stat.ModTime().Unix(), stat.Size(), true) // weak ETag
w.Header().Set(httpx.HeaderETag, etag)

func GenerateFromFileInfo

func GenerateFromFileInfo(info interface {
	ModTime() time.Time
	Size() int64
}, weak bool,
) string

GenerateFromFileInfo generates an etag from fs.FileInfo or os.FileInfo. This helper handles both interface types properly.

Usage:

file, _ := os.Open("largefile.zip")
stat, _ := file.Stat()
etag := etag.GenerateFromFileInfo(stat, true)
w.Header().Set(httpx.HeaderETag, etag)

func Matches

func Matches(ifNoneMatch, etag string) bool

Matches checks if the provided etag matches any in the If-None-Match header

func New

func New(cfg ...Config) func(http.Handler) http.Handler

New creates an ETag middleware with the provided configuration

func Parse

func Parse(etag string) (string, bool)

Parse extracts the hash value from an etag, handling weak ETags Returns the hash value and a boolean indicating if it was a weak etag Example: Parse(`W/"abc123"`) returns ("abc123", true) Example: Parse(`"abc123"`) returns ("abc123", false)

func ServeContentWithETag

func ServeContentWithETag(w http.ResponseWriter, r *http.Request, modTime int64, content io.ReadSeeker)

ServeContentWithETag serves content with automatic etag support. It handles If-None-Match and If-Range headers properly. Similar to http.ServeContent but with our etag generation logic.

Types

type Algorithm

type Algorithm string

Algorithm defines the hashing algorithm for ETag generation

const (
	// FNV uses FNV-1a 64-bit hash (fast, good for most use cases)
	FNV Algorithm = "fnv"
	// MD5 uses MD5 hash (slower, more collision-resistant)
	MD5 Algorithm = "md5"
)

type Config

type Config struct {
	// Algorithm selects the hashing function.
	// Default: FNV
	Algorithm Algorithm

	// Weak determines if ETags should be prefixed with "W/".
	// Use a pointer to distinguish between "not set" and "explicitly set to false".
	// Default: false
	Weak *bool

	// MaxBufferSize is the maximum response body size to buffer for ETag generation.
	// Default: 1MB
	MaxBufferSize int64

	// SkipStatusCodes contains status codes that should not have ETags generated.
	// Default: error status codes (4xx, 5xx, redirects)
	SkipStatusCodes map[int]struct{}

	// SkipContentTypes contains content types that should not have ETags generated.
	// Default: [text/event-stream]
	SkipContentTypes map[string]struct{}

	// ExcludedPaths contains paths to skip ETag generation.
	// Supports exact matches, prefixes (ending with /), and wildcards (ending with *).
	// Cannot be used with IncludedPaths - setting both will panic.
	// Default: []
	ExcludedPaths []string

	// IncludedPaths contains paths where ETag generation is explicitly applied.
	// If set, ETag will only be generated for paths matching these patterns.
	// Supports exact matches, prefixes (ending with /), and wildcards (ending with *).
	// If empty, ETag applies to all paths (subject to ExcludedPaths).
	// Cannot be used with ExcludedPaths - setting both will panic.
	// Default: []
	IncludedPaths []string

	// ExcludedFunc is a custom function to determine if ETag generation should be skipped for a request
	ExcludedFunc func(r *http.Request) bool
}

Config allows customization of ETag middleware behavior

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL