### Install httpheader Package Source: https://github.com/vfaronov/httpheader/blob/master/README.md Use 'go get' to install the httpheader package for your Go project. ```bash go get github.com/vfaronov/httpheader ``` -------------------------------- ### Install go-fuzz Source: https://github.com/vfaronov/httpheader/blob/master/fuzz/README.md Installs the go-fuzz and go-fuzz-build tools. Ensure you are using a GNU userland for these commands to work as expected. ```bash go get -u github.com/dvyukov/go-fuzz/go-fuzz{,-build} ``` -------------------------------- ### Parse and Generate User-Agent and Server Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Shows how to parse User-Agent and Server headers to extract software product information, including name, version, and comments. It also demonstrates generating these headers. ```go package main import ( "bufio" "fmt" "net/http" "strings" "github.com/vfaronov/httpheader" ) func main() { const request = `GET / HTTP/1.1 Host: example.com User-Agent: MyApp/1.2.3 python-requests/2.22.0 (Linux x86_64) ` r, _ := http.ReadRequest(bufio.NewReader(strings.NewReader(request))) // Parse User-Agent - returns []Product with Name, Version, Comment products := httpheader.UserAgent(r.Header) for _, product := range products { fmt.Printf("Name: %s, Version: %s, Comment: %s\n", product.Name, product.Version, product.Comment) // Version-based compatibility handling if product.Name == "MyApp" && product.Version < "2.0" { fmt.Println("Enabling compatibility mode for old MyApp version") } } // Generate User-Agent header h := make(http.Header) httpheader.SetUserAgent(h, []httpheader.Product{ {Name: "MyService", Version: "3.0.1"}, {Name: "Go-http-client", Version: "1.1", Comment: "Linux"}, }) fmt.Println("Generated:", h.Get("User-Agent")) // Server header works the same way httpheader.SetServer(h, []httpheader.Product{ {Name: "nginx", Version: "1.19.0"}, }) fmt.Println("Server:", h.Get("Server")) // Output: // Name: MyApp, Version: 1.2.3, Comment: // Enabling compatibility mode for old MyApp version // Name: python-requests, Version: 2.22.0, Comment: Linux x86_64 // Generated: MyService/3.0.1 Go-http-client/1.1 (Linux) // Server: nginx/1.19.0 } ``` -------------------------------- ### Parse and Generate Accept Header Source: https://context7.com/vfaronov/httpheader/llms.txt Demonstrates parsing an Accept header to determine client media type preferences with quality values and using MatchAccept for content negotiation. Also shows how to generate an Accept header. ```go package main import ( "bufio" "fmt" "net/http" "strings" "github.com/vfaronov/httpheader" ) func main() { const request = `GET / HTTP/1.1 Host: api.example.com Accept: text/*, application/json;q=0.8, text/html;q=0.9 ` r, _ := http.ReadRequest(bufio.NewReader(strings.NewReader(request))) // Parse Accept header - returns []AcceptElem with Type, Q, Params, Ext accept := httpheader.Accept(r.Header) for _, elem := range accept { fmt.Printf("Type: %s, Q: %.1f\n", elem.Type, elem.Q) } // Content negotiation - find best match for your content type acceptJSON := httpheader.MatchAccept(accept, "application/json") acceptXML := httpheader.MatchAccept(accept, "text/xml") acceptHTML := httpheader.MatchAccept(accept, "text/html") fmt.Printf("JSON q=%.1f, XML q=%.1f, HTML q=%.1f\n", acceptJSON.Q, acceptXML.Q, acceptHTML.Q) if acceptXML.Q > acceptJSON.Q { fmt.Println("Client prefers XML over JSON") } // Generate Accept header h := make(http.Header) httpheader.SetAccept(h, []httpheader.AcceptElem{ {Type: "application/json", Q: 1.0}, {Type: "text/html", Q: 0.9}, {Type: "*/*", Q: 0.1}, }) fmt.Println("Generated:", h.Get("Accept")) // Output: // Type: text/*, Q: 1.0 // Type: application/json, Q: 0.8 // Type: text/html, Q: 0.9 // JSON q=0.8, XML q=1.0, HTML q=0.9 // Client prefers XML over JSON // Generated: application/json, text/html;q=0.9, */*;q=0.1 } ``` -------------------------------- ### Handle ETag and Conditional Headers in Go Source: https://context7.com/vfaronov/httpheader/llms.txt Shows how to set ETags and perform strong or weak comparisons for conditional requests like If-Match and If-None-Match. ```go package main import ( "fmt" "net/http" "github.com/vfaronov/httpheader" ) func main() { // Set ETag on response respHeader := make(http.Header) httpheader.SetETag(respHeader, httpheader.EntityTag{ Opaque: "abc123", Weak: false, }) fmt.Println("ETag:", respHeader.Get("Etag")) // Weak ETag httpheader.SetETag(respHeader, httpheader.EntityTag{ Opaque: "xyz789", Weak: true, }) fmt.Println("Weak ETag:", respHeader.Get("Etag")) // Parse If-Match header reqHeader := make(http.Header) reqHeader.Set("If-Match", `"abc123", "def456"`) clientTags := httpheader.IfMatch(reqHeader) serverTag := httpheader.EntityTag{Opaque: "abc123"} // Strong comparison (for If-Match) if httpheader.Match(clientTags, serverTag) { fmt.Println("ETag matches - proceed with update") } // Parse If-None-Match header reqHeader.Set("If-None-Match", `W/"abc123", "def456"`) noneMatchTags := httpheader.IfNoneMatch(reqHeader) // Weak comparison (for If-None-Match / caching) if httpheader.MatchWeak(noneMatchTags, serverTag) { fmt.Println("Resource not modified - return 304") } // Handle wildcard If-Match: * reqHeader.Set("If-Match", "*") wildcardTags := httpheader.IfMatch(reqHeader) if wildcardTags[0] == httpheader.AnyTag { fmt.Println("Wildcard - matches any existing resource") } // Match() handles wildcard automatically if httpheader.Match(wildcardTags, serverTag) { fmt.Println("Wildcard matches any tag") } // Output: // ETag: "abc123" // Weak ETag: W/"xyz789" // ETag matches - proceed with update // Resource not modified - return 304 // Wildcard - matches any existing resource // Wildcard matches any tag } ``` -------------------------------- ### Parse and Generate Content-Type Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Shows how to parse the Content-Type header to extract media type and parameters like charset. Also demonstrates generating a Content-Type header with specified parameters. ```go package main import ( "fmt" "net/http" "github.com/vfaronov/httpheader" ) func main() { // Parse Content-Type h := make(http.Header) h.Set("Content-Type", "text/html; charset=utf-8; boundary=something") mtype, params := httpheader.ContentType(h) fmt.Println("Media Type:", mtype) fmt.Println("Charset:", params["charset"]) // Generate Content-Type respHeader := make(http.Header) httpheader.SetContentType(respHeader, "application/json", map[string]string{ "charset": "utf-8", }) fmt.Println("Generated CT:", respHeader.Get("Content-Type")) // Parse Content-Disposition h2 := make(http.Header) h2.Set("Content-Disposition", `attachment; filename="report.pdf"; filename*=UTF-8''report%20%E2%9C%93.pdf`) dtype, filename, params2 := httpheader.ContentDisposition(h2) fmt.Println("Disposition:", dtype) fmt.Println("Filename:", filename) // filename* overrides filename // Generate Content-Disposition for file download // Handles Unicode filenames automatically with RFC 8187 encoding downloadHeader := make(http.Header) httpheader.SetContentDisposition(downloadHeader, "attachment", "report.pdf", nil) fmt.Println("Download:", downloadHeader.Get("Content-Disposition")) // Unicode filename - automatically encoded properly httpheader.SetContentDisposition(downloadHeader, "attachment", "report.pdf", nil) fmt.Println("Unicode:", downloadHeader.Get("Content-Disposition")) _ = params2 // Additional params available if needed // Output: // Media Type: text/html // Charset: utf-8 // Generated CT: application/json; charset=utf-8 // Disposition: attachment // Filename: report // Download: attachment; filename=report.pdf } ``` -------------------------------- ### Manage Authentication Headers in Go Source: https://context7.com/vfaronov/httpheader/llms.txt Demonstrates parsing and generating WWW-Authenticate and Authorization headers, including support for Basic, Bearer, and Digest schemes. ```go package main import ( "encoding/base64" "fmt" "net/http" "github.com/vfaronov/httpheader" ) func main() { // Parse WWW-Authenticate challenges h := make(http.Header) h.Set("WWW-Authenticate", `Bearer realm="api", error="invalid_token", Basic realm="Admin Area"`) challenges := httpheader.WWWAuthenticate(h) for _, auth := range challenges { fmt.Printf("Scheme: %s, Realm: %s\n", auth.Scheme, auth.Realm) if auth.Params != nil { fmt.Printf(" Params: %v\n", auth.Params) } } // Generate WWW-Authenticate respHeader := make(http.Header) httpheader.SetWWWAuthenticate(respHeader, []httpheader.Auth{ {Scheme: "bearer", Realm: "api", Params: map[string]string{"error": "invalid_token"}}, {Scheme: "basic", Realm: "Admin"}, }) fmt.Println("WWW-Auth:", respHeader.Get("Www-Authenticate")) // Parse Authorization header reqHeader := make(http.Header) credentials := base64.StdEncoding.EncodeToString([]byte("user:pass")) reqHeader.Set("Authorization", "Basic "+credentials) auth := httpheader.Authorization(reqHeader) fmt.Printf("Auth Scheme: %s, Token: %s\n", auth.Scheme, auth.Token) // Generate Authorization header clientHeader := make(http.Header) httpheader.SetAuthorization(clientHeader, httpheader.Auth{ Scheme: "bearer", Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", }) fmt.Println("Auth:", clientHeader.Get("Authorization")) // Digest authentication with params httpheader.SetAuthorization(clientHeader, httpheader.Auth{ Scheme: "digest", Realm: "api@example.com", Params: map[string]string{ "username": "admin", "nonce": "abc123", "response": "def456", "uri": "/resource", }, }) fmt.Println("Digest:", clientHeader.Get("Authorization")) // Output: // Scheme: bearer, Realm: api // Params: map[error:invalid_token] // Scheme: basic, Realm: Admin Area // WWW-Auth: Bearer realm="api", error=invalid_token, Basic realm="Admin" // Auth Scheme: basic, Token: dXNlcjpwYXNz // Auth: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... } ``` -------------------------------- ### Parse and Generate Via Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Manage Via headers to track message chains through proxies. ```go package main import ( "fmt" "net/http" "github.com/vfaronov/httpheader" ) func main() { h := make(http.Header) h.Set("Via", "1.1 proxy1.example.com, 1.0 proxy2.example.com (Apache)") // Parse Via header - returns []ViaElem via := httpheader.Via(h) for _, elem := range via { fmt.Printf("Proto: %s, By: %s, Comment: %s\n", elem.ReceivedProto, elem.ReceivedBy, elem.Comment) } // Generate Via header respHeader := make(http.Header) httpheader.SetVia(respHeader, []httpheader.ViaElem{ {ReceivedProto: "HTTP/1.1", ReceivedBy: "gateway.example.com"}, {ReceivedProto: "HTTP/2.0", ReceivedBy: "edge.example.com", Comment: "nginx"}, }) fmt.Println("Via:", respHeader.Get("Via")) // Append to Via chain httpheader.AddVia(respHeader, httpheader.ViaElem{ ReceivedProto: "HTTP/1.1", ReceivedBy: "final-proxy.example.com", }) fmt.Println("Via headers:", respHeader["Via"]) // Output: // Proto: HTTP/1.1, By: proxy1.example.com, Comment: // Proto: HTTP/1.0, By: proxy2.example.com, Comment: Apache // Via: 1.1 gateway.example.com, 2.0 edge.example.com (nginx) } ``` -------------------------------- ### Parse and Generate Prefer and Preference-Applied Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Use these functions to manage client preferences and server-applied preferences in HTTP headers. ```go package main import ( "fmt" "net/http" "github.com/vfaronov/httpheader" ) func main() { // Parse Prefer header reqHeader := make(http.Header) reqHeader.Set("Prefer", "return=minimal, respond-async, wait=30") prefs := httpheader.Prefer(reqHeader) if pref, ok := prefs["return"]; ok { fmt.Println("Return preference:", pref.Value) } if _, ok := prefs["respond-async"]; ok { fmt.Println("Client prefers async response") } if pref, ok := prefs["wait"]; ok { fmt.Println("Wait timeout:", pref.Value, "seconds") } // Generate Prefer header clientHeader := make(http.Header) httpheader.SetPrefer(clientHeader, map[string]httpheader.Pref{ "return": {Value: "representation"}, "respond-async": {}, "handling": {Value: "lenient"}, }) fmt.Println("Prefer:", clientHeader.Get("Prefer")) // Generate Preference-Applied response header respHeader := make(http.Header) httpheader.SetPreferenceApplied(respHeader, map[string]string{ "return": "minimal", "respond-async": "", }) fmt.Println("Preference-Applied:", respHeader.Get("Preference-Applied")) // Parse Preference-Applied applied := httpheader.PreferenceApplied(respHeader) for name, value := range applied { if value == "" { fmt.Printf("Applied: %s (no value)\n", name) } else { fmt.Printf("Applied: %s=%s\n", name, value) } } // Output: // Return preference: minimal // Client prefers async response // Wait timeout: 30 seconds // Prefer: return=representation, respond-async, handling=lenient // Preference-Applied: return=minimal, respond-async } ``` -------------------------------- ### Parse and Process HTTP Headers in Go Source: https://github.com/vfaronov/httpheader/blob/master/README.md Demonstrates parsing a raw HTTP request string and extracting information from Forwarded, User-Agent, and Accept headers using the httpheader package. ```go const request = `GET / HTTP/1.1 Host: api.example.com User-Agent: MyApp/1.2.3 python-requests/2.22.0 Accept: text/*, application/json;q=0.8 Forwarded: for="198.51.100.30:14852";by="[2001:db8::ae:56]";proto=https ` r, _ := http.ReadRequest(bufio.NewReader(strings.NewReader(request))) forwarded := httpheader.Forwarded(r.Header) fmt.Println("received request from user at", forwarded[0].For.IP) for _, product := range httpheader.UserAgent(r.Header) { if product.Name == "MyApp" && product.Version < "2.0" { fmt.Println("enabling compatibility mode for", product) } } accept := httpheader.Accept(r.Header) acceptJSON := httpheader.MatchAccept(accept, "application/json") acceptXML := httpheader.MatchAccept(accept, "text/xml") if acceptXML.Q > acceptJSON.Q { fmt.Println("responding with XML") } // Output: received request from user at 198.51.100.30 // enabling compatibility mode for {MyApp 1.2.3 } // responding with XML ``` -------------------------------- ### Parse and Generate Link Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Demonstrates parsing an existing Link header and generating new ones for pagination and other link relations. Supports RFC 8288 and RFC 8187. ```go package main import ( "fmt" "net/http" "net/url" "github.com/vfaronov/httpheader" ) func main() { h := make(http.Header) h.Set("Link", `; rel="next", ; rel="prev", ; rel=stylesheet; type="text/css"`) // Parse requires the base URL (typically from request) base, _ := url.Parse("https://example.com/page/1") links := httpheader.Link(h, base) for _, link := range links { fmt.Printf("Rel: %s, Target: %s, Type: %s\n", link.Rel, link.Target, link.Type) } // Find specific link relations for _, link := range links { if link.Rel == "next" { fmt.Println("Next page:", link.Target) } } // Generate Link header with pagination respHeader := make(http.Header) nextURL, _ := url.Parse("https://api.example.com/items?page=3") prevURL, _ := url.Parse("https://api.example.com/items?page=1") httpheader.SetLink(respHeader, []httpheader.LinkElem{ {Target: nextURL, Rel: "next"}, {Target: prevURL, Rel: "prev"}, {Target: nextURL, Rel: "preload", Type: "application/json"}, }) fmt.Println("Generated:", respHeader.Get("Link")) // Link with title containing Unicode (uses RFC 8187 encoding) docURL, _ := url.Parse("https://example.com/doc") httpheader.AddLink(respHeader, httpheader.LinkElem{ Target: docURL, Rel: "describedby", Title: "Documentation", }) // Output: // Rel: next, Target: https://example.com/page/2, Type: // Rel: prev, Target: https://example.com/page/1, Type: // Rel: stylesheet, Target: https://example.com/style.css, Type: text/css // Next page: https://example.com/page/2 } ``` -------------------------------- ### Parse and Generate Allow and Vary Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Use this snippet to parse and generate HTTP Allow and Vary headers. The Allow header indicates supported HTTP methods, while the Vary header is used for cache variation. Ensure the http package is imported. ```go package main import ( "fmt" "net/http" "github.com/vfaronov/httpheader" ) func main() { // Parse Allow header h := make(http.Header) h.Set("Allow", "GET, HEAD, POST, OPTIONS") methods := httpheader.Allow(h) fmt.Println("Allowed methods:", methods) // Generate Allow header (commonly in 405 responses) respHeader := make(http.Header) httpheader.SetAllow(respHeader, []string{"GET", "HEAD", "OPTIONS"}) fmt.Println("Allow:", respHeader.Get("Allow")) // Parse Vary header - returns map[string]bool with canonical header names h2 := make(http.Header) h2.Set("Vary", "Accept-Encoding, Accept-Language, User-Agent") vary := httpheader.Vary(h2) fmt.Println("Varies on Accept-Encoding:", vary["Accept-Encoding"]) fmt.Println("Varies on Cookie:", vary["Cookie"]) // Check for wildcard Vary h3 := make(http.Header) h3.Set("Vary", "*") varyWildcard := httpheader.Vary(h3) if varyWildcard["*"] { fmt.Println("Response varies on everything (not cacheable)") } // Generate Vary header cacheHeader := make(http.Header) httpheader.SetVary(cacheHeader, map[string]bool{ "Accept-Encoding": true, "Accept-Language": true, }) fmt.Println("Vary:", cacheHeader.Get("Vary")) // Append to Vary header httpheader.AddVary(cacheHeader, "Authorization", "Cookie") fmt.Println("Vary headers:", cacheHeader["Vary"]) // Output: // Allowed methods: [GET HEAD POST OPTIONS] // Allow: GET, HEAD, OPTIONS // Varies on Accept-Encoding: true // Varies on Cookie: false // Response varies on everything (not cacheable) } ``` -------------------------------- ### Parse and Generate Retry-After Header Source: https://context7.com/vfaronov/httpheader/llms.txt This snippet demonstrates how to parse and generate the Retry-After HTTP header. It handles both seconds-based delays and HTTP-date formats. Ensure the time and net/http packages are imported. ```go package main import ( "fmt" "net/http" "time" "github.com/vfaronov/httpheader" ) func main() { // Parse Retry-After with seconds h := make(http.Header) h.Set("Retry-After", "120") h.Set("Date", time.Now().UTC().Format(http.TimeFormat)) retryTime := httpheader.RetryAfter(h) fmt.Printf("Retry after: %s (in %v)\n", retryTime.Format(time.RFC3339), time.Until(retryTime).Round(time.Second)) // Parse Retry-After with HTTP-date h2 := make(http.Header) futureTime := time.Now().Add(5 * time.Minute).UTC() h2.Set("Retry-After", futureTime.Format(http.TimeFormat)) retryTime2 := httpheader.RetryAfter(h2) fmt.Printf("Retry at: %s\n", retryTime2.Format(time.RFC3339)) // Generate Retry-After header respHeader := make(http.Header) httpheader.SetRetryAfter(respHeader, time.Now().Add(30*time.Second)) fmt.Println("Retry-After:", respHeader.Get("Retry-After")) // Output varies based on current time } ``` -------------------------------- ### Parse and Generate Warning Headers Source: https://context7.com/vfaronov/httpheader/llms.txt Handle Warning headers for conveying status information, particularly in caching scenarios. ```go package main import ( "fmt" "net/http" "time" "github.com/vfaronov/httpheader" ) func main() { h := make(http.Header) h.Set("Warning", `110 proxy.example.com "Response is stale" "Sun, 06 Nov 1994 08:49:37 GMT", 112 - "Disconnected operation"`) // Parse Warning header - returns []WarningElem warnings := httpheader.Warning(h) for _, w := range warnings { fmt.Printf("Code: %d, Agent: %s, Text: %s\n", w.Code, w.Agent, w.Text) if !w.Date.IsZero() { fmt.Printf(" Date: %s\n", w.Date) } } // Generate Warning header respHeader := make(http.Header) httpheader.SetWarning(respHeader, []httpheader.WarningElem{ {Code: 110, Agent: "cache.example.com", Text: "Response is stale"}, {Code: 199, Text: "Miscellaneous warning"}, // Agent defaults to "-" }) fmt.Println("Warning:", respHeader.Get("Warning")) // Add warning with date httpheader.AddWarning(respHeader, httpheader.WarningElem{ Code: 113, Agent: "proxy.example.com", Text: "Heuristic expiration", Date: time.Now().UTC(), }) // Output: // Code: 110, Agent: proxy.example.com, Text: Response is stale // Date: 1994-11-06 08:49:37 +0000 UTC // Code: 112, Agent: -, Text: Disconnected operation // Warning: 110 cache.example.com "Response is stale", 199 - "Miscellaneous warning" } ``` -------------------------------- ### Parse and Generate Forwarded Headers in Go Source: https://context7.com/vfaronov/httpheader/llms.txt Use httpheader.Forwarded to parse proxy chain information and httpheader.SetForwarded or httpheader.AddForwarded to construct or update headers. ```go package main import ( "bufio" "fmt" "net" "net/http" "strings" "github.com/vfaronov/httpheader" ) func main() { const request = `GET / HTTP/1.1 Host: api.example.com Forwarded: for="198.51.100.30:14852";by="[2001:db8::ae:56]";proto=https;host=example.com ` r, _ := http.ReadRequest(bufio.NewReader(strings.NewReader(request))) // Parse Forwarded header - returns []ForwardedElem forwarded := httpheader.Forwarded(r.Header) for _, elem := range forwarded { fmt.Println("Client IP:", elem.For.IP) fmt.Println("Client Port:", elem.For.Port) fmt.Println("Proxy IP:", elem.By.IP) fmt.Println("Original Proto:", elem.Proto) fmt.Println("Original Host:", elem.Host) } // Generate Forwarded header (e.g., in a proxy) h := make(http.Header) httpheader.SetForwarded(h, []httpheader.ForwardedElem{ { For: httpheader.Node{IP: net.ParseIP("203.0.113.50"), Port: 8080}, By: httpheader.Node{IP: net.ParseIP("10.0.0.1")}, Proto: "https", Host: "api.example.com", }, }) fmt.Println("Generated:", h.Get("Forwarded")) // Append to existing Forwarded chain httpheader.AddForwarded(h, httpheader.ForwardedElem{ For: httpheader.Node{IP: net.ParseIP("10.0.0.1")}, By: httpheader.Node{IP: net.ParseIP("10.0.0.2")}, }) fmt.Println("With append:", h["Forwarded"]) // Output: // Client IP: 198.51.100.30 // Client Port: 14852 // Proxy IP: 2001:db8::ae:56 // Original Proto: https // Original Host: example.com // Generated: for="203.0.113.50:8080";by=10.0.0.1;proto=https;host=api.example.com } ``` -------------------------------- ### Fuzz WWW-Authenticate header for an hour Source: https://github.com/vfaronov/httpheader/blob/master/fuzz/README.md Specifically fuzzes the WWW-Authenticate header for a duration of one hour. Adjust TIME parameter for different durations. ```bash make WWW-Authenticate.fuzz TIME=1h ``` -------------------------------- ### Fuzz each header Source: https://github.com/vfaronov/httpheader/blob/master/fuzz/README.md Fuzzes each header for which a .fuzz directory has been prepared. Run this for several minutes to test parsers. ```bash make *.fuzz ``` -------------------------------- ### Parse and Generate Cache-Control Headers in Go Source: https://context7.com/vfaronov/httpheader/llms.txt Use httpheader.CacheControl to parse directives into a struct and httpheader.SetCacheControl to generate headers. Delta values like max-age require the Value() method to retrieve the duration. ```go package main import ( "fmt" "net/http" "time" "github.com/vfaronov/httpheader" ) func main() { h := make(http.Header) h.Set("Cache-Control", "public, max-age=3600, stale-while-revalidate=60, immutable") // Parse Cache-Control - returns CacheDirectives struct cc := httpheader.CacheControl(h) fmt.Println("Public:", cc.Public) fmt.Println("Immutable:", cc.Immutable) fmt.Println("NoStore:", cc.NoStore) // Delta values use Value() to get duration and presence if maxAge, ok := cc.MaxAge.Value(); ok { fmt.Println("Max-Age:", maxAge) } if swr, ok := cc.StaleWhileRevalidate.Value(); ok { fmt.Println("Stale-While-Revalidate:", swr) } // Generate Cache-Control for responses respHeader := make(http.Header) httpheader.SetCacheControl(respHeader, httpheader.CacheDirectives{ Public: true, MaxAge: httpheader.DeltaSeconds(86400), StaleWhileRevalidate: httpheader.DeltaSeconds(3600), Immutable: true, }) fmt.Println("Generated:", respHeader.Get("Cache-Control")) // Generate Cache-Control for requests reqHeader := make(http.Header) httpheader.SetCacheControl(reqHeader, httpheader.CacheDirectives{ NoCache: true, MinFresh: httpheader.DeltaSeconds(int(time.Hour.Seconds())), }) fmt.Println("Request CC:", reqHeader.Get("Cache-Control")) // Handle no-cache with specific headers h2 := make(http.Header) h2.Set("Cache-Control", `no-cache="Set-Cookie, Authorization"`) cc2 := httpheader.CacheControl(h2) fmt.Println("NoCacheHeaders:", cc2.NoCacheHeaders) // Output: // Public: true // Immutable: true // NoStore: false // Max-Age: 1h0m0s // Stale-While-Revalidate: 1m0s // Generated: public, immutable, max-age=86400, stale-while-revalidate=3600 // Request CC: no-cache, min-fresh=3600 // NoCacheHeaders: [Set-Cookie Authorization] } ``` -------------------------------- ### Clean up go-fuzz artifacts Source: https://github.com/vfaronov/httpheader/blob/master/fuzz/README.md Removes all files and directories generated by go-fuzz. This command will error if any crashers have been found. ```bash make clean ``` -------------------------------- ### RFC 8187 Extended Value Encoding Source: https://context7.com/vfaronov/httpheader/llms.txt Use this code to decode and encode extended parameter values according to RFC 8187, which is essential for handling non-ASCII characters in headers like `filename*`. Ensure the fmt package is imported. ```go package main import ( "fmt" "github.com/vfaronov/httpheader" ) func main() { // Decode ext-value (e.g., from filename* parameter) encoded := "UTF-8'en'%C2%A3%20and%20%E2%82%AC%20rates" text, lang, err := httpheader.DecodeExtValue(encoded) if err != nil { fmt.Println("Error:", err) return } fmt.Printf("Text: %s, Language: %s\n", text, lang) // Encode value for use in ext-value parameters encoded2 := httpheader.EncodeExtValue("report.pdf", "en") fmt.Println("Encoded (ASCII):", encoded2) // Encode Unicode filename encoded3 := httpheader.EncodeExtValue("rapport.pdf", "fr") fmt.Println("Encoded (French):", encoded3) // With special characters encoded4 := httpheader.EncodeExtValue("file name.pdf", "") fmt.Println("Encoded (spaces):", encoded4) // Output: // Text: £ and € rates, Language: en // Encoded (ASCII): UTF-8'en'report.pdf // Encoded (French): UTF-8'fr'rapport.pdf // Encoded (spaces): UTF-8''file%20name.pdf } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.