From c460cba7293d5d15c52237344c4d482bdc143795 Mon Sep 17 00:00:00 2001 From: kiyon Date: Tue, 28 Jul 2020 16:48:05 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=F0=9F=91=B7=20add=20app.Stack=20test=20cas?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app_test.go b/app_test.go index dd872986..fc5384a0 100644 --- a/app_test.go +++ b/app_test.go @@ -835,3 +835,24 @@ func Test_App_Init_Error_View(t *testing.T) { }() _ = app.Settings.Views.Render(nil, "", nil) } + +func Test_App_Stack(t *testing.T) { + app := New() + + app.Use("/path0", func(_ *Ctx) {}) + app.Get("/path1", func(_ *Ctx) {}) + app.Get("/path2", func(_ *Ctx) {}) + app.Post("/path3", func(_ *Ctx) {}) + + stack := app.Stack() + utils.AssertEqual(t, 9, len(stack)) + utils.AssertEqual(t, 3, len(stack[methodInt(MethodGet)])) + utils.AssertEqual(t, 3, len(stack[methodInt(MethodHead)])) + utils.AssertEqual(t, 2, len(stack[methodInt(MethodPost)])) + utils.AssertEqual(t, 1, len(stack[methodInt(MethodPut)])) + utils.AssertEqual(t, 1, len(stack[methodInt(MethodPatch)])) + utils.AssertEqual(t, 1, len(stack[methodInt(MethodDelete)])) + utils.AssertEqual(t, 1, len(stack[methodInt(MethodConnect)])) + utils.AssertEqual(t, 1, len(stack[methodInt(MethodOptions)])) + utils.AssertEqual(t, 1, len(stack[methodInt(MethodTrace)])) +} From d15aae1e566600488053093caf1ddcf885c4a546 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 08:46:36 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=91=B7=20add=20app.init=20test=20case?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_test.go | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/app_test.go b/app_test.go index fc5384a0..aa6d88f2 100644 --- a/app_test.go +++ b/app_test.go @@ -5,12 +5,14 @@ package fiber import ( + "bytes" "crypto/tls" "errors" "fmt" "io" "io/ioutil" "net" + "net/http" "net/http/httptest" "reflect" "regexp" @@ -856,3 +858,83 @@ func Test_App_Stack(t *testing.T) { utils.AssertEqual(t, 1, len(stack[methodInt(MethodOptions)])) utils.AssertEqual(t, 1, len(stack[methodInt(MethodTrace)])) } + +// go test -run Test_App_ReadTimeout +func Test_App_ReadTimeout(t *testing.T) { + app := New(&Settings{ + ReadTimeout: time.Nanosecond, + DisableStartupMessage: true, + }) + + app.Get("/read-timeout", func(c *Ctx) { + c.SendString("I should not be sent") + }) + + go func() { + time.Sleep(500 * time.Millisecond) + resp, err := http.Get("http://127.0.0.1:4004/read-timeout") + if resp != nil { + utils.AssertEqual(t, 408, resp.StatusCode) + } + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, nil, app.Shutdown()) + }() + + utils.AssertEqual(t, nil, app.Listen(4004)) +} + +// go test -run Test_App_BadRequest +func Test_App_BadRequest(t *testing.T) { + app := New(&Settings{ + DisableStartupMessage: true, + }) + + app.Get("/bad-request", func(c *Ctx) { + c.SendString("I should not be sent") + }) + + go func() { + time.Sleep(500 * time.Millisecond) + conn, err := net.Dial("tcp4", "127.0.0.1:4004") + utils.AssertEqual(t, nil, err) + defer conn.Close() + + _, err = conn.Write([]byte("BadRequest\r\n")) + utils.AssertEqual(t, nil, err) + + buf := make([]byte, 1024) + var n int + n, err = conn.Read(buf) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, true, bytes.Contains(buf[:n], []byte("400 Bad Request"))) + + utils.AssertEqual(t, nil, app.Shutdown()) + }() + + utils.AssertEqual(t, nil, app.Listen(4004)) +} + +// go test -run Test_App_SmallReadBuffer +func Test_App_SmallReadBuffer(t *testing.T) { + app := New(&Settings{ + ReadBufferSize: 1, + DisableStartupMessage: true, + }) + + app.Get("/small-read-buffer", func(c *Ctx) { + c.SendString("I should not be sent") + }) + + go func() { + time.Sleep(500 * time.Millisecond) + resp, err := http.Get("http://127.0.0.1:4004/small-read-buffer") + if resp != nil { + utils.AssertEqual(t, 431, resp.StatusCode) + } + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, nil, app.Shutdown()) + }() + + utils.AssertEqual(t, nil, app.Listen(4004)) +} From 377972350722a471a0219592191d021b07e29510 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 09:14:15 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=91=B7=20add=20app.Test=20test=20case?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_test.go | 17 +++++++++++++++++ utils.go | 1 - 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app_test.go b/app_test.go index aa6d88f2..4b0848ef 100644 --- a/app_test.go +++ b/app_test.go @@ -815,6 +815,23 @@ func Test_Test_Timeout(t *testing.T) { utils.AssertEqual(t, true, err != nil, "app.Test(req)") } +type errorReader int + +func (errorReader) Read([]byte) (int, error) { + return 0, errors.New("errorReader") +} + +func Test_Test_DumpError(t *testing.T) { + app := New() + app.Settings.DisableStartupMessage = true + + app.Get("/", func(_ *Ctx) {}) + + resp, err := app.Test(httptest.NewRequest("GET", "/", errorReader(0))) + utils.AssertEqual(t, true, resp == nil) + utils.AssertEqual(t, "errorReader", err.Error()) +} + func Test_App_Handler(t *testing.T) { h := New().Handler() utils.AssertEqual(t, "fasthttp.RequestHandler", reflect.TypeOf(h).String()) diff --git a/utils.go b/utils.go index 903c9389..5f578dc5 100644 --- a/utils.go +++ b/utils.go @@ -248,7 +248,6 @@ func (a testAddr) String() string { } type testConn struct { - net.Conn r bytes.Buffer w bytes.Buffer } From 5ee5418b36e3db1c84e1d93920792de9b9b65734 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 10:03:47 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=91=B7=20add=20ctx.SendFile=20test=20?= =?UTF-8?q?cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ctx_test.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ctx_test.go b/ctx_test.go index 9ce93b20..ff0bfbaf 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -1259,13 +1259,20 @@ func Test_Ctx_SendFile(t *testing.T) { utils.AssertEqual(t, StatusNotModified, ctx.Fasthttp.Response.StatusCode()) utils.AssertEqual(t, []byte(nil), ctx.Fasthttp.Response.Body()) app.ReleaseCtx(ctx) +} - // test 404 - // ctx = app.AcquireCtx(&fasthttp.RequestCtx{}) - // err = ctx.SendFile("./john_doe.go") - // // check expectation - // utils.AssertEqual(t, StatusNotFound, ctx.Fasthttp.Response.StatusCode()) - // app.ReleaseCtx(ctx) +// go test -race -run Test_Ctx_SendFile_404 +func Test_Ctx_SendFile_404(t *testing.T) { + t.Parallel() + app := New() + app.Get("/", func(ctx *Ctx) { + err := ctx.SendFile("./john_dow.go/") + utils.AssertEqual(t, false, err == nil) + }) + + resp, err := app.Test(httptest.NewRequest("GET", "/", nil)) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, StatusNotFound, resp.StatusCode) } // go test -race -run Test_Ctx_SendFile_Immutable From 7863cd14588335d65ccbc53a1fbb590c5b6a70d9 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 11:07:47 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=91=B7=20add=20ctx.Render=20test=20ca?= =?UTF-8?q?ses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/TEST_DATA/template-invalid.html | 1 + ctx.go | 11 +-------- ctx_test.go | 31 ++++++++++++++++++++++++- utils.go | 14 +++++++++++ 4 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 .github/TEST_DATA/template-invalid.html diff --git a/.github/TEST_DATA/template-invalid.html b/.github/TEST_DATA/template-invalid.html new file mode 100644 index 00000000..ac4f6d13 --- /dev/null +++ b/.github/TEST_DATA/template-invalid.html @@ -0,0 +1 @@ +

{{.Title}

diff --git a/ctx.go b/ctx.go index 8c2c84ff..f3f4d940 100644 --- a/ctx.go +++ b/ctx.go @@ -15,7 +15,6 @@ import ( "log" "mime/multipart" "net/http" - "os" "path/filepath" "strconv" "strings" @@ -791,15 +790,7 @@ func (ctx *Ctx) Render(name string, bind interface{}, layouts ...string) (err er } else { // Render raw template using 'name' as filepath if no engine is set var tmpl *template.Template - // Read file - f, err := os.Open(filepath.Clean(name)) - if err != nil { - return err - } - if _, err = buf.ReadFrom(f); err != nil { - return err - } - if err = f.Close(); err != nil { + if _, err = readContent(buf, name); err != nil { return err } // Parse template diff --git a/ctx_test.go b/ctx_test.go index ff0bfbaf..d10225c1 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -10,6 +10,7 @@ package fiber import ( "bufio" "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -1500,7 +1501,10 @@ func Test_Ctx_Render(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, "

Hello, World!

", string(ctx.Fasthttp.Response.Body())) - err = ctx.Render("./.github/TEST_DATA/invalid.html", nil) + err = ctx.Render("./.github/TEST_DATA/template-non-exists.html", nil) + utils.AssertEqual(t, false, err == nil) + + err = ctx.Render("./.github/TEST_DATA/template-invalid.html", nil) utils.AssertEqual(t, false, err == nil) } @@ -1533,6 +1537,7 @@ func Test_Ctx_Render_Engine(t *testing.T) { utils.AssertEqual(t, "

Hello, World!

", string(ctx.Fasthttp.Response.Body())) } +// go test -v -run=^$ -bench=Benchmark_Ctx_Render_Engine -benchmem -count=4 func Benchmark_Ctx_Render_Engine(b *testing.B) { engine := &testTemplateEngine{} err := engine.Load() @@ -1552,19 +1557,43 @@ func Benchmark_Ctx_Render_Engine(b *testing.B) { utils.AssertEqual(b, "

Hello, World!

", string(ctx.Fasthttp.Response.Body())) } +type errorTemplateEngine struct{} + +func (t errorTemplateEngine) Render(w io.Writer, name string, bind interface{}, layout ...string) error { + return errors.New("errorTemplateEngine") +} + +func (t errorTemplateEngine) Load() error { return nil } + +// go test -run Test_Ctx_Render_Engine_Error +func Test_Ctx_Render_Engine_Error(t *testing.T) { + app := New() + app.Settings.Views = errorTemplateEngine{} + ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(ctx) + err := ctx.Render("index.tmpl", nil) + utils.AssertEqual(t, false, err == nil) +} + // go test -run Test_Ctx_Render_Go_Template func Test_Ctx_Render_Go_Template(t *testing.T) { t.Parallel() + file, err := ioutil.TempFile(os.TempDir(), "fiber") utils.AssertEqual(t, nil, err) defer os.Remove(file.Name()) + _, err = file.Write([]byte("template")) utils.AssertEqual(t, nil, err) + err = file.Close() utils.AssertEqual(t, nil, err) + app := New() + ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(ctx) + err = ctx.Render(file.Name(), nil) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, "template", string(ctx.Fasthttp.Response.Body())) diff --git a/utils.go b/utils.go index 5f578dc5..eaa7c7b7 100644 --- a/utils.go +++ b/utils.go @@ -8,7 +8,10 @@ import ( "bytes" "fmt" "hash/crc32" + "io" "net" + "os" + "path/filepath" "strings" "time" @@ -17,6 +20,17 @@ import ( fasthttp "github.com/valyala/fasthttp" ) +// readContent opens a named file and read content from it +func readContent(rf io.ReaderFrom, name string) (int64, error) { + // Read file + f, err := os.Open(filepath.Clean(name)) + if err != nil { + return 0, err + } + defer f.Close() + return rf.ReadFrom(f) +} + // quoteString escape special characters in a given string func quoteString(raw string) string { bb := bytebufferpool.Get() From 9cac73e7bad26359a79970656d41fb20c3bec5c1 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 11:29:27 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=91=B7=20fix=20Security=20/=20Gosec,?= =?UTF-8?q?=20handle=20f.Close=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils.go b/utils.go index eaa7c7b7..9852f834 100644 --- a/utils.go +++ b/utils.go @@ -21,13 +21,15 @@ import ( ) // readContent opens a named file and read content from it -func readContent(rf io.ReaderFrom, name string) (int64, error) { +func readContent(rf io.ReaderFrom, name string) (n int64, err error) { // Read file f, err := os.Open(filepath.Clean(name)) if err != nil { return 0, err } - defer f.Close() + defer func() { + err = f.Close() + }() return rf.ReadFrom(f) } From dd33a797726e0cfbbfee5248c1c0c6fdebc421f8 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 13:08:33 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=F0=9F=91=B7=20improve=20read=20timeout=20t?= =?UTF-8?q?est=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_test.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/app_test.go b/app_test.go index 4b0848ef..3bc2484b 100644 --- a/app_test.go +++ b/app_test.go @@ -880,7 +880,9 @@ func Test_App_Stack(t *testing.T) { func Test_App_ReadTimeout(t *testing.T) { app := New(&Settings{ ReadTimeout: time.Nanosecond, + IdleTimeout: time.Minute, DisableStartupMessage: true, + DisableKeepalive: true, }) app.Get("/read-timeout", func(c *Ctx) { @@ -889,11 +891,21 @@ func Test_App_ReadTimeout(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) - resp, err := http.Get("http://127.0.0.1:4004/read-timeout") - if resp != nil { - utils.AssertEqual(t, 408, resp.StatusCode) - } + + conn, err := net.Dial("tcp4", "127.0.0.1:4004") utils.AssertEqual(t, nil, err) + defer conn.Close() + + _, err = conn.Write([]byte("HEAD /read-timeout HTTP/1.1\r\n")) + utils.AssertEqual(t, nil, err) + + buf := make([]byte, 1024) + var n int + n, err = conn.Read(buf) + + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, true, bytes.Contains(buf[:n], []byte("408 Request Timeout"))) + utils.AssertEqual(t, nil, app.Shutdown()) }() From 0d4b3c4c27a8baac78a9a040a3919da8c5e4acce Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 14:52:13 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=F0=9F=91=B7=20use=20different=20port=20in?= =?UTF-8?q?=20every=20test=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app_test.go b/app_test.go index 3bc2484b..14025f64 100644 --- a/app_test.go +++ b/app_test.go @@ -924,7 +924,7 @@ func Test_App_BadRequest(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) - conn, err := net.Dial("tcp4", "127.0.0.1:4004") + conn, err := net.Dial("tcp4", "127.0.0.1:4005") utils.AssertEqual(t, nil, err) defer conn.Close() @@ -941,7 +941,7 @@ func Test_App_BadRequest(t *testing.T) { utils.AssertEqual(t, nil, app.Shutdown()) }() - utils.AssertEqual(t, nil, app.Listen(4004)) + utils.AssertEqual(t, nil, app.Listen(4005)) } // go test -run Test_App_SmallReadBuffer @@ -957,7 +957,7 @@ func Test_App_SmallReadBuffer(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) - resp, err := http.Get("http://127.0.0.1:4004/small-read-buffer") + resp, err := http.Get("http://127.0.0.1:4006/small-read-buffer") if resp != nil { utils.AssertEqual(t, 431, resp.StatusCode) } @@ -965,5 +965,5 @@ func Test_App_SmallReadBuffer(t *testing.T) { utils.AssertEqual(t, nil, app.Shutdown()) }() - utils.AssertEqual(t, nil, app.Listen(4004)) + utils.AssertEqual(t, nil, app.Listen(4006)) } From 96b571165a1001eadaa1a6c397bb78e491a42d26 Mon Sep 17 00:00:00 2001 From: kiyon Date: Wed, 29 Jul 2020 15:18:49 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=91=B7=20remove=20read=20timeout=20te?= =?UTF-8?q?st=20case=20temporarily?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_test.go | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/app_test.go b/app_test.go index 14025f64..11923df4 100644 --- a/app_test.go +++ b/app_test.go @@ -877,40 +877,40 @@ func Test_App_Stack(t *testing.T) { } // go test -run Test_App_ReadTimeout -func Test_App_ReadTimeout(t *testing.T) { - app := New(&Settings{ - ReadTimeout: time.Nanosecond, - IdleTimeout: time.Minute, - DisableStartupMessage: true, - DisableKeepalive: true, - }) - - app.Get("/read-timeout", func(c *Ctx) { - c.SendString("I should not be sent") - }) - - go func() { - time.Sleep(500 * time.Millisecond) - - conn, err := net.Dial("tcp4", "127.0.0.1:4004") - utils.AssertEqual(t, nil, err) - defer conn.Close() - - _, err = conn.Write([]byte("HEAD /read-timeout HTTP/1.1\r\n")) - utils.AssertEqual(t, nil, err) - - buf := make([]byte, 1024) - var n int - n, err = conn.Read(buf) - - utils.AssertEqual(t, nil, err) - utils.AssertEqual(t, true, bytes.Contains(buf[:n], []byte("408 Request Timeout"))) - - utils.AssertEqual(t, nil, app.Shutdown()) - }() - - utils.AssertEqual(t, nil, app.Listen(4004)) -} +//func Test_App_ReadTimeout(t *testing.T) { +// app := New(&Settings{ +// ReadTimeout: time.Nanosecond, +// IdleTimeout: time.Minute, +// DisableStartupMessage: true, +// DisableKeepalive: true, +// }) +// +// app.Get("/read-timeout", func(c *Ctx) { +// c.SendString("I should not be sent") +// }) +// +// go func() { +// time.Sleep(500 * time.Millisecond) +// +// conn, err := net.Dial("tcp4", "127.0.0.1:4004") +// utils.AssertEqual(t, nil, err) +// defer conn.Close() +// +// _, err = conn.Write([]byte("HEAD /read-timeout HTTP/1.1\r\n")) +// utils.AssertEqual(t, nil, err) +// +// buf := make([]byte, 1024) +// var n int +// n, err = conn.Read(buf) +// +// utils.AssertEqual(t, nil, err) +// utils.AssertEqual(t, true, bytes.Contains(buf[:n], []byte("408 Request Timeout"))) +// +// utils.AssertEqual(t, nil, app.Shutdown()) +// }() +// +// utils.AssertEqual(t, nil, app.Listen(4004)) +//} // go test -run Test_App_BadRequest func Test_App_BadRequest(t *testing.T) {