From 645da2b2ef2be1f16e97a943d5900d0503ed2171 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Tue, 7 Jul 2020 15:40:12 +0300 Subject: [PATCH] HandleDir: add Attachments options to DirOptions have a bit more work to do on that, if Gzip option is true then it does not work and it's not the 'if gzip' statement inside the handler Former-commit-id: 866578d29b6a63ee60a22b0eb9b37288c717b7e2 --- _examples/file-server/file-server/main.go | 13 ++++++++- aliases.go | 3 ++ core/router/fs.go | 35 +++++++++++++++++++++-- go.mod | 4 +-- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/_examples/file-server/file-server/main.go b/_examples/file-server/file-server/main.go index 7531d504..993cd7a5 100644 --- a/_examples/file-server/file-server/main.go +++ b/_examples/file-server/file-server/main.go @@ -54,8 +54,19 @@ func main() { filesRouter := app.Party("/files") { filesRouter.HandleDir("/", uploadDir, iris.DirOptions{ - Gzip: true, + Gzip: false, ShowList: true, + + // Optionally, force-send files to the client inside of showing to the browser. + Attachments: iris.Attachments{ + Enable: true, + // Optionally, control data sent per second: + Limit: 50.0 * iris.KB, + Burst: 100 * iris.KB, + // Change the destination name through: + // NameFunc: func(systemName string) string {...} + }, + DirList: iris.DirListRich(iris.DirListRichOptions{ // Optionally, use a custom template for listing: // Tmpl: dirListRichTemplate, diff --git a/aliases.go b/aliases.go index 6d5cde24..a1c6bc13 100644 --- a/aliases.go +++ b/aliases.go @@ -98,6 +98,9 @@ type ( // `FileServer` and `Party#HandleDir` can use to serve files and assets. // A shortcut for the `router.DirOptions`, useful when `FileServer` or `HandleDir` is being used. DirOptions = router.DirOptions + // Attachments options for files to be downloaded and saved locally by the client. + // See `DirOptions`. + Attachments = router.Attachments // DirListRichOptions the options for the `DirListRich` helper function. // A shortcut for the `router.DirListRichOptions`. // Useful when `DirListRich` function is passed to `DirOptions.DirList` field. diff --git a/core/router/fs.go b/core/router/fs.go index dff49d3f..0ff5a645 100644 --- a/core/router/fs.go +++ b/core/router/fs.go @@ -24,6 +24,19 @@ const indexName = "/index.html" // DirListFunc is the function signature for customizing directory and file listing. type DirListFunc func(ctx context.Context, dirName string, dir http.File) error +// Attachments options for files to be downloaded and saved locally by the client. +// See `DirOptions`. +type Attachments struct { + // Set to true to enable the files to be downloaded and + // saved locally by the client, instead of serving the file. + Enable bool + // Options to send files with a limit of bytes sent per second. + Limit float64 + Burst int + // Use this function to change the sent filename. + NameFunc func(systemName string) (attachmentName string) +} + // DirOptions contains the optional settings that // `FileServer` and `Party#HandleDir` can use to serve files and assets. type DirOptions struct { @@ -37,9 +50,16 @@ type DirOptions struct { // List the files inside the current requested directory if `IndexName` not found. ShowList bool - // If `ShowList` is true then this function will be used instead of the default one to show the list of files of a current requested directory(dir). + // If `ShowList` is true then this function will be used instead + // of the default one to show the list of files of a current requested directory(dir). + // See `DirListRich` package-level function too. DirList DirListFunc + // Files downloaded and saved locally. + // Gzip option MUST be false in order for this to work. + // TODO(@kataras): find a way to make it work. + Attachments Attachments + // When embedded. Asset func(name string) ([]byte, error) // we need this to make it compatible os.File. AssetInfo func(name string) (os.FileInfo, error) // we need this for range support on embedded files. @@ -343,6 +363,7 @@ func FileServer(directory string, opts ...DirOptions) context.Handler { // if false then check if the dev did something like `ctx.Gzip(true)`. _, gzip = ctx.ResponseWriter().(*context.GzipResponseWriter) } + // ctx.Gzip(options.Gzip) f, err := fs.Open(name) if err != nil { @@ -454,7 +475,17 @@ func FileServer(directory string, opts ...DirOptions) context.Handler { return } - http.ServeContent(ctx.ResponseWriter(), ctx.Request(), info.Name(), info.ModTime(), f) + if options.Attachments.Enable { + destName := info.Name() + if nameFunc := options.Attachments.NameFunc; nameFunc != nil { + destName = nameFunc(destName) + } + + ctx.ResponseWriter().Header().Set(context.ContentDispositionHeaderKey, "attachment;filename="+destName) + } + + // If limit is 0 then same as ServeContent. + ctx.ServeContentWithRate(f, info.Name(), info.ModTime(), options.Attachments.Limit, options.Attachments.Burst) if serveCode := ctx.GetStatusCode(); context.StatusCodeNotSuccessful(serveCode) { plainStatusCode(ctx, serveCode) return diff --git a/go.mod b/go.mod index f536f382..59982028 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/kataras/pio v0.0.8 github.com/kataras/sitemap v0.0.5 github.com/klauspost/compress v1.10.10 - github.com/mediocregopher/radix/v3 v3.5.1 + github.com/mediocregopher/radix/v3 v3.5.2 github.com/microcosm-cc/bluemonday v1.0.3 github.com/ryanuber/columnize v2.1.0+incompatible github.com/schollz/closestmatch v2.1.0+incompatible @@ -33,7 +33,7 @@ require ( github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1 go.etcd.io/bbolt v1.3.5 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 + golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae golang.org/x/text v0.3.3 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e