| @@ -10,8 +10,10 @@ import ( | |||
| "encoding/base64" | |||
| "fmt" | |||
| "html/template" | |||
| "io" | |||
| "net/http" | |||
| "net/url" | |||
| "path/filepath" | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| @@ -62,7 +64,7 @@ type Context struct { | |||
| HTTPS string | |||
| Git string | |||
| } | |||
| *models.Mirror | |||
| Mirror *models.Mirror | |||
| } | |||
| } | |||
| @@ -243,6 +245,41 @@ func (ctx *Context) CsrfTokenValid() bool { | |||
| return true | |||
| } | |||
| func (ctx *Context) ServeFile(file string, names ...string) { | |||
| var name string | |||
| if len(names) > 0 { | |||
| name = names[0] | |||
| } else { | |||
| name = filepath.Base(file) | |||
| } | |||
| ctx.Res.Header().Set("Content-Description", "File Transfer") | |||
| ctx.Res.Header().Set("Content-Type", "application/octet-stream") | |||
| ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+name) | |||
| ctx.Res.Header().Set("Content-Transfer-Encoding", "binary") | |||
| ctx.Res.Header().Set("Expires", "0") | |||
| ctx.Res.Header().Set("Cache-Control", "must-revalidate") | |||
| ctx.Res.Header().Set("Pragma", "public") | |||
| http.ServeFile(ctx.Res, ctx.Req, file) | |||
| } | |||
| func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) { | |||
| modtime := time.Now() | |||
| for _, p := range params { | |||
| switch v := p.(type) { | |||
| case time.Time: | |||
| modtime = v | |||
| } | |||
| } | |||
| ctx.Res.Header().Set("Content-Description", "File Transfer") | |||
| ctx.Res.Header().Set("Content-Type", "application/octet-stream") | |||
| ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+name) | |||
| ctx.Res.Header().Set("Content-Transfer-Encoding", "binary") | |||
| ctx.Res.Header().Set("Expires", "0") | |||
| ctx.Res.Header().Set("Cache-Control", "must-revalidate") | |||
| ctx.Res.Header().Set("Pragma", "public") | |||
| http.ServeContent(ctx.Res, ctx.Req, name, modtime, r) | |||
| } | |||
| type Flash struct { | |||
| url.Values | |||
| ErrorMsg, SuccessMsg string | |||
| @@ -0,0 +1,68 @@ | |||
| // Copyright 2014 The Gogs Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package repo | |||
| import ( | |||
| "os" | |||
| "path/filepath" | |||
| "github.com/Unknwon/com" | |||
| "github.com/go-martini/martini" | |||
| "github.com/gogits/gogs/modules/base" | |||
| "github.com/gogits/gogs/modules/middleware" | |||
| ) | |||
| func SingleDownload(ctx *middleware.Context, params martini.Params) { | |||
| // Get tree path | |||
| treename := params["_1"] | |||
| blob, err := ctx.Repo.Commit.GetBlobByPath(treename) | |||
| if err != nil { | |||
| ctx.Handle(404, "repo.SingleDownload(GetBlobByPath)", err) | |||
| return | |||
| } | |||
| data, err := blob.Data() | |||
| if err != nil { | |||
| ctx.Handle(404, "repo.SingleDownload(Data)", err) | |||
| return | |||
| } | |||
| contentType, isTextFile := base.IsTextFile(data) | |||
| _, isImageFile := base.IsImageFile(data) | |||
| ctx.Res.Header().Set("Content-Type", contentType) | |||
| if !isTextFile && !isImageFile { | |||
| ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(treename)) | |||
| ctx.Res.Header().Set("Content-Transfer-Encoding", "binary") | |||
| } | |||
| ctx.Res.Write(data) | |||
| } | |||
| func ZipDownload(ctx *middleware.Context, params martini.Params) { | |||
| commitId := ctx.Repo.CommitId | |||
| archivesPath := filepath.Join(ctx.Repo.GitRepo.Path, "archives") | |||
| if !com.IsDir(archivesPath) { | |||
| if err := os.Mkdir(archivesPath, 0755); err != nil { | |||
| ctx.Handle(404, "ZipDownload -> os.Mkdir(archivesPath)", err) | |||
| return | |||
| } | |||
| } | |||
| zipPath := filepath.Join(archivesPath, commitId+".zip") | |||
| if com.IsFile(zipPath) { | |||
| ctx.ServeFile(zipPath, ctx.Repo.Repository.Name+".zip") | |||
| return | |||
| } | |||
| err := ctx.Repo.Commit.CreateArchive(zipPath) | |||
| if err != nil { | |||
| ctx.Handle(404, "ZipDownload -> CreateArchive "+zipPath, err) | |||
| return | |||
| } | |||
| ctx.ServeFile(zipPath, ctx.Repo.Repository.Name+".zip") | |||
| } | |||
| @@ -145,7 +145,7 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| return | |||
| } | |||
| if entry != nil && entry.IsFile() { | |||
| if entry != nil && !entry.IsDir() { | |||
| blob := entry.Blob() | |||
| if data, err := blob.Data(); err != nil { | |||
| @@ -154,7 +154,7 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| ctx.Data["FileSize"] = blob.Size() | |||
| ctx.Data["IsFile"] = true | |||
| ctx.Data["FileName"] = blob.Name | |||
| ext := path.Ext(blob.Name) | |||
| ext := path.Ext(blob.Name()) | |||
| if len(ext) > 0 { | |||
| ext = ext[1:] | |||
| } | |||
| @@ -168,7 +168,7 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| if isImageFile { | |||
| ctx.Data["IsImageFile"] = true | |||
| } else { | |||
| readmeExist := base.IsMarkdownFile(blob.Name) || base.IsReadmeFile(blob.Name) | |||
| readmeExist := base.IsMarkdownFile(blob.Name()) || base.IsReadmeFile(blob.Name()) | |||
| ctx.Data["ReadmeExist"] = readmeExist | |||
| if readmeExist { | |||
| ctx.Data["FileContent"] = string(base.RenderMarkdown(data, "")) | |||
| @@ -193,7 +193,7 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| files := make([][]interface{}, 0, len(entries)) | |||
| for _, te := range entries { | |||
| c, err := ctx.Repo.Commit.GetCommitOfRelPath(filepath.Join(treePath, te.Name)) | |||
| c, err := ctx.Repo.Commit.GetCommitOfRelPath(filepath.Join(treePath, te.Name())) | |||
| if err != nil { | |||
| ctx.Handle(404, "repo.Single(SubTree)", err) | |||
| return | |||
| @@ -207,7 +207,7 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| var readmeFile *git.Blob | |||
| for _, f := range entries { | |||
| if !f.IsFile() || !base.IsReadmeFile(f.Name) { | |||
| if f.IsDir() || !base.IsReadmeFile(f.Name()) { | |||
| continue | |||
| } else { | |||
| readmeFile = f.Blob() | |||
| @@ -260,32 +260,6 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| ctx.HTML(200, "repo/single") | |||
| } | |||
| func SingleDownload(ctx *middleware.Context, params martini.Params) { | |||
| // Get tree path | |||
| treename := params["_1"] | |||
| blob, err := ctx.Repo.Commit.GetBlobByPath(treename) | |||
| if err != nil { | |||
| ctx.Handle(404, "repo.SingleDownload(GetBlobByPath)", err) | |||
| return | |||
| } | |||
| data, err := blob.Data() | |||
| if err != nil { | |||
| ctx.Handle(404, "repo.SingleDownload(Data)", err) | |||
| return | |||
| } | |||
| contentType, isTextFile := base.IsTextFile(data) | |||
| _, isImageFile := base.IsImageFile(data) | |||
| ctx.Res.Header().Set("Content-Type", contentType) | |||
| if !isTextFile && !isImageFile { | |||
| ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(treename)) | |||
| ctx.Res.Header().Set("Content-Transfer-Encoding", "binary") | |||
| } | |||
| ctx.Res.Write(data) | |||
| } | |||
| func basicEncode(username, password string) string { | |||
| auth := username + ":" + password | |||
| return base64.StdEncoding.EncodeToString([]byte(auth)) | |||
| @@ -176,6 +176,7 @@ func runWeb(*cli.Context) { | |||
| r.Get("/commit/:branchname", repo.Diff) | |||
| r.Get("/commit/:branchname/**", repo.Diff) | |||
| r.Get("/releases", repo.Releases) | |||
| r.Get("/archive/:branchname/:reponame.zip", repo.ZipDownload) | |||
| }, ignSignIn, middleware.RepoAssignment(true, true)) | |||
| m.Group("/:username", func(r martini.Router) { | |||