Changes
5 changed files (+133/-29)
-
-
@@ -37,18 +37,23 @@ func generateETag(fi os.FileInfo) string {// HandleTimeCache handles time-based caching for a HTTP request func HandleTimeCache(req *http.Request, w http.ResponseWriter, fi os.FileInfo) (handled bool) { return HandleGenericTimeCache(req, w, fi.ModTime()) } // HandleGenericTimeCache handles time-based caching for a HTTP request func HandleGenericTimeCache(req *http.Request, w http.ResponseWriter, lastModified time.Time) (handled bool) { AddCacheControlToHeader(w.Header(), setting.StaticCacheTime) ifModifiedSince := req.Header.Get("If-Modified-Since") if ifModifiedSince != "" { t, err := time.Parse(http.TimeFormat, ifModifiedSince) if err == nil && fi.ModTime().Unix() <= t.Unix() { if err == nil && lastModified.Unix() <= t.Unix() { w.WriteHeader(http.StatusNotModified) return true } } w.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat)) w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat)) return false }
-
@@ -85,3 +90,33 @@ func checkIfNoneMatchIsValid(req *http.Request, etag string) bool {} return false } // HandleGenericETagTimeCache handles ETag-based caching with Last-Modified caching for a HTTP request. // It returns true if the request was handled. func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag string, lastModified time.Time) (handled bool) { if len(etag) > 0 { w.Header().Set("Etag", etag) } if !lastModified.IsZero() { w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat)) } if len(etag) > 0 { if checkIfNoneMatchIsValid(req, etag) { w.WriteHeader(http.StatusNotModified) return true } } if !lastModified.IsZero() { ifModifiedSince := req.Header.Get("If-Modified-Since") if ifModifiedSince != "" { t, err := time.Parse(http.TimeFormat, ifModifiedSince) if err == nil && lastModified.Unix() <= t.Unix() { w.WriteHeader(http.StatusNotModified) return true } } } AddCacheControlToHeader(w.Header(), setting.StaticCacheTime) return false }
-
-
-
@@ -9,13 +9,16 @@ import ("encoding/base64" "fmt" "net/http" "path" "time" "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common"
-
@@ -62,18 +65,50 @@ func GetRawFile(ctx *context.APIContext) {return } blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath) blob, lastModified := getBlobForEntry(ctx) if ctx.Written() { return } if err := common.ServeBlob(ctx.Context, blob, lastModified); err != nil { ctx.Error(http.StatusInternalServerError, "ServeBlob", err) } } func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, lastModified time.Time) { entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { if git.IsErrNotExist(err) { ctx.NotFound() } else { ctx.Error(http.StatusInternalServerError, "GetBlobByPath", err) ctx.Error(http.StatusInternalServerError, "GetTreeEntryByPath", err) } return } if err = common.ServeBlob(ctx.Context, blob); err != nil { ctx.Error(http.StatusInternalServerError, "ServeBlob", err) if entry.IsDir() || entry.IsSubModule() { ctx.NotFound("getBlobForEntry", nil) return } var c *git.LastCommitCache if setting.CacheService.LastCommit.Enabled && ctx.Repo.CommitsCount >= setting.CacheService.LastCommit.CommitsCount { c = git.NewLastCommitCache(ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache()) } info, _, err := git.Entries([]*git.TreeEntry{entry}).GetCommitsInfo(ctx, ctx.Repo.Commit, path.Dir("/" + ctx.Repo.TreePath)[1:], c) if err != nil { ctx.Error(http.StatusInternalServerError, "GetCommitsInfo", err) return } if len(info) == 1 { // Not Modified lastModified = info[0].Commit.Committer.When } blob = entry.Blob() return } // GetArchive get archive of a repository
-
-
-
@@ -10,6 +10,7 @@ import ("path" "path/filepath" "strings" "time" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/context"
-
@@ -22,8 +23,8 @@ import () // ServeBlob download a git.Blob func ServeBlob(ctx *context.Context, blob *git.Blob) error { if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`) { func ServeBlob(ctx *context.Context, blob *git.Blob, lastModified time.Time) error { if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) { return nil }
-
-
-
@@ -6,7 +6,11 @@package repo import ( "path" "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/httpcache"
-
@@ -18,8 +22,8 @@ import () // ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error { if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`) { func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified time.Time) error { if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) { return nil }
-
@@ -45,7 +49,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {log.Error("ServeBlobOrLFS: Close: %v", err) } closed = true return common.ServeBlob(ctx, blob) return common.ServeBlob(ctx, blob, lastModified) } if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`) { return nil
-
@@ -76,37 +80,65 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {} closed = true return common.ServeBlob(ctx, blob) return common.ServeBlob(ctx, blob, lastModified) } // SingleDownload download a file by repos path func SingleDownload(ctx *context.Context) { blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath) func getBlobForEntry(ctx *context.Context) (blob *git.Blob, lastModified time.Time) { entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { if git.IsErrNotExist(err) { ctx.NotFound("GetBlobByPath", nil) ctx.NotFound("GetTreeEntryByPath", err) } else { ctx.ServerError("GetBlobByPath", err) ctx.ServerError("GetTreeEntryByPath", err) } return } if err = common.ServeBlob(ctx, blob); err != nil { if entry.IsDir() || entry.IsSubModule() { ctx.NotFound("getBlobForEntry", nil) return } var c *git.LastCommitCache if setting.CacheService.LastCommit.Enabled && ctx.Repo.CommitsCount >= setting.CacheService.LastCommit.CommitsCount { c = git.NewLastCommitCache(ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache()) } info, _, err := git.Entries([]*git.TreeEntry{entry}).GetCommitsInfo(ctx, ctx.Repo.Commit, path.Dir("/" + ctx.Repo.TreePath)[1:], c) if err != nil { ctx.ServerError("GetCommitsInfo", err) return } if len(info) == 1 { // Not Modified lastModified = info[0].Commit.Committer.When } blob = entry.Blob() return } // SingleDownload download a file by repos path func SingleDownload(ctx *context.Context) { blob, lastModified := getBlobForEntry(ctx) if blob == nil { return } if err := common.ServeBlob(ctx, blob, lastModified); err != nil { ctx.ServerError("ServeBlob", err) } } // SingleDownloadOrLFS download a file by repos path redirecting to LFS if necessary func SingleDownloadOrLFS(ctx *context.Context) { blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath) if err != nil { if git.IsErrNotExist(err) { ctx.NotFound("GetBlobByPath", nil) } else { ctx.ServerError("GetBlobByPath", err) } blob, lastModified := getBlobForEntry(ctx) if blob == nil { return } if err = ServeBlobOrLFS(ctx, blob); err != nil { if err := ServeBlobOrLFS(ctx, blob, lastModified); err != nil { ctx.ServerError("ServeBlobOrLFS", err) } }
-
@@ -122,7 +154,7 @@ func DownloadByID(ctx *context.Context) {} return } if err = common.ServeBlob(ctx, blob); err != nil { if err = common.ServeBlob(ctx, blob, time.Time{}); err != nil { ctx.ServerError("ServeBlob", err) } }
-
@@ -138,7 +170,7 @@ func DownloadByIDOrLFS(ctx *context.Context) {} return } if err = ServeBlobOrLFS(ctx, blob); err != nil { if err = ServeBlobOrLFS(ctx, blob, time.Time{}); err != nil { ctx.ServerError("ServeBlob", err) } }
-
-
-
@@ -13,6 +13,7 @@ import ("net/url" "path/filepath" "strings" "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/unit"
-
@@ -627,7 +628,7 @@ func WikiRaw(ctx *context.Context) {} if entry != nil { if err = common.ServeBlob(ctx, entry.Blob()); err != nil { if err = common.ServeBlob(ctx, entry.Blob(), time.Time{}); err != nil { ctx.ServerError("ServeBlob", err) } return
-