diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index d2d18e6..947c9f7 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "regexp" + "strings" "sync" "time" @@ -48,9 +49,15 @@ type LocalStorage struct { Path string `yaml:"path"` } +type Accel struct { + EnableByHeader string `yaml:"enable-by-header"` + ResponseWithHeaders []string `yaml:"response-with-headers"` +} + type Storage struct { Type string `yaml:"type"` Local *LocalStorage `yaml:"local"` + Accel Accel `yaml:"accel"` } type Cache struct { @@ -146,6 +153,9 @@ func configFromFile(path string) (*Config, error) { Local: &LocalStorage{ Path: "./data", }, + Accel: Accel{ + ResponseWithHeaders: []string{"X-Sendfile", "X-Accel-Redirect"}, + }, }, Misc: MiscConfig{ FirstChunkBytes: 1024 * 1024 * 50, @@ -171,6 +181,24 @@ func configFromFile(path string) (*Config, error) { return config, nil } +func (server *Server) serveFile(w http.ResponseWriter, r *http.Request, path string) { + if location := r.Header.Get(server.Storage.Accel.EnableByHeader); server.Storage.Accel.EnableByHeader != "" && location != "" { + relPath, err := filepath.Rel(server.Storage.Local.Path, path) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + accelPath := filepath.Join(location, relPath) + + for _, headerKey := range server.Storage.Accel.ResponseWithHeaders { + w.Header().Set(headerKey, accelPath) + } + + return + } + + http.ServeFile(w, r, path) +} + func (server *Server) handleRequest(w http.ResponseWriter, r *http.Request) { fullpath := filepath.Join(server.Storage.Local.Path, r.URL.Path) fullpath, err := filepath.Abs(fullpath) @@ -194,17 +222,17 @@ func (server *Server) handleRequest(w http.ResponseWriter, r *http.Request) { if localStatus == localExistsButNeedHead { if ranged { server.streamOnline(nil, r, mtime, fullpath) - http.ServeFile(w, r, fullpath) + server.serveFile(w, r, fullpath) } else { server.streamOnline(w, r, mtime, fullpath) } } else { - http.ServeFile(w, r, fullpath) + server.serveFile(w, r, fullpath) } } else { if ranged { server.streamOnline(nil, r, mtime, fullpath) - http.ServeFile(w, r, fullpath) + server.serveFile(w, r, fullpath) } else { server.streamOnline(w, r, mtime, fullpath) } @@ -274,7 +302,7 @@ func (server *Server) streamOnline(w http.ResponseWriter, r *http.Request, mtime if chunks == nil && mtime != zeroTime { logrus.WithFields(logrus.Fields{"upstreamIdx": selectedIdx, "key": key}).Trace("not modified. using local version") if w != nil { - http.ServeFile(w, r, key) + server.serveFile(w, r, key) } return } @@ -292,7 +320,7 @@ func (server *Server) streamOnline(w http.ResponseWriter, r *http.Request, mtime if response.StatusCode == http.StatusNotModified { logrus.WithField("upstreamIdx", selectedIdx).Trace("not modified. using local version") os.Chtimes(key, zeroTime, time.Now()) - http.ServeFile(w, r, key) + server.serveFile(w, r, key) return } diff --git a/config.yaml b/config.yaml index 96a53c2..b314238 100644 --- a/config.yaml +++ b/config.yaml @@ -44,3 +44,17 @@ storage: type: local # ignored local: path: /data # defaults to ./data + + accel: + # example nginx config: + ## location /i { + ## internal; + ## alias /path/to/data; + ## } + ## location / { + ## proxy_pass 127.0.0.1:8881; + ## proxy_set_header X-Accel-Path /i; + ## } + ## + + # enable-by-header: "X-Accel-Path"