Use param support + optimizations (#361)

* Benchmark workflow

* Update router.go

* Clean root

* Add mutex

* Benchmark workflow

* Benchmark workflow
* Add mutex
* Enable benchmark tests
* Enable race testing

Co-Authored-By: ReneWerner87 <renewerner87@users.noreply.github.com>

* Benchmark Workflow

* Benchmark workflow
* Add mutex
* Enable benchmark tests
* Enable race testing

Co-Authored-By: ReneWerner87 <renewerner87@users.noreply.github.com>

* Update security workflow

* Benchmark workflow
* Add mutex
* Enable benchmark tests
* Enable race testing

Co-Authored-By: ReneWerner87 <renewerner87@users.noreply.github.com>

* Make Ctx pool accessible

- Add ctx benchmarks

* v1.9.6

* v1.9.6

Co-Authored-By: ReneWerner87 <renewerner87@googlemail.com>

* Improve context functions

* Add utils benchmarks

* Update benchmarks & tests

* Add utils tests

* New tests

* update test

* Move fastpath tests

* offer negotiation

* Cleanup

* Update Vary

Co-Authored-By: RW <renewerner87@googlemail.com>

* Optimize Append

Co-Authored-By: RW <renewerner87@googlemail.com>

* Optimize more methods

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>

* Add param support to Use

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>

* Add use_params tests

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>

* v1.9.7

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>

* Tests

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>

* v1.9.7

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>
Co-Authored-By: József Sallai <jozsef@sallai.me>
Co-Authored-By: Thomas van Vugt <thomasvvugt@users.noreply.github.com>

* Update app_test.go

Co-Authored-By: RW <renewerner87@googlemail.com>
Co-Authored-By: Vic Shóstak <vikkyshostak@gmail.com>
Co-Authored-By: József Sallai <jozsef@sallai.me>
Co-Authored-By: Thomas van Vugt <thomasvvugt@users.noreply.github.com>
Co-Authored-By: Nifty255 <nifty255@users.noreply.github.com>

* Rename argument

Co-Authored-By: RW <renewerner87@googlemail.com>

* Add nosec for WriteByte

Co-Authored-By: RW <renewerner87@googlemail.com>

* Add media article

* Update media articles

* Fix typo

Co-Authored-By: Thomas van Vugt <thomasvvugt@users.noreply.github.com>

* Fix typo

Co-authored-by: ReneWerner87 <renewerner87@users.noreply.github.com>
Co-authored-by: ReneWerner87 <renewerner87@googlemail.com>
Co-authored-by: Vic Shóstak <vikkyshostak@gmail.com>
Co-authored-by: József Sallai <jozsef@sallai.me>
Co-authored-by: Thomas van Vugt <thomasvvugt@users.noreply.github.com>
Co-authored-by: Nifty255 <nifty255@users.noreply.github.com>
pull/366/head
Fenny 2020-05-12 19:24:04 +02:00 committed by GitHub
parent 99f95b2561
commit e719fa00bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1563 additions and 1342 deletions

12
.github/README.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Media
@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Contribute
@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

14
.github/README_de.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Medien
@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Mitwirken
@ -526,6 +530,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -541,6 +546,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](https://github.com/gofiber/fiber/graphs/contributors). `Fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/blob/master/LICENSE). Official logo was created by [Vic Shóstak](https://github.com/koddr) and distributed under [Creative Commons](https://creativecommons.org/licenses/by-sa/4.0/) license (CC BY-SA 4.0 International).
**Third-party library licenses**
**Third-party MIT licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_es.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Medios
@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Contribuir
@ -526,6 +530,7 @@ Fiber es un proyecto open source que se mantiene a través de donaciones para pa
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -544,3 +549,4 @@ Copyright (c) 2019-presente [Fenny](https://github.com/fenny) y [contribuyentes]
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_fr.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Media
@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Contribuer
@ -526,6 +530,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -544,3 +549,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

13
.github/README_he.md vendored
View File

@ -66,7 +66,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</div>
</p>
@ -579,15 +579,16 @@ For an more _maintainable_ middleware _ecosystem_, we've put official [middlewar
<div dir="rtl">
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -615,6 +616,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
</div>
<div dir="rtl">
@ -630,7 +633,9 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Is switching from Express to Fiber worth it? 🤔](https://dev.to/koddr/are-sure-what-your-lovely-web-framework-running-so-fast-2jl1) — _01 Apr 2020_
- [Creating Fast APIs In Go Using Fiber](https://dev.to/jozsefsallai/creating-fast-apis-in-go-using-fiber-59m9) — _07 Apr 2020_
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
</div>
<div dir="rtl">
@ -672,6 +677,7 @@ Fiber היא פרויקט קוד פתוח שתשלום חשובונתיו מסת
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -702,4 +708,5 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**רישיונות של ספריות צד שלישי**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)
</div>

12
.github/README_id.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -469,15 +469,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -494,6 +495,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Media
@ -505,6 +508,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Berkontribusi
@ -528,6 +532,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -546,3 +551,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_ja.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 メディア
@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 貢献する
@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_ko.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 미디어
@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 기여
@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_nl.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -471,15 +471,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -496,6 +497,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Media
@ -507,6 +510,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Bijdragen
@ -530,6 +534,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -548,3 +553,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_pt.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -467,15 +467,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -492,6 +493,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Mídia
@ -503,6 +506,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Contribuindo
@ -526,6 +530,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -544,3 +549,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

12
.github/README_ru.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -469,15 +469,16 @@ func main() {
Чтобы создать более _поддерживаемую_ middleware _экосистему_, мы вынесли [middlewares](https://docs.gofiber.io/middleware) в отдельные репозитории:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -495,6 +496,8 @@ func main() {
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Медиа
@ -506,6 +509,7 @@ func main() {
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Помощь проекту
@ -531,6 +535,7 @@ Fiber — это проект с открытым исходным кодом,
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -549,3 +554,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

27
.github/README_tr.md vendored
View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -465,15 +465,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -490,17 +491,21 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 Medya
- [Welcome to Fiber — an Express.js styled web framework written in Go with ❤️](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) — _03 Şubat 2020_
- [Fiber released v1.7! 🎉 What's new and is it still fast, flexible and friendly?](https://dev.to/koddr/fiber-v2-is-out-now-what-s-new-and-is-he-still-fast-flexible-and-friendly-3ipf) — _21 Şubat 2020_
- [🚀 Fiber v1.8. What's new, updated and re-thinked?](https://dev.to/koddr/fiber-v1-8-what-s-new-updated-and-re-thinked-339h) — _03 Mart 2020_
- [Is switching from Express to Fiber worth it? 🤔](https://dev.to/koddr/are-sure-what-your-lovely-web-framework-running-so-fast-2jl1) — _01 Nisan 2020_
- [Creating Fast APIs In Go Using Fiber](https://dev.to/jozsefsallai/creating-fast-apis-in-go-using-fiber-59m9) — _07 Nisan 2020_
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Nisan 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Nisan 2020_
- [Welcome to Fiber — an Express.js styled web framework written in Go with ❤️](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) — _03 Feb 2020_
- [Fiber released v1.7! 🎉 What's new and is it still fast, flexible and friendly?](https://dev.to/koddr/fiber-v2-is-out-now-what-s-new-and-is-he-still-fast-flexible-and-friendly-3ipf) — _21 Feb 2020_
- [🚀 Fiber v1.8. What's new, updated and re-thinked?](https://dev.to/koddr/fiber-v1-8-what-s-new-updated-and-re-thinked-339h) — _03 Mar 2020_
- [Is switching from Express to Fiber worth it? 🤔](https://dev.to/koddr/are-sure-what-your-lovely-web-framework-running-so-fast-2jl1) — _01 Apr 2020_
- [Creating Fast APIs In Go Using Fiber](https://dev.to/jozsefsallai/creating-fast-apis-in-go-using-fiber-59m9) — _07 Apr 2020_
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 Destek
@ -523,6 +528,7 @@ Fiber, alan adı, gitbook, netlify, serverless yer sağlayıcısı giderleri ve
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -541,3 +547,4 @@ Telif (c) 2019-günümüz [Fenny](https://github.com/fenny) ve [Contributors](ht
**3. Parti yazılım lisanları**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

View File

@ -65,7 +65,7 @@
<img src="https://img.shields.io/github/workflow/status/gofiber/fiber/Gosec?label=gosec&style=flat-square">
</a>
<a href="https://gofiber.io/discord">
<img src="https://img.shields.io/badge/Discord-join%20channel-7289DA?style=flat-square">
<img src="https://img.shields.io/badge/discord-join%20channel-7289DA?style=flat-square">
</a>
</p>
<p align="center">
@ -470,15 +470,16 @@ func main() {
For an more _maintainable_ middleware _ecosystem_, we've put official [middlewares](https://docs.gofiber.io/middleware) into separate repositories:
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/compression](https://github.com/gofiber/compression)
- [gofiber/basicauth](https://github.com/gofiber/basicauth)
- [gofiber/requestid](https://github.com/gofiber/requestid)
- [gofiber/websocket](https://github.com/gofiber/websocket)
- [gofiber/keyauth](https://github.com/gofiber/keyauth)
- [gofiber/rewrite](https://github.com/gofiber/rewrite)
- [gofiber/recover](https://github.com/gofiber/recover)
- [gofiber/limiter](https://github.com/gofiber/limiter)
- [gofiber/session](https://github.com/gofiber/session)
- [gofiber/adaptor](https://github.com/gofiber/adaptor)
- [gofiber/logger](https://github.com/gofiber/logger)
- [gofiber/helmet](https://github.com/gofiber/helmet)
- [gofiber/embed](https://github.com/gofiber/embed)
@ -495,6 +496,8 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [arsmn/fiber-introspect](https://github.com/arsmn/fiber-introspect)
- [shareed2k/fiber_tracing](https://github.com/shareed2k/fiber_tracing)
- [shareed2k/fiber_limiter](https://github.com/shareed2k/fiber_limiter)
- [thomasvvugt/fiber-boilerplate](https://github.com/thomasvvugt/fiber-boilerplate)
- [arsmn/gqlgen](https://github.com/arsmn/gqlgen)
## 💬 媒体
@ -506,6 +509,7 @@ This is a list of middlewares that are created by the Fiber community, please cr
- [Building a Basic REST API in Go using Fiber](https://tutorialedge.net/golang/basic-rest-api-go-fiber/) - _23 Apr 2020_
- [📺 Building a REST API using GORM and Fiber](https://youtu.be/Iq2qT0fRhAA) - _25 Apr 2020_
- [🌎 Create a travel list app with Go, Fiber, Angular, MongoDB and Google Cloud Secret Manager](https://blog.yongweilun.me/create-a-travel-list-app-with-go-fiber-angular-mongodb-and-google-cloud-secret-manager-ck9fgxy0p061pcss1xt1ubu8t) - _25 Apr 2020_
- [Fiber v1.9.6 🔥 How to improve performance by 817% and stay fast, flexible and friendly?](https://dev.to/koddr/fiber-v1-9-5-how-to-improve-performance-by-817-and-stay-fast-flexible-and-friendly-2dp6) - _12 May 2020_
## 👍 贡献
@ -529,6 +533,7 @@ Fiber is an open source project that runs on donations to pay the bills e.g. our
| ![](https://avatars.githubusercontent.com/u/635852?s=25 ) | [@bihe](https://github.com/bihe) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/307334?s=25 ) | [@justdave](https://github.com/justdave) | ☕ x 3 |
| ![](https://avatars.githubusercontent.com/u/11155743?s=25 ) | [@koddr](https://github.com/koddr) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/29042462?s=25 ) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/2978730?s=25 ) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/44171355?s=25 ) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 |
| ![](https://avatars.githubusercontent.com/u/5638101?s=25 ) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 |
@ -547,3 +552,4 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](
**Third-party library licenses**
- [FastHTTP](https://github.com/valyala/fasthttp/blob/master/LICENSE)
- [Schema](https://github.com/gorilla/schema/blob/master/LICENSE)
- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE)

48
app.go
View File

@ -25,7 +25,7 @@ import (
)
// Version of current package
const Version = "1.9.6"
const Version = "1.9.7"
// Map is a shortcut for map[string]interface{}
type Map map[string]interface{}
@ -33,8 +33,7 @@ type Map map[string]interface{}
// App denotes the Fiber application.
type App struct {
// Internal fields
testconn *testConn // Test connection
routes [][]*Route // Route stack
routes [][]*Route // Route stack
// External fields
Settings *Settings // Fiber settings
@ -144,10 +143,8 @@ func New(settings ...*Settings) *App {
getBytes = getBytesImmutable
}
}
// Setup test listener
app.testconn = new(testConn)
// Setup server
app.server = app.newServer()
// Update fiber server settings with fasthttp server
app.updateSettings()
// Return application
return app
}
@ -353,10 +350,8 @@ func (grp *Group) All(path string, handlers ...func(*Ctx)) *Group {
// Preforkin is not available using app.Serve(ln net.Listener)
// You can pass an optional *tls.Config to enable TLS.
func (app *App) Serve(ln net.Listener, tlsconfig ...*tls.Config) error {
// Create fasthttp server
app.mutex.Lock()
app.server = app.newServer()
app.mutex.Unlock()
// Update fiber server settings
app.updateSettings()
// TLS config
if len(tlsconfig) > 0 {
ln = tls.NewListener(ln, tlsconfig[0])
@ -383,10 +378,8 @@ func (app *App) Listen(address interface{}, tlsconfig ...*tls.Config) error {
if !strings.Contains(addr, ":") {
addr = ":" + addr
}
// Create fasthttp server
app.mutex.Lock()
app.server = app.newServer()
app.mutex.Unlock()
// Update fiber server settings
app.updateSettings()
// Setup listener
var ln net.Listener
var err error
@ -428,14 +421,6 @@ func (app *App) Shutdown() error {
return app.server.Shutdown()
}
// TestRaw is like Test buf for raw HTTP strings: GET / HTTP/1.1\r\n\r\n
func (app *App) TestRaw(request string) error {
if _, err := app.testconn.r.WriteString(request); err != nil {
return err
}
return app.server.ServeConn(app.testconn)
}
// Test is used for internal debugging by passing a *http.Request
// Timeout is optional and defaults to 1s, -1 will disable it completely.
func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, error) {
@ -448,14 +433,18 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
if err != nil {
return nil, err
}
// Update server settings
app.updateSettings()
// Create test connection
conn := new(testConn)
// Write raw http request
if _, err = app.testconn.r.Write(dump); err != nil {
if _, err = conn.r.Write(dump); err != nil {
return nil, err
}
// Serve conn to server
channel := make(chan error)
go func() {
channel <- app.server.ServeConn(app.testconn)
channel <- app.server.ServeConn(conn)
}()
// Wait for callback
if timeout >= 0 {
@ -476,7 +465,7 @@ func (app *App) Test(request *http.Request, msTimeout ...int) (*http.Response, e
return nil, err
}
// Read response
buffer := bufio.NewReader(&app.testconn.w)
buffer := bufio.NewReader(&conn.w)
// Convert raw http response to *http.Response
resp, err := http.ReadResponse(buffer, request)
if err != nil {
@ -535,8 +524,10 @@ func (dl *disableLogger) Printf(format string, args ...interface{}) {
// fmt.Println(fmt.Sprintf(format, args...))
}
func (app *App) newServer() *fasthttp.Server {
return &fasthttp.Server{
func (app *App) updateSettings() {
// Create fasthttp server
app.mutex.Lock()
app.server = &fasthttp.Server{
Handler: app.handler,
Name: app.Settings.ServerHeader,
Concurrency: app.Settings.Concurrency,
@ -560,4 +551,5 @@ func (app *App) newServer() *fasthttp.Server {
}
},
}
app.mutex.Unlock()
}

View File

@ -3,3 +3,5 @@
// 📌 API Documentation: https://docs.gofiber.io
package fiber
// // go test -v ./... -run=^$ -bench=Benchmark_Ctx_Acce -benchmem -count=3

View File

@ -20,23 +20,19 @@ func testStatus200(t *testing.T, app *App, url string, method string) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Nested_Params(t *testing.T) {
func Test_App_Nested_Params(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
t.Log(c.Route().Path)
c.Status(400).Send("Should move on")
})
app.Get("/test/:param", func(c *Ctx) {
t.Log(c.Route().Path)
c.Status(400).Send("Should move on")
})
app.Get("/test/:param/test", func(c *Ctx) {
t.Log(c.Route().Path)
c.Status(400).Send("Should move on")
})
app.Get("/test/:param/test/:param2", func(c *Ctx) {
t.Log(c.Route().Path)
c.Status(200).Send("Good job")
})
@ -47,16 +43,27 @@ func Test_Nested_Params(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Raw(t *testing.T) {
func Test_App_Use_Params(t *testing.T) {
app := New()
app.Get("/", func(c *Ctx) {
c.SendString("Hello, World!")
app.Use("/prefix/:param", func(c *Ctx) {
assertEqual(t, "john", c.Params("param"))
})
app.TestRaw("GET / HTTP/1.1\r\n\r\n")
}
app.Use("/:param/*", func(c *Ctx) {
assertEqual(t, "john", c.Params("param"))
assertEqual(t, "doe", c.Params("*"))
})
func Test_Order(t *testing.T) {
resp, err := app.Test(httptest.NewRequest("GET", "/prefix/john", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
resp, err = app.Test(httptest.NewRequest("GET", "/john/doe", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_App_Order(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -83,7 +90,7 @@ func Test_Order(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, "123", string(body))
}
func Test_Methods(t *testing.T) {
func Test_App_Methods(t *testing.T) {
var dummyHandler = func(c *Ctx) {}
@ -124,7 +131,7 @@ func Test_Methods(t *testing.T) {
}
func Test_New(t *testing.T) {
func Test_App_New(t *testing.T) {
app := New()
app.Get("/", func(*Ctx) {
@ -138,14 +145,14 @@ func Test_New(t *testing.T) {
})
}
func Test_Shutdown(t *testing.T) {
func Test_App_Shutdown(t *testing.T) {
app := New(&Settings{
DisableStartupMessage: true,
})
_ = app.Shutdown()
}
func Test_Static(t *testing.T) {
func Test_App_Static(t *testing.T) {
app := New()
grp := app.Group("/v1")
@ -179,7 +186,7 @@ func Test_Static(t *testing.T) {
assertEqual(t, false, resp.Header.Get("Content-Length") == "")
}
func Test_Group(t *testing.T) {
func Test_App_Group(t *testing.T) {
var dummyHandler = func(c *Ctx) {}
app := New()
@ -229,7 +236,7 @@ func Test_Group(t *testing.T) {
testStatus200(t, app, "/test/v1/users", "GET")
}
func Test_Listen(t *testing.T) {
func Test_App_Listen(t *testing.T) {
app := New(&Settings{
DisableStartupMessage: true,
})
@ -245,7 +252,7 @@ func Test_Listen(t *testing.T) {
app.Listen("3003")
}
func Test_Serve(t *testing.T) {
func Test_App_Serve(t *testing.T) {
app := New(&Settings{
DisableStartupMessage: true,
Prefork: true,

207
ctx.go
View File

@ -24,6 +24,7 @@ import (
"time"
schema "github.com/gorilla/schema"
"github.com/valyala/bytebufferpool"
fasthttp "github.com/valyala/fasthttp"
)
@ -100,7 +101,7 @@ func ReleaseCtx(ctx *Ctx) {
}
// Accepts checks if the specified extensions or content types are acceptable.
func (ctx *Ctx) Accepts(offers ...string) (offer string) {
func (ctx *Ctx) Accepts(offers ...string) string {
if len(offers) == 0 {
return ""
}
@ -112,11 +113,6 @@ func (ctx *Ctx) Accepts(offers ...string) (offer string) {
specs := strings.Split(h, ",")
for i := range offers {
mimetype := getMIME(offers[i])
// if mimetype != "" {
// mimetype = strings.Split(mimetype, ";")[0]
// } else {
// mimetype = offer
// }
for k := range specs {
spec := strings.TrimSpace(specs[k])
if strings.HasPrefix(spec, "*/*") {
@ -138,80 +134,18 @@ func (ctx *Ctx) Accepts(offers ...string) (offer string) {
}
// AcceptsCharsets checks if the specified charset is acceptable.
func (ctx *Ctx) AcceptsCharsets(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
h := ctx.Get(HeaderAcceptCharset)
if h == "" {
return offers[0]
}
specs := strings.Split(h, ",")
for i := range offers {
for k := range specs {
spec := strings.TrimSpace(specs[k])
if strings.HasPrefix(spec, "*") {
return offers[i]
}
if strings.HasPrefix(spec, offers[i]) {
return offers[i]
}
}
}
return ""
func (ctx *Ctx) AcceptsCharsets(offers ...string) string {
return getOffer(ctx.Get(HeaderAcceptCharset), offers...)
}
// AcceptsEncodings checks if the specified encoding is acceptable.
func (ctx *Ctx) AcceptsEncodings(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
h := ctx.Get(HeaderAcceptEncoding)
if h == "" {
return offers[0]
}
specs := strings.Split(h, ",")
for i := range offers {
for k := range specs {
spec := strings.TrimSpace(specs[k])
if strings.HasPrefix(spec, "*") {
return offers[i]
}
if strings.HasPrefix(spec, offers[i]) {
return offers[i]
}
}
}
return ""
func (ctx *Ctx) AcceptsEncodings(offers ...string) string {
return getOffer(ctx.Get(HeaderAcceptEncoding), offers...)
}
// AcceptsLanguages checks if the specified language is acceptable.
func (ctx *Ctx) AcceptsLanguages(offers ...string) (offer string) {
if len(offers) == 0 {
return ""
}
h := ctx.Get(HeaderAcceptLanguage)
if h == "" {
return offers[0]
}
specs := strings.Split(h, ",")
for i := range offers {
for k := range specs {
spec := strings.TrimSpace(specs[k])
if strings.HasPrefix(spec, "*") {
return offers[i]
}
if strings.HasPrefix(spec, offers[i]) {
return offers[i]
}
}
}
return ""
func (ctx *Ctx) AcceptsLanguages(offers ...string) string {
return getOffer(ctx.Get(HeaderAcceptLanguage), offers...)
}
// Append the specified value to the HTTP response header field.
@ -220,15 +154,17 @@ func (ctx *Ctx) Append(field string, values ...string) {
if len(values) == 0 {
return
}
h := getString(ctx.Fasthttp.Response.Header.Peek(field))
h := ctx.Fasthttp.Response.Header.Peek(field)
for i := range values {
if h == "" {
h += values[i]
} else {
h += ", " + values[i]
var value = getBytes(values[i])
if len(h) == 0 {
h = append(h, value...)
} else if 0 != bytes.Compare(h, value) && !bytes.HasSuffix(h, append([]byte{' '}, value...)) &&
!bytes.Contains(h, append(append([]byte{}, value...), ',')) {
h = append(append(h, ',', ' '), value...)
}
}
ctx.Set(field, h)
ctx.Fasthttp.Response.Header.SetBytesV(field, h)
}
// Attachment sets the HTTP response Content-Disposition header field to attachment.
@ -321,7 +257,7 @@ func (ctx *Ctx) ClearCookie(key ...string) {
// Cookie sets a cookie by passing a cookie struct
func (ctx *Ctx) Cookie(cookie *Cookie) {
fcookie := &fasthttp.Cookie{}
fcookie := fasthttp.AcquireCookie()
fcookie.SetKey(cookie.Name)
fcookie.SetValue(cookie.Value)
fcookie.SetPath(cookie.Path)
@ -346,6 +282,7 @@ func (ctx *Ctx) Cookie(cookie *Cookie) {
fcookie.SetSameSite(fasthttp.CookieSameSiteDisabled)
}
ctx.Fasthttp.Response.Header.SetCookie(fcookie)
fasthttp.ReleaseCookie(fcookie)
}
// Cookies is used for getting a cookie value by key
@ -381,9 +318,13 @@ func (ctx *Ctx) Error() error {
// It uses Accepts to select a proper format.
// If the header is not specified or there is no proper format, text/plain is used.
func (ctx *Ctx) Format(body interface{}) {
var b string
accept := ctx.Accepts("html", "json")
// Get accepted content type
accept := ctx.Accepts("html", "json", "txt", "xml")
// Set accepted content type
ctx.Type(accept)
// Type convert provided body
var b string
switch val := body.(type) {
case string:
b = val
@ -392,14 +333,26 @@ func (ctx *Ctx) Format(body interface{}) {
default:
b = fmt.Sprintf("%v", val)
}
// Format based on the accept content type
switch accept {
case "html":
ctx.SendString("<p>" + b + "</p>")
case "json":
if err := ctx.JSON(body); err != nil {
// Fix
ctx.Send(body) // Fallback
log.Println("Format: error serializing json ", err)
}
case "text":
ctx.SendString(b)
case "xml":
raw, err := xml.Marshal(body)
if err != nil {
ctx.Send(body) // Fallback
log.Println("Format: error serializing xml ", err)
} else {
ctx.SendString(getString(raw))
}
default:
ctx.SendString(b)
}
@ -542,39 +495,48 @@ func (ctx *Ctx) JSON(data interface{}) error {
// By default, the callback name is simply callback.
func (ctx *Ctx) JSONP(data interface{}, callback ...string) error {
raw, err := json.Marshal(&data)
// Check for errors
if err != nil {
return err
}
str := "callback("
if len(callback) > 0 {
str = callback[0] + "("
}
str += getString(raw) + ");"
var result, cb string
ctx.Set(HeaderXContentTypeOptions, "nosniff")
if len(callback) > 0 {
cb = callback[0]
} else {
cb = "callback"
}
result = cb + "(" + getString(raw) + ");"
ctx.Fasthttp.Response.Header.Set(HeaderXContentTypeOptions, "nosniff")
ctx.Fasthttp.Response.Header.SetContentType(MIMEApplicationJavaScript)
ctx.Fasthttp.Response.SetBodyString(str)
ctx.Fasthttp.Response.SetBodyString(result)
return nil
}
// Links joins the links followed by the property to populate the responses Link HTTP header field.
// #nosec G104
func (ctx *Ctx) Links(link ...string) {
h := ""
if len(link) == 0 {
return
}
bb := bytebufferpool.Get()
for i := range link {
l := link[i]
if i%2 == 0 {
h += "<" + l + ">"
bb.WriteByte('<')
bb.WriteString(link[i])
bb.WriteByte('>')
} else {
h += `; rel="` + l + `",`
bb.WriteString(`; rel="`)
bb.WriteString(link[i])
bb.WriteString(`",`)
}
}
if len(link) > 0 {
h = strings.TrimSuffix(h, ",")
ctx.Set(HeaderLink, h)
}
ctx.Fasthttp.Response.Header.Set(HeaderLink, strings.TrimSuffix(bb.String(), ","))
bytebufferpool.Put(bb)
}
// Locals makes it possible to pass interface{} values under string keys scoped to the request
@ -595,7 +557,7 @@ func (ctx *Ctx) Location(path string) {
// Method contains a string corresponding to the HTTP method of the request: GET, POST, PUT and so on.
func (ctx *Ctx) Method(override ...string) string {
if len(override) > 0 {
ctx.method = override[0]
ctx.method = strings.ToUpper(override[0])
}
return ctx.method
}
@ -627,16 +589,16 @@ func (ctx *Ctx) OriginalURL() string {
// Params is used to get the route parameters.
// Defaults to empty string "", if the param doesn't exist.
func (ctx *Ctx) Params(key string) (value string) {
if ctx.route.Params == nil {
return
}
func (ctx *Ctx) Params(key string) string {
for i := range ctx.route.Params {
if (ctx.route.Params)[i] == key {
if len(key) != len(ctx.route.Params[i]) {
continue
}
if ctx.route.Params[i] == key {
return ctx.values[i]
}
}
return
return ""
}
// Path returns the path part of the request URL.
@ -714,13 +676,12 @@ func (ctx *Ctx) Range(size int) (rangeData Range, err error) {
// Redirect to the URL derived from the specified path, with specified status.
// If status is not specified, status defaults to 302 Found
func (ctx *Ctx) Redirect(path string, status ...int) {
code := 302
ctx.Fasthttp.Response.Header.Set(HeaderLocation, path)
if len(status) > 0 {
code = status[0]
ctx.Fasthttp.Response.SetStatusCode(status[0])
} else {
ctx.Fasthttp.Response.SetStatusCode(StatusFound)
}
ctx.Set(HeaderLocation, path)
ctx.Fasthttp.Response.SetStatusCode(code)
}
// Render a template with data and sends a text/html response.
@ -860,23 +821,7 @@ func (ctx *Ctx) Type(ext string) *Ctx {
// Vary adds the given header field to the Vary response header.
// This will append the header, if not already listed, otherwise leaves it listed in the current location.
func (ctx *Ctx) Vary(fields ...string) {
if len(fields) == 0 {
return
}
h := strings.ToLower(getString(ctx.Fasthttp.Response.Header.Peek(HeaderVary)))
for i := range fields {
fields[i] = strings.ToLower(fields[i])
if len(h) == 0 {
h += fields[i]
} else if !strings.Contains(h, " "+fields[i]) && !strings.Contains(h, fields[i]+"") || !strings.Contains(h, fields[i]+",") {
// Next developer, it's your job to optimize the following problem
// Does the header value "Accept" exist in the following header value
// "Origin, User-Agent, Accept-Encoding"
// "Accept-Encoding" contains "Accept", false positive
h += ", " + fields[i]
}
}
ctx.Set(HeaderVary, h)
ctx.Append(HeaderVary, fields...)
}
// Write appends any input to the HTTP body response.
@ -896,5 +841,5 @@ func (ctx *Ctx) Write(bodies ...interface{}) {
// XHR returns a Boolean property, that is true, if the requests X-Requested-With header field is XMLHttpRequest,
// indicating that the request was issued by a client library (such as jQuery).
func (ctx *Ctx) XHR() bool {
return strings.ToLower(ctx.Get(HeaderXRequestedWith)) == "xmlhttprequest"
return strings.EqualFold(ctx.Get(HeaderXRequestedWith), "xmlhttprequest")
}

View File

@ -13,6 +13,8 @@ import (
"github.com/valyala/fasthttp"
)
// go test -v ./... -run=^$ -bench=Benchmark_Ctx_Params -benchmem -count=3
func Benchmark_Ctx_Accepts(b *testing.B) {
c := AcquireCtx(&fasthttp.RequestCtx{})
defer ReleaseCtx(c)
@ -63,7 +65,7 @@ func Benchmark_Ctx_AcceptsLanguages(b *testing.B) {
var res string
for n := 0; n < b.N; n++ {
res = c.AcceptsEncodings("fr")
res = c.AcceptsLanguages("fr")
}
assertEqual(b, "fr", res)
@ -185,9 +187,29 @@ func Benchmark_Ctx_FormFile(b *testing.B) {
// TODO
// }
// func Benchmark_Ctx_Params(b *testing.B) {
// TODO
// }
func Benchmark_Ctx_Params(b *testing.B) {
c := AcquireCtx(&fasthttp.RequestCtx{})
defer ReleaseCtx(c)
c.route = &Route{
Params: []string{
"param1", "param2", "param3", "param4",
},
}
c.values = []string{
"john", "doe", "is", "awesome",
}
var res string
for n := 0; n < b.N; n++ {
res = c.Params("param1")
res = c.Params("param2")
res = c.Params("param3")
res = c.Params("param4")
}
assertEqual(b, "awesome", res)
}
// func Benchmark_Ctx_Path(b *testing.B) {
// TODO
@ -217,13 +239,32 @@ func Benchmark_Ctx_FormFile(b *testing.B) {
// TODO
// }
// func Benchmark_Ctx_Subdomains(b *testing.B) {
// TODO
// }
func Benchmark_Ctx_Subdomains(b *testing.B) {
c := AcquireCtx(&fasthttp.RequestCtx{})
defer ReleaseCtx(c)
// func Benchmark_Ctx_Append(b *testing.B) {
// TODO
// }
c.Fasthttp.Request.SetRequestURI("http://john.doe.google.com")
var res []string
for n := 0; n < b.N; n++ {
res = c.Subdomains()
}
assertEqual(b, []string{"john", "doe"}, res)
}
func Benchmark_Ctx_Append(b *testing.B) {
c := AcquireCtx(&fasthttp.RequestCtx{})
defer ReleaseCtx(c)
for n := 0; n < b.N; n++ {
c.Append("X-Custom-Header", "Hello")
c.Append("X-Custom-Header", "World")
c.Append("X-Custom-Header", "Hello")
}
assertEqual(b, "Hello, World", getString(c.Fasthttp.Response.Header.Peek("X-Custom-Header")))
}
// func Benchmark_Ctx_Attachment(b *testing.B) {
// TODO
@ -233,9 +274,19 @@ func Benchmark_Ctx_FormFile(b *testing.B) {
// TODO
// }
// func Benchmark_Ctx_Cookie(b *testing.B) {
// TODO
// }
func Benchmark_Ctx_Cookie(b *testing.B) {
c := AcquireCtx(&fasthttp.RequestCtx{})
defer ReleaseCtx(c)
for n := 0; n < b.N; n++ {
c.Cookie(&Cookie{
Name: "John",
Value: "Doe",
})
}
assertEqual(b, "John=Doe; path=/", getString(c.Fasthttp.Response.Header.Peek("Set-Cookie")))
}
// func Benchmark_Ctx_Download(b *testing.B) {
// TODO
@ -246,12 +297,28 @@ func Benchmark_Ctx_Format(b *testing.B) {
defer ReleaseCtx(c)
c.Fasthttp.Request.Header.Set("Accept", "text/html")
for n := 0; n < b.N; n++ {
c.Format("Hello, World!")
}
assertEqual(b, "<p>Hello, World!</p>", string(c.Fasthttp.Response.Body()))
c.Fasthttp.Request.Header.Set("Accept", "application/json")
for n := 0; n < b.N; n++ {
c.Format("Hello, World!")
}
assertEqual(b, `"Hello, World!"`, string(c.Fasthttp.Response.Body()))
c.Fasthttp.Request.Header.Set("Accept", "text/plain")
for n := 0; n < b.N; n++ {
c.Format("Hello, World!")
}
assertEqual(b, `Hello, World!`, string(c.Fasthttp.Response.Body()))
c.Fasthttp.Request.Header.Set("Accept", "application/xml")
for n := 0; n < b.N; n++ {
c.Format("Hello, World!")
}
assertEqual(b, `<string>Hello, World!</string>`, string(c.Fasthttp.Response.Body()))
}
func Benchmark_Ctx_JSON(b *testing.B) {
@ -319,6 +386,7 @@ func Benchmark_Ctx_Redirect(b *testing.B) {
defer ReleaseCtx(c)
for n := 0; n < b.N; n++ {
c.Redirect("http://example.com")
c.Redirect("http://example.com", 301)
}
assertEqual(b, 301, c.Fasthttp.Response.StatusCode())
@ -335,8 +403,8 @@ func Benchmark_Ctx_Send(b *testing.B) {
defer ReleaseCtx(c)
for n := 0; n < b.N; n++ {
c.Send([]byte("Hello, World"))
c.Send("Hello, World")
c.Send([]byte("Hello, World"), "Hello, World!", "Hello, World!")
c.Send("Hello, World", 50, 30, 20)
c.Send(1337)
}
assertEqual(b, "1337", string(c.Fasthttp.Response.Body()))
@ -404,7 +472,7 @@ func Benchmark_Ctx_Vary(b *testing.B) {
c.Vary("Origin")
}
assertEqual(b, "Origin", string(c.Fasthttp.Response.Header.Peek("Vary")))
//assertEqual(b, "origin", string(c.Fasthttp.Response.Header.Peek("Vary")))
}
func Benchmark_Ctx_Write(b *testing.B) {

View File

@ -20,7 +20,7 @@ import (
"time"
)
func Test_Accepts(t *testing.T) {
func Test_Ctx_Accepts(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -36,7 +36,7 @@ func Test_Accepts(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_AcceptsCharsets(t *testing.T) {
func Test_Ctx_AcceptsCharsets(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -50,7 +50,7 @@ func Test_AcceptsCharsets(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_AcceptsEncodings(t *testing.T) {
func Test_Ctx_AcceptsEncodings(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -64,7 +64,7 @@ func Test_AcceptsEncodings(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_AcceptsLanguages(t *testing.T) {
func Test_Ctx_AcceptsLanguages(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -78,7 +78,7 @@ func Test_AcceptsLanguages(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_BaseURL(t *testing.T) {
func Test_Ctx_BaseURL(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -91,7 +91,7 @@ func Test_BaseURL(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Body(t *testing.T) {
func Test_Ctx_Body(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@ -109,7 +109,7 @@ func Test_Body(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_BodyParser(t *testing.T) {
func Test_Ctx_BodyParser(t *testing.T) {
app := New()
type Demo struct {
@ -147,7 +147,7 @@ func Test_BodyParser(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Cookies(t *testing.T) {
func Test_Ctx_Cookies(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -161,7 +161,7 @@ func Test_Cookies(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_FormFile(t *testing.T) {
func Test_Ctx_FormFile(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@ -199,7 +199,7 @@ func Test_FormFile(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_FormValue(t *testing.T) {
func Test_Ctx_FormValue(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@ -220,7 +220,7 @@ func Test_FormValue(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Fresh(t *testing.T) {
func Test_Ctx_Fresh(t *testing.T) {
app := New()
// TODO
app.Get("/test", func(c *Ctx) {
@ -233,7 +233,7 @@ func Test_Fresh(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Get(t *testing.T) {
func Test_Ctx_Get(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -248,7 +248,7 @@ func Test_Get(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Hostname(t *testing.T) {
func Test_Ctx_Hostname(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -261,7 +261,7 @@ func Test_Hostname(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_IP(t *testing.T) {
func Test_Ctx_IP(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -274,7 +274,7 @@ func Test_IP(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_IPs(t *testing.T) {
func Test_Ctx_IPs(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -289,7 +289,7 @@ func Test_IPs(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
// func Test_Is(t *testing.T) {
// func Test_Ctx_Is(t *testing.T) {
// app := New()
// app.Get("/test", func(c *Ctx) {
// c.Is(".json")
@ -309,26 +309,22 @@ func Test_IPs(t *testing.T) {
// t.Fatalf(`%s: StatusCode %v`, t.Name(), resp.StatusCode)
// }
// }
func Test_Locals(t *testing.T) {
func Test_Ctx_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)
}
assertEqual(t, "doe", c.Locals("john"))
})
req := httptest.NewRequest("GET", "/test", nil)
resp, err := app.Test(req)
resp, err := app.Test(httptest.NewRequest("GET", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Method(t *testing.T) {
func Test_Ctx_Method(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -340,25 +336,20 @@ func Test_Method(t *testing.T) {
app.Put("/test", func(c *Ctx) {
assertEqual(t, "PUT", c.Method())
})
req := httptest.NewRequest("GET", "/test", nil)
resp, err := app.Test(req)
resp, err := app.Test(httptest.NewRequest("GET", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
req = httptest.NewRequest("POST", "/test", nil)
resp, err = app.Test(req)
resp, err = app.Test(httptest.NewRequest("POST", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
req = httptest.NewRequest("PUT", "/test", nil)
resp, err = app.Test(req)
resp, err = app.Test(httptest.NewRequest("PUT", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_MultipartForm(t *testing.T) {
func Test_Ctx_MultipartForm(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@ -381,20 +372,18 @@ func Test_MultipartForm(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_OriginalURL(t *testing.T) {
func Test_Ctx_OriginalURL(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
assertEqual(t, "http://google.com/test?search=demo", c.OriginalURL())
})
req := httptest.NewRequest("GET", "http://google.com/test?search=demo", nil)
resp, err := app.Test(req)
resp, err := app.Test(httptest.NewRequest("GET", "http://google.com/test?search=demo", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Params(t *testing.T) {
func Test_Ctx_Params(t *testing.T) {
app := New()
app.Get("/test/:user", func(c *Ctx) {
@ -408,25 +397,20 @@ func Test_Params(t *testing.T) {
app.Get("/test3/:optional?", func(c *Ctx) {
assertEqual(t, "", c.Params("optional"))
})
req := httptest.NewRequest("GET", "/test/john", nil)
resp, err := app.Test(req)
resp, err := app.Test(httptest.NewRequest("GET", "/test/john", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
req = httptest.NewRequest("GET", "/test2/im/a/cookie", nil)
resp, err = app.Test(req)
resp, err = app.Test(httptest.NewRequest("GET", "/test2/im/a/cookie", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
req = httptest.NewRequest("GET", "/test3", nil)
resp, err = app.Test(req)
resp, err = app.Test(httptest.NewRequest("GET", "/test3", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Path(t *testing.T) {
func Test_Ctx_Path(t *testing.T) {
app := New()
app.Get("/test/:user", func(c *Ctx) {
@ -439,7 +423,7 @@ func Test_Path(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Query(t *testing.T) {
func Test_Ctx_Query(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -452,7 +436,7 @@ func Test_Query(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Range(t *testing.T) {
func Test_Ctx_Range(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -470,7 +454,7 @@ func Test_Range(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Route(t *testing.T) {
func Test_Ctx_Route(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -483,7 +467,7 @@ func Test_Route(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_SaveFile(t *testing.T) {
func Test_Ctx_SaveFile(t *testing.T) {
app := New()
app.Post("/test", func(c *Ctx) {
@ -520,7 +504,7 @@ func Test_SaveFile(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Secure(t *testing.T) {
func Test_Ctx_Secure(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -543,7 +527,7 @@ func Test_Secure(t *testing.T) {
// assertEqual(t, nil, err, "app.Test(req)")
// assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Stale(t *testing.T) {
func Test_Ctx_Stale(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -556,7 +540,7 @@ func Test_Stale(t *testing.T) {
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Subdomains(t *testing.T) {
func Test_Ctx_Subdomains(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -570,21 +554,21 @@ func Test_Subdomains(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
}
func Test_Append(t *testing.T) {
func Test_Ctx_Append(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
c.Append("X-Test", "hel")
c.Append("X-Test", "lo", "world")
c.Append("X-Test", "Hello")
c.Append("X-Test", "World")
c.Append("X-Test", "Hello", "World")
})
req := httptest.NewRequest("GET", "/test", nil)
resp, err := app.Test(req)
resp, err := app.Test(httptest.NewRequest("GET", "/test", nil))
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "hel, lo, world", resp.Header.Get("X-Test"))
assertEqual(t, "Hello, World", resp.Header.Get("X-Test"))
}
func Test_Attachment(t *testing.T) {
func Test_Ctx_Attachment(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -600,7 +584,7 @@ func Test_Attachment(t *testing.T) {
assertEqual(t, "image/png", resp.Header.Get("Content-Type"))
}
func Test_ClearCookie(t *testing.T) {
func Test_Ctx_ClearCookie(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -627,7 +611,7 @@ func Test_ClearCookie(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, true, strings.Contains(resp.Header.Get("Set-Cookie"), "expires="))
}
func Test_Cookie(t *testing.T) {
func Test_Ctx_Cookie(t *testing.T) {
app := New()
expire := time.Now().Add(24 * time.Hour)
@ -651,7 +635,7 @@ func Test_Cookie(t *testing.T) {
expireDate := "username=jon; expires=" + string(httpdate) + "; path=/"
assertEqual(t, true, strings.Contains(resp.Header.Get("Set-Cookie"), expireDate))
}
func Test_Download(t *testing.T) {
func Test_Ctx_Download(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -676,7 +660,7 @@ func Test_Download(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, true, bytes.Equal(expect, body))
}
func Test_Format(t *testing.T) {
func Test_Ctx_Format(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -710,7 +694,7 @@ func Test_Format(t *testing.T) {
assertEqual(t, `"Hello, World!"`, string(body))
}
func Test_JSON(t *testing.T) {
func Test_Ctx_JSON(t *testing.T) {
app := New()
type SomeStruct struct {
@ -738,7 +722,7 @@ func Test_JSON(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `{"Name":"Grame","Age":20}`, string(body))
}
func Test_JSONP(t *testing.T) {
func Test_Ctx_JSONP(t *testing.T) {
app := New()
type SomeStruct struct {
@ -766,7 +750,7 @@ func Test_JSONP(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `john({"Name":"Grame","Age":20});`, string(body))
}
func Test_Links(t *testing.T) {
func Test_Ctx_Links(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -783,7 +767,7 @@ func Test_Links(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, `<http://api.example.com/users?page=2>; rel="next",<http://api.example.com/users?page=5>; rel="last"`, resp.Header.Get("Link"))
}
func Test_Location(t *testing.T) {
func Test_Ctx_Location(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -797,7 +781,7 @@ func Test_Location(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "http://example.com", resp.Header.Get("Location"))
}
func Test_Next(t *testing.T) {
func Test_Ctx_Next(t *testing.T) {
app := New()
app.Use("/", func(c *Ctx) {
@ -815,7 +799,7 @@ func Test_Next(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "Works", resp.Header.Get("X-Next-Result"))
}
func Test_Redirect(t *testing.T) {
func Test_Ctx_Redirect(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -828,10 +812,10 @@ func Test_Redirect(t *testing.T) {
assertEqual(t, 301, resp.StatusCode, "Status code")
assertEqual(t, "http://example.com", resp.Header.Get("Location"))
}
func Test_Render(t *testing.T) {
func Test_Ctx_Render(t *testing.T) {
// TODO
}
func Test_Send(t *testing.T) {
func Test_Ctx_Send(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -850,7 +834,7 @@ func Test_Send(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `1337`, string(body))
}
func Test_SendBytes(t *testing.T) {
func Test_Ctx_SendBytes(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -867,7 +851,7 @@ func Test_SendBytes(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Hello, World`, string(body))
}
func Test_SendStatus(t *testing.T) {
func Test_Ctx_SendStatus(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -884,7 +868,7 @@ func Test_SendStatus(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Unsupported Media Type`, string(body))
}
func Test_SendString(t *testing.T) {
func Test_Ctx_SendString(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -901,7 +885,7 @@ func Test_SendString(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Don't crash please`, string(body))
}
func Test_Set(t *testing.T) {
func Test_Ctx_Set(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -920,7 +904,7 @@ func Test_Set(t *testing.T) {
assertEqual(t, "2", resp.Header.Get("X-2"))
assertEqual(t, "1337", resp.Header.Get("X-3"))
}
func Test_Status(t *testing.T) {
func Test_Ctx_Status(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -937,7 +921,7 @@ func Test_Status(t *testing.T) {
assertEqual(t, nil, err)
assertEqual(t, `Hello, World`, string(body))
}
func Test_Type(t *testing.T) {
func Test_Ctx_Type(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -951,7 +935,7 @@ func Test_Type(t *testing.T) {
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "application/json", resp.Header.Get("Content-Type"))
}
func Test_Vary(t *testing.T) {
func Test_Ctx_Vary(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -965,9 +949,9 @@ func Test_Vary(t *testing.T) {
resp, err := app.Test(req)
assertEqual(t, nil, err, "app.Test(req)")
assertEqual(t, 200, resp.StatusCode, "Status code")
assertEqual(t, "origin, user-agent, accept-encoding, accept", resp.Header.Get("Vary"))
assertEqual(t, "Origin, User-Agent, Accept-Encoding, Accept", resp.Header.Get("Vary"))
}
func Test_Write(t *testing.T) {
func Test_Ctx_Write(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {
@ -987,7 +971,7 @@ func Test_Write(t *testing.T) {
assertEqual(t, `Hello, World! 123`, string(body))
}
func Test_XHR(t *testing.T) {
func Test_Ctx_XHR(t *testing.T) {
app := New()
app.Get("/test", func(c *Ctx) {

1
go.mod
View File

@ -4,5 +4,6 @@ go 1.11
require (
github.com/gorilla/schema v1.1.0
github.com/valyala/bytebufferpool v1.0.0
github.com/valyala/fasthttp v1.12.0
)

168
params.go
View File

@ -1,168 +0,0 @@
// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
// 📝 Github Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io
// ⚠️ This path parser was based on urlpath by @ucarion (MIT License).
// 💖 Modified for the Fiber router by @renanbastos93 & @renewerner87
// 🤖 ucarion/urlpath - renanbastos93/fastpath - renewerner87/fastpath
package fiber
import (
"strings"
)
// paramsParser holds the path segments and param names
type parsedParams struct {
Segs []paramSeg
Params []string
}
// paramsSeg holds the segment metadata
type paramSeg struct {
Param string
Const string
IsParam bool
IsOptional bool
IsLast bool
}
var paramsDummy = make([]string, 100, 100)
const wildcardParam string = "*"
// New ...
func parseParams(pattern string) (p parsedParams) {
var patternCount int
aPattern := []string{""}
if pattern != "" {
aPattern = strings.Split(pattern, "/")[1:] // every route starts with an "/"
}
patternCount = len(aPattern)
var out = make([]paramSeg, patternCount)
var params []string
var segIndex int
for i := 0; i < patternCount; i++ {
partLen := len(aPattern[i])
if partLen == 0 { // skip empty parts
continue
}
// is parameter ?
if aPattern[i][0] == '*' || aPattern[i][0] == ':' {
out[segIndex] = paramSeg{
Param: paramTrimmer(aPattern[i]),
IsParam: true,
IsOptional: aPattern[i] == wildcardParam || aPattern[i][partLen-1] == '?',
}
params = append(params, out[segIndex].Param)
} else {
// combine const segments
if segIndex > 0 && out[segIndex-1].IsParam == false {
segIndex--
out[segIndex].Const += "/" + aPattern[i]
// create new const segment
} else {
out[segIndex] = paramSeg{
Const: aPattern[i],
}
}
}
segIndex++
}
if segIndex == 0 {
segIndex++
}
out[segIndex-1].IsLast = true
p = parsedParams{Segs: out[:segIndex:segIndex], Params: params}
//fmt.Printf("%+v\n", p)
return
}
// Match ...
func (p *parsedParams) matchParams(s string) ([]string, bool) {
lenKeys := len(p.Params)
params := paramsDummy[0:lenKeys:lenKeys]
var i, j, paramsIterator, partLen int
if len(s) > 0 {
s = s[1:]
}
for index, segment := range p.Segs {
partLen = len(s)
// check parameter
if segment.IsParam {
// determine parameter length
if segment.Param == wildcardParam {
if segment.IsLast {
i = partLen
} else {
// for the expressjs behavior -> "/api/*/:param" - "/api/joker/batman/robin/1" -> "joker/batman/robin", "1"
i = findCharPos(s, '/', strings.Count(s, "/")-(len(p.Segs)-(index+1))+1)
}
} else {
i = strings.IndexByte(s, '/')
}
if i == -1 {
i = partLen
}
if false == segment.IsOptional && i == 0 {
return nil, false
}
params[paramsIterator] = s[:i]
paramsIterator++
} else {
// check const segment
i = len(segment.Const)
if partLen < i || (i == 0 && partLen > 0) || s[:i] != segment.Const || (partLen > i && s[i] != '/') {
return nil, false
}
}
// reduce founded part from the string
if partLen > 0 {
j = i + 1
if segment.IsLast || partLen < j {
j = i
}
s = s[j:]
}
}
if len(s) != 0 {
return nil, false
}
return params, true
}
func paramTrimmer(param string) string {
start := 0
end := len(param)
if param[start] != ':' { // is not a param
return param
}
start++
if param[end-1] == '?' { // is ?
end--
}
return param[start:end]
}
func findCharPos(s string, char byte, matchCount int) int {
if matchCount == 0 {
matchCount = 1
}
endPos, pos := 0, 0
for matchCount > 0 && pos != -1 {
if pos > 0 {
s = s[pos+1:]
endPos++
}
pos = strings.IndexByte(s, char)
endPos += pos
matchCount--
}
return endPos
}

View File

@ -61,46 +61,29 @@ func (app *App) nextRoute(ctx *Ctx) {
}
func (r *Route) matchRoute(path string) (match bool, values []string) {
// Middleware routes allow prefix matches
if r.use {
// Match any path if wildcard and pass path as param
if r.star {
return true, []string{path}
}
// Match any path if route equals '/'
if r.root {
if r.root == true || strings.HasPrefix(path, r.Path) {
return true, values
}
// Middleware matches path prefix
if strings.HasPrefix(path, r.Path) {
return true, values
}
// No prefix match, and we do not allow params in app.use
return false, values
// Check for a simple path match
} else if len(r.Path) == len(path) && r.Path == path {
return true, values
// Middleware routes allow prefix matches
} else if r.root == true && path == "/" {
return true, values
}
// '*' wildcard matches any path
if r.star {
if r.star == true {
return true, []string{path}
}
// Check if a single '/' matches
if r.root && path == "/" {
return true, values
}
// Does this route have parameters
if len(r.Params) > 0 {
// Do we have a match?
params, ok := r.parsed.matchParams(path)
// We have a match!
if ok {
return true, params
// Match params
if values, match = r.parsed.getMatch(path, r.use); match {
return
}
}
// Check for a simple path match
if len(r.Path) == len(path) && r.Path == path {
return true, values
}
// Nothing match
// No match
return false, values
}
@ -153,12 +136,12 @@ func (app *App) registerMethod(method, path string, handlers ...func(*Ctx)) {
}
var isStar = path == "/*"
// Middleware containing only a `/` equals wildcard
if isUse && path == "/" {
isStar = true
}
// if isUse && path == "/" {
// isStar = true
// }
var isRoot = path == "/"
// Route properties
var isParsed = parseParams(original)
var isParsed = getParams(original)
for i := range handlers {
route := &Route{
use: isUse,
@ -168,7 +151,7 @@ func (app *App) registerMethod(method, path string, handlers ...func(*Ctx)) {
Path: path,
Method: method,
Params: isParsed.Params,
Params: isParsed.params,
Handler: handlers[i],
}
if method == "*" {

File diff suppressed because it is too large Load Diff

View File

@ -6,240 +6,3 @@
// 🤖 ucarion/urlpath - renanbastos93/fastpath - renewerner87/fastpath
package fiber
import (
"fmt"
"reflect"
"testing"
)
type testcase struct {
uri string
params []string
ok bool
}
func Test_With_Param_And_Wildcard(t *testing.T) {
checkCases(
t,
parseParams("/api/v1/:param/*"),
[]testcase{
{uri: "/api/v1/entity", params: []string{"entity", ""}, ok: true},
{uri: "/api/v1/entity/", params: []string{"entity", ""}, ok: true},
{uri: "/api/v1/entity/1", params: []string{"entity", "1"}, ok: true},
{uri: "/api/v", params: nil, ok: false},
{uri: "/api/v2", params: nil, ok: false},
{uri: "/api/v1/", params: nil, ok: false},
},
)
}
func Test_With_A_Param_Optional(t *testing.T) {
checkCases(
t,
parseParams("/api/v1/:param?"),
[]testcase{
{uri: "/api/v1", params: []string{""}, ok: true},
{uri: "/api/v1/", params: []string{""}, ok: true},
{uri: "/api/v1/optional", params: []string{"optional"}, ok: true},
{uri: "/api/v", params: nil, ok: false},
{uri: "/api/v2", params: nil, ok: false},
{uri: "/api/xyz", params: nil, ok: false},
},
)
}
func Test_With_With_Wildcard(t *testing.T) {
checkCases(
t,
parseParams("/api/v1/*"),
[]testcase{
{uri: "/api/v1", params: []string{""}, ok: true},
{uri: "/api/v1/", params: []string{""}, ok: true},
{uri: "/api/v1/entity", params: []string{"entity"}, ok: true},
{uri: "/api/v1/entity/1/2", params: []string{"entity/1/2"}, ok: true},
{uri: "/api/v", params: nil, ok: false},
{uri: "/api/v2", params: nil, ok: false},
{uri: "/api/abc", params: nil, ok: false},
},
)
}
func Test_With_With_Param(t *testing.T) {
checkCases(
t,
parseParams("/api/v1/:param"),
[]testcase{
{uri: "/api/v1/entity", params: []string{"entity"}, ok: true},
{uri: "/api/v1/entity/8728382", params: nil, ok: false},
{uri: "/api/v1", params: nil, ok: false},
{uri: "/api/v1/", params: nil, ok: false},
},
)
}
func Test_With_Without_A_Param_Or_Wildcard(t *testing.T) {
checkCases(
t,
parseParams("/api/v1/const"),
[]testcase{
{uri: "/api/v1/const", params: []string{}, ok: true},
{uri: "/api/v1", params: nil, ok: false},
{uri: "/api/v1/", params: nil, ok: false},
{uri: "/api/v1/something", params: nil, ok: false},
},
)
}
func Test_With_With_A_Param_And_Wildcard_Differents_Positions(t *testing.T) {
checkCases(
t,
parseParams("/api/v1/:param/abc/*"),
[]testcase{
{uri: "/api/v1/well/abc/wildcard", params: []string{"well", "wildcard"}, ok: true},
{uri: "/api/v1/well/abc/", params: []string{"well", ""}, ok: true},
{uri: "/api/v1/well/abc", params: []string{"well", ""}, ok: true},
{uri: "/api/v1/well/ttt", params: nil, ok: false},
},
)
}
func Test_With_With_Params_And_Optional(t *testing.T) {
checkCases(
t,
parseParams("/api/:day/:month?/:year?"),
[]testcase{
{uri: "/api/1", params: []string{"1", "", ""}, ok: true},
{uri: "/api/1/", params: []string{"1", "", ""}, ok: true},
{uri: "/api/1/2", params: []string{"1", "2", ""}, ok: true},
{uri: "/api/1/2/3", params: []string{"1", "2", "3"}, ok: true},
{uri: "/api/", params: nil, ok: false},
},
)
}
func Test_With_With_Simple_Wildcard(t *testing.T) {
checkCases(
t,
parseParams("/api/*"),
[]testcase{
{uri: "/api/", params: []string{""}, ok: true},
{uri: "/api/joker", params: []string{"joker"}, ok: true},
{uri: "/api", params: []string{""}, ok: true},
{uri: "/api/v1/entity", params: []string{"v1/entity"}, ok: true},
{uri: "/api2/v1/entity", params: nil, ok: false},
{uri: "/api_ignore/v1/entity", params: nil, ok: false},
},
)
}
func Test_With_With_Wildcard_And_Optional(t *testing.T) {
checkCases(
t,
parseParams("/api/*/:param?"),
[]testcase{
{uri: "/api/", params: []string{"", ""}, ok: true},
{uri: "/api/joker", params: []string{"joker", ""}, ok: true},
{uri: "/api/joker/batman", params: []string{"joker", "batman"}, ok: true},
{uri: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, ok: true},
{uri: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, ok: true},
{uri: "/api", params: []string{"", ""}, ok: true},
},
)
}
func Test_With_With_Wildcard_And_Param(t *testing.T) {
checkCases(
t,
parseParams("/api/*/:param"),
[]testcase{
{uri: "/api/test/abc", params: []string{"test", "abc"}, ok: true},
{uri: "/api/joker/batman", params: []string{"joker", "batman"}, ok: true},
{uri: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, ok: true},
{uri: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, ok: true},
{uri: "/api", params: nil, ok: false},
},
)
}
func Test_With_With_Wildcard_And_2Params(t *testing.T) {
checkCases(
t,
parseParams("/api/*/:param/:param2"),
[]testcase{
{uri: "/api/test/abc", params: nil, ok: false},
{uri: "/api/joker/batman", params: nil, ok: false},
{uri: "/api/joker/batman/robin", params: []string{"joker", "batman", "robin"}, ok: true},
{uri: "/api/joker/batman/robin/1", params: []string{"joker/batman", "robin", "1"}, ok: true},
{uri: "/api/joker/batman/robin/1/2", params: []string{"joker/batman/robin", "1", "2"}, ok: true},
{uri: "/api", params: nil, ok: false},
},
)
}
func Test_With_With_Simple_Path(t *testing.T) {
checkCases(
t,
parseParams("/"),
[]testcase{
{uri: "/api", params: nil, ok: false},
{uri: "", params: []string{}, ok: true},
{uri: "/", params: []string{}, ok: true},
},
)
}
func Test_With_With_Empty_Path(t *testing.T) {
checkCases(
t,
parseParams(""),
[]testcase{
{uri: "/api", params: nil, ok: false},
{uri: "", params: []string{}, ok: true},
{uri: "/", params: []string{}, ok: true},
},
)
}
func Test_With_With_FileName(t *testing.T) {
checkCases(
t,
parseParams("/config/abc.json"),
[]testcase{
{uri: "/config/abc.json", params: []string{}, ok: true},
{uri: "config/abc.json", params: nil, ok: false},
{uri: "/config/efg.json", params: nil, ok: false},
{uri: "/config", params: nil, ok: false},
},
)
}
func Test_With_With_FileName_And_Wildcard(t *testing.T) {
checkCases(
t,
parseParams("/config/*.json"),
[]testcase{
{uri: "/config/abc.json", params: []string{"abc.json"}, ok: true},
{uri: "/config/efg.json", params: []string{"efg.json"}, ok: true},
//{uri: "/config/efg.csv", params: nil, ok: false},// doesn`t work, current: params: "efg.csv", true
{uri: "config/abc.json", params: nil, ok: false},
{uri: "/config", params: nil, ok: false},
},
)
}
func Test_With_With_Simple_Path_And_NoMatch(t *testing.T) {
checkCases(
t,
parseParams("/xyz"),
[]testcase{
{uri: "xyz", params: nil, ok: false},
{uri: "xyz/", params: nil, ok: false},
},
)
}
func checkCases(tParent *testing.T, parser parsedParams, tcases []testcase) {
for _, tcase := range tcases {
tParent.Run(fmt.Sprintf("%+v", tcase), func(t *testing.T) {
params, ok := parser.matchParams(tcase.uri)
if !reflect.DeepEqual(params, tcase.params) {
t.Errorf("Path.Match() got = %v, want %v", params, tcase.params)
}
if ok != tcase.ok {
t.Errorf("Path.Match() got1 = %v, want %v", ok, tcase.ok)
}
})
}
}

184
utils.go
View File

@ -110,6 +110,30 @@ func getArgument(arg string) bool {
return false
}
// return valid offer for header negotiation
func getOffer(header string, offers ...string) string {
if len(offers) == 0 {
return ""
}
if header == "" {
return offers[0]
}
specs := strings.Split(header, ",")
for i := range offers {
for k := range specs {
spec := strings.TrimSpace(specs[k])
if strings.HasPrefix(spec, "*") {
return offers[i]
}
if strings.HasPrefix(spec, offers[i]) {
return offers[i]
}
}
}
return ""
}
// Adapted from:
// https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L110
func parseTokenList(noneMatchBytes []byte) []string {
@ -688,3 +712,163 @@ const (
StatusNotExtended = 510 // RFC 2774, 7
StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)
// ⚠️ This path parser was based on urlpath by @ucarion (MIT License).
// 💖 Modified for the Fiber router by @renanbastos93 & @renewerner87
// 🤖 ucarion/urlpath - renanbastos93/fastpath - renewerner87/fastpath
// paramsParser holds the path segments and param names
type parsedParams struct {
segs []paramSeg
params []string
}
// paramsSeg holds the segment metadata
type paramSeg struct {
Param string
Const string
IsParam bool
IsOptional bool
IsLast bool
}
var paramsDummy = make([]string, 100, 100)
const wildcardParam string = "*"
// New ...
func getParams(pattern string) (p parsedParams) {
var patternCount int
aPattern := []string{""}
if pattern != "" {
aPattern = strings.Split(pattern, "/")[1:] // every route starts with an "/"
}
patternCount = len(aPattern)
var out = make([]paramSeg, patternCount)
var params []string
var segIndex int
for i := 0; i < patternCount; i++ {
partLen := len(aPattern[i])
if partLen == 0 { // skip empty parts
continue
}
// is parameter ?
if aPattern[i][0] == '*' || aPattern[i][0] == ':' {
out[segIndex] = paramSeg{
Param: getTrimmedParam(aPattern[i]),
IsParam: true,
IsOptional: aPattern[i] == wildcardParam || aPattern[i][partLen-1] == '?',
}
params = append(params, out[segIndex].Param)
} else {
// combine const segments
if segIndex > 0 && out[segIndex-1].IsParam == false {
segIndex--
out[segIndex].Const += "/" + aPattern[i]
// create new const segment
} else {
out[segIndex] = paramSeg{
Const: aPattern[i],
}
}
}
segIndex++
}
if segIndex == 0 {
segIndex++
}
out[segIndex-1].IsLast = true
p = parsedParams{segs: out[:segIndex:segIndex], params: params}
//fmt.Printf("%+v\n", p)
return
}
// Match ...
func (p *parsedParams) getMatch(s string, partialCheck bool) ([]string, bool) {
lenKeys := len(p.params)
params := paramsDummy[0:lenKeys:lenKeys]
var i, j, paramsIterator, partLen int
if len(s) > 0 {
s = s[1:]
}
for index, segment := range p.segs {
partLen = len(s)
// check parameter
if segment.IsParam {
// determine parameter length
if segment.Param == wildcardParam {
if segment.IsLast {
i = partLen
} else {
// for the expressjs behavior -> "/api/*/:param" - "/api/joker/batman/robin/1" -> "joker/batman/robin", "1"
i = getCharPos(s, '/', strings.Count(s, "/")-(len(p.segs)-(index+1))+1)
}
} else {
i = strings.IndexByte(s, '/')
}
if i == -1 {
i = partLen
}
if false == segment.IsOptional && i == 0 {
return nil, false
}
params[paramsIterator] = s[:i]
paramsIterator++
} else {
// check const segment
i = len(segment.Const)
if partLen < i || (i == 0 && partLen > 0) || s[:i] != segment.Const || (partLen > i && s[i] != '/') {
return nil, false
}
}
// reduce founded part from the string
if partLen > 0 {
j = i + 1
if segment.IsLast || partLen < j {
j = i
}
s = s[j:]
}
}
if len(s) != 0 && !partialCheck {
return nil, false
}
return params, true
}
func getTrimmedParam(param string) string {
start := 0
end := len(param)
if param[start] != ':' { // is not a param
return param
}
start++
if param[end-1] == '?' { // is ?
end--
}
return param[start:end]
}
func getCharPos(s string, char byte, matchCount int) int {
if matchCount == 0 {
matchCount = 1
}
endPos, pos := 0, 0
for matchCount > 0 && pos != -1 {
if pos > 0 {
s = s[pos+1:]
endPos++
}
pos = strings.IndexByte(s, char)
endPos += pos
matchCount--
}
return endPos
}

122
utils_bench_test.go Normal file
View File

@ -0,0 +1,122 @@
// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
// 📝 Github Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io
package fiber
import (
"testing"
)
// go test -v ./... -run=^$ -bench=Benchmark_CC_ -benchmem -count=3
// func Benchmark_Utils_assertEqual(b *testing.B) {
// // TODO
// }
func Benchmark_Utils_getGroupPath(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = getGroupPath("/v1", "/")
_ = getGroupPath("/v1", "/api")
_ = getGroupPath("/v1", "/api/register/:project")
_ = getGroupPath("/v1/long/path/john/doe", "/why/this/name/is/so/awesome")
}
}
func Benchmark_Utils_getMIME(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = getMIME(".json")
_ = getMIME(".xml")
_ = getMIME("xml")
_ = getMIME("json")
}
}
// func Benchmark_Utils_getArgument(b *testing.B) {
// // TODO
// }
// func Benchmark_Utils_parseTokenList(b *testing.B) {
// // TODO
// }
func Benchmark_Utils_getString(b *testing.B) {
raw := []byte("Hello, World!")
for n := 0; n < b.N; n++ {
_ = getString(raw)
}
}
func Benchmark_Utils_getStringImmutable(b *testing.B) {
raw := []byte("Hello, World!")
for n := 0; n < b.N; n++ {
_ = getStringImmutable(raw)
}
}
func Benchmark_Utils_getBytes(b *testing.B) {
raw := "Hello, World!"
for n := 0; n < b.N; n++ {
_ = getBytes(raw)
}
}
func Benchmark_Utils_getBytesImmutable(b *testing.B) {
raw := "Hello, World!"
for n := 0; n < b.N; n++ {
_ = getBytesImmutable(raw)
}
}
func Benchmark_Utils_methodINT(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = methodINT[MethodGet]
_ = methodINT[MethodHead]
_ = methodINT[MethodPost]
_ = methodINT[MethodPut]
_ = methodINT[MethodPatch]
_ = methodINT[MethodDelete]
_ = methodINT[MethodConnect]
_ = methodINT[MethodOptions]
_ = methodINT[MethodTrace]
}
}
func Benchmark_Utils_statusMessage(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = statusMessage[100]
_ = statusMessage[304]
_ = statusMessage[423]
_ = statusMessage[507]
}
}
func Benchmark_Utils_extensionMIME(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = extensionMIME[".json"]
_ = extensionMIME["json"]
_ = extensionMIME["xspf"]
_ = extensionMIME[".xspf"]
_ = extensionMIME["avi"]
_ = extensionMIME[".avi"]
}
}
// func Benchmark_Utils_getParams(b *testing.B) {
// // TODO
// }
// func Benchmark_Utils_matchParams(b *testing.B) {
// // TODO
// }
func Benchmark_Utils_getTrimmedParam(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = getTrimmedParam(":param")
_ = getTrimmedParam(":param?")
}
}
// func Benchmark_Utils_getCharPos(b *testing.B) {
// // TODO
// }

255
utils_test.go Normal file
View File

@ -0,0 +1,255 @@
// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
// 📝 Github Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io
package fiber
import (
"fmt"
"testing"
)
// func Test_Utils_assertEqual(t *testing.T) {
// // TODO
// }
// func Test_Utils_setETag(t *testing.T) {
// // TODO
// }
func Test_Utils_getGroupPath(t *testing.T) {
res := getGroupPath("/v1", "/")
assertEqual(t, "/v1", res)
res = getGroupPath("/v1", "/")
assertEqual(t, "/v1", res)
res = getGroupPath("/", "/")
assertEqual(t, "/", res)
res = getGroupPath("/v1/api/", "/")
assertEqual(t, "/v1/api/", res)
}
func Test_Utils_getMIME(t *testing.T) {
res := getMIME(".json")
assertEqual(t, "application/json", res)
res = getMIME(".xml")
assertEqual(t, "application/xml", res)
res = getMIME("xml")
assertEqual(t, "application/xml", res)
res = getMIME("json")
assertEqual(t, "application/json", res)
}
// func Test_Utils_getArgument(t *testing.T) {
// // TODO
// }
// func Test_Utils_parseTokenList(t *testing.T) {
// // TODO
// }
func Test_Utils_getString(t *testing.T) {
res := getString([]byte("Hello, World!"))
assertEqual(t, "Hello, World!", res)
}
func Test_Utils_getStringImmutable(t *testing.T) {
res := getStringImmutable([]byte("Hello, World!"))
assertEqual(t, "Hello, World!", res)
}
func Test_Utils_getBytes(t *testing.T) {
res := getBytes("Hello, World!")
assertEqual(t, []byte("Hello, World!"), res)
}
func Test_Utils_getBytesImmutable(t *testing.T) {
res := getBytesImmutable("Hello, World!")
assertEqual(t, []byte("Hello, World!"), res)
}
func Test_Utils_methodINT(t *testing.T) {
res := methodINT[MethodGet]
assertEqual(t, 0, res)
res = methodINT[MethodHead]
assertEqual(t, 1, res)
res = methodINT[MethodPost]
assertEqual(t, 2, res)
res = methodINT[MethodPut]
assertEqual(t, 3, res)
res = methodINT[MethodPatch]
assertEqual(t, 4, res)
res = methodINT[MethodDelete]
assertEqual(t, 5, res)
res = methodINT[MethodConnect]
assertEqual(t, 6, res)
res = methodINT[MethodOptions]
assertEqual(t, 7, res)
res = methodINT[MethodTrace]
assertEqual(t, 8, res)
}
func Test_Utils_statusMessage(t *testing.T) {
res := statusMessage[102]
assertEqual(t, "Processing", res)
res = statusMessage[303]
assertEqual(t, "See Other", res)
res = statusMessage[404]
assertEqual(t, "Not Found", res)
res = statusMessage[507]
assertEqual(t, "Insufficient Storage", res)
}
func Test_Utils_extensionMIME(t *testing.T) {
res := extensionMIME[".html"]
assertEqual(t, "text/html", res)
res = extensionMIME["html"]
assertEqual(t, "text/html", res)
res = extensionMIME[".msp"]
assertEqual(t, "application/octet-stream", res)
res = extensionMIME["msp"]
assertEqual(t, "application/octet-stream", res)
}
// func Test_Utils_getParams(t *testing.T) {
// // TODO
// }
func Test_Utils_matchParams(t *testing.T) {
type testparams struct {
url string
params []string
match bool
}
testCase := func(r string, cases []testparams) {
parser := getParams(r)
for _, c := range cases {
params, match := parser.getMatch(c.url, false)
assertEqual(t, c.params, params, fmt.Sprintf("route: '%s', url: '%s'", r, c.url))
assertEqual(t, c.match, match, fmt.Sprintf("route: '%s', url: '%s'", r, c.url))
}
}
testCase("/api/v1/:param/*", []testparams{
{url: "/api/v1/entity", params: []string{"entity", ""}, match: true},
{url: "/api/v1/entity/", params: []string{"entity", ""}, match: true},
{url: "/api/v1/entity/1", params: []string{"entity", "1"}, match: true},
{url: "/api/v", params: nil, match: false},
{url: "/api/v2", params: nil, match: false},
{url: "/api/v1/", params: nil, match: false},
})
testCase("/api/v1/:param?", []testparams{
{url: "/api/v1", params: []string{""}, match: true},
{url: "/api/v1/", params: []string{""}, match: true},
{url: "/api/v1/optional", params: []string{"optional"}, match: true},
{url: "/api/v", params: nil, match: false},
{url: "/api/v2", params: nil, match: false},
{url: "/api/xyz", params: nil, match: false},
})
testCase("/api/v1/*", []testparams{
{url: "/api/v1", params: []string{""}, match: true},
{url: "/api/v1/", params: []string{""}, match: true},
{url: "/api/v1/entity", params: []string{"entity"}, match: true},
{url: "/api/v1/entity/1/2", params: []string{"entity/1/2"}, match: true},
{url: "/api/v", params: nil, match: false},
{url: "/api/v2", params: nil, match: false},
{url: "/api/abc", params: nil, match: false},
})
testCase("/api/v1/:param", []testparams{
{url: "/api/v1/entity", params: []string{"entity"}, match: true},
{url: "/api/v1/entity/8728382", params: nil, match: false},
{url: "/api/v1", params: nil, match: false},
{url: "/api/v1/", params: nil, match: false},
})
testCase("/api/v1/const", []testparams{
{url: "/api/v1/const", params: []string{}, match: true},
{url: "/api/v1", params: nil, match: false},
{url: "/api/v1/", params: nil, match: false},
{url: "/api/v1/something", params: nil, match: false},
})
testCase("/api/v1/:param/abc/*", []testparams{
{url: "/api/v1/well/abc/wildcard", params: []string{"well", "wildcard"}, match: true},
{url: "/api/v1/well/abc/", params: []string{"well", ""}, match: true},
{url: "/api/v1/well/abc", params: []string{"well", ""}, match: true},
{url: "/api/v1/well/ttt", params: nil, match: false},
})
testCase("/api/:day/:month?/:year?", []testparams{
{url: "/api/1", params: []string{"1", "", ""}, match: true},
{url: "/api/1/", params: []string{"1", "", ""}, match: true},
{url: "/api/1/2", params: []string{"1", "2", ""}, match: true},
{url: "/api/1/2/3", params: []string{"1", "2", "3"}, match: true},
{url: "/api/", params: nil, match: false},
})
testCase("/api/*", []testparams{
{url: "/api/", params: []string{""}, match: true},
{url: "/api/joker", params: []string{"joker"}, match: true},
{url: "/api", params: []string{""}, match: true},
{url: "/api/v1/entity", params: []string{"v1/entity"}, match: true},
{url: "/api2/v1/entity", params: nil, match: false},
{url: "/api_ignore/v1/entity", params: nil, match: false},
})
testCase("/api/*/:param?", []testparams{
{url: "/api/", params: []string{"", ""}, match: true},
{url: "/api/joker", params: []string{"joker", ""}, match: true},
{url: "/api/joker/batman", params: []string{"joker", "batman"}, match: true},
{url: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, match: true},
{url: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, match: true},
{url: "/api", params: []string{"", ""}, match: true},
})
testCase("/api/*/:param", []testparams{
{url: "/api/test/abc", params: []string{"test", "abc"}, match: true},
{url: "/api/joker/batman", params: []string{"joker", "batman"}, match: true},
{url: "/api/joker/batman/robin", params: []string{"joker/batman", "robin"}, match: true},
{url: "/api/joker/batman/robin/1", params: []string{"joker/batman/robin", "1"}, match: true},
{url: "/api", params: nil, match: false},
})
testCase("/api/*/:param/:param2", []testparams{
{url: "/api/test/abc", params: nil, match: false},
{url: "/api/joker/batman", params: nil, match: false},
{url: "/api/joker/batman/robin", params: []string{"joker", "batman", "robin"}, match: true},
{url: "/api/joker/batman/robin/1", params: []string{"joker/batman", "robin", "1"}, match: true},
{url: "/api/joker/batman/robin/1/2", params: []string{"joker/batman/robin", "1", "2"}, match: true},
{url: "/api", params: nil, match: false},
})
testCase("/", []testparams{
{url: "/api", params: nil, match: false},
{url: "", params: []string{}, match: true},
{url: "/", params: []string{}, match: true},
})
testCase("/config/abc.json", []testparams{
{url: "/config/abc.json", params: []string{}, match: true},
{url: "config/abc.json", params: nil, match: false},
{url: "/config/efg.json", params: nil, match: false},
{url: "/config", params: nil, match: false},
})
testCase("/config/*.json", []testparams{
{url: "/config/abc.json", params: []string{"abc.json"}, match: true},
{url: "/config/efg.json", params: []string{"efg.json"}, match: true},
//{url: "/config/efg.csv", params: nil, match: false},// doesn`t work, current: params: "efg.csv", true
{url: "config/abc.json", params: nil, match: false},
{url: "/config", params: nil, match: false},
})
testCase("/xyz", []testparams{
{url: "xyz", params: nil, match: false},
{url: "xyz/", params: nil, match: false},
})
}
// func Test_Utils_getTrimmedParam(t *testing.T) {
// // TODO
// }
// func Test_Utils_getCharPos(t *testing.T) {
// // TODO
// }