Skip to content

ngehrsitz/httpcache

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

httpcache

httpcache

CI Security Coverage Go Report Card License GoDoc

Package httpcache provides an http.RoundTripper implementation that works as a mostly RFC 9111 (HTTP Caching) compliant cache for HTTP responses. It improves application performance by reducing redundant HTTP requests and supports various backends for use cases such as API caching, web scraping, and microservices.

RFC Compliance: This implementation follows RFC 9111 (2022), which obsoletes RFC 7234 (2014). See the compliance features for details on supported directives and behaviors.

Note: This is a maintained fork of gregjones/httpcache, which is no longer actively maintained. This fork aims to modernize the codebase while maintaining backward compatibility, fix bugs, and add new features.

Use Cases

  • API Caching: Reduce latency and server load by caching API responses.
  • Web Scraping: Avoid repeated requests to the same endpoints.
  • Microservices: Cache responses between services for better performance.
  • Web Applications: Improve user experience by caching dynamic content.
  • Resource Caching: Store static or frequently accessed resources locally.

Table of Contents

Features

  • βœ… RFC 9111 Compliant (~95% compliance) - Implements HTTP Caching standard (obsoletes RFC 7234)
    • βœ… Age header calculation with full Section 4.2.3 algorithm (request_time, response_time, response_delay tracking)
    • βœ… Age header validation per Section 5.1 (handles multiple values, invalid values with logging)
    • βœ… Cache-Control directive validation per Section 4.2.1 (duplicate detection, conflict resolution, value validation)
    • βœ… Warning headers for stale responses (Section 5.5 - deprecated but supported for compatibility)
    • βœ… must-revalidate directive enforcement (Section 5.2.2.1)
    • βœ… Pragma: no-cache support (Section 5.4 - HTTP/1.0 backward compatibility)
    • βœ… Cache invalidation on unsafe methods (Section 4.4)
    • βœ… Content-Location and Location header invalidation (Section 4.4)
    • βœ… Same-origin policy enforcement for cache invalidation
    • βœ… Cache-Control: private directive support (Section 5.2.2.6)
    • βœ… Cache-Control: must-understand directive support (Section 5.2.2.3)
    • βœ… Vary header matching per Section 4.1 (wildcard, whitespace normalization, case-insensitive)
    • βœ… Vary header separation - Optional separate cache entries for response variants (Section 4.1)
    • βœ… Authorization header handling per Section 3.5 (secure caching in shared caches)
  • βœ… Multiple Backends - Memory, Disk, Redis, LevelDB, Memcache, PostgreSQL, MongoDB, NATS K/V, Hazelcast, Cloud Storage (S3/GCS/Azure)
  • βœ… Multi-Tier Caching - Combine multiple backends with automatic fallback and promotion
  • βœ… Compression Wrapper - Automatic Gzip, Brotli, or Snappy compression for cached data
  • βœ… Security Wrapper - Optional SHA-256 key hashing and AES-256 encryption
  • βœ… Thread-Safe - Safe for concurrent use
  • βœ… Zero Dependencies - Core package uses only Go standard library
  • βœ… Easy Integration - Drop-in replacement for http.Client
  • βœ… ETag & Validation - Automatic cache revalidation
  • βœ… Stale-If-Error - Resilient caching with RFC 5861 support
  • βœ… Stale-While-Revalidate - Async cache updates for better performance (RFC 5861)
  • βœ… Configurable Cache Mode - Use as private cache (default) or shared/public cache

Quick Start

package main

import (
    "fmt"
    "io"
    "net/http"
    
    "github.com/sandrolain/httpcache"
)

func main() {
    // Create a cached HTTP client
    transport := httpcache.NewMemoryCacheTransport()
    client := transport.Client()
    
    // Make requests - second request will be cached!
    resp, _ := client.Get("https://example.com")
    io.Copy(io.Discard, resp.Body)
    resp.Body.Close()
    
    // Check if response came from cache
    if resp.Header.Get(httpcache.XFromCache) == "1" {
        fmt.Println("Response was cached!")
    }
}

Installation

go get github.com/sandrolain/httpcache

Documentation

πŸ“š Core Documentation

πŸ” Quick Navigation

Getting Started:

Common Tasks:

Advanced Topics:

Practical Examples

See the examples/ directory for complete, runnable examples:

Each example includes:

  • Complete working code
  • Detailed README
  • Use case explanations
  • Best practices

Limitations

Private Directive for Public Caches

⚠️ Note: When configured as a public cache (IsPublicCache: true), responses with the Cache-Control: private directive are not cached.

Default Behavior: By default, httpcache operates as a private cache, which allows caching of responses marked as private.

Public Cache Mode: When IsPublicCache is set to true, the cache behaves as a shared cache and respects the private directive by not caching such responses.

See Security Considerations and Advanced Features - Private vs Public Cache for details.

Authorization Header in Shared Caches

⚠️ Note: When configured as a shared/public cache (IsPublicCache: true), requests with an Authorization header are NOT cached unless the response contains one of these directives:

  • Cache-Control: public
  • Cache-Control: must-revalidate
  • Cache-Control: s-maxage=<seconds>

This implements RFC 9111 Section 3.5 to prevent unauthorized access to cached authenticated responses in shared caches.

Default Behavior: Private caches (default) can cache Authorization responses without restrictions.

Shared Cache Mode: Requires explicit server permission via the directives above. Additionally, use CacheKeyHeaders to separate cache entries per user:

transport.IsPublicCache = true
transport.CacheKeyHeaders = []string{"Authorization"}  // Separate cache per user

See Authorization Header and Shared Caches for detailed examples and security considerations.

Performance

  • Memory cache: ~100ns per operation
  • Disk cache: ~1-5ms per operation (depends on filesystem)
  • Redis cache: ~1-3ms per operation (network latency dependent)
  • Overhead vs no-cache: < 5% for cache hits

Benchmarks are available in each backend's *_bench_test.go file.

Testing

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Run integration tests (requires Docker)
go test -tags=integration ./...

# Run benchmarks
go test -bench=. ./...

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Run golangci-lint run and govulncheck ./...
  5. Commit your changes (git commit -m 'feat: add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Acknowledgments

This project is a fork of gregjones/httpcache by Greg Jones, which was archived in 2023. We're grateful for the original work and continue its development with modern Go practices.

Additional acknowledgments:

  • RFC 9111 - HTTP Caching (obsoletes RFC 7234)
  • RFC 7234 - HTTP Caching (obsoleted by RFC 9111, still referenced for historical context)
  • RFC 5861 - HTTP Cache-Control Extensions for Stale Content
  • All contributors to the original and forked projects

License

MIT License - see LICENSE.txt for details.

Support

About

A Transport for http.Client that will cache responses according to the HTTP RFC

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 100.0%