diff --git a/.travis.yml b/.travis.yml index 6899832..dd4af48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ jobs: - go: 1.13.x - go: 1.14.x - go: 1.15.x + - go: 1.16.x - go: master install: diff --git a/README.md b/README.md index 75640ac..132f714 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ import "github.com/gin-contrib/static" See the [example](example) [embedmd]:# (example/simple/example.go go) + +#### Serve local file ```go package main @@ -52,3 +54,34 @@ func main() { r.Run(":8080") } ``` + +#### Serve embed folder +```go +package main + +import ( + "embed" + "fmt" + "net/http" + + "github.com/gin-contrib/static" + "github.com/gin-gonic/gin" +) + +//go:embed tmp/server +var server embed.FS + +func main() { + r := gin.Default() + r.Use(static.Serve("/", static.EmbedFolder(server, "tmp/server"))) + r.GET("/ping", func(c *gin.Context) { + c.String(200, "test") + }) + r.NoRoute(func (c *gin.Context) { + fmt.Printf("%s doesn't exists, redirect on /\n", c.Request.URL.Path) + c.Redirect(http.StatusMovedPermanently, "/") + }) + // Listen and Server in 0.0.0.0:8080 + r.Run(":8080") +} +``` \ No newline at end of file diff --git a/embed_folder.go b/embed_folder.go new file mode 100644 index 0000000..15c211c --- /dev/null +++ b/embed_folder.go @@ -0,0 +1,27 @@ +package static + +import ( + "embed" + "io/fs" + "log" + "net/http" +) + +type embedFileSystem struct { + http.FileSystem +} + +func (e embedFileSystem) Exists(prefix string, path string) bool { + _, err := e.Open(path) + return err == nil +} + +func EmbedFolder(fsEmbed embed.FS, targetPath string) ServeFileSystem { + fsys, err := fs.Sub(fsEmbed, targetPath) + if err != nil { + log.Fatalf("static.EmbedFolder - Invalid targetPath value - %s", err) + } + return embedFileSystem{ + FileSystem: http.FS(fsys), + } +} diff --git a/embed_folder_test.go b/embed_folder_test.go new file mode 100644 index 0000000..65ea122 --- /dev/null +++ b/embed_folder_test.go @@ -0,0 +1,40 @@ +package static + +import ( + "embed" + "fmt" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" +) + +//go:embed test/data/server +var server embed.FS + +var embedTests = []struct { + targetURL string // input + httpCode int // expected http code + httpBody string // expected http body + name string // test name +}{ + {"/404.html", 301, "Moved Permanently.\n\n", "Unknown file"}, + {"/", 200, "

Hello Embed

", "Root"}, + {"/index.html", 301, "", "Root by file name automatic redirect"}, + {"/static.html", 200, "

Hello Gin Static

", "Other file"}, +} + +func TestEmbedFolder(t *testing.T) { + router := gin.New() + router.Use(Serve("/", EmbedFolder(server, "test/data/server"))) + router.NoRoute(func(c *gin.Context) { + fmt.Printf("%s doesn't exists, redirect on /\n", c.Request.URL.Path) + c.Redirect(301, "/") + }) + + for _, tt := range embedTests { + w := PerformRequest(router, "GET", tt.targetURL) + assert.Equal(t, tt.httpCode, w.Code, tt.name) + assert.Equal(t, tt.httpBody, w.Body.String(), tt.name) + } +} diff --git a/go.mod b/go.mod index 1fb38e3..8881dcd 100644 --- a/go.mod +++ b/go.mod @@ -6,4 +6,4 @@ require ( github.com/stretchr/testify v1.4.0 ) -go 1.13 +go 1.16 diff --git a/local_file.go b/local_file.go new file mode 100644 index 0000000..f67f08d --- /dev/null +++ b/local_file.go @@ -0,0 +1,47 @@ +package static + +import ( + "net/http" + "os" + "path" + "strings" + + "github.com/gin-gonic/gin" +) + +const INDEX = "index.html" + +type localFileSystem struct { + http.FileSystem + root string + indexes bool +} + +func LocalFile(root string, indexes bool) *localFileSystem { + return &localFileSystem{ + FileSystem: gin.Dir(root, indexes), + root: root, + indexes: indexes, + } +} + +func (l *localFileSystem) Exists(prefix string, filepath string) bool { + if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) { + name := path.Join(l.root, p) + stats, err := os.Stat(name) + if err != nil { + return false + } + if stats.IsDir() { + if !l.indexes { + index := path.Join(name, INDEX) + _, err := os.Stat(index) + if err != nil { + return false + } + } + } + return true + } + return false +} diff --git a/local_file_test.go b/local_file_test.go new file mode 100644 index 0000000..0ab922a --- /dev/null +++ b/local_file_test.go @@ -0,0 +1,34 @@ +package static + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" +) + +func TestLocalFile(t *testing.T) { + // SETUP file + testRoot, _ := os.Getwd() + f, err := ioutil.TempFile(testRoot, "") + if err != nil { + t.Error(err) + } + defer os.Remove(f.Name()) + f.WriteString("Gin Web Framework") + f.Close() + + dir, filename := filepath.Split(f.Name()) + router := gin.New() + router.Use(Serve("/", LocalFile(dir, true))) + + w := PerformRequest(router, "GET", "/"+filename) + assert.Equal(t, w.Code, 200) + assert.Equal(t, w.Body.String(), "Gin Web Framework") + + w = PerformRequest(router, "GET", "/") + assert.Contains(t, w.Body.String(), `