feat: browser cache directives
This commit is contained in:
		
							parent
							
								
									603203848a
								
							
						
					
					
						commit
						190cb99a79
					
				| 
						 | 
					@ -94,7 +94,7 @@ export default {
 | 
				
			||||||
      // reload the image when the file is replaced
 | 
					      // reload the image when the file is replaced
 | 
				
			||||||
      const key = Date.parse(this.modified);
 | 
					      const key = Date.parse(this.modified);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true&k=${key}`;
 | 
					      return `${baseURL}/api/preview/thumb/${path}?k=${key}&inline=true`;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    isThumbsEnabled() {
 | 
					    isThumbsEnabled() {
 | 
				
			||||||
      return enableThumbs;
 | 
					      return enableThumbs;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,8 @@ export function parseToken(token) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const data = JSON.parse(Base64.decode(parts[1]));
 | 
					  const data = JSON.parse(Base64.decode(parts[1]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  document.cookie = `auth=${token}; path=/`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  localStorage.setItem("jwt", token);
 | 
					  localStorage.setItem("jwt", token);
 | 
				
			||||||
  store.commit("setJWT", token);
 | 
					  store.commit("setJWT", token);
 | 
				
			||||||
  store.commit("setUser", data.user);
 | 
					  store.commit("setUser", data.user);
 | 
				
			||||||
| 
						 | 
					@ -81,6 +83,8 @@ export async function signup(username, password) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function logout() {
 | 
					export function logout() {
 | 
				
			||||||
 | 
					  document.cookie = "auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  store.commit("setJWT", "");
 | 
					  store.commit("setJWT", "");
 | 
				
			||||||
  store.commit("setUser", null);
 | 
					  store.commit("setUser", null);
 | 
				
			||||||
  localStorage.setItem("jwt", null);
 | 
					  localStorage.setItem("jwt", null);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -414,7 +414,7 @@ export default {
 | 
				
			||||||
    window.removeEventListener("scroll", this.scrollEvent);
 | 
					    window.removeEventListener("scroll", this.scrollEvent);
 | 
				
			||||||
    window.removeEventListener("resize", this.windowsResize);
 | 
					    window.removeEventListener("resize", this.windowsResize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!this.user.perm.create) return;
 | 
					    if (this.user && !this.user.perm.create) return;
 | 
				
			||||||
    document.removeEventListener("dragover", this.preventDefault);
 | 
					    document.removeEventListener("dragover", this.preventDefault);
 | 
				
			||||||
    document.removeEventListener("dragenter", this.dragEnter);
 | 
					    document.removeEventListener("dragenter", this.dragEnter);
 | 
				
			||||||
    document.removeEventListener("dragleave", this.dragLeave);
 | 
					    document.removeEventListener("dragleave", this.dragLeave);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,11 +175,9 @@ export default {
 | 
				
			||||||
      if (this.req.type === "image" && !this.fullSize) {
 | 
					      if (this.req.type === "image" && !this.fullSize) {
 | 
				
			||||||
        return `${baseURL}/api/preview/big${url.encodePath(
 | 
					        return `${baseURL}/api/preview/big${url.encodePath(
 | 
				
			||||||
          this.req.path
 | 
					          this.req.path
 | 
				
			||||||
        )}?auth=${this.jwt}&k=${key}`;
 | 
					        )}?k=${key}`;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
 | 
					      return `${baseURL}/api/raw${url.encodePath(this.req.path)}?k=${key}`;
 | 
				
			||||||
        this.jwt
 | 
					 | 
				
			||||||
      }&k=${key}`;
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    raw() {
 | 
					    raw() {
 | 
				
			||||||
      return `${this.previewUrl}&inline=true`;
 | 
					      return `${this.previewUrl}&inline=true`;
 | 
				
			||||||
| 
						 | 
					@ -257,7 +255,7 @@ export default {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this.req.subtitles) {
 | 
					      if (this.req.subtitles) {
 | 
				
			||||||
        this.subtitles = this.req.subtitles.map(
 | 
					        this.subtitles = this.req.subtitles.map(
 | 
				
			||||||
          (sub) => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`
 | 
					          (sub) => `${baseURL}/api/raw${sub}?inline=true`
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								http/auth.go
								
								
								
								
							
							
						
						
									
										11
									
								
								http/auth.go
								
								
								
								
							| 
						 | 
					@ -48,11 +48,16 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auth := r.URL.Query().Get("auth")
 | 
						auth := r.URL.Query().Get("auth")
 | 
				
			||||||
	if auth == "" {
 | 
						if auth != "" && strings.Count(auth, ".") == 2 {
 | 
				
			||||||
		return "", request.ErrNoTokenInRequest
 | 
							return auth, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return auth, nil
 | 
						cookie, _ := r.Cookie("auth")
 | 
				
			||||||
 | 
						if cookie != nil && strings.Count(cookie.Value, ".") == 2 {
 | 
				
			||||||
 | 
							return cookie.Value, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return "", request.ErrNoTokenInRequest
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func withUser(fn handleFunc) handleFunc {
 | 
					func withUser(fn handleFunc) handleFunc {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,7 +49,7 @@ func (d *data) Check(path string) bool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
 | 
					func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
 | 
				
			||||||
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		w.Header().Set("Cache-Control", "no-cache")
 | 
							w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		settings, err := store.Settings.Get()
 | 
							settings, err := store.Settings.Get()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,11 @@ func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgServic
 | 
				
			||||||
		return errToStatus(err), err
 | 
							return errToStatus(err), err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isFresh := checkEtag(w, r, file.ModTime.Unix(), file.Size)
 | 
				
			||||||
 | 
						if isFresh {
 | 
				
			||||||
 | 
							return http.StatusNotModified, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
 | 
						cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
 | 
				
			||||||
	cachedFile, ok, err := fileCache.Load(r.Context(), cacheKey)
 | 
						cachedFile, ok, err := fileCache.Load(r.Context(), cacheKey)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -204,6 +204,11 @@ func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) {
 | 
					func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo) (int, error) {
 | 
				
			||||||
 | 
						isFresh := checkEtag(w, r, file.ModTime.Unix(), file.Size)
 | 
				
			||||||
 | 
						if isFresh {
 | 
				
			||||||
 | 
							return http.StatusNotModified, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fd, err := file.Fs.Open(file.Path)
 | 
						fd, err := file.Fs.Open(file.Path)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return http.StatusInternalServerError, err
 | 
							return http.StatusInternalServerError, err
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ package http
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io/fs"
 | 
						"io/fs"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
| 
						 | 
					@ -109,6 +110,9 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
 | 
				
			||||||
			return http.StatusNotFound, nil
 | 
								return http.StatusNotFound, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const maxAge = 86400 // 1 day
 | 
				
			||||||
 | 
							w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%v", maxAge))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if d.settings.Branding.Files != "" {
 | 
							if d.settings.Branding.Files != "" {
 | 
				
			||||||
			if strings.HasPrefix(r.URL.Path, "img/") {
 | 
								if strings.HasPrefix(r.URL.Path, "img/") {
 | 
				
			||||||
				fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
 | 
									fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ package http
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
| 
						 | 
					@ -66,3 +67,11 @@ func stripPrefix(prefix string, h http.Handler) http.Handler {
 | 
				
			||||||
		h.ServeHTTP(w, r2)
 | 
							h.ServeHTTP(w, r2)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkEtag(w http.ResponseWriter, r *http.Request, fTime, fSize int64) bool {
 | 
				
			||||||
 | 
						etag := fmt.Sprintf("%x%x", fTime, fSize)
 | 
				
			||||||
 | 
						w.Header().Set("Cache-Control", "private")
 | 
				
			||||||
 | 
						w.Header().Set("Etag", etag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return r.Header.Get("If-None-Match") == etag
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue