mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
Merge pull request #10 from kataras/master
Update Former-commit-id: 6c5ffc3c8f7a44929db41a7a7457a77cd1029f2d
This commit is contained in:
commit
06f75795bb
|
@ -3,7 +3,8 @@ os:
|
|||
- linux
|
||||
- osx
|
||||
go:
|
||||
- go1.9
|
||||
- "go1.9"
|
||||
- "go1.10"
|
||||
go_import_path: github.com/kataras/iris
|
||||
install:
|
||||
- go get ./... # for iris-contrib/httpexpect, kataras/golog
|
||||
|
|
10
Gopkg.lock
generated
10
Gopkg.lock
generated
|
@ -107,7 +107,7 @@
|
|||
branch = "master"
|
||||
name = "github.com/kataras/golog"
|
||||
packages = ["."]
|
||||
revision = "2ed680e7b1f34147164fa8073373e14fce02ac30"
|
||||
revision = "dd676348ce75fa471fbbcd1bbbd131d00179756a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -115,12 +115,6 @@
|
|||
packages = [".","terminal"]
|
||||
revision = "825e39f34365e7db2c9fbc3692c16220e3bd7418"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kataras/survey"
|
||||
packages = ["."]
|
||||
revision = "20e139a6d2469769ae88e0a3579ba5df71839ca7"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/klauspost/compress"
|
||||
packages = ["flate","gzip"]
|
||||
|
@ -251,7 +245,7 @@
|
|||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "2d6f6f883a06fc0d5f4b14a81e4c28705ea64c15"
|
||||
revision = "c28acc882ebcbfbe8ce9f0f14b9ac26ee138dd51"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
|
@ -42,10 +42,6 @@
|
|||
branch = "master"
|
||||
name = "github.com/kataras/golog"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/kataras/survey"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/klauspost/compress"
|
||||
version = "1.2.1"
|
||||
|
|
38
HISTORY.md
38
HISTORY.md
|
@ -17,6 +17,44 @@ 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 -u github.com/kataras/iris` or let the automatic updater do that for you.
|
||||
|
||||
# Sa, 10 March 2018 | v10.3.0
|
||||
|
||||
- The only one API Change is the [Application/Context/Router#RouteExists](https://godoc.org/github.com/kataras/iris/core/router#Router.RouteExists), it accepts the `Context` as its first argument instead of last now.
|
||||
|
||||
- Fix cors middleware via https://github.com/iris-contrib/middleware/commit/048e2be034ed172c6754448b8a54a9c55debad46, relative issue: https://github.com/kataras/iris/issues/922 (still pending for a verification).
|
||||
|
||||
- Add `Context#NextOr` and `Context#NextOrNotFound`
|
||||
|
||||
```go
|
||||
// NextOr checks if chain has a next handler, if so then it executes it
|
||||
// otherwise it sets a new chain assigned to this Context based on the given handler(s)
|
||||
// and executes its first handler.
|
||||
//
|
||||
// Returns true if next handler exists and executed, otherwise false.
|
||||
//
|
||||
// Note that if no next handler found and handlers are missing then
|
||||
// it sends a Status Not Found (404) to the client and it stops the execution.
|
||||
NextOr(handlers ...Handler) bool
|
||||
// NextOrNotFound checks if chain has a next handler, if so then it executes it
|
||||
// otherwise it sends a Status Not Found (404) to the client and stops the execution.
|
||||
//
|
||||
// Returns true if next handler exists and executed, otherwise false.
|
||||
NextOrNotFound() bool
|
||||
```
|
||||
|
||||
- Add a new `Party#AllowMethods` which if called before any `Handle, Get, Post...` will clone the routes to that methods as well.
|
||||
|
||||
- Fix trailing slash from POST method request redirection as reported at: https://github.com/kataras/iris/issues/921 via https://github.com/kataras/iris/commit/dc589d9135295b4d080a9a91e942aacbfe5d56c5
|
||||
|
||||
- Add examples for read using custom decoder per type, read using custom decoder via `iris#UnmarshalerFunc` and to complete it add an example for the `context#ReadXML`, you can find them [here](https://github.com/kataras/iris/tree/master/_examples#how-to-read-from-contextrequest-httprequest)via https://github.com/kataras/iris/commit/78cd8e5f677fe3ff2c863c5bea7d1c161bf4c31e.
|
||||
|
||||
- Add one more example for custom router macro functions, relative to https://github.com/kataras/iris/issues/918, you can find it [there](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L144-L158), via https://github.com/kataras/iris/commit/a7690c71927cbf3aa876592fab94f04cada91b72
|
||||
|
||||
- Add wrappers for `Pongo`'s `AsValue()` and `AsSaveValue()` by @neenar via PR: https://github.com/kataras/iris/pull/913
|
||||
|
||||
- Remove unnecessary reflection usage on `context#UnmarshalBody` via https://github.com/kataras/iris/commit/4b9e41458b62035ea4933789c0a132c3ef2a90cc
|
||||
|
||||
|
||||
# Th, 15 February 2018 | v10.2.1
|
||||
|
||||
Fix subdomains' `StaticEmbedded` & `StaticWeb` not found errors, as reported by [@speedwheel](https://github.com/speedwheel) via [facebook page's chat](https://facebook.com/iris.framework).
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get -u github.com/kataras/iris` ή αφήστε το αυτόματο updater να το κάνει αυτό για σας.
|
||||
|
||||
# Sa, 10 March 2018 | v10.3.0
|
||||
|
||||
This history entry is not translated yet to the Greek language yet, please refer to the original [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#sa-10-march-2018--v1030) instead.
|
||||
|
||||
# Th, 15 February 2018 | v10.2.1
|
||||
|
||||
Διόρθωση το οποίο αφορά 404 not found errors στα αρχεία που σερβίρονται από τα `StaticEmbedded` και `StaticWeb` των υποτομεών(subdomains), όπως αναφέρθηκε πριν λίγο από τον [@speedwheel](https://github.com/speedwheel) μέσω [της σελίδας μας στο facebook](https://facebook.com/iris.framework).
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
**如何升级**: 打开命令行执行以下命令: `go get -u github.com/kataras/iris` 或者等待自动更新。
|
||||
|
||||
# Sa, 10 March 2018 | v10.3.0
|
||||
|
||||
This history entry is not translated yet to the Chinese language yet, please refer to the original [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#sa-10-march-2018--v1030) instead.
|
||||
|
||||
# 2018 2月15号 | v10.2.1 版本更新
|
||||
|
||||
修正 子域名 (subdomain) 的 `StaticEmbedded` 和 `StaticWeb` 不存在错误, 由 [@speedwheel](https://github.com/speedwheel) 通过 [facebook page's chat](https://facebook.com/iris.framework) 反馈。
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.2-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.3-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
|
||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||
|
||||
|
@ -106,7 +106,7 @@ _Updated at: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
|
|||
|
||||
## Support
|
||||
|
||||
- [HISTORY](HISTORY.md#th-15-february-2018--v1021) file is your best friend, it contains information about the latest features and changes
|
||||
- [HISTORY](HISTORY.md#sa-10-march-2018--v1030) file is your best friend, it contains information about the latest features and changes
|
||||
- Did you happen to find a bug? Post it at [github issues](https://github.com/kataras/iris/issues)
|
||||
- Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the [community chat](https://chat.iris-go.com)
|
||||
- Complete our form-based user experience report by clicking [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||
|
@ -195,7 +195,7 @@ First of all, the most correct way to begin with a web framework is to learn the
|
|||
|
||||
Iris has a great collection of handlers[[1]](middleware/)[[2]](https://github.com/iris-contrib/middleware) that you can use side by side with your web apps. However you are not limited to them - you are free to use any third-party middleware that is compatible with the [net/http](https://golang.org/pkg/net/http/) package, [_examples/convert-handlers](_examples/convert-handlers) will show you the way.
|
||||
|
||||
Iris, unlike others, is 100% compatible with the standards and that's why the majority of the big companies that adapt Go to their workflow, like a very famous US Television Network, trust Iris; it's always up-to-date and it will be aligned with the std `net/http` package which is modernized by the Go Author on each new release of the Go Programming Language forever.
|
||||
Iris, unlike others, is 100% compatible with the standards and that's why the majority of the big companies that adapt Go to their workflow, like a very famous US Television Network, trust Iris; it's up-to-date and it will be always aligned with the std `net/http` package which is modernized by the Go Authors on each new release of the Go Programming Language.
|
||||
|
||||
### Articles
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.2-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.3-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
|
||||
Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go.
|
||||
|
||||
|
@ -108,7 +108,7 @@ _Η τελευταία ενημέρωση έγινε την [Τρίτη, 21 Νο
|
|||
|
||||
## Υποστήριξη
|
||||
|
||||
- To [HISTORY](HISTORY_GR.md#th-15-february-2018--v1021) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές
|
||||
- To [HISTORY](HISTORY_GR.md#sa-10-march-2018--v1030) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές
|
||||
- Μήπως τυχαίνει να βρήκατε κάποιο bug; Δημοσιεύστε το στα [github issues](https://github.com/kataras/iris/issues)
|
||||
- Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com)
|
||||
- Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.2-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.3-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
|
||||
Iris - это быстрая, простая, но полнофункциональная и очень эффективная веб-платформа для Go.
|
||||
|
||||
|
@ -106,7 +106,7 @@ _Обновлено: [Вторник, 21 ноября 2017 г.](_benchmarks/READ
|
|||
|
||||
## Поддержка
|
||||
|
||||
- Файл [HISTORY](HISTORY.md#th-15-february-2018--v1021) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях
|
||||
- Файл [HISTORY](HISTORY.md#sa-10-march-2018--v1030) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях
|
||||
- Вы случайно обнаружили ошибку? Опубликуйте ее на [Github вопросы](https://github.com/kataras/iris/issues)
|
||||
- У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com)
|
||||
- Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.2-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris)<!-- [![release](https://img.shields.io/github/release/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/releases)--> [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![vscode-iris](https://img.shields.io/badge/ext%20-vscode-0c77e3.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[![github closed issues](https://img.shields.io/github/issues-closed-raw/kataras/iris.svg?style=flat-square)](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=flat-square)](https://iris-go.com/v10/recipe) [![release](https://img.shields.io/badge/release%20-v10.3-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases)
|
||||
|
||||
Iris 是一款超快、简洁高效的 Go 语言 Web开发框架。
|
||||
|
||||
|
@ -102,7 +102,7 @@ _更新于: [2017年11月21日星期二](_benchmarks/README_UNIX.md)_
|
|||
|
||||
## 支持
|
||||
|
||||
- [更新记录](HISTORY_ZH.md#th-15-february-2018--v1021) 是您最好的朋友,它包含有关最新功能和更改的信息
|
||||
- [更新记录](HISTORY_ZH.md#sa-10-march-2018--v1030) 是您最好的朋友,它包含有关最新功能和更改的信息
|
||||
- 你碰巧找到了一个错误? 请提交 [github issues](https://github.com/kataras/iris/issues)
|
||||
- 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com)
|
||||
- [点击这里完成我们基于表单的用户体验报告](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
10.2.1:https://github.com/kataras/iris/blob/master/HISTORY.md#th-15-february-2018--v1021
|
||||
10.3.0:https://github.com/kataras/iris/blob/master/HISTORY.md#sa-10-march-2018--v1030
|
|
@ -318,8 +318,11 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
|
|||
|
||||
### How to Read from `context.Request() *http.Request`
|
||||
|
||||
- [Bind JSON](http_request/read-json/main.go)
|
||||
- [Bind Form](http_request/read-form/main.go)
|
||||
- [Read JSON](http_request/read-json/main.go)
|
||||
- [Read XML](http_request/read-xml/main.go)
|
||||
- [Read Form](http_request/read-form/main.go)
|
||||
- [Read Custom per type](http_request/read-custom-per-type/main.go)
|
||||
- [Read Custom via Unmarshaler](http_request/read-custom-via-unmarshaler/main.go)
|
||||
- [Upload/Read File](http_request/upload-file/main.go)
|
||||
- [Upload multiple files with an easy way](http_request/upload-files/main.go)
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
// $ go get github.com/rs/cors
|
||||
// $ go run main.go
|
||||
// go get -u github.com/iris-contrib/middleware/...
|
||||
|
||||
import (
|
||||
"github.com/kataras/iris"
|
||||
|
@ -10,15 +9,14 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
|
||||
app := iris.New()
|
||||
|
||||
crs := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts.
|
||||
AllowCredentials: true,
|
||||
})
|
||||
|
||||
v1 := app.Party("/api/v1")
|
||||
v1.Use(crs)
|
||||
v1 := app.Party("/api/v1", crs).AllowMethods(iris.MethodOptions) // <- important for the preflight.
|
||||
{
|
||||
v1.Get("/home", func(ctx iris.Context) {
|
||||
ctx.WriteString("Hello from /home")
|
||||
|
@ -29,15 +27,13 @@ func main() {
|
|||
v1.Post("/send", func(ctx iris.Context) {
|
||||
ctx.WriteString("sent")
|
||||
})
|
||||
v1.Put("/send", func(ctx iris.Context) {
|
||||
ctx.WriteString("updated")
|
||||
})
|
||||
v1.Delete("/send", func(ctx iris.Context) {
|
||||
ctx.WriteString("deleted")
|
||||
})
|
||||
}
|
||||
|
||||
// or use that to wrap the entire router
|
||||
// even before the path and method matching
|
||||
// this should work better and with all cors' features.
|
||||
// Use that instead, if suits you.
|
||||
// app.WrapRouter(cors.WrapNext(cors.Options{
|
||||
// AllowedOrigins: []string{"*"},
|
||||
// AllowCredentials: true,
|
||||
// }))
|
||||
app.Run(iris.Addr("localhost:8080"))
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
// Follow these steps first:
|
||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
||||
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||
// $ go-bindata ./assets/...
|
||||
// $ go build
|
||||
// $ ./embedding-files-into-app
|
||||
|
|
|
@ -2,7 +2,7 @@ package main
|
|||
|
||||
import "github.com/kataras/iris"
|
||||
|
||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
||||
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||
// $ go-bindata ./public/...
|
||||
// $ go build
|
||||
// $ ./embedded-single-page-application-with-other-routes
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
||||
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||
// $ go-bindata ./public/...
|
||||
// $ go build
|
||||
// $ ./embedded-single-page-application
|
||||
|
|
65
_examples/http_request/read-custom-per-type/main.go
Normal file
65
_examples/http_request/read-custom-per-type/main.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
|
||||
// use Postman or whatever to do a POST request
|
||||
// (however you are always free to use app.Get and GET http method requests to read body of course)
|
||||
// to the http://localhost:8080 with RAW BODY:
|
||||
/*
|
||||
addr: localhost:8080
|
||||
serverName: Iris
|
||||
*/
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Post("/", handler)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// simple yaml stuff, read more at https://github.com/go-yaml/yaml
|
||||
type config struct {
|
||||
Addr string `yaml:"addr"`
|
||||
ServerName string `yaml:"serverName"`
|
||||
}
|
||||
|
||||
// Decode implements the `kataras/iris/context#BodyDecoder` optional interface
|
||||
// that any go type can implement in order to be self-decoded when reading the request's body.
|
||||
func (c *config) Decode(body []byte) error {
|
||||
return yaml.Unmarshal(body, c)
|
||||
}
|
||||
|
||||
func handler(ctx iris.Context) {
|
||||
var c config
|
||||
|
||||
//
|
||||
// Note:
|
||||
// second parameter is nil because our &c implements the `context#BodyDecoder`
|
||||
// which has a priority over the context#Unmarshaler (which can be a more global option for reading request's body)
|
||||
// see the `http_request/read-custom-via-unmarshaler/main.go` example to learn how to use the context#Unmarshaler too.
|
||||
//
|
||||
// Note 2:
|
||||
// If you need to read the body again for any reason
|
||||
// you should disable the body consumption via `app.Run(..., iris.WithoutBodyConsumptionOnUnmarshal)`.
|
||||
//
|
||||
|
||||
if err := ctx.UnmarshalBody(&c, nil); err != nil {
|
||||
ctx.StatusCode(iris.StatusBadRequest)
|
||||
ctx.WriteString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Writef("Received: %#+v", c)
|
||||
}
|
17
_examples/http_request/read-custom-per-type/main_test.go
Normal file
17
_examples/http_request/read-custom-per-type/main_test.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/httptest"
|
||||
)
|
||||
|
||||
func TestReadCustomPerType(t *testing.T) {
|
||||
app := newApp()
|
||||
e := httptest.New(t, app)
|
||||
|
||||
expectedResponse := `Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}`
|
||||
|
||||
e.POST("/").WithText("addr: localhost:8080\nserverName: Iris").Expect().
|
||||
Status(httptest.StatusOK).Body().Equal(expectedResponse)
|
||||
}
|
73
_examples/http_request/read-custom-via-unmarshaler/main.go
Normal file
73
_examples/http_request/read-custom-via-unmarshaler/main.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
|
||||
// use Postman or whatever to do a POST request
|
||||
// (however you are always free to use app.Get and GET http method requests to read body of course)
|
||||
// to the http://localhost:8080 with RAW BODY:
|
||||
/*
|
||||
addr: localhost:8080
|
||||
serverName: Iris
|
||||
*/
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Post("/", handler)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// simple yaml stuff, read more at https://github.com/go-yaml/yaml
|
||||
type config struct {
|
||||
Addr string `yaml:"addr"`
|
||||
ServerName string `yaml:"serverName"`
|
||||
}
|
||||
|
||||
/*
|
||||
type myBodyDecoder struct{}
|
||||
|
||||
var DefaultBodyDecoder = myBodyDecoder{}
|
||||
|
||||
// Implements the `kataras/iris/context#Unmarshaler` but at our example
|
||||
// we will use the simplest `context#UnmarshalerFunc` to pass just the yaml.Unmarshal.
|
||||
//
|
||||
// Can be used as: ctx.UnmarshalBody(&c, DefaultBodyDecoder)
|
||||
func (r *myBodyDecoder) Unmarshal(data []byte, outPtr interface{}) error {
|
||||
return yaml.Unmarshal(data, outPtr)
|
||||
}
|
||||
*/
|
||||
|
||||
func handler(ctx iris.Context) {
|
||||
var c config
|
||||
|
||||
//
|
||||
// Note:
|
||||
// yaml.Unmarshal already implements the `context#Unmarshaler`
|
||||
// so we can use it directly, like the json.Unmarshal(ctx.ReadJSON), xml.Unmarshal(ctx.ReadXML)
|
||||
// and every library which follows the best practises and is aligned with the Go standards.
|
||||
//
|
||||
// Note 2:
|
||||
// If you need to read the body again for any reason
|
||||
// you should disable the body consumption via `app.Run(..., iris.WithoutBodyConsumptionOnUnmarshal)`.
|
||||
//
|
||||
|
||||
if err := ctx.UnmarshalBody(&c, iris.UnmarshalerFunc(yaml.Unmarshal)); err != nil {
|
||||
ctx.StatusCode(iris.StatusBadRequest)
|
||||
ctx.WriteString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Writef("Received: %#+v", c)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/httptest"
|
||||
)
|
||||
|
||||
func TestReadCustomViaUnmarshaler(t *testing.T) {
|
||||
app := newApp()
|
||||
e := httptest.New(t, app)
|
||||
|
||||
expectedResponse := `Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}`
|
||||
|
||||
e.POST("/").WithText("addr: localhost:8080\nserverName: Iris").Expect().
|
||||
Status(httptest.StatusOK).Body().Equal(expectedResponse)
|
||||
}
|
|
@ -11,16 +11,18 @@ type Company struct {
|
|||
}
|
||||
|
||||
func MyHandler(ctx iris.Context) {
|
||||
c := &Company{}
|
||||
if err := ctx.ReadJSON(c); err != nil {
|
||||
var c Company
|
||||
|
||||
if err := ctx.ReadJSON(&c); err != nil {
|
||||
ctx.StatusCode(iris.StatusBadRequest)
|
||||
ctx.WriteString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Writef("Received: %#v\n", c)
|
||||
ctx.Writef("Received: %#+v\n", c)
|
||||
}
|
||||
|
||||
// simple json stuff, read more at https://golang.org/pkg/encoding/json
|
||||
type Person struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
|
@ -55,9 +57,9 @@ func main() {
|
|||
"Other": "Something here"
|
||||
}
|
||||
*/
|
||||
// and Content-Type to application/json
|
||||
// and Content-Type to application/json (optionally but good practise)
|
||||
//
|
||||
// The response should be:
|
||||
// Received: &main.Company{Name:"iris-Go", City:"New York", Other:"Something here"}
|
||||
app.Run(iris.Addr(":8080"))
|
||||
// Received: main.Company{Name:"iris-Go", City:"New York", Other:"Something here"}
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
}
|
||||
|
|
50
_examples/http_request/read-xml/main.go
Normal file
50
_examples/http_request/read-xml/main.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
|
||||
// use Postman or whatever to do a POST request
|
||||
// to the http://localhost:8080 with RAW BODY:
|
||||
/*
|
||||
<person name="Winston Churchill" age="90">
|
||||
<description>Description of this person, the body of this inner element.</description>
|
||||
</person>
|
||||
*/
|
||||
// and Content-Type to application/xml (optionally but good practise)
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."}
|
||||
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Post("/", handler)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// simple xml stuff, read more at https://golang.org/pkg/encoding/xml
|
||||
type person struct {
|
||||
XMLName xml.Name `xml:"person"` // element name
|
||||
Name string `xml:"name,attr"` // ,attr for attribute.
|
||||
Age int `xml:"age,attr"` // ,attr attribute.
|
||||
Description string `xml:"description"` // inner element name, value is its body.
|
||||
}
|
||||
|
||||
func handler(ctx iris.Context) {
|
||||
var p person
|
||||
if err := ctx.ReadXML(&p); err != nil {
|
||||
ctx.StatusCode(iris.StatusBadRequest)
|
||||
ctx.WriteString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Writef("Received: %#+v", p)
|
||||
}
|
18
_examples/http_request/read-xml/main_test.go
Normal file
18
_examples/http_request/read-xml/main_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/httptest"
|
||||
)
|
||||
|
||||
func TestReadXML(t *testing.T) {
|
||||
app := newApp()
|
||||
e := httptest.New(t, app)
|
||||
|
||||
expectedResponse := `Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."}`
|
||||
send := `<person name="Winston Churchill" age="90"><description>Description of this person, the body of this inner element.</description></person>`
|
||||
|
||||
e.POST("/").WithText(send).Expect().
|
||||
Status(httptest.StatusOK).Body().Equal(expectedResponse)
|
||||
}
|
|
@ -2,7 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
|
||||
"github.com/kataras/iris/_examples/http_responsewriter/herotemplate/template"
|
||||
|
||||
|
@ -13,11 +12,15 @@ import (
|
|||
// $ go run app.go
|
||||
//
|
||||
// Read more at https://github.com/shiyanhui/hero/hero
|
||||
|
||||
func main() {
|
||||
|
||||
app := iris.New()
|
||||
|
||||
app.Get("/users", func(ctx iris.Context) {
|
||||
ctx.Gzip(true)
|
||||
ctx.ContentType("text/html")
|
||||
|
||||
var userList = []string{
|
||||
"Alice",
|
||||
"Bob",
|
||||
|
@ -25,30 +28,27 @@ func main() {
|
|||
}
|
||||
|
||||
// Had better use buffer sync.Pool.
|
||||
// Hero exports GetBuffer and PutBuffer for this.
|
||||
// Hero(github.com/shiyanhui/hero/hero) exports GetBuffer and PutBuffer for this.
|
||||
//
|
||||
// buffer := hero.GetBuffer()
|
||||
// defer hero.PutBuffer(buffer)
|
||||
buffer := new(bytes.Buffer)
|
||||
template.UserList(userList, buffer)
|
||||
|
||||
if _, err := ctx.Write(buffer.Bytes()); err != nil {
|
||||
log.Printf("ERR: %s\n", err)
|
||||
}
|
||||
})
|
||||
|
||||
app.Get("/users2", func(ctx iris.Context) {
|
||||
var userList = []string{
|
||||
"Alice",
|
||||
"Bob",
|
||||
"Tom",
|
||||
}
|
||||
// buffer := new(bytes.Buffer)
|
||||
// template.UserList(userList, buffer)
|
||||
// ctx.Write(buffer.Bytes())
|
||||
|
||||
// using an io.Writer for automatic buffer management (i.e. hero built-in buffer pool),
|
||||
// iris context implements the io.Writer by its ResponseWriter
|
||||
// which is an enhanced version of the standard http.ResponseWriter
|
||||
// but still 100% compatible.
|
||||
template.UserListToWriter(userList, ctx)
|
||||
// but still 100% compatible, GzipResponseWriter too:
|
||||
// _, err := template.UserListToWriter(userList, ctx.GzipResponseWriter())
|
||||
buffer := new(bytes.Buffer)
|
||||
template.UserList(userList, buffer)
|
||||
|
||||
_, err := ctx.Write(buffer.Bytes())
|
||||
if err != nil {
|
||||
ctx.StatusCode(iris.StatusInternalServerError)
|
||||
ctx.WriteString(err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
app.Run(iris.Addr(":8080"))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
|
@ -140,6 +141,24 @@ func main() {
|
|||
ctx.Writef("Hello id: %d looking for friend id: ", id, friendid)
|
||||
}) // this will throw e 504 error code instead of 404 if all route's macros not passed.
|
||||
|
||||
// Another example using a custom regexp and any custom logic.
|
||||
latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$"
|
||||
latLonRegex, err := regexp.Compile(latLonExpr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.Macros().String.RegisterFunc("coordinate", func() func(paramName string) (ok bool) {
|
||||
// MatchString is a type of func(string) bool, so we can return that as it's.
|
||||
return latLonRegex.MatchString
|
||||
})
|
||||
|
||||
app.Get("/coordinates/{lat:string coordinate() else 502}/{lon:string coordinate() else 502}", func(ctx iris.Context) {
|
||||
ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon"))
|
||||
})
|
||||
|
||||
//
|
||||
|
||||
// http://localhost:8080/game/a-zA-Z/level/0-9
|
||||
// remember, alphabetical is lowercase or uppercase letters only.
|
||||
app.Get("/game/{name:alphabetical}/level/{level:int}", func(ctx iris.Context) {
|
||||
|
|
|
@ -8,7 +8,7 @@ func main() {
|
|||
app := iris.New()
|
||||
|
||||
none := app.None("/invisible/{username}", func(ctx iris.Context) {
|
||||
ctx.Writef("Hello %s with method: %s", ctx.Values().GetString("username"), ctx.Method())
|
||||
ctx.Writef("Hello %s with method: %s", ctx.Params().Get("username"), ctx.Method())
|
||||
|
||||
if from := ctx.Values().GetString("from"); from != "" {
|
||||
ctx.Writef("\nI see that you're coming from %s", from)
|
||||
|
|
|
@ -58,15 +58,11 @@ func (v *pageView) increment() {
|
|||
}
|
||||
|
||||
func (v *pageView) decrement() {
|
||||
oldCount := v.count
|
||||
if oldCount > 0 {
|
||||
atomic.StoreUint64(&v.count, oldCount-1)
|
||||
}
|
||||
atomic.AddUint64(&v.count, ^uint64(0))
|
||||
}
|
||||
|
||||
func (v *pageView) getCount() uint64 {
|
||||
val := atomic.LoadUint64(&v.count)
|
||||
return val
|
||||
return atomic.LoadUint64(&v.count)
|
||||
}
|
||||
|
||||
type (
|
||||
|
|
|
@ -13,7 +13,7 @@ func main() {
|
|||
return "Greetings " + s + "!"
|
||||
})
|
||||
|
||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
||||
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||
// $ go-bindata ./templates/...
|
||||
// $ go build
|
||||
// $ ./embedding-templates-into-app
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestConfigurationStatic(t *testing.T) {
|
|||
|
||||
afterNew = *app.config
|
||||
|
||||
if app.config.DisableBodyConsumptionOnUnmarshal == false {
|
||||
if !app.config.DisableBodyConsumptionOnUnmarshal {
|
||||
t.Fatalf("Passing a Configuration field as Option fails, expected DisableBodyConsumptionOnUnmarshal to be true but was false")
|
||||
}
|
||||
|
||||
|
|
|
@ -48,4 +48,8 @@ type Application interface {
|
|||
// If a handler is not already registered,
|
||||
// then it creates & registers a new trivial handler on the-fly.
|
||||
FireErrorCode(ctx Context)
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
RouteExists(ctx Context, method, path string) bool
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -49,20 +48,24 @@ type (
|
|||
//
|
||||
// Note: This is totally optionally, the default decoders
|
||||
// for ReadJSON is the encoding/json and for ReadXML is the encoding/xml.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-per-type/main.go
|
||||
BodyDecoder interface {
|
||||
Decode(data []byte) error
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by types that can unmarshal any raw data
|
||||
// TIP INFO: Any v object which implements the BodyDecoder can be override the unmarshaler.
|
||||
// Unmarshaler is the interface implemented by types that can unmarshal any raw data.
|
||||
// TIP INFO: Any pointer to a value which implements the BodyDecoder can be override the unmarshaler.
|
||||
Unmarshaler interface {
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
Unmarshal(data []byte, outPtr interface{}) error
|
||||
}
|
||||
|
||||
// UnmarshalerFunc a shortcut for the Unmarshaler interface
|
||||
//
|
||||
// See 'Unmarshaler' and 'BodyDecoder' for more.
|
||||
UnmarshalerFunc func(data []byte, v interface{}) error
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
|
||||
UnmarshalerFunc func(data []byte, outPtr interface{}) error
|
||||
)
|
||||
|
||||
// Unmarshal parses the X-encoded data and stores the result in the value pointed to by v.
|
||||
|
@ -310,7 +313,21 @@ type Context interface {
|
|||
//
|
||||
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
|
||||
Next()
|
||||
// NextHandler returns(but it is NOT executes) the next handler from the handlers chain.
|
||||
// NextOr checks if chain has a next handler, if so then it executes it
|
||||
// otherwise it sets a new chain assigned to this Context based on the given handler(s)
|
||||
// and executes its first handler.
|
||||
//
|
||||
// Returns true if next handler exists and executed, otherwise false.
|
||||
//
|
||||
// Note that if no next handler found and handlers are missing then
|
||||
// it sends a Status Not Found (404) to the client and it stops the execution.
|
||||
NextOr(handlers ...Handler) bool
|
||||
// NextOrNotFound checks if chain has a next handler, if so then it executes it
|
||||
// otherwise it sends a Status Not Found (404) to the client and stops the execution.
|
||||
//
|
||||
// Returns true if next handler exists and executed, otherwise false.
|
||||
NextOrNotFound() bool
|
||||
// NextHandler returns (it doesn't execute) the next handler from the handlers chain.
|
||||
//
|
||||
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||
NextHandler() Handler
|
||||
|
@ -550,6 +567,8 @@ type Context interface {
|
|||
//
|
||||
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-file
|
||||
FormFile(key string) (multipart.File, *multipart.FileHeader, error)
|
||||
// UploadFormFiles uploads any received file(s) from the client
|
||||
// to the system physical location "destDirectory".
|
||||
|
@ -574,6 +593,9 @@ type Context interface {
|
|||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
//
|
||||
// See `FormFile` to a more controlled to receive a file.
|
||||
//
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-files
|
||||
UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error)
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
|
@ -596,16 +618,24 @@ type Context interface {
|
|||
// should be called before reading the request body from the client.
|
||||
SetMaxRequestBodySize(limitOverBytes int64)
|
||||
|
||||
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type
|
||||
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type.
|
||||
// Examples of usage: context.ReadJSON, context.ReadXML.
|
||||
UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error
|
||||
// ReadJSON reads JSON from request's body and binds it to a value of any json-valid type.
|
||||
ReadJSON(jsonObject interface{}) error
|
||||
// ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
|
||||
ReadXML(xmlObject interface{}) error
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
|
||||
UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error
|
||||
// ReadJSON reads JSON from request's body and binds it to a pointer of a value of any json-valid type.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-json/main.go
|
||||
ReadJSON(jsonObjectPtr interface{}) error
|
||||
// ReadXML reads XML from request's body and binds it to a pointer of a value of any xml-valid type.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-xml/main.go
|
||||
ReadXML(xmlObjectPtr interface{}) error
|
||||
// ReadForm binds the formObject with the form data
|
||||
// it supports any kind of struct.
|
||||
ReadForm(formObject interface{}) error
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-form/main.go
|
||||
ReadForm(formObjectPtr interface{}) error
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Body (raw) Writers |
|
||||
|
@ -880,7 +910,7 @@ type Context interface {
|
|||
// TransactionsSkipped returns true if the transactions skipped or canceled at all.
|
||||
TransactionsSkipped() bool
|
||||
|
||||
// Exec calls the framewrok's ServeCtx
|
||||
// Exec calls the `context/Application#ServeCtx`
|
||||
// based on this context but with a changed method and path
|
||||
// like it was requested by the user, but it is not.
|
||||
//
|
||||
|
@ -903,7 +933,11 @@ type Context interface {
|
|||
// Context's Values and the Session are kept in order to be able to communicate via the result route.
|
||||
//
|
||||
// It's for extreme use cases, 99% of the times will never be useful for you.
|
||||
Exec(method string, path string)
|
||||
Exec(method, path string)
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
RouteExists(method, path string) bool
|
||||
|
||||
// Application returns the iris app instance which belongs to this context.
|
||||
// Worth to notice that this function returns an interface
|
||||
|
@ -1260,7 +1294,39 @@ func (ctx *context) Next() { // or context.Next(ctx)
|
|||
Next(ctx)
|
||||
}
|
||||
|
||||
// NextHandler returns, but it doesn't executes, the next handler from the handlers chain.
|
||||
// NextOr checks if chain has a next handler, if so then it executes it
|
||||
// otherwise it sets a new chain assigned to this Context based on the given handler(s)
|
||||
// and executes its first handler.
|
||||
//
|
||||
// Returns true if next handler exists and executed, otherwise false.
|
||||
//
|
||||
// Note that if no next handler found and handlers are missing then
|
||||
// it sends a Status Not Found (404) to the client and it stops the execution.
|
||||
func (ctx *context) NextOr(handlers ...Handler) bool {
|
||||
if next := ctx.NextHandler(); next != nil {
|
||||
next(ctx)
|
||||
ctx.Skip() // skip this handler from the chain.
|
||||
return true
|
||||
}
|
||||
|
||||
if len(handlers) == 0 {
|
||||
ctx.NotFound()
|
||||
ctx.StopExecution()
|
||||
return false
|
||||
}
|
||||
|
||||
ctx.Do(handlers)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// NextOrNotFound checks if chain has a next handler, if so then it executes it
|
||||
// otherwise it sends a Status Not Found (404) to the client and stops the execution.
|
||||
//
|
||||
// Returns true if next handler exists and executed, otherwise false.
|
||||
func (ctx *context) NextOrNotFound() bool { return ctx.NextOr() }
|
||||
|
||||
// NextHandler returns (it doesn't execute) the next handler from the handlers chain.
|
||||
//
|
||||
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||
func (ctx *context) NextHandler() Handler {
|
||||
|
@ -1884,6 +1950,8 @@ func (ctx *context) PostValues(name string) []string {
|
|||
//
|
||||
// The default form's memory maximum size is 32MB, it can be changed by the
|
||||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-file
|
||||
func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
|
||||
// we don't have access to see if the request is body stream
|
||||
// and then the ParseMultipartForm can be useless
|
||||
|
@ -1917,6 +1985,8 @@ func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader,
|
|||
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||
//
|
||||
// See `FormFile` to a more controlled to receive a file.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/http_request/upload-files
|
||||
func (ctx *context) UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error) {
|
||||
err = ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
|
||||
if err != nil {
|
||||
|
@ -2008,7 +2078,9 @@ func (ctx *context) SetMaxRequestBodySize(limitOverBytes int64) {
|
|||
|
||||
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type
|
||||
// Examples of usage: context.ReadJSON, context.ReadXML.
|
||||
func (ctx *context) UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error {
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
|
||||
func (ctx *context) UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error {
|
||||
if ctx.request.Body == nil {
|
||||
return errors.New("unmarshal: empty body")
|
||||
}
|
||||
|
@ -2028,18 +2100,19 @@ func (ctx *context) UnmarshalBody(v interface{}, unmarshaler Unmarshaler) error
|
|||
// in this case the v should be a pointer also,
|
||||
// but this is up to the user's custom Decode implementation*
|
||||
//
|
||||
// See 'BodyDecoder' for more
|
||||
if decoder, isDecoder := v.(BodyDecoder); isDecoder {
|
||||
// See 'BodyDecoder' for more.
|
||||
if decoder, isDecoder := outPtr.(BodyDecoder); isDecoder {
|
||||
return decoder.Decode(rawData)
|
||||
}
|
||||
|
||||
// check if v is already a pointer, if yes then pass as it's
|
||||
if reflect.TypeOf(v).Kind() == reflect.Ptr {
|
||||
return unmarshaler.Unmarshal(rawData, v)
|
||||
}
|
||||
// finally, if the v doesn't contains a self-body decoder and it's not a pointer
|
||||
// use the custom unmarshaler to bind the body
|
||||
return unmarshaler.Unmarshal(rawData, &v)
|
||||
// // check if v is already a pointer, if yes then pass as it's
|
||||
// if reflect.TypeOf(v).Kind() == reflect.Ptr {
|
||||
// return unmarshaler.Unmarshal(rawData, v)
|
||||
// } <- no need for that, ReadJSON is documented enough to receive a pointer,
|
||||
// we don't need to reduce the performance here by using the reflect.TypeOf method.
|
||||
|
||||
// f the v doesn't contains a self-body decoder use the custom unmarshaler to bind the body.
|
||||
return unmarshaler.Unmarshal(rawData, outPtr)
|
||||
}
|
||||
|
||||
func (ctx *context) shouldOptimize() bool {
|
||||
|
@ -2047,6 +2120,8 @@ func (ctx *context) shouldOptimize() bool {
|
|||
}
|
||||
|
||||
// ReadJSON reads JSON from request's body and binds it to a value of any json-valid type.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-json/main.go
|
||||
func (ctx *context) ReadJSON(jsonObject interface{}) error {
|
||||
var unmarshaler = json.Unmarshal
|
||||
if ctx.shouldOptimize() {
|
||||
|
@ -2056,6 +2131,8 @@ func (ctx *context) ReadJSON(jsonObject interface{}) error {
|
|||
}
|
||||
|
||||
// ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-xml/main.go
|
||||
func (ctx *context) ReadXML(xmlObject interface{}) error {
|
||||
return ctx.UnmarshalBody(xmlObject, UnmarshalerFunc(xml.Unmarshal))
|
||||
}
|
||||
|
@ -2066,6 +2143,8 @@ var (
|
|||
|
||||
// ReadForm binds the formObject with the form data
|
||||
// it supports any kind of struct.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-form/main.go
|
||||
func (ctx *context) ReadForm(formObject interface{}) error {
|
||||
values := ctx.FormValues()
|
||||
if values == nil {
|
||||
|
@ -3086,7 +3165,10 @@ func (ctx *context) TransactionsSkipped() bool {
|
|||
//
|
||||
// It's for extreme use cases, 99% of the times will never be useful for you.
|
||||
func (ctx *context) Exec(method string, path string) {
|
||||
if path != "" {
|
||||
if path == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if method == "" {
|
||||
method = "GET"
|
||||
}
|
||||
|
@ -3097,10 +3179,9 @@ func (ctx *context) Exec(method string, path string) {
|
|||
|
||||
// backup the request path information
|
||||
backupPath := ctx.Path()
|
||||
bakcupMethod := ctx.Method()
|
||||
backupMethod := ctx.Method()
|
||||
// don't backupValues := ctx.Values().ReadOnly()
|
||||
|
||||
// [sessions stays]
|
||||
// [values stays]
|
||||
// reset handlers
|
||||
ctx.SetHandlers(nil)
|
||||
|
@ -3110,6 +3191,8 @@ func (ctx *context) Exec(method string, path string) {
|
|||
req.RequestURI = path
|
||||
req.URL.Path = path
|
||||
req.Method = method
|
||||
req.Host = req.Host
|
||||
|
||||
// execute the route from the (internal) context router
|
||||
// this way we keep the sessions and the values
|
||||
ctx.Application().ServeHTTPC(ctx)
|
||||
|
@ -3120,14 +3203,19 @@ func (ctx *context) Exec(method string, path string) {
|
|||
// set the request back to its previous state
|
||||
req.RequestURI = backupPath
|
||||
req.URL.Path = backupPath
|
||||
req.Method = bakcupMethod
|
||||
req.Method = backupMethod
|
||||
|
||||
// don't fill the values in order to be able to communicate from and to.
|
||||
// // fill the values as they were before
|
||||
// backupValues.Visit(func(key string, value interface{}) {
|
||||
// ctx.Values().Set(key, value)
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
func (ctx *context) RouteExists(method, path string) bool {
|
||||
return ctx.Application().RouteExists(ctx, method, path)
|
||||
}
|
||||
|
||||
// Application returns the iris app instance which belongs to this context.
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
const (
|
||||
// Version is the string representation of the current local Iris Web Framework version.
|
||||
Version = "10.2.1"
|
||||
Version = "10.3.0"
|
||||
)
|
||||
|
||||
// CheckForUpdates checks for any available updates
|
||||
|
|
|
@ -180,7 +180,7 @@ func (e Entry) BoolDefault(def bool) (bool, error) {
|
|||
// respects the immutable.
|
||||
func (e Entry) Value() interface{} {
|
||||
if e.immutable {
|
||||
// take its value, no pointer even if setted with a rreference.
|
||||
// take its value, no pointer even if setted with a reference.
|
||||
vv := reflect.Indirect(reflect.ValueOf(e.ValueRaw))
|
||||
|
||||
// return copy of that slice
|
||||
|
|
|
@ -42,6 +42,12 @@ type repository struct {
|
|||
}
|
||||
|
||||
func (r *repository) register(route *Route) {
|
||||
for _, r := range r.routes {
|
||||
if r.String() == route.String() {
|
||||
return // do not register any duplicates, the sooner the better.
|
||||
}
|
||||
}
|
||||
|
||||
r.routes = append(r.routes, route)
|
||||
}
|
||||
|
||||
|
@ -92,10 +98,15 @@ type APIBuilder struct {
|
|||
doneGlobalHandlers context.Handlers
|
||||
// the per-party
|
||||
relativePath string
|
||||
// allowMethods are filled with the `AllowMethods` func.
|
||||
// They are used to create new routes
|
||||
// per any party's (and its children) routes registered
|
||||
// if the method "x" wasn't registered already via the `Handle` (and its extensions like `Get`, `Post`...).
|
||||
allowMethods []string
|
||||
}
|
||||
|
||||
var _ Party = &APIBuilder{}
|
||||
var _ RoutesProvider = &APIBuilder{} // passed to the default request handler (routerHandler)
|
||||
var _ Party = (*APIBuilder)(nil)
|
||||
var _ RoutesProvider = (*APIBuilder)(nil) // passed to the default request handler (routerHandler)
|
||||
|
||||
// NewAPIBuilder creates & returns a new builder
|
||||
// which is responsible to build the API and the router handler.
|
||||
|
@ -129,6 +140,16 @@ func (api *APIBuilder) GetReporter() *errors.Reporter {
|
|||
return api.reporter
|
||||
}
|
||||
|
||||
// AllowMethods will re-register the future routes that will be registered
|
||||
// via `Handle`, `Get`, `Post`, ... to the given "methods" on that Party and its children "Parties",
|
||||
// duplicates are not registered.
|
||||
//
|
||||
// Call of `AllowMethod` will override any previous allow methods.
|
||||
func (api *APIBuilder) AllowMethods(methods ...string) Party {
|
||||
api.allowMethods = methods
|
||||
return api
|
||||
}
|
||||
|
||||
// Handle registers a route to the server's api.
|
||||
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
|
||||
//
|
||||
|
@ -170,23 +191,30 @@ func (api *APIBuilder) Handle(method string, relativePath string, handlers ...co
|
|||
// here we separate the subdomain and relative path
|
||||
subdomain, path := splitSubdomainAndPath(fullpath)
|
||||
|
||||
r, err := NewRoute(method, subdomain, path, possibleMainHandlerName, routeHandlers, api.macros)
|
||||
// if allowMethods are empty, then simply register with the passed, main, method.
|
||||
methods := append(api.allowMethods, method)
|
||||
|
||||
var (
|
||||
route *Route // the latest one is this route registered, see methods append.
|
||||
err error // not used outside of loop scope.
|
||||
)
|
||||
|
||||
for _, m := range methods {
|
||||
route, err = NewRoute(m, subdomain, path, possibleMainHandlerName, routeHandlers, api.macros)
|
||||
if err != nil { // template path parser errors:
|
||||
api.reporter.Add("%v -> %s:%s:%s", err, method, subdomain, path)
|
||||
return nil
|
||||
return nil // fail on first error.
|
||||
}
|
||||
|
||||
// Add UseGlobal & DoneGlobal Handlers
|
||||
r.use(api.beginGlobalHandlers)
|
||||
r.done(api.doneGlobalHandlers)
|
||||
route.use(api.beginGlobalHandlers)
|
||||
route.done(api.doneGlobalHandlers)
|
||||
|
||||
// global
|
||||
api.routes.register(r)
|
||||
api.routes.register(route)
|
||||
}
|
||||
|
||||
// per -party, used for done handlers
|
||||
// api.apiRoutes = append(api.apiRoutes, r)
|
||||
|
||||
return r
|
||||
return route
|
||||
}
|
||||
|
||||
// HandleMany works like `Handle` but can receive more than one
|
||||
|
@ -259,6 +287,10 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
|||
// append the parent's + child's handlers
|
||||
middleware := joinHandlers(api.middleware, handlers)
|
||||
|
||||
// the allow methods per party and its children.
|
||||
allowMethods := make([]string, len(api.allowMethods))
|
||||
copy(allowMethods, api.allowMethods)
|
||||
|
||||
return &APIBuilder{
|
||||
// global/api builder
|
||||
macros: api.macros,
|
||||
|
@ -269,8 +301,9 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
|||
reporter: api.reporter,
|
||||
// per-party/children
|
||||
middleware: middleware,
|
||||
doneHandlers: api.doneHandlers,
|
||||
doneHandlers: api.doneHandlers[0:],
|
||||
relativePath: fullpath,
|
||||
allowMethods: allowMethods,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ type RequestHandler interface {
|
|||
HandleRequest(context.Context)
|
||||
// Build should builds the handler, it's being called on router's BuildRouter.
|
||||
Build(provider RoutesProvider) error
|
||||
// RouteExists reports whether a particular route exists.
|
||||
RouteExists(ctx context.Context, method, path string) bool
|
||||
}
|
||||
|
||||
type tree struct {
|
||||
|
@ -160,6 +162,14 @@ func (h *routerHandler) HandleRequest(ctx context.Context) {
|
|||
r.URL.Path = path
|
||||
url := r.URL.String()
|
||||
|
||||
// Fixes https://github.com/kataras/iris/issues/921
|
||||
// This is caused for security reasons, imagine a payment shop,
|
||||
// you can't just permantly redirect a POST request, so just 307 (RFC 7231, 6.4.7).
|
||||
if method == http.MethodPost || method == http.MethodPut {
|
||||
ctx.Redirect(url, http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(url, http.StatusMovedPermanently)
|
||||
|
||||
// RFC2616 recommends that a short note "SHOULD" be included in the
|
||||
|
@ -244,3 +254,57 @@ func (h *routerHandler) HandleRequest(ctx context.Context) {
|
|||
|
||||
ctx.StatusCode(http.StatusNotFound)
|
||||
}
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
func (h *routerHandler) RouteExists(ctx context.Context, method, path string) bool {
|
||||
for i := range h.trees {
|
||||
t := h.trees[i]
|
||||
if method != t.Method {
|
||||
continue
|
||||
}
|
||||
|
||||
if h.hosts && t.Subdomain != "" {
|
||||
requestHost := ctx.Host()
|
||||
if netutil.IsLoopbackSubdomain(requestHost) {
|
||||
// this fixes a bug when listening on
|
||||
// 127.0.0.1:8080 for example
|
||||
// and have a wildcard subdomain and a route registered to root domain.
|
||||
continue // it's not a subdomain, it's something like 127.0.0.1 probably
|
||||
}
|
||||
// it's a dynamic wildcard subdomain, we have just to check if ctx.subdomain is not empty
|
||||
if t.Subdomain == SubdomainWildcardIndicator {
|
||||
// mydomain.com -> invalid
|
||||
// localhost -> invalid
|
||||
// sub.mydomain.com -> valid
|
||||
// sub.localhost -> valid
|
||||
serverHost := ctx.Application().ConfigurationReadOnly().GetVHost()
|
||||
if serverHost == requestHost {
|
||||
continue // it's not a subdomain, it's a full domain (with .com...)
|
||||
}
|
||||
|
||||
dotIdx := strings.IndexByte(requestHost, '.')
|
||||
slashIdx := strings.IndexByte(requestHost, '/')
|
||||
if dotIdx > 0 && (slashIdx == -1 || slashIdx > dotIdx) {
|
||||
// if "." was found anywhere but not at the first path segment (host).
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
// continue to that, any subdomain is valid.
|
||||
} else if !strings.HasPrefix(requestHost, t.Subdomain) { // t.Subdomain contains the dot.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
_, handlers := t.Nodes.Find(path, ctx.Params())
|
||||
if len(handlers) > 0 {
|
||||
// found
|
||||
return true
|
||||
}
|
||||
|
||||
// not found or method not allowed.
|
||||
break
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -6,9 +6,6 @@ import (
|
|||
"github.com/kataras/iris/core/router/macro"
|
||||
)
|
||||
|
||||
// Party is here to separate the concept of
|
||||
// api builder and the sub api builder.
|
||||
|
||||
// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
|
||||
// Party could also be named as 'Join' or 'Node' or 'Group' , Party chosen because it is fun.
|
||||
//
|
||||
|
@ -68,6 +65,14 @@ type Party interface {
|
|||
//
|
||||
// Returns this Party.
|
||||
Reset() Party
|
||||
|
||||
// AllowMethods will re-register the future routes that will be registered
|
||||
// via `Handle`, `Get`, `Post`, ... to the given "methods" on that Party and its children "Parties",
|
||||
// duplicates are not registered.
|
||||
//
|
||||
// Call of `AllowMethod` will override any previous allow methods.
|
||||
AllowMethods(methods ...string) Party
|
||||
|
||||
// Handle registers a route to the server's router.
|
||||
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
|
||||
//
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/kataras/iris/core/netutil"
|
||||
"github.com/kataras/iris/core/router/macro/interpreter/lexer"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -73,30 +74,91 @@ func joinPath(path1 string, path2 string) string {
|
|||
// iteratively until no further processing can be done:
|
||||
//
|
||||
// 1. Replace multiple slashes with a single slash.
|
||||
// 3. Eliminate each inner .. path name element (the parent directory)
|
||||
// along with the non-.. element that precedes it.
|
||||
// 4. Eliminate .. elements that begin a rooted path:
|
||||
// that is, replace "/.." by "/" at the beginning of a path.
|
||||
// 2. Replace '\' with '/'
|
||||
// 3. Replace "\\" with '/'
|
||||
// 4. Ignore anything inside '{' and '}'
|
||||
// 5. Makes sure that prefixed with '/'
|
||||
// 6. Remove trailing '/'.
|
||||
//
|
||||
// The returned path ends in a slash only if it is the root "/".
|
||||
func cleanPath(s string) string {
|
||||
// note that we don't care about the performance here, it's before the server ran.
|
||||
if s == "" || s == "." {
|
||||
return "/"
|
||||
}
|
||||
|
||||
// remove suffix "/"
|
||||
// remove suffix "/".
|
||||
if lidx := len(s) - 1; s[lidx] == '/' {
|
||||
s = s[:lidx]
|
||||
}
|
||||
|
||||
// prefix with "/"
|
||||
// prefix with "/".
|
||||
s = prefix(s, "/")
|
||||
|
||||
// remove the os specific dir sep
|
||||
s = strings.Replace(s, "\\", "/", -1)
|
||||
// If you're learning go through Iris I will ask you to ignore the
|
||||
// following part, it's not the recommending way to do that,
|
||||
// but it's understable to me.
|
||||
var (
|
||||
insideMacro = false
|
||||
i = -1
|
||||
)
|
||||
|
||||
// use std path to clean the path
|
||||
s = path.Clean(s)
|
||||
for {
|
||||
i++
|
||||
if len(s) <= i {
|
||||
break
|
||||
}
|
||||
|
||||
if s[i] == lexer.Begin {
|
||||
insideMacro = true
|
||||
continue
|
||||
}
|
||||
|
||||
if s[i] == lexer.End {
|
||||
insideMacro = false
|
||||
continue
|
||||
}
|
||||
|
||||
// when inside {} then don't try to clean it.
|
||||
if !insideMacro {
|
||||
if s[i] == '/' {
|
||||
if len(s)-1 >= i+1 && s[i+1] == '/' { // we have "//".
|
||||
bckp := s
|
||||
s = bckp[:i] + "/"
|
||||
// forward two, we ignore the second "/" in the raw.
|
||||
i = i + 2
|
||||
if len(bckp)-1 >= i {
|
||||
s += bckp[i:]
|
||||
}
|
||||
}
|
||||
// if we have just a single slash then continue.
|
||||
continue
|
||||
}
|
||||
|
||||
if s[i] == '\\' { // this will catch "\\" and "\".
|
||||
bckp := s
|
||||
s = bckp[:i] + "/"
|
||||
|
||||
if len(bckp)-1 >= i+1 {
|
||||
s += bckp[i+1:]
|
||||
i++
|
||||
}
|
||||
|
||||
if len(s)-1 > i && s[i] == '\\' {
|
||||
bckp := s
|
||||
s = bckp[:i]
|
||||
if len(bckp)-1 >= i+2 {
|
||||
s = bckp[:i-1] + bckp[i+1:]
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -4,6 +4,38 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestCleanPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
expected string
|
||||
}{
|
||||
{"noslashPrefix",
|
||||
"/noslashPrefix"},
|
||||
{"slashSuffix/",
|
||||
"/slashSuffix"},
|
||||
{"noSlashPrefixAndslashSuffix/",
|
||||
"/noSlashPrefixAndslashSuffix"},
|
||||
// don't do any clean up inside {},
|
||||
// fixes #927.
|
||||
{"/total/{year:string regexp(\\d{4})}",
|
||||
"/total/{year:string regexp(\\d{4})}"},
|
||||
{"/total/{year:string regexp(\\d{4})}/more",
|
||||
"/total/{year:string regexp(\\d{4})}/more"},
|
||||
{"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}",
|
||||
"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}"},
|
||||
{"/single_no_params",
|
||||
"/single_no_params"},
|
||||
{"/single/{id:int}",
|
||||
"/single/{id:int}"},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
if expected, got := tt.expected, cleanPath(tt.path); expected != got {
|
||||
t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
|
@ -50,8 +82,8 @@ func TestSplitSubdomainAndPath(t *testing.T) {
|
|||
}{
|
||||
{"admin./users/42", "admin.", "/users/42"},
|
||||
{"//api/users\\42", "", "/api/users/42"},
|
||||
{"admin./users/\\42", "admin.", "/users/42"},
|
||||
{"*./users/\\42", "*.", "/users/42"},
|
||||
{"admin./users//42", "admin.", "/users/42"},
|
||||
{"*./users/42/", "*.", "/users/42"},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
|
|
|
@ -147,6 +147,12 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
router.mainHandler(w, r)
|
||||
}
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
func (router *Router) RouteExists(ctx context.Context, method, path string) bool {
|
||||
return router.requestHandler.RouteExists(ctx, method, path)
|
||||
}
|
||||
|
||||
type wrapper struct {
|
||||
router http.HandlerFunc // http.HandlerFunc to catch the CURRENT state of its .ServeHTTP on case of future change.
|
||||
wrapperFunc func(http.ResponseWriter, *http.Request, http.HandlerFunc)
|
||||
|
|
41
core/router/router_test.go
Normal file
41
core/router/router_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package router_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/httptest"
|
||||
)
|
||||
|
||||
func TestRouteExists(t *testing.T) {
|
||||
// build the api
|
||||
app := iris.New()
|
||||
emptyHandler := func(context.Context) {}
|
||||
|
||||
// setup the tested routes
|
||||
app.Handle("GET", "/route-exists", emptyHandler)
|
||||
app.Handle("POST", "/route-with-param/{param}", emptyHandler)
|
||||
|
||||
// check RouteExists
|
||||
app.Handle("GET", "/route-test", func(ctx context.Context) {
|
||||
if ctx.RouteExists("GET", "/route-not-exists") {
|
||||
t.Error("Route with path should not exists")
|
||||
}
|
||||
|
||||
if ctx.RouteExists("POST", "/route-exists") {
|
||||
t.Error("Route with method should not exists")
|
||||
}
|
||||
|
||||
if !ctx.RouteExists("GET", "/route-exists") {
|
||||
t.Error("Route 1 should exists")
|
||||
}
|
||||
|
||||
if !ctx.RouteExists("POST", "/route-with-param/a-param") {
|
||||
t.Error("Route 2 should exists")
|
||||
}
|
||||
})
|
||||
|
||||
// run the tests
|
||||
httptest.New(t, app, httptest.Debug(false)).Request("GET", "/route-test").Expect().Status(iris.StatusOK)
|
||||
}
|
6
doc.go
6
doc.go
|
@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
|
|||
|
||||
Current Version
|
||||
|
||||
10.0.0
|
||||
10.3.0
|
||||
|
||||
Installation
|
||||
|
||||
|
@ -1121,7 +1121,7 @@ Example code:
|
|||
|
||||
|
||||
|
||||
View engine supports bundled(https://github.com/jteeuwen/go-bindata) template files too.
|
||||
View engine supports bundled(https://github.com/shuLhan/go-bindata) template files too.
|
||||
go-bindata gives you two functions, asset and assetNames,
|
||||
these can be setted to each of the template engines using the `.Binary` func.
|
||||
|
||||
|
@ -1133,7 +1133,7 @@ Example code:
|
|||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
||||
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||
// $ go-bindata ./templates/...
|
||||
// $ go build
|
||||
// $ ./embedding-templates-into-app
|
||||
|
|
10
go19.go
10
go19.go
|
@ -17,6 +17,16 @@ type (
|
|||
// Developers send responses to the client's request through a Context.
|
||||
// Developers get request information from the client's request by a Context.
|
||||
Context = context.Context
|
||||
// UnmarshalerFunc a shortcut, an alias for the `context#UnmarshalerFunc` type
|
||||
// which implements the `context#Unmarshaler` interface for reading request's body
|
||||
// via custom decoders, most of them already implement the `context#UnmarshalerFunc`
|
||||
// like the json.Unmarshal, xml.Unmarshal, yaml.Unmarshal and every library which
|
||||
// follows the best practises and is aligned with the Go standards.
|
||||
//
|
||||
// See 'context#UnmarshalBody` for more.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
|
||||
UnmarshalerFunc = context.UnmarshalerFunc
|
||||
// A Handler responds to an HTTP request.
|
||||
// It writes reply headers and data to the Context.ResponseWriter() and then return.
|
||||
// Returning signals that the request is finished;
|
||||
|
|
|
@ -128,10 +128,9 @@ func (r *Service) GetBytes(key string) ([]byte, error) {
|
|||
func (r *Service) Delete(key string) error {
|
||||
c := r.pool.Get()
|
||||
defer c.Close()
|
||||
if _, err := c.Do("DEL", r.Config.Prefix+key); err != nil {
|
||||
|
||||
_, err := c.Do("DEL", r.Config.Prefix+key)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func dial(network string, addr string, pass string) (redis.Conn, error) {
|
||||
|
|
|
@ -112,7 +112,7 @@ func hi(ctx iris.Context) {
|
|||
|
||||
## Embedded
|
||||
|
||||
View engine supports bundled(https://github.com/jteeuwen/go-bindata) template files too.
|
||||
View engine supports bundled(https://github.com/shuLhan/go-bindata) template files too.
|
||||
`go-bindata` gives you two functions, `Assset` and `AssetNames`,
|
||||
these can be setted to each of the template engines using the `.Binary` function.
|
||||
|
||||
|
@ -125,7 +125,7 @@ import "github.com/kataras/iris"
|
|||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
||||
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||
// $ go-bindata ./templates/...
|
||||
// $ go build
|
||||
// $ ./embedding-templates-into-app
|
||||
|
|
|
@ -44,6 +44,18 @@ type (
|
|||
TagParser func(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error)
|
||||
)
|
||||
|
||||
// AsValue converts any given value to a view.Value.
|
||||
// Usually being used within own functions passed to a template
|
||||
// through a Context or within filter functions.
|
||||
func AsValue(i interface{}) *Value {
|
||||
return (*Value)(pongo2.AsValue(i))
|
||||
}
|
||||
|
||||
// AsSafeValue works like AsValue, but does not apply the 'escape' filter.
|
||||
func AsSafeValue(i interface{}) *Value {
|
||||
return (*Value)(pongo2.AsSafeValue(i))
|
||||
}
|
||||
|
||||
// GetValue returns the `Value` as *pongo2.Value type.
|
||||
// This method was added by balthild at https://github.com/kataras/iris/pull/765
|
||||
func (value *Value) GetValue() *pongo2.Value {
|
||||
|
|
|
@ -128,7 +128,7 @@ func (s *HandlebarsEngine) loadDirectory() error {
|
|||
// instead of the html/template engine which works like {{ render "myfile.html"}} and accepts the parent binding, with handlebars we can't do that because of lack of runtime helpers (dublicate error)
|
||||
|
||||
var templateErr error
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, _ error) error {
|
||||
if info == nil || info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -147,6 +147,9 @@ func New(cfg Config) *Server {
|
|||
func (s *Server) Handler() context.Handler {
|
||||
return func(ctx context.Context) {
|
||||
c := s.Upgrade(ctx)
|
||||
if c.Err() != nil {
|
||||
return
|
||||
}
|
||||
// NOTE TO ME: fire these first BEFORE startReader and startPinger
|
||||
// in order to set the events and any messages to send
|
||||
// the startPinger will send the OK to the client and only
|
||||
|
|
Loading…
Reference in New Issue
Block a user