Skip to content

Instantly share code, notes, and snippets.

@elico
Created June 12, 2016 22:43
Show Gist options
  • Save elico/9bb3da6b7937ce09a0c2d91637b3be5c to your computer and use it in GitHub Desktop.
Save elico/9bb3da6b7937ce09a0c2d91637b3be5c to your computer and use it in GitHub Desktop.
A reverse http caching proxy with example of how to override traffic to pass the cache.
package main
import (
"flag"
"github.com/lox/httpcache"
"github.com/lox/httpcache/httplog"
"log"
"net/http"
"net/http/httputil"
"os"
"strings"
)
const (
defaultListen = "0.0.0.0:8080"
defaultDir = "./cachedata"
)
var (
listen string
useDisk bool
private bool
dir string
dumpHttp bool
verbose bool
)
func hanlderToFunc(cache http.Handler, proxy http.Handler) http.HandlerFunc {
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
switch {
case (req.Method == "GET" && strings.HasPrefix(req.URL.Path, "/static")):
cache.ServeHTTP(res, req)
return
default:
proxy.ServeHTTP(res, req)
return
}
})
}
func init() {
flag.StringVar(&listen, "listen", defaultListen, "the host and port to bind to")
flag.StringVar(&dir, "dir", defaultDir, "the dir to store cache data in, implies -disk")
flag.BoolVar(&useDisk, "disk", false, "whether to store cache data to disk")
flag.BoolVar(&verbose, "v", false, "show verbose output and debugging")
flag.BoolVar(&private, "private", false, "make the cache private")
flag.BoolVar(&dumpHttp, "dumphttp", false, "dumps http requests and responses to stdout")
flag.Parse()
if verbose {
httpcache.DebugLogging = true
}
}
func main() {
proxy := &httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Scheme = "http"
r.URL.Host = "127.0.0.1:80"
},
}
var cache httpcache.Cache
if useDisk && dir != "" {
log.Printf("storing cached resources in %s", dir)
if err := os.MkdirAll(dir, 0700); err != nil {
log.Fatal(err)
}
var err error
cache, err = httpcache.NewDiskCache(dir)
if err != nil {
log.Fatal(err)
}
} else {
cache = httpcache.NewMemoryCache()
}
handler := httpcache.NewHandler(cache, proxy)
handler.Shared = !private
if verbose {
respLogger := httplog.NewResponseLogger(handler)
respLogger.DumpRequests = dumpHttp
respLogger.DumpResponses = dumpHttp
respLogger.DumpErrors = dumpHttp
log.Printf("listening on http://%s", listen)
log.Fatal(http.ListenAndServe(listen, hanlderToFunc(respLogger, proxy)))
} else {
log.Printf("listening on http://%s", listen)
log.Fatal(http.ListenAndServe(listen, hanlderToFunc(handler, proxy)))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment