mirror of
https://github.com/kataras/iris.git
synced 2025-01-24 03:01: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
|
- linux
|
||||||
- osx
|
- osx
|
||||||
go:
|
go:
|
||||||
- go1.9
|
- "go1.9"
|
||||||
|
- "go1.10"
|
||||||
go_import_path: github.com/kataras/iris
|
go_import_path: github.com/kataras/iris
|
||||||
install:
|
install:
|
||||||
- go get ./... # for iris-contrib/httpexpect, kataras/golog
|
- go get ./... # for iris-contrib/httpexpect, kataras/golog
|
||||||
|
|
10
Gopkg.lock
generated
10
Gopkg.lock
generated
|
@ -107,7 +107,7 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/kataras/golog"
|
name = "github.com/kataras/golog"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "2ed680e7b1f34147164fa8073373e14fce02ac30"
|
revision = "dd676348ce75fa471fbbcd1bbbd131d00179756a"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -115,12 +115,6 @@
|
||||||
packages = [".","terminal"]
|
packages = [".","terminal"]
|
||||||
revision = "825e39f34365e7db2c9fbc3692c16220e3bd7418"
|
revision = "825e39f34365e7db2c9fbc3692c16220e3bd7418"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/kataras/survey"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "20e139a6d2469769ae88e0a3579ba5df71839ca7"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/klauspost/compress"
|
name = "github.com/klauspost/compress"
|
||||||
packages = ["flate","gzip"]
|
packages = ["flate","gzip"]
|
||||||
|
@ -251,7 +245,7 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix"]
|
packages = ["unix"]
|
||||||
revision = "2d6f6f883a06fc0d5f4b14a81e4c28705ea64c15"
|
revision = "c28acc882ebcbfbe8ce9f0f14b9ac26ee138dd51"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
|
@ -42,10 +42,6 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/kataras/golog"
|
name = "github.com/kataras/golog"
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
branch = "master"
|
|
||||||
name = "github.com/kataras/survey"
|
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/klauspost/compress"
|
name = "github.com/klauspost/compress"
|
||||||
version = "1.2.1"
|
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.
|
**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
|
# 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).
|
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 να το κάνει αυτό για σας.
|
**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `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
|
# 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).
|
Διόρθωση το οποίο αφορά 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` 或者等待自动更新。
|
**如何升级**: 打开命令行执行以下命令: `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 版本更新
|
# 2018 2月15号 | v10.2.1 版本更新
|
||||||
|
|
||||||
修正 子域名 (subdomain) 的 `StaticEmbedded` 和 `StaticWeb` 不存在错误, 由 [@speedwheel](https://github.com/speedwheel) 通过 [facebook page's chat](https://facebook.com/iris.framework) 反馈。
|
修正 子域名 (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>
|
<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.
|
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
|
## 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)
|
- 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)
|
- 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)
|
- 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 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
|
### 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>
|
<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.
|
Το 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)
|
- Μήπως τυχαίνει να βρήκατε κάποιο bug; Δημοσιεύστε το στα [github issues](https://github.com/kataras/iris/issues)
|
||||||
- Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com)
|
- Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com)
|
||||||
- Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](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>
|
<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.
|
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)
|
- Вы случайно обнаружили ошибку? Опубликуйте ее на [Github вопросы](https://github.com/kataras/iris/issues)
|
||||||
- У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com)
|
- У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com)
|
||||||
- Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](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>
|
<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开发框架。
|
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)
|
- 你碰巧找到了一个错误? 请提交 [github issues](https://github.com/kataras/iris/issues)
|
||||||
- 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com)
|
- 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com)
|
||||||
- [点击这里完成我们基于表单的用户体验报告](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- [点击这里完成我们基于表单的用户体验报告](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`
|
### How to Read from `context.Request() *http.Request`
|
||||||
|
|
||||||
- [Bind JSON](http_request/read-json/main.go)
|
- [Read JSON](http_request/read-json/main.go)
|
||||||
- [Bind Form](http_request/read-form/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/Read File](http_request/upload-file/main.go)
|
||||||
- [Upload multiple files with an easy way](http_request/upload-files/main.go)
|
- [Upload multiple files with an easy way](http_request/upload-files/main.go)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// $ go get github.com/rs/cors
|
// go get -u github.com/iris-contrib/middleware/...
|
||||||
// $ go run main.go
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kataras/iris"
|
"github.com/kataras/iris"
|
||||||
|
@ -10,15 +9,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
crs := cors.New(cors.Options{
|
crs := cors.New(cors.Options{
|
||||||
AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts.
|
AllowedOrigins: []string{"*"}, // allows everything, use that to change the hosts.
|
||||||
AllowCredentials: true,
|
AllowCredentials: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
v1 := app.Party("/api/v1")
|
v1 := app.Party("/api/v1", crs).AllowMethods(iris.MethodOptions) // <- important for the preflight.
|
||||||
v1.Use(crs)
|
|
||||||
{
|
{
|
||||||
v1.Get("/home", func(ctx iris.Context) {
|
v1.Get("/home", func(ctx iris.Context) {
|
||||||
ctx.WriteString("Hello from /home")
|
ctx.WriteString("Hello from /home")
|
||||||
|
@ -29,15 +27,13 @@ func main() {
|
||||||
v1.Post("/send", func(ctx iris.Context) {
|
v1.Post("/send", func(ctx iris.Context) {
|
||||||
ctx.WriteString("sent")
|
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"))
|
app.Run(iris.Addr("localhost:8080"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Follow these steps first:
|
// Follow these steps first:
|
||||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||||
// $ go-bindata ./assets/...
|
// $ go-bindata ./assets/...
|
||||||
// $ go build
|
// $ go build
|
||||||
// $ ./embedding-files-into-app
|
// $ ./embedding-files-into-app
|
||||||
|
|
|
@ -2,7 +2,7 @@ package main
|
||||||
|
|
||||||
import "github.com/kataras/iris"
|
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-bindata ./public/...
|
||||||
// $ go build
|
// $ go build
|
||||||
// $ ./embedded-single-page-application-with-other-routes
|
// $ ./embedded-single-page-application-with-other-routes
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"github.com/kataras/iris"
|
"github.com/kataras/iris"
|
||||||
)
|
)
|
||||||
|
|
||||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||||
// $ go-bindata ./public/...
|
// $ go-bindata ./public/...
|
||||||
// $ go build
|
// $ go build
|
||||||
// $ ./embedded-single-page-application
|
// $ ./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) {
|
func MyHandler(ctx iris.Context) {
|
||||||
c := &Company{}
|
var c Company
|
||||||
if err := ctx.ReadJSON(c); err != nil {
|
|
||||||
|
if err := ctx.ReadJSON(&c); err != nil {
|
||||||
ctx.StatusCode(iris.StatusBadRequest)
|
ctx.StatusCode(iris.StatusBadRequest)
|
||||||
ctx.WriteString(err.Error())
|
ctx.WriteString(err.Error())
|
||||||
return
|
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 {
|
type Person struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Age int `json:"age"`
|
Age int `json:"age"`
|
||||||
|
@ -55,9 +57,9 @@ func main() {
|
||||||
"Other": "Something here"
|
"Other": "Something here"
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// and Content-Type to application/json
|
// and Content-Type to application/json (optionally but good practise)
|
||||||
//
|
//
|
||||||
// The response should be:
|
// The response should be:
|
||||||
// Received: &main.Company{Name:"iris-Go", City:"New York", Other:"Something here"}
|
// Received: main.Company{Name:"iris-Go", City:"New York", Other:"Something here"}
|
||||||
app.Run(iris.Addr(":8080"))
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/kataras/iris/_examples/http_responsewriter/herotemplate/template"
|
"github.com/kataras/iris/_examples/http_responsewriter/herotemplate/template"
|
||||||
|
|
||||||
|
@ -13,11 +12,15 @@ import (
|
||||||
// $ go run app.go
|
// $ go run app.go
|
||||||
//
|
//
|
||||||
// Read more at https://github.com/shiyanhui/hero/hero
|
// Read more at https://github.com/shiyanhui/hero/hero
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
app.Get("/users", func(ctx iris.Context) {
|
app.Get("/users", func(ctx iris.Context) {
|
||||||
|
ctx.Gzip(true)
|
||||||
|
ctx.ContentType("text/html")
|
||||||
|
|
||||||
var userList = []string{
|
var userList = []string{
|
||||||
"Alice",
|
"Alice",
|
||||||
"Bob",
|
"Bob",
|
||||||
|
@ -25,30 +28,27 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Had better use buffer sync.Pool.
|
// 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()
|
// buffer := hero.GetBuffer()
|
||||||
// defer hero.PutBuffer(buffer)
|
// defer hero.PutBuffer(buffer)
|
||||||
buffer := new(bytes.Buffer)
|
// buffer := new(bytes.Buffer)
|
||||||
template.UserList(userList, buffer)
|
// template.UserList(userList, buffer)
|
||||||
|
// ctx.Write(buffer.Bytes())
|
||||||
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",
|
|
||||||
}
|
|
||||||
|
|
||||||
// using an io.Writer for automatic buffer management (i.e. hero built-in buffer pool),
|
// using an io.Writer for automatic buffer management (i.e. hero built-in buffer pool),
|
||||||
// iris context implements the io.Writer by its ResponseWriter
|
// iris context implements the io.Writer by its ResponseWriter
|
||||||
// which is an enhanced version of the standard http.ResponseWriter
|
// which is an enhanced version of the standard http.ResponseWriter
|
||||||
// but still 100% compatible.
|
// but still 100% compatible, GzipResponseWriter too:
|
||||||
template.UserListToWriter(userList, ctx)
|
// _, 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"))
|
app.Run(iris.Addr(":8080"))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/kataras/iris"
|
"github.com/kataras/iris"
|
||||||
|
@ -140,6 +141,24 @@ func main() {
|
||||||
ctx.Writef("Hello id: %d looking for friend id: ", id, friendid)
|
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.
|
}) // 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
|
// http://localhost:8080/game/a-zA-Z/level/0-9
|
||||||
// remember, alphabetical is lowercase or uppercase letters only.
|
// remember, alphabetical is lowercase or uppercase letters only.
|
||||||
app.Get("/game/{name:alphabetical}/level/{level:int}", func(ctx iris.Context) {
|
app.Get("/game/{name:alphabetical}/level/{level:int}", func(ctx iris.Context) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
none := app.None("/invisible/{username}", func(ctx iris.Context) {
|
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 != "" {
|
if from := ctx.Values().GetString("from"); from != "" {
|
||||||
ctx.Writef("\nI see that you're coming from %s", from)
|
ctx.Writef("\nI see that you're coming from %s", from)
|
||||||
|
|
|
@ -58,15 +58,11 @@ func (v *pageView) increment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *pageView) decrement() {
|
func (v *pageView) decrement() {
|
||||||
oldCount := v.count
|
atomic.AddUint64(&v.count, ^uint64(0))
|
||||||
if oldCount > 0 {
|
|
||||||
atomic.StoreUint64(&v.count, oldCount-1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *pageView) getCount() uint64 {
|
func (v *pageView) getCount() uint64 {
|
||||||
val := atomic.LoadUint64(&v.count)
|
return atomic.LoadUint64(&v.count)
|
||||||
return val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
|
@ -13,7 +13,7 @@ func main() {
|
||||||
return "Greetings " + s + "!"
|
return "Greetings " + s + "!"
|
||||||
})
|
})
|
||||||
|
|
||||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||||
// $ go-bindata ./templates/...
|
// $ go-bindata ./templates/...
|
||||||
// $ go build
|
// $ go build
|
||||||
// $ ./embedding-templates-into-app
|
// $ ./embedding-templates-into-app
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestConfigurationStatic(t *testing.T) {
|
||||||
|
|
||||||
afterNew = *app.config
|
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")
|
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,
|
// If a handler is not already registered,
|
||||||
// then it creates & registers a new trivial handler on the-fly.
|
// then it creates & registers a new trivial handler on the-fly.
|
||||||
FireErrorCode(ctx Context)
|
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"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -49,20 +48,24 @@ type (
|
||||||
//
|
//
|
||||||
// Note: This is totally optionally, the default decoders
|
// Note: This is totally optionally, the default decoders
|
||||||
// for ReadJSON is the encoding/json and for ReadXML is the encoding/xml.
|
// 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 {
|
BodyDecoder interface {
|
||||||
Decode(data []byte) error
|
Decode(data []byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshaler is the interface implemented by types that can unmarshal any raw data
|
// 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.
|
// TIP INFO: Any pointer to a value which implements the BodyDecoder can be override the unmarshaler.
|
||||||
Unmarshaler interface {
|
Unmarshaler interface {
|
||||||
Unmarshal(data []byte, v interface{}) error
|
Unmarshal(data []byte, outPtr interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalerFunc a shortcut for the Unmarshaler interface
|
// UnmarshalerFunc a shortcut for the Unmarshaler interface
|
||||||
//
|
//
|
||||||
// See 'Unmarshaler' and 'BodyDecoder' for more.
|
// 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.
|
// 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.
|
// Note: Custom context should override this method in order to be able to pass its own context.Context implementation.
|
||||||
Next()
|
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.
|
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||||
NextHandler() 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
|
// 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.
|
// `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)
|
FormFile(key string) (multipart.File, *multipart.FileHeader, error)
|
||||||
// UploadFormFiles uploads any received file(s) from the client
|
// UploadFormFiles uploads any received file(s) from the client
|
||||||
// to the system physical location "destDirectory".
|
// 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.
|
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||||
//
|
//
|
||||||
// See `FormFile` to a more controlled to receive a file.
|
// 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)
|
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.
|
// should be called before reading the request body from the client.
|
||||||
SetMaxRequestBodySize(limitOverBytes int64)
|
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.
|
// 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.
|
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-custom-via-unmarshaler/main.go
|
||||||
ReadJSON(jsonObject interface{}) error
|
UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) error
|
||||||
// ReadXML reads XML from request's body and binds it to a value of any xml-valid type.
|
// ReadJSON reads JSON from request's body and binds it to a pointer of a value of any json-valid type.
|
||||||
ReadXML(xmlObject interface{}) error
|
//
|
||||||
|
// 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
|
// ReadForm binds the formObject with the form data
|
||||||
// it supports any kind of struct.
|
// 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 |
|
// | Body (raw) Writers |
|
||||||
|
@ -880,7 +910,7 @@ type Context interface {
|
||||||
// TransactionsSkipped returns true if the transactions skipped or canceled at all.
|
// TransactionsSkipped returns true if the transactions skipped or canceled at all.
|
||||||
TransactionsSkipped() bool
|
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
|
// based on this context but with a changed method and path
|
||||||
// like it was requested by the user, but it is not.
|
// 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.
|
// 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.
|
// 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.
|
// Application returns the iris app instance which belongs to this context.
|
||||||
// Worth to notice that this function returns an interface
|
// Worth to notice that this function returns an interface
|
||||||
|
@ -1260,7 +1294,39 @@ func (ctx *context) Next() { // or context.Next(ctx)
|
||||||
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.
|
// Use .Skip() to skip this handler if needed to execute the next of this returning handler.
|
||||||
func (ctx *context) NextHandler() 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
|
// 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.
|
// `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) {
|
func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
|
||||||
// we don't have access to see if the request is body stream
|
// we don't have access to see if the request is body stream
|
||||||
// and then the ParseMultipartForm can be useless
|
// 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.
|
// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
|
||||||
//
|
//
|
||||||
// See `FormFile` to a more controlled to receive a file.
|
// 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) {
|
func (ctx *context) UploadFormFiles(destDirectory string, before ...func(Context, *multipart.FileHeader)) (n int64, err error) {
|
||||||
err = ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
|
err = ctx.request.ParseMultipartForm(ctx.Application().ConfigurationReadOnly().GetPostMaxMemory())
|
||||||
if err != nil {
|
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
|
// UnmarshalBody reads the request's body and binds it to a value or pointer of any type
|
||||||
// Examples of usage: context.ReadJSON, context.ReadXML.
|
// 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 {
|
if ctx.request.Body == nil {
|
||||||
return errors.New("unmarshal: empty body")
|
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,
|
// in this case the v should be a pointer also,
|
||||||
// but this is up to the user's custom Decode implementation*
|
// but this is up to the user's custom Decode implementation*
|
||||||
//
|
//
|
||||||
// See 'BodyDecoder' for more
|
// See 'BodyDecoder' for more.
|
||||||
if decoder, isDecoder := v.(BodyDecoder); isDecoder {
|
if decoder, isDecoder := outPtr.(BodyDecoder); isDecoder {
|
||||||
return decoder.Decode(rawData)
|
return decoder.Decode(rawData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if v is already a pointer, if yes then pass as it's
|
// // check if v is already a pointer, if yes then pass as it's
|
||||||
if reflect.TypeOf(v).Kind() == reflect.Ptr {
|
// if reflect.TypeOf(v).Kind() == reflect.Ptr {
|
||||||
return unmarshaler.Unmarshal(rawData, v)
|
// return unmarshaler.Unmarshal(rawData, v)
|
||||||
}
|
// } <- no need for that, ReadJSON is documented enough to receive a pointer,
|
||||||
// finally, if the v doesn't contains a self-body decoder and it's not a pointer
|
// we don't need to reduce the performance here by using the reflect.TypeOf method.
|
||||||
// use the custom unmarshaler to bind the body
|
|
||||||
return unmarshaler.Unmarshal(rawData, &v)
|
// 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 {
|
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.
|
// 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 {
|
func (ctx *context) ReadJSON(jsonObject interface{}) error {
|
||||||
var unmarshaler = json.Unmarshal
|
var unmarshaler = json.Unmarshal
|
||||||
if ctx.shouldOptimize() {
|
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.
|
// 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 {
|
func (ctx *context) ReadXML(xmlObject interface{}) error {
|
||||||
return ctx.UnmarshalBody(xmlObject, UnmarshalerFunc(xml.Unmarshal))
|
return ctx.UnmarshalBody(xmlObject, UnmarshalerFunc(xml.Unmarshal))
|
||||||
}
|
}
|
||||||
|
@ -2066,6 +2143,8 @@ var (
|
||||||
|
|
||||||
// ReadForm binds the formObject with the form data
|
// ReadForm binds the formObject with the form data
|
||||||
// it supports any kind of struct.
|
// 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 {
|
func (ctx *context) ReadForm(formObject interface{}) error {
|
||||||
values := ctx.FormValues()
|
values := ctx.FormValues()
|
||||||
if values == nil {
|
if values == nil {
|
||||||
|
@ -3086,48 +3165,57 @@ func (ctx *context) TransactionsSkipped() bool {
|
||||||
//
|
//
|
||||||
// It's for extreme use cases, 99% of the times will never be useful for you.
|
// It's for extreme use cases, 99% of the times will never be useful for you.
|
||||||
func (ctx *context) Exec(method string, path string) {
|
func (ctx *context) Exec(method string, path string) {
|
||||||
if path != "" {
|
if path == "" {
|
||||||
if method == "" {
|
return
|
||||||
method = "GET"
|
|
||||||
}
|
|
||||||
|
|
||||||
// backup the handlers
|
|
||||||
backupHandlers := ctx.Handlers()[0:]
|
|
||||||
backupPos := ctx.HandlerIndex(-1)
|
|
||||||
|
|
||||||
// backup the request path information
|
|
||||||
backupPath := ctx.Path()
|
|
||||||
bakcupMethod := ctx.Method()
|
|
||||||
// don't backupValues := ctx.Values().ReadOnly()
|
|
||||||
|
|
||||||
// [sessions stays]
|
|
||||||
// [values stays]
|
|
||||||
// reset handlers
|
|
||||||
ctx.SetHandlers(nil)
|
|
||||||
|
|
||||||
req := ctx.Request()
|
|
||||||
// set the request to be align with the 'againstRequestPath'
|
|
||||||
req.RequestURI = path
|
|
||||||
req.URL.Path = path
|
|
||||||
req.Method = method
|
|
||||||
// execute the route from the (internal) context router
|
|
||||||
// this way we keep the sessions and the values
|
|
||||||
ctx.Application().ServeHTTPC(ctx)
|
|
||||||
|
|
||||||
// set back the old handlers and the last known index
|
|
||||||
ctx.SetHandlers(backupHandlers)
|
|
||||||
ctx.HandlerIndex(backupPos)
|
|
||||||
// set the request back to its previous state
|
|
||||||
req.RequestURI = backupPath
|
|
||||||
req.URL.Path = backupPath
|
|
||||||
req.Method = bakcupMethod
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if method == "" {
|
||||||
|
method = "GET"
|
||||||
|
}
|
||||||
|
|
||||||
|
// backup the handlers
|
||||||
|
backupHandlers := ctx.Handlers()[0:]
|
||||||
|
backupPos := ctx.HandlerIndex(-1)
|
||||||
|
|
||||||
|
// backup the request path information
|
||||||
|
backupPath := ctx.Path()
|
||||||
|
backupMethod := ctx.Method()
|
||||||
|
// don't backupValues := ctx.Values().ReadOnly()
|
||||||
|
|
||||||
|
// [values stays]
|
||||||
|
// reset handlers
|
||||||
|
ctx.SetHandlers(nil)
|
||||||
|
|
||||||
|
req := ctx.Request()
|
||||||
|
// set the request to be align with the 'againstRequestPath'
|
||||||
|
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)
|
||||||
|
|
||||||
|
// set back the old handlers and the last known index
|
||||||
|
ctx.SetHandlers(backupHandlers)
|
||||||
|
ctx.HandlerIndex(backupPos)
|
||||||
|
// set the request back to its previous state
|
||||||
|
req.RequestURI = backupPath
|
||||||
|
req.URL.Path = backupPath
|
||||||
|
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.
|
// Application returns the iris app instance which belongs to this context.
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Version is the string representation of the current local Iris Web Framework version.
|
// 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
|
// CheckForUpdates checks for any available updates
|
||||||
|
|
|
@ -180,7 +180,7 @@ func (e Entry) BoolDefault(def bool) (bool, error) {
|
||||||
// respects the immutable.
|
// respects the immutable.
|
||||||
func (e Entry) Value() interface{} {
|
func (e Entry) Value() interface{} {
|
||||||
if e.immutable {
|
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))
|
vv := reflect.Indirect(reflect.ValueOf(e.ValueRaw))
|
||||||
|
|
||||||
// return copy of that slice
|
// return copy of that slice
|
||||||
|
|
|
@ -42,6 +42,12 @@ type repository struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *repository) register(route *Route) {
|
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)
|
r.routes = append(r.routes, route)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,10 +98,15 @@ type APIBuilder struct {
|
||||||
doneGlobalHandlers context.Handlers
|
doneGlobalHandlers context.Handlers
|
||||||
// the per-party
|
// the per-party
|
||||||
relativePath string
|
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 _ Party = (*APIBuilder)(nil)
|
||||||
var _ RoutesProvider = &APIBuilder{} // passed to the default request handler (routerHandler)
|
var _ RoutesProvider = (*APIBuilder)(nil) // passed to the default request handler (routerHandler)
|
||||||
|
|
||||||
// NewAPIBuilder creates & returns a new builder
|
// NewAPIBuilder creates & returns a new builder
|
||||||
// which is responsible to build the API and the router handler.
|
// which is responsible to build the API and the router handler.
|
||||||
|
@ -129,6 +140,16 @@ func (api *APIBuilder) GetReporter() *errors.Reporter {
|
||||||
return api.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.
|
// 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.
|
// 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
|
// here we separate the subdomain and relative path
|
||||||
subdomain, path := splitSubdomainAndPath(fullpath)
|
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.
|
||||||
if err != nil { // template path parser errors:
|
methods := append(api.allowMethods, method)
|
||||||
api.reporter.Add("%v -> %s:%s:%s", err, method, subdomain, path)
|
|
||||||
return nil
|
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 // fail on first error.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add UseGlobal & DoneGlobal Handlers
|
||||||
|
route.use(api.beginGlobalHandlers)
|
||||||
|
route.done(api.doneGlobalHandlers)
|
||||||
|
|
||||||
|
// global
|
||||||
|
api.routes.register(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add UseGlobal & DoneGlobal Handlers
|
return route
|
||||||
r.use(api.beginGlobalHandlers)
|
|
||||||
r.done(api.doneGlobalHandlers)
|
|
||||||
|
|
||||||
// global
|
|
||||||
api.routes.register(r)
|
|
||||||
|
|
||||||
// per -party, used for done handlers
|
|
||||||
// api.apiRoutes = append(api.apiRoutes, r)
|
|
||||||
|
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleMany works like `Handle` but can receive more than one
|
// 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
|
// append the parent's + child's handlers
|
||||||
middleware := joinHandlers(api.middleware, 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{
|
return &APIBuilder{
|
||||||
// global/api builder
|
// global/api builder
|
||||||
macros: api.macros,
|
macros: api.macros,
|
||||||
|
@ -269,8 +301,9 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
||||||
reporter: api.reporter,
|
reporter: api.reporter,
|
||||||
// per-party/children
|
// per-party/children
|
||||||
middleware: middleware,
|
middleware: middleware,
|
||||||
doneHandlers: api.doneHandlers,
|
doneHandlers: api.doneHandlers[0:],
|
||||||
relativePath: fullpath,
|
relativePath: fullpath,
|
||||||
|
allowMethods: allowMethods,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ type RequestHandler interface {
|
||||||
HandleRequest(context.Context)
|
HandleRequest(context.Context)
|
||||||
// Build should builds the handler, it's being called on router's BuildRouter.
|
// Build should builds the handler, it's being called on router's BuildRouter.
|
||||||
Build(provider RoutesProvider) error
|
Build(provider RoutesProvider) error
|
||||||
|
// RouteExists reports whether a particular route exists.
|
||||||
|
RouteExists(ctx context.Context, method, path string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type tree struct {
|
type tree struct {
|
||||||
|
@ -160,6 +162,14 @@ func (h *routerHandler) HandleRequest(ctx context.Context) {
|
||||||
r.URL.Path = path
|
r.URL.Path = path
|
||||||
url := r.URL.String()
|
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)
|
ctx.Redirect(url, http.StatusMovedPermanently)
|
||||||
|
|
||||||
// RFC2616 recommends that a short note "SHOULD" be included in the
|
// 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)
|
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"
|
"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 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.
|
// 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.
|
// Returns this Party.
|
||||||
Reset() 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.
|
// 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.
|
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
|
||||||
//
|
//
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kataras/iris/core/netutil"
|
"github.com/kataras/iris/core/netutil"
|
||||||
|
"github.com/kataras/iris/core/router/macro/interpreter/lexer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -73,30 +74,91 @@ func joinPath(path1 string, path2 string) string {
|
||||||
// iteratively until no further processing can be done:
|
// iteratively until no further processing can be done:
|
||||||
//
|
//
|
||||||
// 1. Replace multiple slashes with a single slash.
|
// 1. Replace multiple slashes with a single slash.
|
||||||
// 3. Eliminate each inner .. path name element (the parent directory)
|
// 2. Replace '\' with '/'
|
||||||
// along with the non-.. element that precedes it.
|
// 3. Replace "\\" with '/'
|
||||||
// 4. Eliminate .. elements that begin a rooted path:
|
// 4. Ignore anything inside '{' and '}'
|
||||||
// that is, replace "/.." by "/" at the beginning of a path.
|
// 5. Makes sure that prefixed with '/'
|
||||||
|
// 6. Remove trailing '/'.
|
||||||
//
|
//
|
||||||
// The returned path ends in a slash only if it is the root "/".
|
// The returned path ends in a slash only if it is the root "/".
|
||||||
func cleanPath(s string) string {
|
func cleanPath(s string) string {
|
||||||
|
// note that we don't care about the performance here, it's before the server ran.
|
||||||
if s == "" || s == "." {
|
if s == "" || s == "." {
|
||||||
return "/"
|
return "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove suffix "/"
|
// remove suffix "/".
|
||||||
if lidx := len(s) - 1; s[lidx] == '/' {
|
if lidx := len(s) - 1; s[lidx] == '/' {
|
||||||
s = s[:lidx]
|
s = s[:lidx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefix with "/"
|
// prefix with "/".
|
||||||
s = prefix(s, "/")
|
s = prefix(s, "/")
|
||||||
|
|
||||||
// remove the os specific dir sep
|
// If you're learning go through Iris I will ask you to ignore the
|
||||||
s = strings.Replace(s, "\\", "/", -1)
|
// 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
|
for {
|
||||||
s = path.Clean(s)
|
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
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,38 @@ import (
|
||||||
"testing"
|
"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) {
|
func TestSplitPath(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
path string
|
path string
|
||||||
|
@ -50,8 +82,8 @@ func TestSplitSubdomainAndPath(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"admin./users/42", "admin.", "/users/42"},
|
{"admin./users/42", "admin.", "/users/42"},
|
||||||
{"//api/users\\42", "", "/api/users/42"},
|
{"//api/users\\42", "", "/api/users/42"},
|
||||||
{"admin./users/\\42", "admin.", "/users/42"},
|
{"admin./users//42", "admin.", "/users/42"},
|
||||||
{"*./users/\\42", "*.", "/users/42"},
|
{"*./users/42/", "*.", "/users/42"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
|
|
@ -147,6 +147,12 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
router.mainHandler(w, r)
|
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 {
|
type wrapper struct {
|
||||||
router http.HandlerFunc // http.HandlerFunc to catch the CURRENT state of its .ServeHTTP on case of future change.
|
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)
|
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
|
Current Version
|
||||||
|
|
||||||
10.0.0
|
10.3.0
|
||||||
|
|
||||||
Installation
|
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,
|
go-bindata gives you two functions, asset and assetNames,
|
||||||
these can be setted to each of the template engines using the `.Binary` func.
|
these can be setted to each of the template engines using the `.Binary` func.
|
||||||
|
|
||||||
|
@ -1133,7 +1133,7 @@ Example code:
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||||
// $ go-bindata ./templates/...
|
// $ go-bindata ./templates/...
|
||||||
// $ go build
|
// $ go build
|
||||||
// $ ./embedding-templates-into-app
|
// $ ./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 send responses to the client's request through a Context.
|
||||||
// Developers get request information from the client's request by a Context.
|
// Developers get request information from the client's request by a Context.
|
||||||
Context = context.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.
|
// A Handler responds to an HTTP request.
|
||||||
// It writes reply headers and data to the Context.ResponseWriter() and then return.
|
// It writes reply headers and data to the Context.ResponseWriter() and then return.
|
||||||
// Returning signals that the request is finished;
|
// 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 {
|
func (r *Service) Delete(key string) error {
|
||||||
c := r.pool.Get()
|
c := r.pool.Get()
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
if _, err := c.Do("DEL", r.Config.Prefix+key); err != nil {
|
|
||||||
return err
|
_, err := c.Do("DEL", r.Config.Prefix+key)
|
||||||
}
|
return err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dial(network string, addr string, pass string) (redis.Conn, error) {
|
func dial(network string, addr string, pass string) (redis.Conn, error) {
|
||||||
|
|
|
@ -112,7 +112,7 @@ func hi(ctx iris.Context) {
|
||||||
|
|
||||||
## Embedded
|
## 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`,
|
`go-bindata` gives you two functions, `Assset` and `AssetNames`,
|
||||||
these can be setted to each of the template engines using the `.Binary` function.
|
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() {
|
func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
// $ go get -u github.com/jteeuwen/go-bindata/...
|
// $ go get -u github.com/shuLhan/go-bindata/...
|
||||||
// $ go-bindata ./templates/...
|
// $ go-bindata ./templates/...
|
||||||
// $ go build
|
// $ go build
|
||||||
// $ ./embedding-templates-into-app
|
// $ ./embedding-templates-into-app
|
||||||
|
|
|
@ -44,6 +44,18 @@ type (
|
||||||
TagParser func(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error)
|
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.
|
// GetValue returns the `Value` as *pongo2.Value type.
|
||||||
// This method was added by balthild at https://github.com/kataras/iris/pull/765
|
// This method was added by balthild at https://github.com/kataras/iris/pull/765
|
||||||
func (value *Value) GetValue() *pongo2.Value {
|
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)
|
// 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
|
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() {
|
if info == nil || info.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,9 @@ func New(cfg Config) *Server {
|
||||||
func (s *Server) Handler() context.Handler {
|
func (s *Server) Handler() context.Handler {
|
||||||
return func(ctx context.Context) {
|
return func(ctx context.Context) {
|
||||||
c := s.Upgrade(ctx)
|
c := s.Upgrade(ctx)
|
||||||
|
if c.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
// NOTE TO ME: fire these first BEFORE startReader and startPinger
|
// NOTE TO ME: fire these first BEFORE startReader and startPinger
|
||||||
// in order to set the events and any messages to send
|
// in order to set the events and any messages to send
|
||||||
// the startPinger will send the OK to the client and only
|
// the startPinger will send the OK to the client and only
|
||||||
|
|
Loading…
Reference in New Issue
Block a user