diff --git a/README.md b/README.md
index 9dde693d..dfc98fb2 100644
--- a/README.md
+++ b/README.md
@@ -1228,13 +1228,17 @@ func main() {
### HTML rendering
-Using LoadHTMLGlob() or LoadHTMLFiles()
+Using LoadHTMLGlob(), LoadHTMLFiles() or LoadHTMLFilesRecursively
```go
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
+
+ // load recursively all .html files in "public" folder
+ //router.LoadHTMLFilesRecursively("public", []string{".html"})
+
router.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
diff --git a/gin.go b/gin.go
index 1c2acbc8..32d0d149 100644
--- a/gin.go
+++ b/gin.go
@@ -11,6 +11,9 @@ import (
"net/http"
"os"
"path"
+ "path/filepath"
+ "sort"
+ "strings"
"sync"
"github.com/gin-gonic/gin/internal/bytesconv"
@@ -205,6 +208,26 @@ func (engine *Engine) LoadHTMLFiles(files ...string) {
engine.SetHTMLTemplate(templ)
}
+// LoadHTMLFilesRecursively loads recursively a slice of HTML files mathing an extension
+// and associates the result with HTML renderer.
+func (engine *Engine) LoadHTMLFilesRecursively(folder string, extensionsAllowed []string) {
+
+ files := []string{}
+ sort.Strings(extensionsAllowed)
+
+ filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
+ extension := strings.ToLower(filepath.Ext(path))
+ indexFound := sort.SearchStrings(extensionsAllowed, extension)
+ if indexFound < len(extensionsAllowed) && extensionsAllowed[indexFound] == extension {
+ files = append(files, path)
+ }
+
+ return nil
+ })
+
+ engine.LoadHTMLFiles(files...)
+}
+
// SetHTMLTemplate associate a template with HTML renderer.
func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
if len(engine.trees) > 0 {
diff --git a/gin_test.go b/gin_test.go
index 11bdd79c..56da0e4e 100644
--- a/gin_test.go
+++ b/gin_test.go
@@ -58,77 +58,134 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool, loadMethod func(*Engine
return ts
}
-func TestLoadHTMLGlobDebugMode(t *testing.T) {
- ts := setupHTMLFiles(
- t,
- DebugMode,
- false,
- func(router *Engine) {
- router.LoadHTMLGlob("./testdata/template/*")
- },
- )
- defer ts.Close()
-
- res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
- if err != nil {
- fmt.Println(err)
- }
-
- resp, _ := ioutil.ReadAll(res.Body)
- assert.Equal(t, "
Hello world
", string(resp))
+func setupHTMLFiles(t *testing.T, mode string, tls bool) func() {
+ go func() {
+ SetMode(mode)
+ router := New()
+ router.Delims("{[{", "}]}")
+ router.SetFuncMap(template.FuncMap{
+ "formatAsDate": formatAsDate,
+ })
+ router.LoadHTMLFiles("./fixtures/basic/hello.tmpl", "./fixtures/basic/raw.tmpl")
+ router.GET("/test", func(c *Context) {
+ c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
+ })
+ router.GET("/raw", func(c *Context) {
+ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
+ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
+ })
+ })
+ if tls {
+ // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1`
+ router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem")
+ } else {
+ router.Run(":8888")
+ }
+ }()
+ t.Log("waiting 1 second for server startup")
+ time.Sleep(1 * time.Second)
+ return func() {}
}
-func TestLoadHTMLGlobTestMode(t *testing.T) {
- ts := setupHTMLFiles(
- t,
- TestMode,
- false,
- func(router *Engine) {
- router.LoadHTMLGlob("./testdata/template/*")
- },
- )
- defer ts.Close()
-
- res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
- if err != nil {
- fmt.Println(err)
- }
-
- resp, _ := ioutil.ReadAll(res.Body)
- assert.Equal(t, "Hello world
", string(resp))
+func setupHTMLGlob(t *testing.T, mode string, tls bool) func() {
+ go func() {
+ SetMode(mode)
+ router := New()
+ router.Delims("{[{", "}]}")
+ router.SetFuncMap(template.FuncMap{
+ "formatAsDate": formatAsDate,
+ })
+ router.LoadHTMLGlob("./fixtures/basic/*")
+ router.GET("/test", func(c *Context) {
+ c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
+ })
+ router.GET("/raw", func(c *Context) {
+ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
+ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
+ })
+ })
+ if tls {
+ // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1`
+ router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem")
+ } else {
+ router.Run(":8888")
+ }
+ }()
+ t.Log("waiting 1 second for server startup")
+ time.Sleep(1 * time.Second)
+ return func() {}
}
-func TestLoadHTMLGlobReleaseMode(t *testing.T) {
- ts := setupHTMLFiles(
- t,
- ReleaseMode,
- false,
- func(router *Engine) {
- router.LoadHTMLGlob("./testdata/template/*")
- },
- )
- defer ts.Close()
+func setupHTMLFilesRecursively(t *testing.T, mode string, tls bool) func() {
+ go func() {
+ SetMode(mode)
+ router := New()
+ router.Delims("{[{", "}]}")
+ router.SetFuncMap(template.FuncMap{
+ "formatAsDate": formatAsDate,
+ })
+ router.LoadHTMLFilesRecursively("./fixtures/basic/", []string{".tmpl"})
+ router.GET("/test", func(c *Context) {
+ c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
+ })
+ router.GET("/raw", func(c *Context) {
+ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
+ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
+ })
+ })
+ if tls {
+ // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1`
+ router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem")
+ } else {
+ router.Run(":8888")
+ }
+ }()
+ t.Log("waiting 1 second for server startup")
+ time.Sleep(1 * time.Second)
+ return func() {}
+}
- res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
+func TestLoadHTMLGlob(t *testing.T) {
+ td := setupHTMLGlob(t, DebugMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/test")
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
- assert.Equal(t, "Hello world
", string(resp))
+ assert.Equal(t, "Hello world
", string(resp[:]))
+
+ td()
+}
+
+func TestLoadHTMLGlob2(t *testing.T) {
+ td := setupHTMLGlob(t, TestMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/test")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp[:]))
+
+ td()
+}
+
+func TestLoadHTMLGlob3(t *testing.T) {
+ td := setupHTMLGlob(t, ReleaseMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/test")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp[:]))
+
+ td()
}
func TestLoadHTMLGlobUsingTLS(t *testing.T) {
- ts := setupHTMLFiles(
- t,
- DebugMode,
- true,
- func(router *Engine) {
- router.LoadHTMLGlob("./testdata/template/*")
- },
- )
- defer ts.Close()
-
+ td := setupHTMLGlob(t, DebugMode, true)
// Use InsecureSkipVerify for avoiding `x509: certificate signed by unknown authority` error
tr := &http.Transport{
TLSClientConfig: &tls.Config{
@@ -136,33 +193,29 @@ func TestLoadHTMLGlobUsingTLS(t *testing.T) {
},
}
client := &http.Client{Transport: tr}
- res, err := client.Get(fmt.Sprintf("%s/test", ts.URL))
+ res, err := client.Get("https://127.0.0.1:9999/test")
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
- assert.Equal(t, "Hello world
", string(resp))
+ assert.Equal(t, "Hello world
", string(resp[:]))
+
+ td()
}
func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
- ts := setupHTMLFiles(
- t,
- DebugMode,
- false,
- func(router *Engine) {
- router.LoadHTMLGlob("./testdata/template/*")
- },
- )
- defer ts.Close()
-
- res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL))
+ time.Now()
+ td := setupHTMLGlob(t, DebugMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/raw")
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
- assert.Equal(t, "Date: 2017/07/01\n", string(resp))
+ assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))
+
+ td()
}
func init() {
@@ -283,6 +336,75 @@ func TestLoadHTMLFilesFuncMap(t *testing.T) {
assert.Equal(t, "Date: 2017/07/01\n", string(resp))
}
+func TestLoadHTMLFilesRecursively(t *testing.T) {
+ td := setupHTMLFilesRecursively(t, TestMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/test")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp[:]))
+ td()
+}
+
+func TestLoadHTMLFilesRecursively2(t *testing.T) {
+ td := setupHTMLFilesRecursively(t, DebugMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/test")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp[:]))
+ td()
+}
+
+func TestLoadHTMLFilesRecursively3(t *testing.T) {
+ td := setupHTMLFilesRecursively(t, ReleaseMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/test")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp[:]))
+ td()
+}
+
+func TestLoadHTMLFilesRecursivelyUsingTLS(t *testing.T) {
+ td := setupHTMLFilesRecursively(t, TestMode, true)
+ // Use InsecureSkipVerify for avoiding `x509: certificate signed by unknown authority` error
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+ client := &http.Client{Transport: tr}
+ res, err := client.Get("https://127.0.0.1:9999/test")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp[:]))
+ td()
+}
+
+func TestLoadHTMLFilesRecursivelyFuncMap(t *testing.T) {
+ time.Now()
+ td := setupHTMLFilesRecursively(t, TestMode, false)
+ res, err := http.Get("http://127.0.0.1:8888/raw")
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))
+
+ td()
+}
+
func TestAddRoute(t *testing.T) {
router := New()
router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}})