diff --git a/HISTORY.md b/HISTORY.md index 0c8dde07c..eab2ec0f3 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -19,10 +19,15 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene **How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris/v12@latest` and `go mod tidy -compat=1.21`. + # Next Changes apply to `main` branch. +# Thu, 18 Jan 2024 | v12.2.10 + +- Simplify the `/core/host` subpackage and remove its `DeferFlow` and `RestoreFlow` methods. +- Fix internal `trimHandlerName` and other minor stuff. - New `iris.NonBlocking()` configuration option to run the server without blocking the main routine, `Application.Wait(context.Context) error` method can be used to block and wait for the server to be up and running. Example: ```go diff --git a/README.md b/README.md index db77875de..0fd36b095 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Try the official [Iris Command Line Interface](https://github.com/kataras/iris-c # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) Iris is a fast, simple yet fully featured and very efficient web framework for Go. @@ -586,7 +586,7 @@ The only requirement is the [Go Programming Language](https://go.dev/dl/). $ mkdir myapp $ cd myapp $ go mod init myapp -$ go get github.com/kataras/iris/v12@latest # or @v12.2.9 +$ go get github.com/kataras/iris/v12@latest # or @v ```
Install on existing project diff --git a/README_ES.md b/README_ES.md index 6940e7e2e..622b9ac08 100644 --- a/README_ES.md +++ b/README_ES.md @@ -1,6 +1,6 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) Iris es un framework web rápido, simple pero con muchas funcionalidades y muy eficiente para Go. Proporciona una base bellamente expresiva y fácil de usar para su próximo sitio web o API. @@ -49,7 +49,7 @@ $ go run ejemplo.go Iris contiene un extenso y completo **[wiki](https://www.iris-go.com/#ebookDonateForm)** que facilita comenzar con el framework. -Para obtener una documentación técnica más detallada, puede dirigirse a nuestros [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9). Y para código ejecutable siempre puede visitar el subdirectorio del repositorio [\_examples](_examples/). +Para obtener una documentación técnica más detallada, puede dirigirse a nuestros [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v). Y para código ejecutable siempre puede visitar el subdirectorio del repositorio [\_examples](_examples/). ### ¿Te gusta leer mientras viajas? diff --git a/README_FA.md b/README_FA.md index eb6f93953..2cdc42a69 100644 --- a/README_FA.md +++ b/README_FA.md @@ -10,7 +10,7 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) آیریس یک چارچوب وب پر سرعت ، ساده و در عین حال کاملاً برجسته و بسیار کارآمد برای Go است. @@ -137,7 +137,7 @@ func (c *userController) PutBy(id uint64, req request) response { $ mkdir myapp $ cd myapp $ go mod init myapp -$ go get github.com/kataras/iris/v12@latest # or @v12.2.9 +$ go get github.com/kataras/iris/v12@latest # or @v ```
diff --git a/README_FR.md b/README_FR.md index 6d8c7327e..0f7c7065b 100644 --- a/README_FR.md +++ b/README_FR.md @@ -1,6 +1,6 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) @@ -57,7 +57,7 @@ Iris possède un **[wiki](https://www.iris-go.com/#ebookDonateForm)** complet et -Pour une documentation encore plus complète vous pouvez visiter notre [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9) (en Anglais). Et vous trouverez du code executable dans le dossier [\_examples](_examples/). +Pour une documentation encore plus complète vous pouvez visiter notre [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v) (en Anglais). Et vous trouverez du code executable dans le dossier [\_examples](_examples/). ### Vous préférez une version PDF? diff --git a/README_GR.md b/README_GR.md index 3e3f4338b..29b196c95 100644 --- a/README_GR.md +++ b/README_GR.md @@ -1,6 +1,6 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go γλώσσα προγραμματισμού. Παρέχει ένα εκφραστικό και εύχρηστο υπόβαθρο για την επόμενη ιστοσελίδα σας. @@ -53,7 +53,7 @@ $ go run example.go Το Iris περιέχει εκτενείς και λεπτομερείς **[book](https://www.iris-go.com/#ebookDonateForm)** καθιστώντας το εύκολο στην εκμάθηση. -Για λεπτομερέστερη τεχνική τεκμηρίωση μπορείτε να κατευθυνθείτε προς τα [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9) μας. Και για εκτελέσιμο κώδικα μπορείτε πάντα να επισκέπτεστε τα [παραδείγματα](_examples/). +Για λεπτομερέστερη τεχνική τεκμηρίωση μπορείτε να κατευθυνθείτε προς τα [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v) μας. Και για εκτελέσιμο κώδικα μπορείτε πάντα να επισκέπτεστε τα [παραδείγματα](_examples/). ### Σας αρέσει να διαβάζετε ενώ ταξιδεύετε; diff --git a/README_JA.md b/README_JA.md index 600c9953c..e7218e712 100644 --- a/README_JA.md +++ b/README_JA.md @@ -6,7 +6,7 @@ Try the official [Iris Command Line Interface](https://github.com/kataras/iris-c # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) Irisは、高速でシンプルでありながら、十分な機能を備えた、非常に効率的なGo用Webフレームワークです。 @@ -219,7 +219,7 @@ Irisが提供する機能の一部: $ mkdir myapp $ cd myapp $ go mod init myapp -$ go get github.com/kataras/iris/v12@latest # or @v12.2.9 +$ go get github.com/kataras/iris/v12@latest # or @v ```
既存のプロジェクトにインストールする場合 diff --git a/README_KO.md b/README_KO.md index 05c594d7b..d4be33216 100644 --- a/README_KO.md +++ b/README_KO.md @@ -1,6 +1,6 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) Iris는 단순하고 빠르며 좋은 성능과 모든 기능을 갖춘 Go언어용 웹 프레임워크입니다. 당신의 웹사이트나 API를 위해서 아름답고 사용하기 쉬운 기반을 제공합니다. @@ -49,7 +49,7 @@ $ go run example.go Iris는 광범위하고 꼼꼼한 **[wiki](https://www.iris-go.com/#ebookDonateForm)** 를 가지고 있기 때문에 쉽게 프레임워크를 시작할 수 있습니다. -더 자세한 기술문서를 보시려면 [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9)를 방문하세요. 그리고 실행가능한 예제코드는 [\_examples](_examples/) 하위 디렉토리에 있습니다. +더 자세한 기술문서를 보시려면 [godocs](https://pkg.go.dev/github.com/kataras/iris/v12@v)를 방문하세요. 그리고 실행가능한 예제코드는 [\_examples](_examples/) 하위 디렉토리에 있습니다. ### 여행하면서 독서를 즐기세요? diff --git a/README_PT_BR.md b/README_PT_BR.md index c605b19a1..e3ac80e5a 100644 --- a/README_PT_BR.md +++ b/README_PT_BR.md @@ -2,7 +2,7 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-270-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-270-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) @@ -226,7 +226,7 @@ O único requisito é a [Linguagem de programação Go](https://go.dev/dl/). $ mkdir myapp $ cd myapp $ go mod init myapp -$ go get github.com/kataras/iris/v12@latest # or @v12.2.9 +$ go get github.com/kataras/iris/v12@latest # or @v ```
Instalar num projeto existente diff --git a/README_RU.md b/README_RU.md index 37766319d..41674d83d 100644 --- a/README_RU.md +++ b/README_RU.md @@ -1,6 +1,6 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![FOSSA Status](https://img.shields.io/badge/LICENSE%20SCAN-PASSING❤️-CD2956?style=for-the-badge&logo=fossa)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![view examples](https://img.shields.io/badge/learn%20by-examples-0C8EC5.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=7E18DD&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) Iris — это быстрый, простой, но полнофункциональный и эффективный веб-фреймворк для Go. Он обеспечивает красивую, выразительную и простую в использовании основу для вашего следующего веб-сайта или API. Узнайте, что [говорят другие люди об Iris](https://iris-go.com/testimonials/) и поставьте **[звёздочку](https://github.com/kataras/iris/stargazers)** этому проекту с открытым исходным кодом, чтобы поддержать его потенциал. @@ -50,7 +50,7 @@ $ go run example.go -Для получения более подробной технической документации вы можете обратиться к нашему [godoc](https://pkg.go.dev/github.com/kataras/iris/v12@v12.2.9). А для живых примеров кода — вы всегда можете посетить [\_examples](_examples/) в поддиректории этого репозитория. +Для получения более подробной технической документации вы можете обратиться к нашему [godoc](https://pkg.go.dev/github.com/kataras/iris/v12@v). А для живых примеров кода — вы всегда можете посетить [\_examples](_examples/) в поддиректории этого репозитория. ### Вы любите читать во время путешествий? diff --git a/README_VN.md b/README_VN.md index 5550319da..4dc792ad5 100644 --- a/README_VN.md +++ b/README_VN.md @@ -6,7 +6,7 @@ Try the official [Iris Command Line Interface](https://github.com/kataras/iris-c # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) Iris là một khung web nhanh, đơn giản nhưng đầy đủ tính năng và rất hiệu quả dành cho Go. @@ -220,7 +220,7 @@ Yêu cầu duy nhất là [Ngôn ngữ lập trình Go](https://go.dev/dl/). $ mkdir myapp $ cd myapp $ go mod init myapp -$ go get github.com/kataras/iris/v12@latest # or @v12.2.9 +$ go get github.com/kataras/iris/v12@latest # or @v ```
Cài đặt trên dự án hiện có diff --git a/README_ZH_HANS.md b/README_ZH_HANS.md index 613845e9c..8046c1bb2 100644 --- a/README_ZH_HANS.md +++ b/README_ZH_HANS.md @@ -10,7 +10,7 @@ # Iris Web Framework -[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-253-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) +[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-253-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) diff --git a/README_ZH_HANT.md b/README_ZH_HANT.md index 52f238743..3c9aded28 100644 --- a/README_ZH_HANT.md +++ b/README_ZH_HANT.md @@ -12,7 +12,7 @@ # Iris Web 框架 -[![組建狀態](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![查看範例](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![聊天室](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![捐助](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) +[![組建狀態](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![查看範例](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![聊天室](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![捐助](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate) @@ -237,7 +237,7 @@ Iris 提供了至少這些功能: $ mkdir myapp $ cd myapp $ go mod init myapp -$ go get github.com/kataras/iris/v12@latest # 或 @v12.2.9 +$ go get github.com/kataras/iris/v12@latest # 或 @v ```
在現有專案安裝 diff --git a/_examples/file-server/embedding-files-into-app-bindata/main_test.go b/_examples/file-server/embedding-files-into-app-bindata/main_test.go index fc546e557..03e32d338 100644 --- a/_examples/file-server/embedding-files-into-app-bindata/main_test.go +++ b/_examples/file-server/embedding-files-into-app-bindata/main_test.go @@ -50,11 +50,11 @@ func (r resource) loadFromBase(dir string) string { } result := string(b) - if runtime.GOOS != "windows" { result = strings.ReplaceAll(result, "\n", "\r\n") result = strings.ReplaceAll(result, "\r\r", "") } + return result } diff --git a/_examples/file-server/embedding-files-into-app/assets/favicon.ico b/_examples/file-server/embedding-files-into-app/assets/favicon.ico new file mode 100644 index 000000000..c370da518 Binary files /dev/null and b/_examples/file-server/embedding-files-into-app/assets/favicon.ico differ diff --git a/_examples/file-server/embedding-files-into-app/main_test.go b/_examples/file-server/embedding-files-into-app/main_test.go index ee3978906..03e32d338 100644 --- a/_examples/file-server/embedding-files-into-app/main_test.go +++ b/_examples/file-server/embedding-files-into-app/main_test.go @@ -50,6 +50,11 @@ func (r resource) loadFromBase(dir string) string { } result := string(b) + if runtime.GOOS != "windows" { + result = strings.ReplaceAll(result, "\n", "\r\n") + result = strings.ReplaceAll(result, "\r\r", "") + } + return result } diff --git a/_examples/logging/json-logger/main_test.go b/_examples/logging/json-logger/main_test.go index 74c66cb38..f55376c3e 100644 --- a/_examples/logging/json-logger/main_test.go +++ b/_examples/logging/json-logger/main_test.go @@ -3,6 +3,9 @@ package main import ( "bytes" "encoding/json" + "fmt" + "path" + "runtime" "strings" "sync" "testing" @@ -30,7 +33,8 @@ func TestJSONLogger(t *testing.T) { app.Get("/ping", ping) - const expectedLogStr = `{"level":"debug","message":"Request path: /ping","fields":{"request_id":null},"stacktrace":[{"function":"json-logger/ping","source":"/home/runner/work/iris/iris/_examples/logging/json-logger/main.go:78"}]}` // gh actions-specific. + expectedSourceDir := getSourceDirPath() + expectedLogStr := fmt.Sprintf(`{"level":"debug","message":"Request path: /ping","fields":{"request_id":null},"stacktrace":[{"function":"json-logger/ping","source":"%s/main.go:78"}]}`, expectedSourceDir) // gh actions-specific. e := httptest.New(t, app, httptest.LogLevel("debug")) wg := new(sync.WaitGroup) wg.Add(iters) @@ -57,3 +61,12 @@ func TestJSONLogger(t *testing.T) { } } } + +func getSourceDirPath() string { + _, file, _, ok := runtime.Caller(1) // get the caller's file. + if !ok { + return "unknown source" + } + + return path.Dir(file) // get the directory of the file (delimiter: /). +} diff --git a/configuration.go b/configuration.go index 0f2ee4cda..848354d93 100644 --- a/configuration.go +++ b/configuration.go @@ -7,7 +7,6 @@ import ( "path/filepath" "runtime" "strings" - "sync" "time" "github.com/kataras/iris/v12/context" @@ -977,25 +976,19 @@ type Configuration struct { // // Defaults to empty map. Other map[string]interface{} `ini:"other" json:"other,omitempty" yaml:"Other" toml:"Other"` - - mu sync.RWMutex // mutex for some of the configuration fields that may change during parallel jobs (see Application.NonBlocking & Wait). } var _ context.ConfigurationReadOnly = (*Configuration)(nil) -// GetVHost returns the non-exported VHost config field. +// GetVHost returns the VHost config field. func (c *Configuration) GetVHost() string { - c.mu.RLock() vhost := c.VHost - c.mu.RUnlock() return vhost } -// SetVHost sets the non-exported VHost config field. +// SetVHost sets the VHost config field. func (c *Configuration) SetVHost(s string) { - c.mu.Lock() c.VHost = s - c.mu.Unlock() } // GetLogLevel returns the LogLevel field. diff --git a/configuration_test.go b/configuration_test.go index 213d0fb79..929b23a25 100644 --- a/configuration_test.go +++ b/configuration_test.go @@ -18,7 +18,7 @@ func TestConfigurationStatic(t *testing.T) { afterNew := *app.config if !reflect.DeepEqual(def, afterNew) { - t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, afterNew) + t.Fatalf("Default configuration is not the same after New expected:\n %#v \ngot:\n %#v", def, afterNew) } afterNew.Charset = "changed" @@ -37,7 +37,7 @@ func TestConfigurationStatic(t *testing.T) { app = New() // empty , means defaults so if !reflect.DeepEqual(def, *app.config) { - t.Fatalf("Default configuration is not the same after NewFromConfig expected:\n %#v \ngot:\n %#v", def, *app.config) + t.Fatalf("Default configuration is not the same after New expected:\n %#v \ngot:\n %#v", def, *app.config) } } diff --git a/context/handler.go b/context/handler.go index 42d4caa37..5939b3cec 100644 --- a/context/handler.go +++ b/context/handler.go @@ -12,7 +12,7 @@ import ( var ( // PackageName is the Iris Go module package name. - PackageName = strings.TrimSuffix(reflect.TypeOf(Handlers{}).PkgPath(), "/context") + PackageName = strings.TrimSuffix(reflect.TypeOf(Context{}).PkgPath(), "/context") // WorkingDir is the (initial) current directory. WorkingDir, _ = os.Getwd() diff --git a/core/host/proxy_test.go b/core/host/proxy_test.go index 4b8ba34fb..258f33fcc 100644 --- a/core/host/proxy_test.go +++ b/core/host/proxy_test.go @@ -2,6 +2,7 @@ package host_test import ( + stdContext "context" "crypto/tls" "net" "net/url" @@ -30,6 +31,7 @@ func TestProxy(t *testing.T) { MinVersion: tls.VersionTLS13, } proxy := host.NewProxy("", u, config) + proxy.Configure(host.NonBlocking()) addr := &net.TCPAddr{ IP: net.IPv4(127, 0, 0, 1), @@ -41,10 +43,15 @@ func TestProxy(t *testing.T) { t.Fatalf("%v while creating listener", err) } - go proxy.Serve(listener) // should be localhost/127.0.0.1:80 but travis throws permission denied. + // non-blocking (see above). + proxy.Serve(listener) + + ctx, cancelFunc := stdContext.WithTimeout(stdContext.Background(), 15*time.Second) + defer cancelFunc() + + // Wait for up to 15 seconds or until the proxy is ready to serve or a serve failure. + proxy.Wait(ctx) - t.Log(listener.Addr().String()) - <-time.After(time.Second) t.Log(listener.Addr().String()) app := iris.New() @@ -60,7 +67,7 @@ func TestProxy(t *testing.T) { ctx.WriteString(unexpectedRoute) }) - l, err := net.Listen("tcp", "localhost:4444") // should be localhost/127.0.0.1:443 but travis throws permission denied. + l, err := net.Listen("tcp", "localhost:4444") if err != nil { t.Fatalf("%v while creating tcp4 listener for new tls local test listener", err) } diff --git a/core/host/supervisor.go b/core/host/supervisor.go index e8ea77a67..93d6cf34e 100644 --- a/core/host/supervisor.go +++ b/core/host/supervisor.go @@ -25,6 +25,13 @@ import ( // Look the `Configure` func for more. type Configurator func(su *Supervisor) +// NonBlocking sets the server to non-blocking mode. Use its `Wait` method to wait for server to be up and running. +func NonBlocking() Configurator { + return func(su *Supervisor) { + su.nonBlocking = true + } +} + // Supervisor is the wrapper and the manager for a compatible server // and it's relative actions, called Tasks. // @@ -34,14 +41,12 @@ type Supervisor struct { // FriendlyAddr can be set to customize the "Now Listening on: {FriendlyAddr}". FriendlyAddr string // e.g mydomain.com instead of :443 when AutoTLS is used, see `WriteStartupLogOnServe` task. disableHTTP1ToHTTP2Redirection bool - closedManually uint32 // future use, accessed atomically (non-zero means we've called the Shutdown) - closedByInterruptHandler uint32 // non-zero means that the end-developer interrupted it by-purpose. - manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin. - autoTLS bool - shouldWait int32 // non-zero means that the host should wait for unblocking - unblockChan chan struct{} - mu sync.Mutex + closedByInterruptHandler uint32 // non-zero means that the end-developer interrupted it by-purpose. + manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin. + autoTLS bool + + mu sync.RWMutex onServe []func(TaskHost) // IgnoreErrors should contains the errors that should be ignored @@ -73,6 +78,10 @@ type Supervisor struct { // If more than zero then tcp keep alive listener is attached instead of the simple TCP listener. // See `iris.Configuration.KeepAlive` KeepAlive time.Duration + + address string + nonBlocking bool + waiter *Waiter } // New returns a new host supervisor @@ -83,10 +92,12 @@ type Supervisor struct { // It has its own flow, which means that you can prevent // to return and exit and restore the flow too. func New(srv *http.Server) *Supervisor { - return &Supervisor{ - Server: srv, - unblockChan: make(chan struct{}, 1), + su := &Supervisor{ + Server: srv, } + + su.waiter = NewWaiter(7, su.getAddress) + return su } // Configure accepts one or more `Configurator`. @@ -113,36 +124,6 @@ func (su *Supervisor) NoRedirect() { su.disableHTTP1ToHTTP2Redirection = true } -// DeferFlow defers the flow of the exeuction, -// i.e: when server should return error and exit -// from app, a DeferFlow call inside a Task -// can wait for a `RestoreFlow` to exit or not exit if -// host's server is "fixed". -// -// See `RestoreFlow` too. -func (su *Supervisor) DeferFlow() { - atomic.StoreInt32(&su.shouldWait, 1) -} - -// RestoreFlow restores the flow of the execution, -// if called without a `DeferFlow` call before -// then it does nothing. -// See tests to understand how that can be useful on specific cases. -// -// See `DeferFlow` too. -func (su *Supervisor) RestoreFlow() { - if su.isWaiting() { - atomic.StoreInt32(&su.shouldWait, 0) - su.mu.Lock() - su.unblockChan <- struct{}{} - su.mu.Unlock() - } -} - -func (su *Supervisor) isWaiting() bool { - return atomic.LoadInt32(&su.shouldWait) != 0 -} - func (su *Supervisor) newListener() (net.Listener, error) { var ( l net.Listener @@ -198,14 +179,28 @@ func (su *Supervisor) validateErr(err error) error { } func (su *Supervisor) notifyErr(err error) { - err = su.validateErr(err) - if err != nil { - su.mu.Lock() - for _, f := range su.onErr { - go f(err) - } - su.mu.Unlock() + if err == nil { + return + } + + su.mu.Lock() + for _, f := range su.onErr { + go f(err) } + su.mu.Unlock() +} + +func (su *Supervisor) getAddress() string { + su.mu.RLock() + addr := su.address + su.mu.RUnlock() + return addr +} + +func (su *Supervisor) setAddress(addr string) { + su.mu.Lock() + su.address = addr + su.mu.Unlock() } // RegisterOnServe registers a function to call on @@ -224,27 +219,36 @@ func (su *Supervisor) notifyServe(host TaskHost) { su.mu.Unlock() } -// Remove all channels, do it with events -// or with channels but with a different channel on each task proc -// I don't know channels are not so safe, when go func and race risk.. -// so better with callbacks.... func (su *Supervisor) supervise(blockFunc func() error) error { host := createTaskHost(su) su.notifyServe(host) atomic.StoreUint32(&su.closedByInterruptHandler, 0) - atomic.StoreUint32(&su.closedManually, 0) + + if su.nonBlocking { + go func() { + err := blockFunc() + if err != nil { + su.waiter.Fail(err) + } + + err = su.validateErr(err) + su.notifyErr(err) + }() + + return nil + } err := blockFunc() + err = su.validateErr(err) su.notifyErr(err) - if su.isWaiting() { - for range su.unblockChan { - break - } - } + return err +} - return su.validateErr(err) +// Wait blocks until server is up and running or a serve failure. +func (su *Supervisor) Wait(ctx context.Context) error { + return su.waiter.Wait(ctx) } // Serve accepts incoming connections on the Listener l, creating a @@ -259,7 +263,11 @@ func (su *Supervisor) supervise(blockFunc func() error) error { // Serve always returns a non-nil error. After Shutdown or Close, the // returned error is http.ErrServerClosed. func (su *Supervisor) Serve(l net.Listener) error { - return su.supervise(func() error { return su.Server.Serve(l) }) + su.setAddress(l.Addr().String()) + + return su.supervise(func() error { + return su.Server.Serve(l) + }) } // ListenAndServe listens on the TCP network address addr @@ -502,7 +510,6 @@ func (su *Supervisor) RegisterOnShutdown(cb func()) { // separately notify such long-lived connections of shutdown and wait // for them to close, if desired. func (su *Supervisor) Shutdown(ctx context.Context) error { - atomic.StoreUint32(&su.closedManually, 1) // future-use if ctx == nil { ctx = context.Background() } diff --git a/core/host/supervisor_task_example_test.go b/core/host/supervisor_task_example_test.go index e2e1d127b..27eb63a67 100644 --- a/core/host/supervisor_task_example_test.go +++ b/core/host/supervisor_task_example_test.go @@ -4,10 +4,7 @@ package host import ( "context" "fmt" - "log" - "net" "net/http" - "os" "time" ) @@ -38,75 +35,3 @@ func ExampleSupervisor_RegisterOnError() { // http: Server closed // http: Server closed } - -type myTestTask struct { - restartEvery time.Duration - maxRestarts int - logger *log.Logger -} - -func (m myTestTask) OnServe(host TaskHost) { - host.Supervisor.DeferFlow() // don't exit on underline server's Shutdown. - - ticker := time.NewTicker(m.restartEvery) - defer ticker.Stop() - rans := 0 - for range ticker.C { - exitAfterXRestarts := m.maxRestarts - if rans == exitAfterXRestarts { - m.logger.Println("exit") - ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) - _ = host.Supervisor.Shutdown(ctx) // total shutdown - host.Supervisor.RestoreFlow() // free to exit (if shutdown) - cancel() - return - } - - rans++ - - m.logger.Println(fmt.Sprintf("closed %d times", rans)) - host.Shutdown(context.TODO()) - - startDelay := 2 * time.Second - time.AfterFunc(startDelay, func() { - m.logger.Println("restart") - if err := host.Serve(); err != nil { // restart - panic(err) - } - }) - - } -} - -func ExampleSupervisor_RegisterOnServe() { - h := New(&http.Server{ - Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - }), - }) - - logger := log.New(os.Stdout, "Supervisor: ", 0) - - mytask := myTestTask{ - restartEvery: 3 * time.Second, - maxRestarts: 2, - logger: logger, - } - - h.RegisterOnServe(mytask.OnServe) - - ln, err := net.Listen("tcp4", ":9394") - if err != nil { - panic(err.Error()) - } - - logger.Println("server started...") - h.Serve(ln) - - // Output: - // Supervisor: server started... - // Supervisor: closed 1 times - // Supervisor: restart - // Supervisor: closed 2 times - // Supervisor: restart - // Supervisor: exit -} diff --git a/core/host/supervisor_test.go b/core/host/supervisor_test.go index c8b3f82b2..9f938efc6 100644 --- a/core/host/supervisor_test.go +++ b/core/host/supervisor_test.go @@ -35,7 +35,7 @@ func newTester(t *testing.T, baseURL string, handler http.Handler) *httpexpect.E BaseURL: baseURL, Client: &http.Client{ Transport: transporter, - Jar: httpexpect.NewJar(), + Jar: httpexpect.NewCookieJar(), }, Reporter: httpexpect.NewAssertReporter(t), } diff --git a/core/host/task.go b/core/host/task.go index a7ea30516..b50f9783b 100644 --- a/core/host/task.go +++ b/core/host/task.go @@ -94,10 +94,10 @@ func WriteStartupLogOnServe(w io.Writer) func(TaskHost) { // This function should be registered on Interrupt. func ShutdownOnInterrupt(su *Supervisor, shutdownTimeout time.Duration) func() { return func() { - ctx, cancel := context.WithTimeout(context.TODO(), shutdownTimeout) + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() + su.shutdownOnInterrupt(ctx) - su.RestoreFlow() } } diff --git a/core/host/waiter.go b/core/host/waiter.go new file mode 100644 index 000000000..85b4ec8f9 --- /dev/null +++ b/core/host/waiter.go @@ -0,0 +1,134 @@ +package host + +import ( + "context" + "fmt" + "math" + "net" + "sync" + "time" +) + +// Waiter is a helper for waiting for a server to be up and running. +type Waiter struct { + defaultMaxRetries int + addressFunc func() string + + failure error // or runError for app.Run. + mu sync.RWMutex +} + +// NewWaiter returns a new Waiter. +func NewWaiter(defaultMaxRetries int, addressFunc func() string) *Waiter { + if defaultMaxRetries <= 0 { + defaultMaxRetries = 7 // 256 seconds max. + } + + return &Waiter{ + defaultMaxRetries: defaultMaxRetries, + addressFunc: addressFunc, + } +} + +// Wait blocks the main goroutine until the application is up and running. +func (w *Waiter) Wait(ctx context.Context) error { + // First check if there is an error already from Done. + if err := w.getFailure(); err != nil { + return err + } + + // Set the base for exponential backoff. + base := 2.0 + + // Get the maximum number of retries by context or force to default max retries (e.g. 7). + var maxRetries int + // Get the deadline of the context. + if deadline, ok := ctx.Deadline(); ok { + now := time.Now() + timeout := deadline.Sub(now) + + maxRetries = getMaxRetries(timeout, base) + } else { + maxRetries = w.defaultMaxRetries + } + + // Set the initial retry interval. + retryInterval := time.Second + + return w.tryConnect(ctx, w.addressFunc, maxRetries, retryInterval, base) +} + +// getMaxRetries calculates the maximum number of retries from the retry interval and the base. +func getMaxRetries(retryInterval time.Duration, base float64) int { + // Convert the retry interval to seconds. + seconds := retryInterval.Seconds() + // Apply the inverse formula. + retries := math.Log(seconds)/math.Log(base) - 1 + return int(math.Round(retries)) +} + +// tryConnect tries to connect to the server with the given context and retry parameters. +func (w *Waiter) tryConnect(ctx context.Context, addressFunc func() string, maxRetries int, retryInterval time.Duration, base float64) error { + // Try to connect to the server in a loop. + for i := 0; i < maxRetries; i++ { + // Check the context before each attempt. + select { + case <-ctx.Done(): + // Context is canceled, return the context error. + return ctx.Err() + default: + address := addressFunc() // Get this server's listening address. + if address == "" { + i-- // Note that this may be modified at another go routine of the serve method. So it may be empty at first chance. So retry fetching the VHost every 1 second. + time.Sleep(time.Second) + continue + } + + // Context is not canceled, proceed with the attempt. + conn, err := net.Dial("tcp", address) + if err == nil { + // Connection successful, close the connection and return nil. + conn.Close() + return nil // exit. + } // ignore error. + + // Connection failed, wait for the retry interval and try again. + time.Sleep(retryInterval) + // After each failed attempt, check the server Run's error again. + if err := w.getFailure(); err != nil { + return err + } + + // Increase the retry interval by the base raised to the power of the number of attempts. + /* + 0 2 seconds + 1 4 seconds + 2 8 seconds + 3 ~16 seconds + 4 ~32 seconds + 5 ~64 seconds + 6 ~128 seconds + 7 ~256 seconds + 8 ~512 seconds + ... + */ + retryInterval = time.Duration(math.Pow(base, float64(i+1))) * time.Second + } + } + // All attempts failed, return an error. + return fmt.Errorf("failed to connect to the server after %d retries", maxRetries) +} + +// Fail is called by the server's Run method when the server failed to start. +func (w *Waiter) Fail(err error) { + w.mu.Lock() + w.failure = err + w.mu.Unlock() +} + +func (w *Waiter) getFailure() error { + w.mu.RLock() + err := w.failure + w.mu.RUnlock() + return err +} diff --git a/doc.go b/doc.go index b4b2c43cc..c7f64f167 100644 --- a/doc.go +++ b/doc.go @@ -10,7 +10,7 @@ Source code and other details for the project are available at GitHub: # Current Version -12.2.9 +12.2.10 # Installation diff --git a/go.mod b/go.mod index 1dfaaf59b..1f04f0c76 100644 --- a/go.mod +++ b/go.mod @@ -35,12 +35,12 @@ require ( github.com/redis/go-redis/v9 v9.4.0 github.com/schollz/closestmatch v2.1.0+incompatible github.com/shirou/gopsutil/v3 v3.23.12 - github.com/tdewolff/minify/v2 v2.20.13 + github.com/tdewolff/minify/v2 v2.20.14 github.com/vmihailenco/msgpack/v5 v5.4.1 github.com/yosssi/ace v0.0.5 go.etcd.io/bbolt v1.3.8 golang.org/x/crypto v0.18.0 - golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 golang.org/x/net v0.20.0 golang.org/x/sys v0.16.0 golang.org/x/text v0.14.0 diff --git a/go.sum b/go.sum index 8d2a74f35..1a417323e 100644 --- a/go.sum +++ b/go.sum @@ -116,6 +116,8 @@ github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20= github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A= github.com/kataras/jwt v0.1.12 h1:FHPgTTj5UqjlBye4PA4/oxknCY+kQ9K34XAi8d37glA= github.com/kataras/jwt v0.1.12/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo= +github.com/kataras/neffos v0.0.23 h1:Jlbn7aK+pl/U/4vfDs1508+tlIdcjE5BdKFtzePsrBI= +github.com/kataras/neffos v0.0.23/go.mod h1:3pzx6A5QUvwavU1RF0uIl5/TNbwyYswmfnfG5z8VBm8= github.com/kataras/neffos v0.0.24-0.20240110215151-1db32f4ef9ed h1:iCsmmi2n7vUyWJ0NS1Wsu8N5oIS+C05fyIo3YTBQHMQ= github.com/kataras/neffos v0.0.24-0.20240110215151-1db32f4ef9ed/go.mod h1:VLyfPmZh2Tbxjc2XKe1J0xwwKqiUD2zTA36Xcp+UIDs= github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM= @@ -158,6 +160,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E= github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= +github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk= +github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= @@ -219,8 +223,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= -github.com/tdewolff/minify/v2 v2.20.13 h1:TDWS1orkBJjq6Sz9NjEvHEeUnAvlfU7jgStGQBwBPGM= -github.com/tdewolff/minify/v2 v2.20.13/go.mod h1:qnIJbnG2dSzk7LIa/UUwgN2OjS8ir6RRlqc0T/1q2xY= +github.com/tdewolff/minify/v2 v2.20.14 h1:sktSuVixRwk0ryQjqvKBu/uYS+MWmkwEFMEWtFZ+TdE= +github.com/tdewolff/minify/v2 v2.20.14/go.mod h1:qnIJbnG2dSzk7LIa/UUwgN2OjS8ir6RRlqc0T/1q2xY= github.com/tdewolff/parse/v2 v2.7.8 h1:1cnVqa8L63xFkc2vfRsZTM6Qy35nJpTvQ2Uvdv3vbvs= github.com/tdewolff/parse/v2 v2.7.8/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= @@ -266,8 +270,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e h1:723BNChdd0c2Wk6WOE320qGBiPtYx0F0Bbm1kriShfE= -golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= diff --git a/httptest/httptest.go b/httptest/httptest.go index 2ef74124c..1d6b302cd 100644 --- a/httptest/httptest.go +++ b/httptest/httptest.go @@ -134,7 +134,7 @@ func New(t IrisTesty, app *iris.Application, setters ...OptionSetter) *httpexpec BaseURL: conf.URL, Client: &http.Client{ Transport: httpexpect.NewBinder(app), - Jar: httpexpect.NewJar(), + Jar: httpexpect.NewCookieJar(), }, Reporter: reporter, } @@ -163,7 +163,7 @@ func NewInsecure(t IrisTesty, setters ...OptionSetter) *httpexpect.Expect { BaseURL: conf.URL, Client: &http.Client{ Transport: transport, - Jar: httpexpect.NewJar(), + Jar: httpexpect.NewCookieJar(), }, Reporter: httpexpect.NewAssertReporter(t), } diff --git a/iris.go b/iris.go index 39c2b69a7..a045612e2 100644 --- a/iris.go +++ b/iris.go @@ -39,7 +39,7 @@ import ( ) // Version is the current version of the Iris Web Framework. -const Version = "12.2.9" +const Version = "12.2.10" // Byte unit helpers. const ( @@ -95,7 +95,7 @@ type Application struct { // Users can wrap it to accept more events. OnBuild func() error - mu sync.Mutex + mu sync.RWMutex // name is the application name and the log prefix for // that Application instance's Logger. See `SetName` and `String`. // Defaults to IRIS_APP_NAME envrinoment variable otherwise empty. @@ -517,10 +517,38 @@ func (l *customHostServerLogger) Write(p []byte) (int, error) { return l.parent.Write(p) } +// this may change during parallel jobs (see Application.NonBlocking & Wait). +func (app *Application) getVHost() string { + app.mu.RLock() + vhost := app.config.VHost + app.mu.RUnlock() + return vhost +} + +func (app *Application) setVHost(vhost string) { + app.mu.Lock() + app.config.VHost = vhost + app.mu.Unlock() +} + // NewHost accepts a standard *http.Server object, // completes the necessary missing parts of that "srv" // and returns a new, ready-to-use, host (supervisor). func (app *Application) NewHost(srv *http.Server) *host.Supervisor { + if app.getVHost() == "" { // vhost now is useful for router subdomain on wildcard subdomains, + // in order to correct decide what to do on: + // mydomain.com -> invalid + // localhost -> invalid + // sub.mydomain.com -> valid + // sub.localhost -> valid + // we need the host (without port if 80 or 443) in order to validate these, so: + app.setVHost(netutil.ResolveVHost(srv.Addr)) + } else { + context.GetDomain = func(_ string) string { // #1886 + return app.config.VHost // GetVHost: here we don't need mutex protection as it's request-time and all modifications are already made. + } + } // before lock. + app.mu.Lock() defer app.mu.Unlock() @@ -551,21 +579,6 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor { // create the new host supervisor // bind the constructed server and return it su := host.New(srv) - - if app.config.GetVHost() == "" { // vhost now is useful for router subdomain on wildcard subdomains, - // in order to correct decide what to do on: - // mydomain.com -> invalid - // localhost -> invalid - // sub.mydomain.com -> valid - // sub.localhost -> valid - // we need the host (without port if 80 or 443) in order to validate these, so: - app.config.SetVHost(netutil.ResolveVHost(srv.Addr)) - } else { - context.GetDomain = func(_ string) string { // #1886 - return app.config.VHost // GetVHost: here we don't need mutex protection as it's request-time and all modifications are already made. - } - } - // app.logger.Debugf("Host: virtual host is %s", app.config.VHost) // the below schedules some tasks that will run among the server @@ -1142,7 +1155,7 @@ func (app *Application) tryConnect(ctx stdContext.Context, maxRetries int, retry // Context is canceled, return the context error. return ctx.Err() default: - address := app.config.GetVHost() // Get this server's listening address. + address := app.getVHost() // Get this server's listening address. if address == "" { i-- // Note that this may be modified at another go routine of the serve method. So it may be empty at first chance. So retry fetching the VHost every 1 second. time.Sleep(time.Second) @@ -1200,7 +1213,7 @@ func (app *Application) tryStartTunneling() { publicAddr := publicAddrs[0] // to make subdomains resolution still based on this new remote, public addresses. - app.config.SetVHost(publicAddr[strings.Index(publicAddr, "://")+3:]) + app.setVHost(publicAddr[strings.Index(publicAddr, "://")+3:]) directLog := []byte(fmt.Sprintf("• Public Address: %s\n", publicAddr)) app.logger.Printer.Write(directLog) // nolint:errcheck