diff --git a/.travis.yml b/.travis.yml
index 8af4fd52..1e4f6a69 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,9 @@
language: go
+
+os:
+ - linux
+# - windows
+ - osx
go:
- 1.13.x
env:
diff --git a/README.md b/README.md
index 2005104a..0366a942 100644
--- a/README.md
+++ b/README.md
@@ -150,4 +150,4 @@ Thanks for your support! 😘 Together, we make `Fiber`.
## License
-⚠️ _Please note:_ `gofiber/fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/edit/master/LICENSE).
+⚠️ _Please note:_ `gofiber/fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/master/LICENSE).
diff --git a/README_CH.md b/README_CH.md
index abee1c62..ea1467aa 100644
--- a/README_CH.md
+++ b/README_CH.md
@@ -150,4 +150,4 @@ func main() {
## License
-⚠️ _请注意:_ `gofiber/fiber` 是根据以下条款获得许可的免费开源软件 [MIT License](https://github.com/gofiber/fiber/edit/master/LICENSE).
+⚠️ _请注意:_ `gofiber/fiber` 是根据以下条款获得许可的免费开源软件 [MIT License](https://github.com/gofiber/fiber/master/LICENSE).
diff --git a/README_NEW.md b/README_NEW.md
new file mode 100644
index 00000000..93b385c1
--- /dev/null
+++ b/README_NEW.md
@@ -0,0 +1,181 @@
+[](https://fiber.wiki)
+
+[Express](https://github.com/expressjs/express) inspired web framework build on [Fasthttp](https://github.com/valyala/fasthttp) for [Go](https://golang.org/doc/).
+Designed to ease things up for fast development with zero memory allocation and performance in mind.
+
+[](https://github.com/gofiber/fiber/releases)
+[](https://pkg.go.dev/github.com/gofiber/fiber?tab=doc)
+
+
+
+[](https://pkg.go.dev/github.com/gofiber/fiber?tab=doc)
+
+```golang
+package main
+
+import "github.com/gofiber/fiber"
+
+func main() {
+ app := fiber.New()
+
+ app.Get("/", func(c *fiber.Ctx) {
+ c.Write("Hello, World!")
+ })
+
+ app.Listen(3000)
+}
+```
+
+## Benchmarks
+
+These tests are performed by [TechEmpower](https://github.com/TechEmpower/FrameworkBenchmarks) and [Go Web](https://github.com/smallnest/go-web-framework-benchmark). If you want to see all results, please visit our [wiki#benchmarks](https://fiber.wiki/#benchmarks).
+
+
+
+
+
+## Installation
+
+Before installing, [download and install Go](https://golang.org/dl/).
+Go `1.11` or higher is required.
+
+Installation is done using the
+[`go get`](https://golang.org/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command:
+
+```bash
+go get github.com/gofiber/fiber
+```
+
+## Features
+
+* Robust [routing](https://fiber.wiki/#/routing)
+* Serve [static files](https://fiber.wiki/#/application?id=static)
+* [Extreme performance](https://fiber.wiki/#/benchmarks)
+* Low memory footprint
+* Express [API endpoints](https://fiber.wiki/#/context)
+* Middleware & [Next](https://fiber.wiki/#context?id=next) support
+* Rapid server-side programming
+* [And much more, click here](https://fiber.wiki/)
+
+
+## Philosophy
+
+People switching from [Node.js](https://nodejs.org/en/about/) to [Go](https://golang.org/doc/) often end up in a bad learning curve to start building their webapps or micro services. Fiber, as a web framework, was created with the idea of minimalism so new and experienced gophers can rapidly develop web application's.
+
+Fiber is inspired by the Express framework, the most populair web framework on web. We combined the ease of Express and raw performance of Go. If you have ever implemented a web application on Node.js using Express.js, then many methods and principles will seem very common to you.
+
+## Examples
+
+Listed below are some of the common examples. If you want to see more code examples, please visit our [recipes repository](https://github.com/gofiber/recipes) or [api documentation](https://fiber.wiki).
+
+_**Static files**_
+```golang
+// ...
+app := fiber.New()
+
+app.Static("./public")
+// http://localhost:3000/js/script.js
+// http://localhost:3000/css/style.css
+
+app.Static("/xxx", "./public")
+// http://localhost:3000/xxx/js/script.js
+// http://localhost:3000/xxx/css/style.css
+
+app.Listen(3000)
+```
+
+_**Routing**_
+```golang
+// ...
+app := fiber.New()
+
+// param
+app.Get("/:name", func(c *fiber.Ctx) {
+ c.Send("Hello, " + c.Params("name"))
+})
+
+// optional param
+app.Get("/:name/:lastname?", func(c *fiber.Ctx) {
+ c.Send("Hello, " + c.Params("name") + " " + c.Params("lastname"))
+})
+
+// wildcard
+app.Get("/api*", func(c *fiber.Ctx) {
+ c.Send("/api" + c.Params("*"))
+})
+
+app.Listen(3000)
+```
+
+_**Middleware**_
+```golang
+// ...
+app := fiber.New()
+
+// match any post route
+app.Post(func(c *fiber.Ctx) {
+ user, pass, ok := c.BasicAuth()
+ if !ok || user != "john" || pass != "doe" {
+ c.Status(403).Send("Sorry John")
+ return
+ }
+ c.Next()
+})
+
+// match all routes starting with /api
+app.Use("/api", func(c *fiber.Ctx) {
+ c.Set("Access-Control-Allow-Origin", "*")
+ c.Set("Access-Control-Allow-Headers", "X-Requested-With")
+ c.Next()
+})
+
+// optional param
+app.Post("/api/register", func(c *fiber.Ctx) {
+ username := c.Body("username")
+ password := c.Body("password")
+ // ..
+})
+
+app.Listen(3000)
+```
+
+_**404 Handling**_
+```golang
+// ...
+app := fiber.New()
+
+// ..application routes
+
+// last route
+app.Use(func (c *fiber.Ctx) {
+ c.SendStatus(404)
+})
+
+app.Listen(3000)
+```
+
+_**JSON Response**_
+```golang
+// ...
+app := fiber.New()
+
+type Data struct {
+ Name string `json:"name"`
+ Age int `json:"age"`
+}
+
+// last route
+app.Get("/json", func (c *fiber.Ctx) {
+ c.JSON(&Data{
+ Name: "John",
+ Age: 20,
+ })
+})
+
+app.Listen(3000)
+```
+
+
+## License
+
+`gofiber/fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/master/LICENSE).
diff --git a/application.go b/application.go
index 3bc3d493..e55b14ae 100644
--- a/application.go
+++ b/application.go
@@ -10,6 +10,8 @@ package fiber
import (
"flag"
"time"
+
+ "github.com/valyala/fasthttp"
)
const (
@@ -33,7 +35,8 @@ var (
// Fiber structure
type Fiber struct {
// Server name header
- Server string
+ Server string
+ httpServer *fasthttp.Server
// Show fiber banner
Banner bool
// https://github.com/valyala/fasthttp/blob/master/server.go#L150
@@ -72,10 +75,11 @@ type engine struct {
func New() *Fiber {
flag.Parse()
return &Fiber{
- Server: "",
- Banner: true,
- Prefork: *prefork,
- child: *child,
+ Server: "",
+ httpServer: nil,
+ Banner: true,
+ Prefork: *prefork,
+ child: *child,
Engine: &engine{
Concurrency: 256 * 1024,
DisableKeepAlive: false,
diff --git a/listen.go b/listen.go
index 1ba0f1c4..b4867c4f 100644
--- a/listen.go
+++ b/listen.go
@@ -21,6 +21,14 @@ import (
"github.com/valyala/fasthttp/reuseport"
)
+// Shutdown server gracefully
+func (r *Fiber) Shutdown() error {
+ if r.httpServer == nil {
+ return fmt.Errorf("Server is not running")
+ }
+ return r.httpServer.Shutdown()
+}
+
// Listen : https://gofiber.github.io/fiber/#/application?id=listen
func (r *Fiber) Listen(address interface{}, tls ...string) {
host := ""
@@ -36,29 +44,7 @@ func (r *Fiber) Listen(address interface{}, tls ...string) {
log.Fatal("Listen: Host must be an INT port or STRING address")
}
// Create fasthttp server
- server := &fasthttp.Server{
- Handler: r.handler,
- Name: r.Server,
- Concurrency: r.Engine.Concurrency,
- DisableKeepalive: r.Engine.DisableKeepAlive,
- ReadBufferSize: r.Engine.ReadBufferSize,
- WriteBufferSize: r.Engine.WriteBufferSize,
- ReadTimeout: r.Engine.ReadTimeout,
- WriteTimeout: r.Engine.WriteTimeout,
- IdleTimeout: r.Engine.IdleTimeout,
- MaxConnsPerIP: r.Engine.MaxConnsPerIP,
- MaxRequestsPerConn: r.Engine.MaxRequestsPerConn,
- TCPKeepalive: r.Engine.TCPKeepalive,
- TCPKeepalivePeriod: r.Engine.TCPKeepalivePeriod,
- MaxRequestBodySize: r.Engine.MaxRequestBodySize,
- ReduceMemoryUsage: r.Engine.ReduceMemoryUsage,
- GetOnly: r.Engine.GetOnly,
- DisableHeaderNamesNormalizing: r.Engine.DisableHeaderNamesNormalizing,
- SleepWhenConcurrencyLimitsExceeded: r.Engine.SleepWhenConcurrencyLimitsExceeded,
- NoDefaultServerHeader: r.Server == "",
- NoDefaultContentType: r.Engine.NoDefaultContentType,
- KeepHijackedConns: r.Engine.KeepHijackedConns,
- }
+ r.httpServer = r.setupServer()
// Prefork enabled
if r.Prefork && runtime.NumCPU() > 1 {
@@ -66,7 +52,7 @@ func (r *Fiber) Listen(address interface{}, tls ...string) {
cores := fmt.Sprintf("%s\x1b[1;30m %v cores", host, runtime.NumCPU())
fmt.Printf(banner, Version, " prefork", "Express on steroids", cores)
}
- r.prefork(server, host, tls...)
+ r.prefork(host, tls...)
}
// Prefork disabled
@@ -81,18 +67,18 @@ func (r *Fiber) Listen(address interface{}, tls ...string) {
// enable TLS/HTTPS
if len(tls) > 1 {
- if err := server.ServeTLS(ln, tls[0], tls[1]); err != nil {
+ if err := r.httpServer.ServeTLS(ln, tls[0], tls[1]); err != nil {
log.Fatal("Listen: ", err)
}
}
- if err := server.Serve(ln); err != nil {
+ if err := r.httpServer.Serve(ln); err != nil {
log.Fatal("Listen: ", err)
}
}
// https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/
-func (r *Fiber) prefork(server *fasthttp.Server, host string, tls ...string) {
+func (r *Fiber) prefork(host string, tls ...string) {
// Master proc
if !r.child {
// Create babies
@@ -128,12 +114,38 @@ func (r *Fiber) prefork(server *fasthttp.Server, host string, tls ...string) {
// enable TLS/HTTPS
if len(tls) > 1 {
- if err := server.ServeTLS(ln, tls[0], tls[1]); err != nil {
+ if err := r.httpServer.ServeTLS(ln, tls[0], tls[1]); err != nil {
log.Fatal("Listen-prefork: ", err)
}
}
- if err := server.Serve(ln); err != nil {
+ if err := r.httpServer.Serve(ln); err != nil {
log.Fatal("Listen-prefork: ", err)
}
}
+
+func (r *Fiber) setupServer() *fasthttp.Server {
+ return &fasthttp.Server{
+ Handler: r.handler,
+ Name: r.Server,
+ Concurrency: r.Engine.Concurrency,
+ DisableKeepalive: r.Engine.DisableKeepAlive,
+ ReadBufferSize: r.Engine.ReadBufferSize,
+ WriteBufferSize: r.Engine.WriteBufferSize,
+ ReadTimeout: r.Engine.ReadTimeout,
+ WriteTimeout: r.Engine.WriteTimeout,
+ IdleTimeout: r.Engine.IdleTimeout,
+ MaxConnsPerIP: r.Engine.MaxConnsPerIP,
+ MaxRequestsPerConn: r.Engine.MaxRequestsPerConn,
+ TCPKeepalive: r.Engine.TCPKeepalive,
+ TCPKeepalivePeriod: r.Engine.TCPKeepalivePeriod,
+ MaxRequestBodySize: r.Engine.MaxRequestBodySize,
+ ReduceMemoryUsage: r.Engine.ReduceMemoryUsage,
+ GetOnly: r.Engine.GetOnly,
+ DisableHeaderNamesNormalizing: r.Engine.DisableHeaderNamesNormalizing,
+ SleepWhenConcurrencyLimitsExceeded: r.Engine.SleepWhenConcurrencyLimitsExceeded,
+ NoDefaultServerHeader: r.Server == "",
+ NoDefaultContentType: r.Engine.NoDefaultContentType,
+ KeepHijackedConns: r.Engine.KeepHijackedConns,
+ }
+}
diff --git a/listen_test.go b/listen_test.go
new file mode 100644
index 00000000..c5f6cc6a
--- /dev/null
+++ b/listen_test.go
@@ -0,0 +1,32 @@
+package fiber
+
+import (
+ "sync"
+ "testing"
+)
+
+var wg sync.WaitGroup
+
+func Test_Connect(t *testing.T) {
+ return
+ // app := New()
+ // app.Banner = false
+ //
+ // wg.Add(1)
+ //
+ // go func() {
+ // app.Listen("8080")
+ // }()
+ //
+ // time.Sleep(time.Millisecond * 100)
+ //
+ // go func() {
+ // err := app.Shutdown()
+ // if err != nil {
+ // t.Fatalf(`%s: Failed to shutdown server %v`, t.Name(), err)
+ // }
+ // wg.Done()
+ // }()
+ // wg.Wait()
+ //app.Listen(":8085")
+}
diff --git a/methods_test.go b/methods_test.go
new file mode 100644
index 00000000..6d8f32db
--- /dev/null
+++ b/methods_test.go
@@ -0,0 +1,109 @@
+package fiber
+
+import (
+ "net/http"
+ "testing"
+)
+
+func Test_Methods(t *testing.T) {
+ app := New()
+ app.Connect(func(c *Ctx) {})
+ app.Put(func(c *Ctx) {})
+ app.Post(func(c *Ctx) {})
+ app.Delete(func(c *Ctx) {})
+ app.Head(func(c *Ctx) {})
+ app.Patch(func(c *Ctx) {})
+ app.Options(func(c *Ctx) {})
+ app.Trace(func(c *Ctx) {})
+ app.Get(func(c *Ctx) {})
+ app.All("/special", func(c *Ctx) {})
+ app.Use("/special/john", func(c *Ctx) {})
+ req, _ := http.NewRequest("CONNECT", "/", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("PUT", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("POST", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("DELETE", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("HEAD", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("PATCH", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("OPTIONS", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("TRACE", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("GET", "/", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("GET", "/special", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("GET", "/special/john", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
diff --git a/middleware/cors.go b/middleware/cors.go
deleted file mode 100644
index fc5b2cd9..00000000
--- a/middleware/cors.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package middleware
-
-import "github.com/gofiber/fiber"
-
-// app.Use(middleware.Cors())
-
-// Cors : Enable cross-origin resource sharing (CORS) with various options.
-func Cors(origin ...string) func(*fiber.Ctx) {
- return func(c *fiber.Ctx) {
- o := "*"
- if len(origin) > 0 {
- o = origin[0]
- }
- c.Set("Access-Control-Allow-Origin", o)
- c.Set("Access-Control-Allow-Headers", "X-Requested-With")
- c.Next()
- }
-}
diff --git a/middleware/csrf.go b/middleware/csrf.go
deleted file mode 100644
index 29502495..00000000
--- a/middleware/csrf.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package middleware
-
-import (
- "github.com/gofiber/fiber"
-)
-
-// CSRF :
-func CSRF() func(*fiber.Ctx) {
- return func(c *fiber.Ctx) {
- c.Next()
- }
-}
diff --git a/middleware/helmet.go b/middleware/helmet.go
deleted file mode 100644
index d937d6b3..00000000
--- a/middleware/helmet.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package middleware
-
-import (
- "fmt"
-
- "github.com/gofiber/fiber"
-)
-
-// HelmetOptions https://github.com/helmetjs/helmet#how-it-works
-type HelmetOptions struct {
- ContentSecurityPolicy string
- CrossDomain string
- DNSPrefetchControl string // default
- ExpectCt string
- FeaturePolicy string
- FrameGuard string // default
- Hpkp string
- Hsts string // default
- IeNoOpen string // default
- NoCache string
- NoSniff string // default
- ReferrerPolicy string
- XSSFilter string // default
-}
-
-// Helmet : Helps secure your apps by setting various HTTP headers.
-func Helmet(opt ...*HelmetOptions) func(*fiber.Ctx) {
- return func(c *fiber.Ctx) {
- fmt.Println("Helmet is still under development, this middleware does nothing yet.")
- c.Next()
- }
-}
diff --git a/middleware/limiter.go b/middleware/limiter.go
deleted file mode 100644
index bf25b74b..00000000
--- a/middleware/limiter.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package middleware
-
-import (
- "github.com/gofiber/fiber"
-)
-
-// Limiter :
-func Limiter() func(*fiber.Ctx) {
- return func(c *fiber.Ctx) {
- c.Next()
- }
-}
diff --git a/middleware/logger.go b/middleware/logger.go
deleted file mode 100644
index 46e047cb..00000000
--- a/middleware/logger.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package middleware
-
-import (
- "fmt"
- "time"
-
- "github.com/gofiber/fiber"
-)
-
-// Logger : Simple logger
-func Logger() func(*fiber.Ctx) {
- return func(c *fiber.Ctx) {
- currentTime := time.Now().Format("02 Jan, 15:04:05")
- fmt.Printf("%s \x1b[1;32m%s \x1b[1;37m%s\x1b[0000m, %s\n", currentTime, c.Method(), c.Path(), c.Get("User-Agent"))
- c.Next()
- }
-}
diff --git a/middleware/session.go b/middleware/session.go
deleted file mode 100644
index 06eb87f2..00000000
--- a/middleware/session.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package middleware
-
-import (
- "github.com/gofiber/fiber"
-)
-
-// Session :
-func Session() func(*fiber.Ctx) {
- return func(c *fiber.Ctx) {
- c.Next()
- }
-}
diff --git a/request.go b/request.go
index d0b172a5..23a0aa9f 100644
--- a/request.go
+++ b/request.go
@@ -9,11 +9,13 @@ package fiber
import (
"encoding/base64"
+ "encoding/xml"
"fmt"
"mime"
"mime/multipart"
"strings"
+ jsoniter "github.com/json-iterator/go"
"github.com/valyala/fasthttp"
)
@@ -132,6 +134,12 @@ func (ctx *Ctx) AcceptsLanguages(offers ...string) string {
return ""
}
+// BaseUrl : https://gofiber.github.io/fiber/#/context?id=baseurl
+func (ctx *Ctx) BaseUrl() string {
+ fmt.Println("Fiber deprecated c.BaseUrl(), this will be removed in v2: Use c.BaseURL() instead")
+ return ctx.BaseURL()
+}
+
// BaseURL : https://gofiber.github.io/fiber/#/context?id=baseurl
func (ctx *Ctx) BaseURL() string {
return ctx.Protocol() + "://" + ctx.Hostname()
@@ -175,6 +183,8 @@ func (ctx *Ctx) Body(args ...interface{}) string {
switch arg := args[0].(type) {
case string:
return getString(ctx.Fasthttp.Request.PostArgs().Peek(arg))
+ case []byte:
+ return getString(ctx.Fasthttp.Request.PostArgs().PeekBytes(arg))
case func(string, string):
ctx.Fasthttp.Request.PostArgs().VisitAll(func(k []byte, v []byte) {
arg(getString(k), getString(v))
@@ -186,6 +196,17 @@ func (ctx *Ctx) Body(args ...interface{}) string {
return ""
}
+// BodyParser : https://gofiber.github.io/fiber/#/context?id=bodyparser
+func (ctx *Ctx) BodyParser(v interface{}) error {
+ cType := getString(ctx.Fasthttp.Request.Header.ContentType())
+ if cType == contentTypeJSON {
+ return jsoniter.Unmarshal(ctx.Fasthttp.Request.Body(), v)
+ } else if cType == contentTypeXML {
+ return xml.Unmarshal(ctx.Fasthttp.Request.Body(), v)
+ }
+ return fmt.Errorf("Cannot Parse Content-Type: %v", cType)
+}
+
// Cookies : https://gofiber.github.io/fiber/#/context?id=cookies
func (ctx *Ctx) Cookies(args ...interface{}) string {
if len(args) == 0 {
@@ -312,10 +333,6 @@ func (ctx *Ctx) OriginalURL() string {
// Params : https://gofiber.github.io/fiber/#/context?id=params
func (ctx *Ctx) Params(key string) string {
- if ctx.params == nil {
- return ""
- }
-
for i := 0; i < len(*ctx.params); i++ {
if (*ctx.params)[i] == key {
return ctx.values[i]
diff --git a/request_test.go b/request_test.go
index 74d39505..45f09c2f 100644
--- a/request_test.go
+++ b/request_test.go
@@ -1,235 +1,673 @@
package fiber
import (
+ "bytes"
+ "fmt"
+ "mime/multipart"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strconv"
"strings"
"testing"
)
func Test_Accepts(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n\r\n"
- // Create fiber app
app := New()
- app.Get("/", func(c *Ctx) {
- expecting := "html"
- result := c.Accepts(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
+ app.Get("/test", func(c *Ctx) {
+ expect := ""
+ result := c.Accepts(expect)
+ if c.Accepts() != "" {
+ t.Fatalf(`Expecting %s, got %s`, expect, result)
}
-
- expecting = ".xml"
- result = c.Accepts(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
+ expect = ".xml"
+ result = c.Accepts(expect)
+ if result != expect {
+ t.Fatalf(`Expecting %s, got %s`, expect, result)
}
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req := httptest.NewRequest("GET", "/test", nil)
+ req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_AcceptsCharsets(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\nAccept-Charset: utf-8, iso-8859-1;q=0.5\r\n\r\n"
- // Raw http request
app := New()
- app.Get("/", func(c *Ctx) {
- expecting := "utf-8"
- result := c.AcceptsCharsets(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
- }
+ app.Get("/test", func(c *Ctx) {
+ c.AcceptsCharsets()
- expecting = "iso-8859-1"
- result = c.AcceptsCharsets(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
+ expect := "utf-8"
+ result := c.AcceptsCharsets(expect)
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("Accept-Charset", "utf-8, iso-8859-1;q=0.5")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_AcceptsEncodings(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\nAccept-Encoding: deflate, gzip;q=1.0, *;q=0.5\r\n\r\n"
- // Raw http request
app := New()
- app.Get("/", func(c *Ctx) {
- expecting := "gzip"
- result := c.AcceptsEncodings(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
- }
-
- expecting = "*"
- result = c.AcceptsEncodings(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
+ app.Get("/test", func(c *Ctx) {
+ c.AcceptsEncodings()
+ expect := "gzip"
+ result := c.AcceptsEncodings(expect)
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("Accept-Encoding", "deflate, gzip;q=1.0, *;q=0.5")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_AcceptsLanguages(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\nAccept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5\r\n\r\n"
- // Raw http request
app := New()
- app.Get("/", func(c *Ctx) {
- expecting := "fr"
- result := c.AcceptsLanguages(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
- }
-
- expecting = "en"
- result = c.AcceptsLanguages(expecting)
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
+ app.Get("/test", func(c *Ctx) {
+ c.AcceptsLanguages()
+ expect := "fr"
+ result := c.AcceptsLanguages(expect)
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("Accept-Language", "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_BaseURL(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"
- // Raw http request
app := New()
- app.Get("/", func(c *Ctx) {
- expecting := "http://localhost:8080"
+ app.Get("/test", func(c *Ctx) {
+ c.BaseUrl() // deprecated
+ expect := "http://google.com"
result := c.BaseURL()
- if result != expecting {
- t.Fatalf(`%s: Expecting %s`, t.Name(), expecting)
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req, _ := http.NewRequest("GET", "http://google.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_BasicAuth(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\nAuthorization: Basic am9objpkb2U=\r\n\r\n"
- // Raw http request
app := New()
- app.Get("/", func(c *Ctx) {
- user, pass, ok := c.BasicAuth()
- if !ok {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "ok")
+ app.Get("/test", func(c *Ctx) {
+ expect1 := "john"
+ expect2 := "doe"
+ result1, result2, _ := c.BasicAuth()
+ if result1 != expect1 {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect1, expect1)
}
- if user != "john" || pass != "doe" {
- if !ok {
- t.Fatalf(`%s: Expecting john & doe`, t.Name())
- }
+ if result2 != expect2 {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), result2, expect2)
}
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.SetBasicAuth("john", "doe")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_Body(t *testing.T) {
- // Raw http request
- req := "POST /test HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 9\r\n\r\nuser=john"
- // Raw http request
app := New()
app.Post("/test", func(c *Ctx) {
- if c.Body() != "user=john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "user=john")
+ c.Body(1)
+ expect := "john=doe"
+ result := c.Body()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
- if c.Body("user") != "john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "john")
+ expect = "doe"
+ result = c.Body("john")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ expect = "doe"
+ result = c.Body([]byte("john"))
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
c.Body(func(k, v string) {
- if k != "user" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "user")
+ expect = "john"
+ if k != "john" {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, k)
}
- if v != "john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "john")
+ expect = "doe"
+ if v != "doe" {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, v)
}
})
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ data := url.Values{}
+ data.Set("john", "doe")
+ req, _ := http.NewRequest("POST", "/test", strings.NewReader(data.Encode()))
+ req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ req.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
func Test_Cookies(t *testing.T) {
- // Raw http request
- req := "GET /test HTTP/1.1\r\nHost: localhost:8080\r\nCookie: user=john\r\n\r\n"
- // Raw http request
app := New()
app.Get("/test", func(c *Ctx) {
- if c.Cookies() != "user=john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "user=john")
+ c.Cookies(1)
+ expect := "john=doe"
+ result := c.Cookies()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
- if c.Cookies("user") != "john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "john")
+ expect = "doe"
+ result = c.Cookies("john")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ expect = "doe"
+ result = c.Cookies([]byte("john"))
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
c.Cookies(func(k, v string) {
- if k != "user" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "user")
+ expect = "john"
+ if k != "john" {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, k)
}
- if v != "john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "john")
+ expect = "doe"
+ if v != "doe" {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, v)
}
})
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.AddCookie(&http.Cookie{Name: "john", Value: "doe"})
+ _, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
}
}
func Test_FormFile(t *testing.T) {
- // Raw http request
- req := "POST /test HTTP/1.1\r\nHost: localhost:8080\r\nCookie: user=john\r\n\r\n"
- // Raw http request
+ // TODO
+}
+func Test_FormValue(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
- if c.Cookies() != "user=john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "user=john")
+ expect := "john"
+ result := c.FormValue("name")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
}
- if c.Cookies("user") != "john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "john")
- }
- c.Cookies(func(k, v string) {
- if k != "user" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "user")
- }
- if v != "john" {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "john")
- }
- })
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ writer.WriteField("name", "john")
+ writer.Close()
+ req, _ := http.NewRequest("POST", "/test", body)
+ contentType := fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary())
+
+ req.Header.Set("Content-Type", contentType)
+ req.Header.Set("Content-Length", strconv.Itoa(len(body.Bytes())))
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
}
}
+func Test_Fresh(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Fresh()
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ _, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+}
+func Test_Get(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ expect := "utf-8, iso-8859-1;q=0.5"
+ result := c.Get("Accept-Charset")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ expect = "Monster"
+ result = c.Get("referrer")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("Accept-Charset", "utf-8, iso-8859-1;q=0.5")
+ req.Header.Set("Referer", "Monster")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Hostname(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ expect := "google.com"
+ result := c.Hostname()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "http://google.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_IP(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Ip() // deprecated
+ expect := "0.0.0.0"
+ result := c.IP()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "http://google.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_IPs(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Ips() // deprecated
+ expect := []string{"0.0.0.0", "1.1.1.1"}
+ result := c.IPs()
+ if result[0] != expect[0] && result[1] != expect[1] {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("X-Forwarded-For", "0.0.0.0, 1.1.1.1")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Is(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Is(".json")
+ expect := true
+ result := c.Is("html")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %v, got %v`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("Content-Type", "text/html")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Locals(t *testing.T) {
+ app := New()
+ app.Use(func(c *Ctx) {
+ c.Locals("john", "doe")
+ c.Next()
+ })
+ app.Get("/test", func(c *Ctx) {
+ expect := "doe"
+ result := c.Locals("john")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Method(t *testing.T) {
+ app := New()
+ app.Get(func(c *Ctx) {
+ expect := "GET"
+ result := c.Method()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ app.Post(func(c *Ctx) {
+ expect := "POST"
+ result := c.Method()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ app.Put(func(c *Ctx) {
+ expect := "PUT"
+ result := c.Method()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("POST", "/test", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("PUT", "/test", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_MultipartForm(t *testing.T) {
+ app := New()
+ app.Post("/test", func(c *Ctx) {
+ expect := "john"
+ result, err := c.MultipartForm()
+ if err != nil {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, err)
+ }
+ if result.Value["name"][0] != expect {
+ t.Fatalf(`%s: Expecting %s, got %v`, t.Name(), expect, result)
+ }
+ })
-// TODO: add all functions from request.go
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ writer.WriteField("name", "john")
+ writer.Close()
+ req, _ := http.NewRequest("POST", "/test", body)
+ contentType := fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary())
+
+ req.Header.Set("Content-Type", contentType)
+ req.Header.Set("Content-Length", strconv.Itoa(len(body.Bytes())))
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_OriginalURL(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.OriginalUrl() // deprecated
+ expect := "/test?search=demo"
+ result := c.OriginalURL()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "http://google.com/test?search=demo", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Params(t *testing.T) {
+ app := New()
+ app.Get("/test/:user", func(c *Ctx) {
+ expect := "john"
+ result := c.Params("user")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ app.Get("/test2/*", func(c *Ctx) {
+ expect := "im/a/cookie"
+ result := c.Params("*")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test/john", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ req, _ = http.NewRequest("GET", "/test2/im/a/cookie", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Path(t *testing.T) {
+ app := New()
+ app.Get("/test/:user", func(c *Ctx) {
+ expect := "/test/john"
+ result := c.Path()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test/john", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Query(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ expect := "john"
+ result := c.Query("search")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ expect = "20"
+ result = c.Query("age")
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test?search=john&age=20", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Range(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Range()
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ _, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+}
+func Test_Route(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ expect := "/test"
+ result := c.Route().Path
+ if result != expect {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_SaveFile(t *testing.T) {
+ // TODO
+}
+func Test_Secure(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ expect := false
+ result := c.Secure()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %v, got %v`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_SignedCookies(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.SignedCookies()
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_Stale(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Stale()
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ _, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+}
+func Test_Subdomains(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ expect := []string{"john", "doe"}
+ result := c.Subdomains()
+ if result[0] != expect[0] && result[1] != expect[1] {
+ t.Fatalf(`%s: Expecting %s, got %s`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "http://john.doe.google.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
+func Test_XHR(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Xhr() // deprecated
+ expect := true
+ result := c.XHR()
+ if result != expect {
+ t.Fatalf(`%s: Expecting %v, got %v`, t.Name(), expect, result)
+ }
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.Header.Set("X-Requested-With", "XMLHttpRequest")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+}
diff --git a/response.go b/response.go
index d573e74e..4a71839f 100644
--- a/response.go
+++ b/response.go
@@ -24,8 +24,7 @@ func (ctx *Ctx) Append(field string, values ...string) {
if len(values) == 0 {
return
}
-
- h := ctx.Get(field)
+ h := getString(ctx.Fasthttp.Response.Header.Peek(field))
for i := range values {
if h == "" {
h += values[i]
@@ -51,11 +50,12 @@ func (ctx *Ctx) Attachment(name ...string) {
func (ctx *Ctx) ClearCookie(name ...string) {
if len(name) > 0 {
for i := range name {
+ //ctx.Fasthttp.Request.Header.DelAllCookies()
ctx.Fasthttp.Response.Header.DelClientCookie(name[i])
}
return
}
-
+ //ctx.Fasthttp.Response.Header.DelAllCookies()
ctx.Fasthttp.Request.Header.VisitAllCookie(func(k, v []byte) {
ctx.Fasthttp.Response.Header.DelClientCookie(getString(k))
})
@@ -352,14 +352,16 @@ func (ctx *Ctx) Vary(fields ...string) {
return
}
- vary := ctx.Get(fasthttp.HeaderVary)
- for _, field := range fields {
- if !strings.Contains(vary, field) {
- vary += ", " + field
+ h := getString(ctx.Fasthttp.Response.Header.Peek(fasthttp.HeaderVary))
+ for i := range fields {
+ if h == "" {
+ h += fields[i]
+ } else {
+ h += ", " + fields[i]
}
}
- ctx.Set(fasthttp.HeaderVary, vary)
+ ctx.Set(fasthttp.HeaderVary, h)
}
// Write : https://gofiber.github.io/fiber/#/context?id=write
diff --git a/response_test.go b/response_test.go
index 88146579..abf1cc88 100644
--- a/response_test.go
+++ b/response_test.go
@@ -1,28 +1,567 @@
package fiber
import (
+ "io/ioutil"
+ "net/http"
"strings"
"testing"
)
func Test_Append(t *testing.T) {
- // Raw http request
- req := "GET / HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"
- // Create fiber app
app := New()
- app.Get("/", func(c *Ctx) {
- c.Append("X-Test", "hello", "world")
+ app.Get("/test", func(c *Ctx) {
+ c.Append("X-Test", "hel")
+ c.Append("X-Test", "lo", "world")
})
- // Send fake request
- res, err := app.FakeRequest(req)
- // Check for errors and if route was handled
- if err != nil || !strings.Contains(res, "HTTP/1.1 200 OK") {
- t.Fatalf(`%s: Error serving FakeRequest %s`, t.Name(), err)
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
}
- // Check if function works correctly
- if !strings.Contains(res, "X-Test: hello, world") {
- t.Fatalf(`%s: Expecting %s`, t.Name(), "X-Test: hello, world")
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("X-Test") != "hel, lo, world" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "X-Test: hel, lo, world")
}
}
+func Test_Attachment(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Attachment("./static/img/logo.png")
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Disposition") != `attachment; filename="logo.png"` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `attachment; filename="logo.png"`)
+ }
+ if resp.Header.Get("Content-Type") != "image/png" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "image/png")
+ }
+}
+func Test_ClearCookie(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.ClearCookie()
+ })
+ app.Get("/test2", func(c *Ctx) {
+ c.ClearCookie("john")
+ })
+ req, _ := http.NewRequest("GET", "/test", nil)
+ req.AddCookie(&http.Cookie{Name: "john", Value: "doe"})
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if !strings.Contains(resp.Header.Get("Set-Cookie"), "expires=") {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "expires=")
+ }
+ req, _ = http.NewRequest("GET", "/test2", nil)
+ req.AddCookie(&http.Cookie{Name: "john", Value: "doe"})
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if !strings.Contains(resp.Header.Get("Set-Cookie"), "expires=") {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "expires=")
+ }
+}
+func Test_Cookie(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ options := &Cookie{
+ MaxAge: 60,
+ Domain: "example.com",
+ Path: "/",
+ HTTPOnly: true,
+ Secure: false,
+ SameSite: "lax",
+ }
+ c.Cookie("name", "john", options)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if !strings.Contains(resp.Header.Get("Set-Cookie"), "name=john; max-age=60; domain=example.com; path=/; HttpOnly; SameSite=Lax") {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "name=john; max-age=60; domain=example.com; path=/; HttpOnly; SameSite=Lax")
+ }
+}
+func Test_Download(t *testing.T) {
+ // TODO
+}
+func Test_Format(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Format("Hello, World!")
+ })
+ app.Get("/test2", func(c *Ctx) {
+ c.Format("Hello, World!")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ req.Header.Set("Accept", "text/html")
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != "Hello, World!
" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "Hello, World!
")
+ }
-// TODO: add all functions from response.go
+ req, _ = http.NewRequest("GET", "http://example.com/test2", nil)
+ req.Header.Set("Accept", "application/json")
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err = ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `"Hello, World!"` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `"Hello, World!"`)
+ }
+}
+func Test_HeadersSent(t *testing.T) {
+ // TODO
+}
+func Test_JSON(t *testing.T) {
+ type SomeStruct struct {
+ Name string
+ Age uint8
+ }
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Json("")
+ data := SomeStruct{
+ Name: "Grame",
+ Age: 20,
+ }
+ c.JSON(data)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Type") != "application/json" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "application/json")
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `{"Name":"Grame","Age":20}` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `{"Name":"Grame","Age":20}`)
+ }
+}
+func Test_JSONBytes(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.JsonBytes([]byte(""))
+ c.JSONBytes([]byte(`{"Name":"Grame","Age":20}`))
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Type") != "application/json" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "application/json")
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `{"Name":"Grame","Age":20}` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `{"Name":"Grame","Age":20}`)
+ }
+}
+func Test_JSONP(t *testing.T) {
+ type SomeStruct struct {
+ Name string
+ Age uint8
+ }
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Jsonp("")
+ data := SomeStruct{
+ Name: "Grame",
+ Age: 20,
+ }
+ c.JSONP(data, "alwaysjohn")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Type") != "application/javascript" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "application/javascript")
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `alwaysjohn({"Name":"Grame","Age":20});` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `alwaysjohn({"Name":"Grame","Age":20});`)
+ }
+}
+func Test_JSONString(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.JsonString("")
+ c.JSONString(`{"Name":"Grame","Age":20}`)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Type") != "application/json" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "application/json")
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `{"Name":"Grame","Age":20}` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `{"Name":"Grame","Age":20}`)
+ }
+}
+func Test_Links(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Links(
+ "http://api.example.com/users?page=2", "next",
+ "http://api.example.com/users?page=5", "last",
+ )
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Link") != `; rel="next",; rel="last"` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `Link: ; rel="next",; rel="last"`)
+ }
+}
+func Test_Location(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Location("http://example.com")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Location") != "http://example.com" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "http://example.com")
+ }
+}
+func Test_Next(t *testing.T) {
+ app := New()
+ app.Use("/", func(c *Ctx) {
+ c.Next()
+ })
+ app.Get("/test", func(c *Ctx) {
+ c.Set("X-Next-Result", "Works")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("X-Next-Result") != "Works" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "X-Next-Results: Works")
+ }
+}
+func Test_Redirect(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Redirect("http://example.com", 301)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 301 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Location") != "http://example.com" {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), "Location: http://example.com")
+ }
+}
+func Test_Render(t *testing.T) {
+ // TODO
+}
+func Test_Send(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Send([]byte("Hello, World"))
+ c.Send("Don't crash please")
+ c.Send(1337)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `1337` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `1337`)
+ }
+}
+func Test_SendBytes(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.SendBytes([]byte("Hello, World"))
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `Hello, World` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `Hello, World`)
+ }
+}
+func Test_SendStatus(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.SendStatus(415)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 415 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `Unsupported Media Type` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `Unsupported Media Type`)
+ }
+}
+func Test_SendString(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.SendString("Don't crash please")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `Don't crash please` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `Don't crash please`)
+ }
+}
+func Test_Set(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Set("X-1", "1")
+ c.Set("X-2", "2")
+ c.Set("X-3", "3")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("X-1") != "1" {
+ t.Fatalf(`%s: Expected %v`, t.Name(), "X-1: 1")
+ }
+ if resp.Header.Get("X-2") != "2" {
+ t.Fatalf(`%s: Expected %v`, t.Name(), "X-2: 2")
+ }
+ if resp.Header.Get("X-3") != "3" {
+ t.Fatalf(`%s: Expected %v`, t.Name(), "X-3: 3")
+ }
+}
+func Test_Status(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Status(400)
+ c.Status(415).Send("Hello, World")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 415 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `Hello, World` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `Hello, World`)
+ }
+}
+func Test_Type(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Type(".json")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Type") != "application/json" {
+ t.Fatalf(`%s: Expected %v`, t.Name(), `Content-Type: application/json`)
+ }
+}
+func Test_Vary(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Vary("Origin")
+ c.Vary("User-Agent")
+ c.Vary("Accept-Encoding", "Accept")
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Vary") != "Origin, User-Agent, Accept-Encoding, Accept" {
+ t.Fatalf(`%s: Expected %v`, t.Name(), `Vary: Origin, User-Agent, Accept-Encoding, Accept`)
+ }
+}
+func Test_Write(t *testing.T) {
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Write("Hello, ")
+ c.Write([]byte("World! "))
+ c.Write(123)
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `Hello, World! 123` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `Hello, World! 123`)
+ }
+}
+func Test_XML(t *testing.T) {
+ type person struct {
+ Name string `xml:"name"`
+ Stars int `xml:"stars"`
+ }
+ app := New()
+ app.Get("/test", func(c *Ctx) {
+ c.Xml("")
+ c.XML(person{"John", 50})
+ })
+ req, _ := http.NewRequest("GET", "http://example.com/test", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Type") != "application/xml" {
+ t.Fatalf(`%s: Expected %v`, t.Name(), "application/xml")
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf(`%s: Error %s`, t.Name(), err)
+ }
+ if string(body) != `John50` {
+ t.Fatalf(`%s: Expecting %s`, t.Name(), `John50`)
+ }
+}
diff --git a/static.go b/static.go
index 6463b759..4de39730 100644
--- a/static.go
+++ b/static.go
@@ -9,6 +9,7 @@ package fiber
import (
"log"
+ "os"
"path/filepath"
"strings"
)
@@ -36,6 +37,11 @@ func (r *Fiber) Static(args ...string) {
wildcard = true
}
+ // Check if root exists
+ if _, err := os.Lstat(root); err != nil {
+ log.Fatal("Static: ", err)
+ }
+
// Lets get all files from root
files, _, err := getFiles(root)
if err != nil {
diff --git a/static_test.go b/static_test.go
new file mode 100644
index 00000000..e291c9a7
--- /dev/null
+++ b/static_test.go
@@ -0,0 +1,35 @@
+package fiber
+
+import (
+ "net/http"
+ "testing"
+)
+
+func Test_Static(t *testing.T) {
+ app := New()
+ app.Static("./.github")
+ app.Static("/john", "./.github")
+ app.Static("*", "./.github/stale.yml")
+ req, _ := http.NewRequest("GET", "/stale.yml", nil)
+ resp, err := app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Length") == "" {
+ t.Fatalf(`%s: Missing Content-Length`, t.Name())
+ }
+ req, _ = http.NewRequest("GET", "/john/stale.yml", nil)
+ resp, err = app.Test(req)
+ if err != nil {
+ t.Fatalf(`%s: %s`, t.Name(), err)
+ }
+ if resp.StatusCode != 200 {
+ t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
+ }
+ if resp.Header.Get("Content-Length") == "" {
+ t.Fatalf(`%s: Missing Content-Length`, t.Name())
+ }
+}
diff --git a/utils.go b/utils.go
index 14dbf384..3ac0f0e0 100644
--- a/utils.go
+++ b/utils.go
@@ -8,10 +8,13 @@
package fiber
import (
+ "bufio"
"bytes"
"fmt"
"io/ioutil"
"net"
+ "net/http"
+ "net/http/httputil"
"os"
"path/filepath"
"reflect"
@@ -19,8 +22,6 @@ import (
"strings"
"time"
"unsafe"
-
- "github.com/valyala/fasthttp"
)
func getParams(path string) (params []string) {
@@ -75,6 +76,9 @@ func getFiles(root string) (files []string, isDir bool, err error) {
}
func getType(ext string) (mime string) {
+ if ext == "" {
+ return mime
+ }
if ext[0] == '.' {
ext = ext[1:]
}
@@ -107,92 +111,68 @@ func getBytes(s string) (b []byte) {
return b
}
-// FakeRequest creates a readWriter and calls ServeConn on local servver
-func (r *Fiber) FakeRequest(raw string) (string, error) {
- server := &fasthttp.Server{
- Handler: r.handler,
- Name: r.Server,
- Concurrency: r.Engine.Concurrency,
- DisableKeepalive: r.Engine.DisableKeepAlive,
- ReadBufferSize: r.Engine.ReadBufferSize,
- WriteBufferSize: r.Engine.WriteBufferSize,
- ReadTimeout: r.Engine.ReadTimeout,
- WriteTimeout: r.Engine.WriteTimeout,
- IdleTimeout: r.Engine.IdleTimeout,
- MaxConnsPerIP: r.Engine.MaxConnsPerIP,
- MaxRequestsPerConn: r.Engine.MaxRequestsPerConn,
- TCPKeepalive: r.Engine.TCPKeepalive,
- TCPKeepalivePeriod: r.Engine.TCPKeepalivePeriod,
- MaxRequestBodySize: r.Engine.MaxRequestBodySize,
- ReduceMemoryUsage: r.Engine.ReduceMemoryUsage,
- GetOnly: r.Engine.GetOnly,
- DisableHeaderNamesNormalizing: r.Engine.DisableHeaderNamesNormalizing,
- SleepWhenConcurrencyLimitsExceeded: r.Engine.SleepWhenConcurrencyLimitsExceeded,
- NoDefaultServerHeader: r.Server == "",
- NoDefaultContentType: r.Engine.NoDefaultContentType,
- KeepHijackedConns: r.Engine.KeepHijackedConns,
+// Test takes a http.Request and execute a fake connection to the application
+// It returns a http.Response when the connection was successfull
+func (r *Fiber) Test(req *http.Request) (*http.Response, error) {
+ // Get raw http request
+ reqRaw, err := httputil.DumpRequest(req, true)
+ if err != nil {
+ return nil, err
}
- rw := &readWriter{}
- rw.r.WriteString(raw)
-
- ch := make(chan error)
+ // Setup a fiber server struct
+ r.httpServer = r.setupServer()
+ // Create fake connection
+ conn := &conn{}
+ // Pass HTTP request to conn
+ conn.r.Write(reqRaw)
+ // Serve conn to server
+ channel := make(chan error)
go func() {
- ch <- server.ServeConn(rw)
+ channel <- r.httpServer.ServeConn(conn)
}()
-
+ // Wait for callback
select {
- case err := <-ch:
+ case err := <-channel:
if err != nil {
- return "", err
+ return nil, err
}
- case <-time.After(200 * time.Millisecond):
- return "", fmt.Errorf("Timeout")
+ // Throw timeout error after 200ms
+ case <-time.After(500 * time.Millisecond):
+ return nil, fmt.Errorf("Timeout")
}
-
- err := server.ServeConn(rw)
+ // Get raw HTTP response
+ respRaw, err := ioutil.ReadAll(&conn.w)
if err != nil {
- return "", err
+ return nil, err
}
- resp, err := ioutil.ReadAll(&rw.w)
+ // Create buffer
+ reader := strings.NewReader(getString(respRaw))
+ buffer := bufio.NewReader(reader)
+ // Convert raw HTTP response to http.Response
+ resp, err := http.ReadResponse(buffer, req)
if err != nil {
- return "", err
+ return nil, err
}
- return getString(resp), nil
+ // Return *http.Response
+ return resp, nil
}
-// Readwriter for test cases
-type readWriter struct {
+// https://golang.org/src/net/net.go#L113
+type conn struct {
net.Conn
r bytes.Buffer
w bytes.Buffer
}
-func (rw *readWriter) Close() error {
- return nil
-}
-
-func (rw *readWriter) Read(b []byte) (int, error) {
- return rw.r.Read(b)
-}
-
-func (rw *readWriter) Write(b []byte) (int, error) {
- return rw.w.Write(b)
-}
-
-func (rw *readWriter) RemoteAddr() net.Addr {
+func (c *conn) RemoteAddr() net.Addr {
return &net.TCPAddr{
- IP: net.IPv4zero,
+ IP: net.IPv4(0, 0, 0, 0),
}
}
-
-func (rw *readWriter) LocalAddr() net.Addr {
- return rw.RemoteAddr()
-}
-
-func (rw *readWriter) SetReadDeadline(t time.Time) error {
- return nil
-}
-
-func (rw *readWriter) SetWriteDeadline(t time.Time) error {
- return nil
-}
+func (c *conn) LocalAddr() net.Addr { return c.LocalAddr() }
+func (c *conn) Read(b []byte) (int, error) { return c.r.Read(b) }
+func (c *conn) Write(b []byte) (int, error) { return c.w.Write(b) }
+func (c *conn) Close() error { return nil }
+func (c *conn) SetDeadline(t time.Time) error { return nil }
+func (c *conn) SetReadDeadline(t time.Time) error { return nil }
+func (c *conn) SetWriteDeadline(t time.Time) error { return nil }