From 1e7df547ba5aa8eb8162d90b83e11fcb736e6254 Mon Sep 17 00:00:00 2001 From: Fenny Date: Mon, 10 Feb 2020 01:24:59 +0100 Subject: [PATCH] Clean up repository --- README.md | 2 +- application.go | 269 ++++++++++++++++++++++++++++++++++++++++++++ application_test.go | 72 ++++++++++++ context.go | 59 ---------- listen.go | 151 ------------------------- listen_test.go | 30 ----- methods.go | 70 ------------ methods_test.go | 109 ------------------ response.go | 14 ++- router.go | 34 ++++++ router_test.go | 1 + static.go | 83 -------------- static_test.go | 35 ------ status.go | 71 ------------ types.go | 124 -------------------- utils.go | 179 +++++++++++++++++++++++++++++ utils_test.go | 1 + 17 files changed, 570 insertions(+), 734 deletions(-) create mode 100644 application_test.go delete mode 100644 context.go delete mode 100644 listen.go delete mode 100644 listen_test.go delete mode 100644 methods.go delete mode 100644 methods_test.go create mode 100644 router_test.go delete mode 100644 static.go delete mode 100644 static_test.go delete mode 100644 status.go delete mode 100644 types.go create mode 100644 utils_test.go diff --git a/README.md b/README.md index 99dc61ed..392c721e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # 🚀 Fiber ru ch -[![](https://img.shields.io/github/release/gofiber/fiber)](https://github.com/gofiber/fiber/releases) ![](https://img.shields.io/github/languages/top/gofiber/fiber) [![](https://godoc.org/github.com/gofiber/fiber?status.svg)](https://godoc.org/github.com/gofiber/fiber) ![](https://goreportcard.com/badge/github.com/gofiber/fiber) [![GitHub license](https://img.shields.io/github/license/gofiber/fiber.svg)](https://github.com/gofiber/fiber/blob/master/LICENSE) [![Join the chat at https://gitter.im/gofiber/community](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gofiber/community) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gofiber/fiber) +[![](https://img.shields.io/github/release/gofiber/fiber)](https://github.com/gofiber/fiber/releases) ![](https://img.shields.io/github/languages/top/gofiber/fiber) [![](https://godoc.org/github.com/gofiber/fiber?status.svg)](https://godoc.org/github.com/gofiber/fiber) ![](https://goreportcard.com/badge/github.com/gofiber/fiber) [![GitHub license](https://img.shields.io/github/license/gofiber/fiber.svg)](https://github.com/gofiber/fiber/blob/master/LICENSE) [![Join the chat at https://gitter.im/gofiber/community](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gofiber/community) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gofiber/fiber) Fiber logo diff --git a/application.go b/application.go index 2967eb2b..e3b9711e 100644 --- a/application.go +++ b/application.go @@ -9,9 +9,19 @@ package fiber import ( "flag" + "fmt" + "log" + "net" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" "time" "github.com/valyala/fasthttp" + "github.com/valyala/fasthttp/reuseport" ) const ( @@ -102,3 +112,262 @@ func New() *Fiber { }, } } + +// Connect establishes a tunnel to the server +// identified by the target resource. +func (r *Fiber) Connect(args ...interface{}) { + r.register("CONNECT", args...) +} + +// Put replaces all current representations +// of the target resource with the request payload. +func (r *Fiber) Put(args ...interface{}) { + r.register("PUT", args...) +} + +// Post is used to submit an entity to the specified resource, +// often causing a change in state or side effects on the server. +func (r *Fiber) Post(args ...interface{}) { + r.register("POST", args...) +} + +// Delete deletes the specified resource. +func (r *Fiber) Delete(args ...interface{}) { + r.register("DELETE", args...) +} + +// Head asks for a response identical to that of a GET request, +// but without the response body. +func (r *Fiber) Head(args ...interface{}) { + r.register("HEAD", args...) +} + +// Patch is used to apply partial modifications to a resource. +func (r *Fiber) Patch(args ...interface{}) { + r.register("PATCH", args...) +} + +// Options is used to describe the communication options +// for the target resource. +func (r *Fiber) Options(args ...interface{}) { + r.register("OPTIONS", args...) +} + +// Trace performs a message loop-back test +// along the path to the target resource. +func (r *Fiber) Trace(args ...interface{}) { + r.register("TRACE", args...) +} + +// Get requests a representation of the specified resource. +// Requests using GET should only retrieve data. +func (r *Fiber) Get(args ...interface{}) { + r.register("GET", args...) +} + +// All matches any HTTP method +func (r *Fiber) All(args ...interface{}) { + r.register("ALL", args...) +} + +// Use only matches the starting path +func (r *Fiber) Use(args ...interface{}) { + r.register("MIDWARE", args...) +} + +// Static https://fiber.wiki/application#static +func (r *Fiber) Static(args ...string) { + prefix := "/" + root := "./" + wildcard := false + // enable / disable gzipping somewhere? + // todo v2.0.0 + gzip := true + + if len(args) == 1 { + root = args[0] + } else if len(args) == 2 { + prefix = args[0] + root = args[1] + if prefix[0] != '/' { + prefix = "/" + prefix + } + } + + // Check if wildcard for single files + // app.Static("*", "./public/index.html") + // app.Static("/*", "./public/index.html") + if prefix == "*" || prefix == "/*" { + 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 { + log.Fatal("Static: ", err) + } + + // ./static/compiled => static/compiled + mount := filepath.Clean(root) + + // Loop over all files + for _, file := range files { + // Ignore the .gzipped files by fasthttp + if strings.Contains(file, ".fasthttp.gz") { + continue + } + + // Time to create a fake path for the route match + // static/index.html => /index.html + path := filepath.Join(prefix, strings.Replace(file, mount, "", 1)) + + // Store original file path to use in ctx handler + filePath := file + + // If the file is an index.html, bind the prefix to index.html directly + if filepath.Base(filePath) == "index.html" || filepath.Base(filePath) == "index.htm" { + r.routes = append(r.routes, &Route{"GET", prefix, wildcard, false, nil, nil, func(c *Ctx) { + c.SendFile(filePath, gzip) + }}) + } + + // Add the route + SendFile(filepath) to routes + r.routes = append(r.routes, &Route{"GET", path, wildcard, false, nil, nil, func(c *Ctx) { + c.SendFile(filePath, gzip) + }}) + } +} + +// Listen : https://fiber.wiki/application#listen +func (r *Fiber) Listen(address interface{}, tls ...string) { + host := "" + switch val := address.(type) { + case int: + host = ":" + strconv.Itoa(val) // 8080 => ":8080" + case string: + if !strings.Contains(val, ":") { + val = ":" + val // "8080" => ":8080" + } + host = val + default: + log.Fatal("Listen: Host must be an INT port or STRING address") + } + // Create fasthttp server + r.httpServer = r.setupServer() + + // Prefork enabled + if r.Prefork && runtime.NumCPU() > 1 { + if r.Banner && !r.child { + cores := fmt.Sprintf("%s\x1b[1;30m %v cores", host, runtime.NumCPU()) + fmt.Printf(banner, Version, " prefork", "Express on steroids", cores) + } + r.prefork(host, tls...) + } + + // Prefork disabled + if r.Banner { + fmt.Printf(banner, Version, "", "Express on steroids", host) + } + + ln, err := net.Listen("tcp4", host) + if err != nil { + log.Fatal("Listen: ", err) + } + + // enable TLS/HTTPS + if len(tls) > 1 { + if err := r.httpServer.ServeTLS(ln, tls[0], tls[1]); err != nil { + log.Fatal("Listen: ", err) + } + } + + if err := r.httpServer.Serve(ln); err != nil { + log.Fatal("Listen: ", err) + } +} + +// Shutdown server gracefully +func (r *Fiber) Shutdown() error { + if r.httpServer == nil { + return fmt.Errorf("Server is not running") + } + return r.httpServer.Shutdown() +} + +// https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ +func (r *Fiber) prefork(host string, tls ...string) { + // Master proc + if !r.child { + // Create babies + childs := make([]*exec.Cmd, runtime.NumCPU()) + + // #nosec G204 + for i := range childs { + childs[i] = exec.Command(os.Args[0], "-prefork", "-child") + childs[i].Stdout = os.Stdout + childs[i].Stderr = os.Stderr + if err := childs[i].Start(); err != nil { + log.Fatal("Listen-prefork: ", err) + } + } + + for _, child := range childs { + if err := child.Wait(); err != nil { + log.Fatal("Listen-prefork: ", err) + } + + } + + os.Exit(0) + } + + // Child proc + runtime.GOMAXPROCS(1) + + ln, err := reuseport.Listen("tcp4", host) + if err != nil { + log.Fatal("Listen-prefork: ", err) + } + + // enable TLS/HTTPS + if len(tls) > 1 { + if err := r.httpServer.ServeTLS(ln, tls[0], tls[1]); err != nil { + log.Fatal("Listen-prefork: ", err) + } + } + + 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/application_test.go b/application_test.go new file mode 100644 index 00000000..b4690a4b --- /dev/null +++ b/application_test.go @@ -0,0 +1,72 @@ +package fiber + +import ( + "net/http" + "testing" +) + +func Test_Methods(t *testing.T) { + app := New() + + handler := func(c *Ctx) {} + methods := []string{"CONNECT", "PUT", "POST", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE", "GET", "ALL", "USE"} + + app.Connect("/CONNECT", handler) + app.Put("/PUT", handler) + app.Post("/POST", handler) + app.Delete("/DELETE", handler) + app.Head("/HEAD", handler) + app.Patch("/PATCH", handler) + app.Options("/OPTIONS", handler) + app.Trace("/TRACE", handler) + app.Get("/GET", handler) + app.All("/ALL", handler) + app.Use("/USE", handler) + + for _, method := range methods { + var req *http.Request + if method == "ALL" { + req, _ = http.NewRequest("CONNECT", "/"+method, nil) + } else if method == "USE" { + req, _ = http.NewRequest("OPTIONS", "/"+method+"/test", nil) + } else { + req, _ = http.NewRequest(method, "/"+method, nil) + } + resp, err := app.Test(req) + if err != nil { + t.Fatalf(`%s: %s %s`, t.Name(), method, err) + } + if resp.StatusCode != 200 { + t.Fatalf(`%s: %s expecting 200 but received %v`, t.Name(), method, resp.StatusCode) + } + } +} + +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/context.go b/context.go deleted file mode 100644 index 0f7428e6..00000000 --- a/context.go +++ /dev/null @@ -1,59 +0,0 @@ -// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖 -// 📌 Please open an issue if you got suggestions or found a bug! -// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki - -// 🦸 Not all heroes wear capes, thank you to some amazing people -// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr - -package fiber - -import ( - "sync" - - "github.com/valyala/fasthttp" -) - -// Ctx : struct -type Ctx struct { - route *Route - next bool - params *[]string - values []string - Fasthttp *fasthttp.RequestCtx -} - -// Cookie : struct -type Cookie struct { - Expire int // time.Unix(1578981376, 0) - MaxAge int - Domain string - Path string - - HTTPOnly bool - Secure bool - SameSite string -} - -// Ctx pool -var poolCtx = sync.Pool{ - New: func() interface{} { - return new(Ctx) - }, -} - -// Get new Ctx from pool -func acquireCtx(fctx *fasthttp.RequestCtx) *Ctx { - ctx := poolCtx.Get().(*Ctx) - ctx.Fasthttp = fctx - return ctx -} - -// Return Context to pool -func releaseCtx(ctx *Ctx) { - ctx.route = nil - ctx.next = false - ctx.params = nil - ctx.values = nil - ctx.Fasthttp = nil - poolCtx.Put(ctx) -} diff --git a/listen.go b/listen.go deleted file mode 100644 index 2f886b1b..00000000 --- a/listen.go +++ /dev/null @@ -1,151 +0,0 @@ -// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖 -// 📌 Please open an issue if you got suggestions or found a bug! -// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki - -// 🦸 Not all heroes wear capes, thank you to some amazing people -// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr - -package fiber - -import ( - "fmt" - "log" - "net" - "os" - "os/exec" - "runtime" - "strconv" - "strings" - - "github.com/valyala/fasthttp" - "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://fiber.wiki/application#listen -func (r *Fiber) Listen(address interface{}, tls ...string) { - host := "" - switch val := address.(type) { - case int: - host = ":" + strconv.Itoa(val) // 8080 => ":8080" - case string: - if !strings.Contains(val, ":") { - val = ":" + val // "8080" => ":8080" - } - host = val - default: - log.Fatal("Listen: Host must be an INT port or STRING address") - } - // Create fasthttp server - r.httpServer = r.setupServer() - - // Prefork enabled - if r.Prefork && runtime.NumCPU() > 1 { - if r.Banner && !r.child { - cores := fmt.Sprintf("%s\x1b[1;30m %v cores", host, runtime.NumCPU()) - fmt.Printf(banner, Version, " prefork", "Express on steroids", cores) - } - r.prefork(host, tls...) - } - - // Prefork disabled - if r.Banner { - fmt.Printf(banner, Version, "", "Express on steroids", host) - } - - ln, err := net.Listen("tcp4", host) - if err != nil { - log.Fatal("Listen: ", err) - } - - // enable TLS/HTTPS - if len(tls) > 1 { - if err := r.httpServer.ServeTLS(ln, tls[0], tls[1]); err != nil { - log.Fatal("Listen: ", err) - } - } - - 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(host string, tls ...string) { - // Master proc - if !r.child { - // Create babies - childs := make([]*exec.Cmd, runtime.NumCPU()) - - // #nosec G204 - for i := range childs { - childs[i] = exec.Command(os.Args[0], "-prefork", "-child") - childs[i].Stdout = os.Stdout - childs[i].Stderr = os.Stderr - if err := childs[i].Start(); err != nil { - log.Fatal("Listen-prefork: ", err) - } - } - - for _, child := range childs { - if err := child.Wait(); err != nil { - log.Fatal("Listen-prefork: ", err) - } - - } - - os.Exit(0) - } - - // Child proc - runtime.GOMAXPROCS(1) - - ln, err := reuseport.Listen("tcp4", host) - if err != nil { - log.Fatal("Listen-prefork: ", err) - } - - // enable TLS/HTTPS - if len(tls) > 1 { - if err := r.httpServer.ServeTLS(ln, tls[0], tls[1]); err != nil { - log.Fatal("Listen-prefork: ", err) - } - } - - 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 deleted file mode 100644 index 6aad4b14..00000000 --- a/listen_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package fiber - -import ( - "testing" -) - -// var wg sync.WaitGroup - -func Test_Connect(t *testing.T) { - // 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.go b/methods.go deleted file mode 100644 index 349fed78..00000000 --- a/methods.go +++ /dev/null @@ -1,70 +0,0 @@ -// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖 -// 📌 Please open an issue if you got suggestions or found a bug! -// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki - -// 🦸 Not all heroes wear capes, thank you to some amazing people -// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr - -package fiber - -// Connect establishes a tunnel to the server -// identified by the target resource. -func (r *Fiber) Connect(args ...interface{}) { - r.register("CONNECT", args...) -} - -// Put replaces all current representations -// of the target resource with the request payload. -func (r *Fiber) Put(args ...interface{}) { - r.register("PUT", args...) -} - -// Post is used to submit an entity to the specified resource, -// often causing a change in state or side effects on the server. -func (r *Fiber) Post(args ...interface{}) { - r.register("POST", args...) -} - -// Delete deletes the specified resource. -func (r *Fiber) Delete(args ...interface{}) { - r.register("DELETE", args...) -} - -// Head asks for a response identical to that of a GET request, -// but without the response body. -func (r *Fiber) Head(args ...interface{}) { - r.register("HEAD", args...) -} - -// Patch is used to apply partial modifications to a resource. -func (r *Fiber) Patch(args ...interface{}) { - r.register("PATCH", args...) -} - -// Options is used to describe the communication options -// for the target resource. -func (r *Fiber) Options(args ...interface{}) { - r.register("OPTIONS", args...) -} - -// Trace performs a message loop-back test -// along the path to the target resource. -func (r *Fiber) Trace(args ...interface{}) { - r.register("TRACE", args...) -} - -// Get requests a representation of the specified resource. -// Requests using GET should only retrieve data. -func (r *Fiber) Get(args ...interface{}) { - r.register("GET", args...) -} - -// All matches any HTTP method -func (r *Fiber) All(args ...interface{}) { - r.register("ALL", args...) -} - -// Use only matches the starting path -func (r *Fiber) Use(args ...interface{}) { - r.register("MIDWARE", args...) -} diff --git a/methods_test.go b/methods_test.go deleted file mode 100644 index 6d8f32db..00000000 --- a/methods_test.go +++ /dev/null @@ -1,109 +0,0 @@ -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/response.go b/response.go index 0fbf5c72..e7f20726 100644 --- a/response.go +++ b/response.go @@ -19,6 +19,18 @@ import ( "github.com/valyala/fasthttp" ) +// Cookie : struct +type Cookie struct { + Expire int // time.Unix(1578981376, 0) + MaxAge int + Domain string + Path string + + HTTPOnly bool + Secure bool + SameSite string +} + // Append : https://fiber.wiki/context#append func (ctx *Ctx) Append(field string, values ...string) { if len(values) == 0 { @@ -224,7 +236,7 @@ func (ctx *Ctx) JsonString(raw string) { ctx.JSONString(raw) } -// JSONString : https://fiber.wiki/context#jsonstring +// JSONString : https://fiber.wiki/context#json func (ctx *Ctx) JSONString(raw string) { ctx.Fasthttp.Response.Header.SetContentType(contentTypeJSON) ctx.Fasthttp.Response.SetBodyString(raw) diff --git a/router.go b/router.go index 27fa85b0..d5ae1dd6 100644 --- a/router.go +++ b/router.go @@ -11,10 +11,20 @@ import ( "log" "regexp" "strings" + "sync" "github.com/valyala/fasthttp" ) +// Ctx : struct +type Ctx struct { + route *Route + next bool + params *[]string + values []string + Fasthttp *fasthttp.RequestCtx +} + // Route : struct type Route struct { // HTTP method in uppercase, can be a * for Use() & All() @@ -33,6 +43,30 @@ type Route struct { Handler func(*Ctx) } +// Ctx pool +var poolCtx = sync.Pool{ + New: func() interface{} { + return new(Ctx) + }, +} + +// Get new Ctx from pool +func acquireCtx(fctx *fasthttp.RequestCtx) *Ctx { + ctx := poolCtx.Get().(*Ctx) + ctx.Fasthttp = fctx + return ctx +} + +// Return Context to pool +func releaseCtx(ctx *Ctx) { + ctx.route = nil + ctx.next = false + ctx.params = nil + ctx.values = nil + ctx.Fasthttp = nil + poolCtx.Put(ctx) +} + // Function to add a route correctly func (r *Fiber) register(method string, args ...interface{}) { // Set if method is Use() midware diff --git a/router_test.go b/router_test.go new file mode 100644 index 00000000..b277214c --- /dev/null +++ b/router_test.go @@ -0,0 +1 @@ +package fiber diff --git a/static.go b/static.go deleted file mode 100644 index 29571898..00000000 --- a/static.go +++ /dev/null @@ -1,83 +0,0 @@ -// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖 -// 📌 Please open an issue if you got suggestions or found a bug! -// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki - -// 🦸 Not all heroes wear capes, thank you to some amazing people -// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr - -package fiber - -import ( - "log" - "os" - "path/filepath" - "strings" -) - -// Static https://fiber.wiki/application#static -func (r *Fiber) Static(args ...string) { - prefix := "/" - root := "./" - wildcard := false - // enable / disable gzipping somewhere? - // todo v2.0.0 - gzip := true - - if len(args) == 1 { - root = args[0] - } else if len(args) == 2 { - prefix = args[0] - root = args[1] - if prefix[0] != '/' { - prefix = "/" + prefix - } - } - - // Check if wildcard for single files - // app.Static("*", "./public/index.html") - // app.Static("/*", "./public/index.html") - if prefix == "*" || prefix == "/*" { - 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 { - log.Fatal("Static: ", err) - } - - // ./static/compiled => static/compiled - mount := filepath.Clean(root) - - // Loop over all files - for _, file := range files { - // Ignore the .gzipped files by fasthttp - if strings.Contains(file, ".fasthttp.gz") { - continue - } - - // Time to create a fake path for the route match - // static/index.html => /index.html - path := filepath.Join(prefix, strings.Replace(file, mount, "", 1)) - - // Store original file path to use in ctx handler - filePath := file - - // If the file is an index.html, bind the prefix to index.html directly - if filepath.Base(filePath) == "index.html" || filepath.Base(filePath) == "index.htm" { - r.routes = append(r.routes, &Route{"GET", prefix, wildcard, false, nil, nil, func(c *Ctx) { - c.SendFile(filePath, gzip) - }}) - } - - // Add the route + SendFile(filepath) to routes - r.routes = append(r.routes, &Route{"GET", path, wildcard, false, nil, nil, func(c *Ctx) { - c.SendFile(filePath, gzip) - }}) - } -} diff --git a/static_test.go b/static_test.go deleted file mode 100644 index e291c9a7..00000000 --- a/static_test.go +++ /dev/null @@ -1,35 +0,0 @@ -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/status.go b/status.go deleted file mode 100644 index 2755d323..00000000 --- a/status.go +++ /dev/null @@ -1,71 +0,0 @@ -// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖 -// 📌 Please open an issue if you got suggestions or found a bug! -// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki - -// 🦸 Not all heroes wear capes, thank you to some amazing people -// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr - -package fiber - -var statusMessages = map[int]string{ - 100: "Continue", - 101: "Switching Protocols", - 102: "Processing", - 200: "OK", - 201: "Created", - 202: "Accepted", - 203: "Non-Authoritative Information", - 204: "No Content", - 205: "Reset Content", - 206: "Partial Content", - 207: "Multi-Status", - 208: "Already Reported", - 226: "IM Used", - 300: "Multiple Choices", - 301: "Moved Permanently", - 302: "Found", - 303: "See Other", - 304: "Not Modified", - 305: "Use Proxy", - 306: "Switch Proxy", - 307: "Temporary Redirect", - 308: "Permanent Redirect", - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Timeout", - 409: "Conflict", - 410: "Gone", - 411: "Length Required", - 412: "Precondition Failed", - 413: "Request Entity Too Large", - 414: "Request URI Too Long", - 415: "Unsupported Media Type", - 416: "Requested Range Not Satisfiable", - 417: "Expectation Failed", - 418: "I'm a teapot", - 422: "Unprocessable Entity", - 423: "Locked", - 424: "Failed Dependency", - 426: "Upgrade Required", - 428: "Precondition Required", - 429: "Too Many Requests", - 431: "Request Header Fields Too Large", - 451: "Unavailable For Legal Reasons", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Timeout", - 505: "HTTP Version Not Supported", - 506: "Variant Also Negotiates", - 507: "Insufficient Storage", - 508: "Loop Detected", - 510: "Not Extended", - 511: "Network Authentication Required", -} diff --git a/types.go b/types.go deleted file mode 100644 index ac38053f..00000000 --- a/types.go +++ /dev/null @@ -1,124 +0,0 @@ -// 🚀 Fiber is an Express.js inspired web framework written in Go with 💖 -// 📌 Please open an issue if you got suggestions or found a bug! -// 🖥 Links: https://github.com/gofiber/fiber, https://fiber.wiki - -// 🦸 Not all heroes wear capes, thank you to some amazing people -// 💖 @valyala, @erikdubbelboer, @savsgio, @julienschmidt, @koddr - -package fiber - -const ( - contentTypeJSON = "application/json" - contentTypeJs = "application/javascript" - contentTypeXML = "application/xml" - contentTypeOctetStream = "application/octet-stream" -) - -// https://github.com/nginx/nginx/blob/master/conf/mime.types -var contentTypes = map[string]string{ - "html": "text/html", - "htm": "text/html", - "shtml": "text/html", - "css": "text/css", - "xml": "text/xml", - "gif": "image/gif", - "jpeg": "image/jpeg", - "jpg": "image/jpeg", - "js": "application/javascript", - "atom": "application/atom+xml", - "rss": "application/rss+xml", - "mml": "text/mathml", - "txt": "text/plain", - "jad": "text/vnd.sun.j2me.app-descriptor", - "wml": "text/vnd.wap.wml", - "htc": "text/x-component", - "png": "image/png", - "svg": "image/svg+xml", - "svgz": "image/svg+xml", - "tif": "image/tiff", - "tiff": "image/tiff", - "wbmp": "image/vnd.wap.wbmp", - "webp": "image/webp", - "ico": "image/x-icon", - "jng": "image/x-jng", - "bmp": "image/x-ms-bmp", - "woff": "font/woff", - "woff2": "font/woff2", - "jar": "application/java-archive", - "war": "application/java-archive", - "ear": "application/java-archive", - "json": "application/json", - "hqx": "application/mac-binhex40", - "doc": "application/msword", - "pdf": "application/pdf", - "ps": "application/postscript", - "eps": "application/postscript", - "ai": "application/postscript", - "rtf": "application/rtf", - "m3u8": "application/vnd.apple.mpegurl", - "kml": "application/vnd.google-earth.kml+xml", - "kmz": "application/vnd.google-earth.kmz", - "xls": "application/vnd.ms-excel", - "eot": "application/vnd.ms-fontobject", - "ppt": "application/vnd.ms-powerpoint", - "odg": "application/vnd.oasis.opendocument.graphics", - "odp": "application/vnd.oasis.opendocument.presentation", - "ods": "application/vnd.oasis.opendocument.spreadsheet", - "odt": "application/vnd.oasis.opendocument.text", - "wmlc": "application/vnd.wap.wmlc", - "7z": "application/x-7z-compressed", - "cco": "application/x-cocoa", - "jardiff": "application/x-java-archive-diff", - "jnlp": "application/x-java-jnlp-file", - "run": "application/x-makeself", - "pl": "application/x-perl", - "pm": "application/x-perl", - "prc": "application/x-pilot", - "pdb": "application/x-pilot", - "rar": "application/x-rar-compressed", - "rpm": "application/x-redhat-package-manager", - "sea": "application/x-sea", - "swf": "application/x-shockwave-flash", - "sit": "application/x-stuffit", - "tcl": "application/x-tcl", - "tk": "application/x-tcl", - "der": "application/x-x509-ca-cert", - "pem": "application/x-x509-ca-cert", - "crt": "application/x-x509-ca-cert", - "xpi": "application/x-xpinstall", - "xhtml": "application/xhtml+xml", - "xspf": "application/xspf+xml", - "zip": "application/zip", - "bin": "application/octet-stream", - "exe": "application/octet-stream", - "dll": "application/octet-stream", - "deb": "application/octet-stream", - "dmg": "application/octet-stream", - "iso": "application/octet-stream", - "img": "application/octet-stream", - "msi": "application/octet-stream", - "msp": "application/octet-stream", - "msm": "application/octet-stream", - "mid": "audio/midi", - "midi": "audio/midi", - "kar": "audio/midi", - "mp3": "audio/mpeg", - "ogg": "audio/ogg", - "m4a": "audio/x-m4a", - "ra": "audio/x-realaudio", - "3gpp": "video/3gpp", - "3gp": "video/3gpp", - "ts": "video/mp2t", - "mp4": "video/mp4", - "mpeg": "video/mpeg", - "mpg": "video/mpeg", - "mov": "video/quicktime", - "webm": "video/webm", - "flv": "video/x-flv", - "m4v": "video/x-m4v", - "mng": "video/x-mng", - "asx": "video/x-ms-asf", - "asf": "video/x-ms-asf", - "wmv": "video/x-ms-wmv", - "avi": "video/x-msvideo", -} diff --git a/utils.go b/utils.go index 806a6e12..3a3c4a5c 100644 --- a/utils.go +++ b/utils.go @@ -179,3 +179,182 @@ 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 } + +var statusMessages = map[int]string{ + 100: "Continue", + 101: "Switching Protocols", + 102: "Processing", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 207: "Multi-Status", + 208: "Already Reported", + 226: "IM Used", + 300: "Multiple Choices", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 306: "Switch Proxy", + 307: "Temporary Redirect", + 308: "Permanent Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 418: "I'm a teapot", + 422: "Unprocessable Entity", + 423: "Locked", + 424: "Failed Dependency", + 426: "Upgrade Required", + 428: "Precondition Required", + 429: "Too Many Requests", + 431: "Request Header Fields Too Large", + 451: "Unavailable For Legal Reasons", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported", + 506: "Variant Also Negotiates", + 507: "Insufficient Storage", + 508: "Loop Detected", + 510: "Not Extended", + 511: "Network Authentication Required", +} + +const ( + contentTypeJSON = "application/json" + contentTypeJs = "application/javascript" + contentTypeXML = "application/xml" + contentTypeOctetStream = "application/octet-stream" +) + +// https://github.com/nginx/nginx/blob/master/conf/mime.types +var contentTypes = map[string]string{ + "html": "text/html", + "htm": "text/html", + "shtml": "text/html", + "css": "text/css", + "xml": "text/xml", + "gif": "image/gif", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "js": "application/javascript", + "atom": "application/atom+xml", + "rss": "application/rss+xml", + "mml": "text/mathml", + "txt": "text/plain", + "jad": "text/vnd.sun.j2me.app-descriptor", + "wml": "text/vnd.wap.wml", + "htc": "text/x-component", + "png": "image/png", + "svg": "image/svg+xml", + "svgz": "image/svg+xml", + "tif": "image/tiff", + "tiff": "image/tiff", + "wbmp": "image/vnd.wap.wbmp", + "webp": "image/webp", + "ico": "image/x-icon", + "jng": "image/x-jng", + "bmp": "image/x-ms-bmp", + "woff": "font/woff", + "woff2": "font/woff2", + "jar": "application/java-archive", + "war": "application/java-archive", + "ear": "application/java-archive", + "json": "application/json", + "hqx": "application/mac-binhex40", + "doc": "application/msword", + "pdf": "application/pdf", + "ps": "application/postscript", + "eps": "application/postscript", + "ai": "application/postscript", + "rtf": "application/rtf", + "m3u8": "application/vnd.apple.mpegurl", + "kml": "application/vnd.google-earth.kml+xml", + "kmz": "application/vnd.google-earth.kmz", + "xls": "application/vnd.ms-excel", + "eot": "application/vnd.ms-fontobject", + "ppt": "application/vnd.ms-powerpoint", + "odg": "application/vnd.oasis.opendocument.graphics", + "odp": "application/vnd.oasis.opendocument.presentation", + "ods": "application/vnd.oasis.opendocument.spreadsheet", + "odt": "application/vnd.oasis.opendocument.text", + "wmlc": "application/vnd.wap.wmlc", + "7z": "application/x-7z-compressed", + "cco": "application/x-cocoa", + "jardiff": "application/x-java-archive-diff", + "jnlp": "application/x-java-jnlp-file", + "run": "application/x-makeself", + "pl": "application/x-perl", + "pm": "application/x-perl", + "prc": "application/x-pilot", + "pdb": "application/x-pilot", + "rar": "application/x-rar-compressed", + "rpm": "application/x-redhat-package-manager", + "sea": "application/x-sea", + "swf": "application/x-shockwave-flash", + "sit": "application/x-stuffit", + "tcl": "application/x-tcl", + "tk": "application/x-tcl", + "der": "application/x-x509-ca-cert", + "pem": "application/x-x509-ca-cert", + "crt": "application/x-x509-ca-cert", + "xpi": "application/x-xpinstall", + "xhtml": "application/xhtml+xml", + "xspf": "application/xspf+xml", + "zip": "application/zip", + "bin": "application/octet-stream", + "exe": "application/octet-stream", + "dll": "application/octet-stream", + "deb": "application/octet-stream", + "dmg": "application/octet-stream", + "iso": "application/octet-stream", + "img": "application/octet-stream", + "msi": "application/octet-stream", + "msp": "application/octet-stream", + "msm": "application/octet-stream", + "mid": "audio/midi", + "midi": "audio/midi", + "kar": "audio/midi", + "mp3": "audio/mpeg", + "ogg": "audio/ogg", + "m4a": "audio/x-m4a", + "ra": "audio/x-realaudio", + "3gpp": "video/3gpp", + "3gp": "video/3gpp", + "ts": "video/mp2t", + "mp4": "video/mp4", + "mpeg": "video/mpeg", + "mpg": "video/mpeg", + "mov": "video/quicktime", + "webm": "video/webm", + "flv": "video/x-flv", + "m4v": "video/x-m4v", + "mng": "video/x-mng", + "asx": "video/x-ms-asf", + "asf": "video/x-ms-asf", + "wmv": "video/x-ms-wmv", + "avi": "video/x-msvideo", +} diff --git a/utils_test.go b/utils_test.go new file mode 100644 index 00000000..b277214c --- /dev/null +++ b/utils_test.go @@ -0,0 +1 @@ +package fiber