mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
replace ioutil with io package and other minor improvements
This commit is contained in:
parent
20d2855a66
commit
ef2643b046
|
@ -28,6 +28,7 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- Make the `Context.JSON` method customizable by modifying the `context.WriteJSON` package-level function.
|
||||||
- Add new `iris.NewGuide` which helps you build a simple and nice JSON API with services as dependencies and better design pattern.
|
- Add new `iris.NewGuide` which helps you build a simple and nice JSON API with services as dependencies and better design pattern.
|
||||||
- Make `Context.Domain()` customizable by letting developers to modify the `Context.GetDomain` package-level function.
|
- Make `Context.Domain()` customizable by letting developers to modify the `Context.GetDomain` package-level function.
|
||||||
- Remove Request Context-based Transaction feature as its usage can be replaced with just the Iris Context (as of go1.7+) and better [project](_examples/project) structure.
|
- Remove Request Context-based Transaction feature as its usage can be replaced with just the Iris Context (as of go1.7+) and better [project](_examples/project) structure.
|
||||||
|
|
5
LICENSE
5
LICENSE
|
@ -1,4 +1,7 @@
|
||||||
Copyright (c) 2017-2022 The Iris Authors. All rights reserved.
|
Copyright (c) 2017-2022, The Iris Authors. All rights reserved.
|
||||||
|
|
||||||
|
The Iris Authors:
|
||||||
|
* Gerasimos (Makis) Maropoulos
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
|
33
README.md
33
README.md
|
@ -19,7 +19,8 @@
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
It provides a [beautifully](iris_guide.go#L31-L44) expressive and easy to use foundation for your next website or API.
|
It provides a beautifully expressive and easy to use foundation for your next website or API.
|
||||||
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
@ -38,7 +39,7 @@ func main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<details><summary>More with simple Handler</summary>
|
<!-- <details><summary>More with simple Handler</summary>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
@ -178,6 +179,34 @@ func main() {
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
As one [Go developer](https://twitter.com/dkuye/status/1532087942696554497) once said, **Iris got you covered all-round and standing strong over the years**.
|
||||||
|
|
||||||
|
Some of the features Iris offers:
|
||||||
|
|
||||||
|
* HTTP/2 (Push, even Embedded data)
|
||||||
|
* Middleware (Accesslog, Basicauth, CORS, gRPC, Anti-Bot hCaptcha, JWT, MethodOverride, ModRevision, Monitor, PPROF, Ratelimit, Anti-Bot reCaptcha, Recovery, RequestID, Rewrite)
|
||||||
|
* API Versioning
|
||||||
|
* Model-View-Controller
|
||||||
|
* Websockets
|
||||||
|
* gRPC
|
||||||
|
* Auto-HTTPS
|
||||||
|
* Builtin support for ngrok to put your app on the internet, the fastest way
|
||||||
|
* Unique Router with dynamic path as parameter with standard types like :uuid, :string, :int... and the ability to create your own
|
||||||
|
* Compression
|
||||||
|
* View Engines (HTML, Django, Amber, Handlebars, Pug/Jade and more)
|
||||||
|
* Create your own File Server and host your own WebDAV server
|
||||||
|
* Cache
|
||||||
|
* Localization (i18n, sitemap)
|
||||||
|
* Sessions
|
||||||
|
* Rich Responses (HTML, Text, Markdown, XML, YAML, Binary, JSON, JSONP, Protocol Buffers, MessagePack, Content Negotiation, Streaming, Server-Sent Events and more)
|
||||||
|
* Response Compression (gzip, deflate, brotli, snappy, s2)
|
||||||
|
* Rich Requests (Bind URL Query, Headers, Form, Text, XML, YAML, Binary, JSON, Validation, Protocol Buffers, MessagePack and more)
|
||||||
|
* Dependency Injection (MVC, Handlers, API Routers)
|
||||||
|
* Testing Suite
|
||||||
|
* And the most important... you get fast answers and support from the 1st day until now - that's six full years!
|
||||||
|
|
||||||
Learn what [others saying about Iris](https://www.iris-go.com/#review) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials.
|
Learn what [others saying about Iris](https://www.iris-go.com/#review) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials.
|
||||||
|
|
||||||
[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/)
|
[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -105,5 +104,5 @@ func BindResponse(resp *http.Response, dest interface{}) error {
|
||||||
func RawResponse(resp *http.Response) ([]byte, error) {
|
func RawResponse(resp *http.Response) ([]byte, error) {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
return ioutil.ReadAll(resp.Body)
|
return io.ReadAll(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
|
@ -51,7 +51,7 @@ func getExample() {
|
||||||
}
|
}
|
||||||
defer cr.Close()
|
defer cr.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(cr)
|
body, err := io.ReadAll(cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func postExample() {
|
||||||
}
|
}
|
||||||
defer cr.Close()
|
defer cr.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(cr)
|
body, err := io.ReadAll(cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func getExample() {
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r)
|
body, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ func postExample() {
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r)
|
body, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
const addr = "127.0.0.1:8080"
|
const addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
|
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
|
||||||
$ ./myapp.exe # run the app
|
$ ./myapp.exe # run the app
|
||||||
*/
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
go runServer()
|
go runServer()
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
const addr = "127.0.0.1:8080"
|
const addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||||
$ ./myapp.exe # run
|
$ ./myapp.exe # run
|
||||||
*/
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
go runServer()
|
go runServer()
|
||||||
|
|
|
@ -8,21 +8,21 @@ import (
|
||||||
const addr = "127.0.0.1:8080"
|
const addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
# Windows requires special linker flags for GUI apps.
|
# Windows requires special linker flags for GUI apps.
|
||||||
# It's also recommended to use TDM-GCC-64 compiler for CGo.
|
# It's also recommended to use TDM-GCC-64 compiler for CGo.
|
||||||
# http://tdm-gcc.tdragon.net/download
|
# http://tdm-gcc.tdragon.net/download
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
|
||||||
$ ./myapp.exe # run
|
$ ./myapp.exe # run
|
||||||
#
|
#
|
||||||
# MacOS uses app bundles for GUI apps
|
# MacOS uses app bundles for GUI apps
|
||||||
$ mkdir -p example.app/Contents/MacOS
|
$ mkdir -p example.app/Contents/MacOS
|
||||||
$ go build -o example.app/Contents/MacOS/example
|
$ go build -o example.app/Contents/MacOS/example
|
||||||
$ open example.app # Or click on the app in Finder
|
$ open example.app # Or click on the app in Finder
|
||||||
#
|
#
|
||||||
# Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
|
# Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
|
||||||
# please refer to: https://github.com/webview/webview/issues/188
|
# please refer to: https://github.com/webview/webview/issues/188
|
||||||
*/
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
go runServer()
|
go runServer()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -47,7 +47,7 @@ func (r resource) loadFromBase(dir string, strip string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// assets/css/main.css
|
// assets/css/main.css
|
||||||
// assets/favicon.ico
|
// assets/favicon.ico
|
||||||
// assets/js/main.js
|
// assets/js/main.js
|
||||||
|
@ -11,7 +11,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -46,7 +46,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// ../embedding-files-into-app/assets/css/main.css
|
// ../embedding-files-into-app/assets/css/main.css
|
||||||
// ../embedding-files-into-app/assets/favicon.ico
|
// ../embedding-files-into-app/assets/favicon.ico
|
||||||
// ../embedding-files-into-app/assets/js/main.js
|
// ../embedding-files-into-app/assets/js/main.js
|
||||||
|
@ -11,7 +11,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -48,7 +48,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// ../http2push/assets/app2/app2app3/css/main.css
|
// ../http2push/assets/app2/app2app3/css/main.css
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
||||||
|
@ -19,7 +19,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// ../http2push/assets/app2/app2app3/css/main.css
|
// ../http2push/assets/app2/app2app3/css/main.css
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir1/text.txt
|
||||||
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
|
||||||
|
@ -19,7 +19,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// public/app.js
|
// public/app.js
|
||||||
// public/css/main.css
|
// public/css/main.css
|
||||||
// public/index.html
|
// public/index.html
|
||||||
|
@ -11,7 +11,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -346,7 +347,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -377,7 +378,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -41,7 +41,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
/*Package main is a proxy + accesslog example.
|
/*
|
||||||
|
Package main is a proxy + accesslog example.
|
||||||
In this example we will make a small proxy which listens requests on "/proxy/+path".
|
In this example we will make a small proxy which listens requests on "/proxy/+path".
|
||||||
With two accesslog instances, one for the main application and one for the /proxy/ requests.
|
With two accesslog instances, one for the main application and one for the /proxy/ requests.
|
||||||
Of cource, you could a single accesslog for the whole application, but for the sake of the example
|
Of cource, you could a single accesslog for the whole application, but for the sake of the example
|
||||||
let's log them separately.
|
let's log them separately.
|
||||||
|
|
||||||
We will make use of iris.StripPrefix and host.ProxyHandler.*/
|
We will make use of iris.StripPrefix and host.ProxyHandler.
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -5,15 +5,15 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld"
|
pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
b, err := ioutil.ReadFile("../server.crt")
|
b, err := os.ReadFile("../server.crt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ type UsersController struct {
|
||||||
// curl -i -u admin:password http://localhost:8080/users
|
// curl -i -u admin:password http://localhost:8080/users
|
||||||
//
|
//
|
||||||
// The correct way if you have sensitive data:
|
// The correct way if you have sensitive data:
|
||||||
|
//
|
||||||
// func (c *UsersController) Get() (results []viewmodels.User) {
|
// func (c *UsersController) Get() (results []viewmodels.User) {
|
||||||
// data := c.Service.GetAll()
|
// data := c.Service.GetAll()
|
||||||
//
|
//
|
||||||
|
@ -38,6 +39,7 @@ type UsersController struct {
|
||||||
// }
|
// }
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// otherwise just return the datamodels.
|
// otherwise just return the datamodels.
|
||||||
func (c *UsersController) Get() (results []datamodels.User) {
|
func (c *UsersController) Get() (results []datamodels.User) {
|
||||||
return c.Service.GetAll()
|
return c.Service.GetAll()
|
||||||
|
|
|
@ -9,9 +9,11 @@ else as well, otherwise I am going with the first one:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// 1
|
// 1
|
||||||
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
|
|
||||||
|
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
|
||||||
m.Router.Use(cache.Handler(10*time.Second))
|
m.Router.Use(cache.Handler(10*time.Second))
|
||||||
})
|
})
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -32,10 +34,12 @@ mvc.Configure(userRouter, ...)
|
||||||
```go
|
```go
|
||||||
// 4
|
// 4
|
||||||
// same:
|
// same:
|
||||||
app.PartyFunc("/user", func(r iris.Party){
|
|
||||||
|
app.PartyFunc("/user", func(r iris.Party){
|
||||||
r.Use(cache.Handler(10*time.Second))
|
r.Use(cache.Handler(10*time.Second))
|
||||||
mvc.Configure(r, ...)
|
mvc.Configure(r, ...)
|
||||||
})
|
})
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to use a middleware for a single route,
|
If you want to use a middleware for a single route,
|
||||||
|
@ -48,7 +52,8 @@ then you just call it on the method:
|
||||||
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
|
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
|
||||||
|
|
||||||
type UserController struct{}
|
type UserController struct{}
|
||||||
func (c *UserController) GetSomething(ctx iris.Context) {
|
|
||||||
|
func (c *UserController) GetSomething(ctx iris.Context) {
|
||||||
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
|
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
|
||||||
// inside it and returns true if so, otherwise false.
|
// inside it and returns true if so, otherwise false.
|
||||||
nextCalled := ctx.Proceed(myMiddleware)
|
nextCalled := ctx.Proceed(myMiddleware)
|
||||||
|
@ -57,7 +62,8 @@ func (c *UserController) GetSomething(ctx iris.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// else do the job here, it's allowed
|
// else do the job here, it's allowed
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
And last, if you want to add a middleware on a specific method
|
And last, if you want to add a middleware on a specific method
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
/*Package main shows how to add done handlers in an MVC application without
|
/*
|
||||||
|
Package main shows how to add done handlers in an MVC application without
|
||||||
the necessity of `ctx.Next()` inside the controller's methods.
|
the necessity of `ctx.Next()` inside the controller's methods.
|
||||||
|
|
||||||
When we want the `Done` handlers of that specific mvc app's `Party`
|
When we want the `Done` handlers of that specific mvc app's `Party`
|
||||||
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`*/
|
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`
|
||||||
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -35,7 +35,9 @@ func pong(ctx iris.Context) {
|
||||||
| | |
|
| | |
|
||||||
| | |
|
| | |
|
||||||
DEV | | | PROD
|
DEV | | | PROD
|
||||||
|
|
||||||
-------------------+---------------------+ | +----------------------+-------------------
|
-------------------+---------------------+ | +----------------------+-------------------
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
| | |
|
| | |
|
||||||
+---+-----+ +----------------v------------------+ +----+----+
|
+---+-----+ +----------------v------------------+ +----+----+
|
||||||
|
@ -64,6 +66,7 @@ func pong(ctx iris.Context) {
|
||||||
| | /greet?name=kataras | |
|
| | /greet?name=kataras | |
|
||||||
| +-----------+-----------+ |
|
| +-----------+-----------+ |
|
||||||
| | |
|
| | |
|
||||||
|
|
||||||
+------------------+--------+ +------------+------------+ +-------+------------------+
|
+------------------+--------+ +------------+------------+ +-------+------------------+
|
||||||
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
|
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
|
||||||
+---------------------------+ +-------------------------+ +--------------------------+
|
+---------------------------+ +-------------------------+ +--------------------------+
|
||||||
|
|
|
@ -23,6 +23,7 @@ type MovieController struct {
|
||||||
// curl -i http://localhost:8080/movies
|
// curl -i http://localhost:8080/movies
|
||||||
//
|
//
|
||||||
// The correct way if you have sensitive data:
|
// The correct way if you have sensitive data:
|
||||||
|
//
|
||||||
// func (c *MovieController) Get() (results []viewmodels.Movie) {
|
// func (c *MovieController) Get() (results []viewmodels.Movie) {
|
||||||
// data := c.Service.GetAll()
|
// data := c.Service.GetAll()
|
||||||
//
|
//
|
||||||
|
@ -31,6 +32,7 @@ type MovieController struct {
|
||||||
// }
|
// }
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// otherwise just return the datamodels.
|
// otherwise just return the datamodels.
|
||||||
func (c *MovieController) Get() (results []datamodels.Movie) {
|
func (c *MovieController) Get() (results []datamodels.Movie) {
|
||||||
return c.Service.GetAll()
|
return c.Service.GetAll()
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (srv *Server) buildRouter() {
|
||||||
ServerName: srv.config.ServerName,
|
ServerName: srv.config.ServerName,
|
||||||
Env: srv.config.Env,
|
Env: srv.config.Env,
|
||||||
Developer: "kataras",
|
Developer: "kataras",
|
||||||
TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
api := srv.Party("/api")
|
api := srv.Party("/api")
|
||||||
|
|
|
@ -8,7 +8,7 @@ func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
|
||||||
// body, err := ioutil.ReadAll(ctx.Request().Body) once or
|
// body, err := io.ReadAll(ctx.Request().Body) once or
|
||||||
body, err := ctx.GetBody() // as many times as you need.
|
body, err := ctx.GetBody() // as many times as you need.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.StopWithError(iris.StatusInternalServerError, err)
|
ctx.StopWithError(iris.StatusInternalServerError, err)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
|
@ -69,7 +69,7 @@ func TestContentNegotiation(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawResponse, err := ioutil.ReadAll(zr)
|
rawResponse, err := io.ReadAll(zr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ import (
|
||||||
"github.com/kataras/iris/v12/core/router"
|
"github.com/kataras/iris/v12/core/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* A Router should contain all three of the following methods:
|
/*
|
||||||
|
A Router should contain all three of the following methods:
|
||||||
- HandleRequest should handle the request based on the Context.
|
- HandleRequest should handle the request based on the Context.
|
||||||
HandleRequest(ctx iris.Context)
|
HandleRequest(ctx iris.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.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -29,7 +29,7 @@ func (r resource) loadFromBase(dir string) string {
|
||||||
|
|
||||||
fullpath := filepath.Join(dir, filename)
|
fullpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(fullpath)
|
b, err := os.ReadFile(fullpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fullpath + " failed with error: " + err.Error())
|
panic(fullpath + " failed with error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/*Package main is a simple example of the behavior change of the execution flow of the handlers,
|
/*
|
||||||
|
Package main is a simple example of the behavior change of the execution flow of the handlers,
|
||||||
normally we need the `ctx.Next()` to call the next handler in a route's handler chain,
|
normally we need the `ctx.Next()` to call the next handler in a route's handler chain,
|
||||||
but with the `ExecutionRules` we can change this default behavior.
|
but with the `ExecutionRules` we can change this default behavior.
|
||||||
Please read below before continue.
|
Please read below before continue.
|
||||||
|
@ -8,11 +9,11 @@ The `Party#SetExecutionRules` alters the execution flow of the route handlers.
|
||||||
For example, if for some reason the desired result is the (done or all) handlers
|
For example, if for some reason the desired result is the (done or all) handlers
|
||||||
to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers:
|
to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers:
|
||||||
|
|
||||||
app.SetExecutionRules(iris.ExecutionRules {
|
app.SetExecutionRules(iris.ExecutionRules {
|
||||||
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
|
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
|
||||||
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
|
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
|
||||||
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
|
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
|
||||||
})
|
})
|
||||||
|
|
||||||
Note that if `true` then the only remained way to "break" the handler chain
|
Note that if `true` then the only remained way to "break" the handler chain
|
||||||
is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter).
|
is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter).
|
||||||
|
@ -22,7 +23,6 @@ the same rules will be applied to that as well.
|
||||||
|
|
||||||
Reset of these rules to their defaults (before `Party#Handle`) can be done
|
Reset of these rules to their defaults (before `Party#Handle`) can be done
|
||||||
with `Party#SetExecutionRules(iris.ExecutionRules{})`.
|
with `Party#SetExecutionRules(iris.ExecutionRules{})`.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,7 +13,7 @@ import (
|
||||||
// The rest possible checks is up to you, take it as as an exercise!
|
// The rest possible checks is up to you, take it as as an exercise!
|
||||||
func TestURLShortener(t *testing.T) {
|
func TestURLShortener(t *testing.T) {
|
||||||
// temp db file
|
// temp db file
|
||||||
f, err := ioutil.TempFile("", "shortener")
|
f, err := os.CreateTemp("", "shortener")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("creating temp file for database failed: %v", err)
|
t.Fatalf("creating temp file for database failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
// Code generated by go-bindata. (@generated) DO NOT EDIT.
|
||||||
|
|
||||||
//Package main generated by go-bindata.// sources:
|
// Package main generated by go-bindata.// sources:
|
||||||
// templates/layouts/layout.html
|
// templates/layouts/layout.html
|
||||||
// templates/layouts/mylayout.html
|
// templates/layouts/mylayout.html
|
||||||
// templates/page1.html
|
// templates/page1.html
|
||||||
|
@ -12,7 +12,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -323,7 +324,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -332,11 +331,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -394,7 +395,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
|
//
|
||||||
// data/
|
// data/
|
||||||
// foo.txt
|
// foo.txt
|
||||||
// img/
|
// img/
|
||||||
// a.png
|
// a.png
|
||||||
// b.png
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
|
||||||
|
@ -321,7 +322,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -53,7 +52,7 @@ func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
|
||||||
if !fi.ModTime().After(lastMod) {
|
if !fi.ModTime().After(lastMod) {
|
||||||
return nil, lastMod, nil
|
return nil, lastMod, nil
|
||||||
}
|
}
|
||||||
p, err := ioutil.ReadFile(filename)
|
p, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fi.ModTime(), err
|
return nil, fi.ModTime(), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// The cases are filtered in order of their registration.
|
// The cases are filtered in order of their registration.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
|
//
|
||||||
// switcher := Switch(Hosts{
|
// switcher := Switch(Hosts{
|
||||||
// "mydomain.com": app,
|
// "mydomain.com": app,
|
||||||
// "test.mydomain.com": testSubdomainApp,
|
// "test.mydomain.com": testSubdomainApp,
|
||||||
|
|
|
@ -99,6 +99,7 @@ func MustLoad[T User](filename string) *Auth[T] {
|
||||||
// Must is a helper that wraps a call to a function returning (*Auth[T], error)
|
// Must is a helper that wraps a call to a function returning (*Auth[T], error)
|
||||||
// and panics if the error is non-nil. It is intended for use in variable
|
// and panics if the error is non-nil. It is intended for use in variable
|
||||||
// initializations such as
|
// initializations such as
|
||||||
|
//
|
||||||
// var s = auth.Must(auth.New[MyUser](config))
|
// var s = auth.Must(auth.New[MyUser](config))
|
||||||
func Must[T User](s *Auth[T], err error) *Auth[T] {
|
func Must[T User](s *Auth[T], err error) *Auth[T] {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -142,6 +143,7 @@ func New[T User](config Configuration) (*Auth[T], error) {
|
||||||
// method when a Provider of T and ErrorHandler is available through the registered Party's dependencies.
|
// method when a Provider of T and ErrorHandler is available through the registered Party's dependencies.
|
||||||
//
|
//
|
||||||
// Usage Example:
|
// Usage Example:
|
||||||
|
//
|
||||||
// api := app.Party("/api")
|
// api := app.Party("/api")
|
||||||
// api.EnsureStaticBindings().RegisterDependency(
|
// api.EnsureStaticBindings().RegisterDependency(
|
||||||
// NewAuthProviderErrorHandler(),
|
// NewAuthProviderErrorHandler(),
|
||||||
|
|
1
cache/browser.go
vendored
1
cache/browser.go
vendored
|
@ -49,6 +49,7 @@ var NoCache = func(ctx *context.Context) {
|
||||||
// Usage: `app.Use(cache.StaticCache(24 * time.Hour))` or `app.Use(cache.Staticcache(-1))`.
|
// Usage: `app.Use(cache.StaticCache(24 * time.Hour))` or `app.Use(cache.Staticcache(-1))`.
|
||||||
// A middleware, which is a simple Handler can be called inside another handler as well, example:
|
// A middleware, which is a simple Handler can be called inside another handler as well, example:
|
||||||
// cacheMiddleware := cache.StaticCache(...)
|
// cacheMiddleware := cache.StaticCache(...)
|
||||||
|
//
|
||||||
// func(ctx iris.Context){
|
// func(ctx iris.Context){
|
||||||
// cacheMiddleware(ctx)
|
// cacheMiddleware(ctx)
|
||||||
// [...]
|
// [...]
|
||||||
|
|
6
cache/client/client.go
vendored
6
cache/client/client.go
vendored
|
@ -2,7 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ import (
|
||||||
// register one client handler per route.
|
// register one client handler per route.
|
||||||
//
|
//
|
||||||
// it's just calls a remote cache service server/handler,
|
// it's just calls a remote cache service server/handler,
|
||||||
// which lives on other, external machine.
|
|
||||||
//
|
//
|
||||||
|
// which lives on other, external machine.
|
||||||
type ClientHandler struct {
|
type ClientHandler struct {
|
||||||
// bodyHandler the original route's handler
|
// bodyHandler the original route's handler
|
||||||
bodyHandler context.Handler
|
bodyHandler context.Handler
|
||||||
|
@ -162,7 +162,7 @@ func (h *ClientHandler) ServeHTTP(ctx *context.Context) {
|
||||||
// get the status code , content type and the write the response body
|
// get the status code , content type and the write the response body
|
||||||
ctx.ContentType(response.Header.Get(cfg.ContentTypeHeader))
|
ctx.ContentType(response.Header.Get(cfg.ContentTypeHeader))
|
||||||
ctx.StatusCode(response.StatusCode)
|
ctx.StatusCode(response.StatusCode)
|
||||||
responseBody, err := ioutil.ReadAll(response.Body)
|
responseBody, err := io.ReadAll(response.Body)
|
||||||
response.Body.Close()
|
response.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
1
cache/client/rule/validator.go
vendored
1
cache/client/rule/validator.go
vendored
|
@ -22,6 +22,7 @@ type PreValidator func(*context.Context) bool
|
||||||
//
|
//
|
||||||
// Q: What's the difference between this and a PreValidator?
|
// Q: What's the difference between this and a PreValidator?
|
||||||
// A: PreValidator runs BEFORE trying to get the cache, it cares only for the request
|
// A: PreValidator runs BEFORE trying to get the cache, it cares only for the request
|
||||||
|
//
|
||||||
// and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
|
// and if at least one PreValidator returns false then it just runs the original handler and stop there, at the other hand
|
||||||
// a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
|
// a PostValidator runs if all PreValidators returns true and original handler is executed but with a response recorder,
|
||||||
// also the PostValidator should return true to store the cached response.
|
// also the PostValidator should return true to store the cached response.
|
||||||
|
|
|
@ -2,7 +2,6 @@ package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -65,7 +64,7 @@ func parseYAML(filename string) (Configuration, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the raw contents of the file
|
// read the raw contents of the file
|
||||||
data, err := ioutil.ReadFile(yamlAbsPath)
|
data, err := os.ReadFile(yamlAbsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c, fmt.Errorf("parse yaml: %w", err)
|
return c, fmt.Errorf("parse yaml: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -112,7 +111,6 @@ func YAML(filename string) Configuration {
|
||||||
// Read more about toml's implementation at:
|
// Read more about toml's implementation at:
|
||||||
// https://github.com/toml-lang/toml
|
// https://github.com/toml-lang/toml
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Accepts the absolute path of the configuration file.
|
// Accepts the absolute path of the configuration file.
|
||||||
// An error will be shown to the user via panic with the error message.
|
// An error will be shown to the user via panic with the error message.
|
||||||
// Error may occur when the file does not exist or is not formatted correctly.
|
// Error may occur when the file does not exist or is not formatted correctly.
|
||||||
|
@ -144,7 +142,7 @@ func TOML(filename string) Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the raw contents of the file
|
// read the raw contents of the file
|
||||||
data, err := ioutil.ReadFile(tomlAbsPath)
|
data, err := os.ReadFile(tomlAbsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("toml :%w", err))
|
panic(fmt.Errorf("toml :%w", err))
|
||||||
}
|
}
|
||||||
|
@ -754,6 +752,7 @@ type Configuration struct {
|
||||||
// then the application tries to optimize for the best performance where is possible.
|
// then the application tries to optimize for the best performance where is possible.
|
||||||
//
|
//
|
||||||
// Defaults to false.
|
// Defaults to false.
|
||||||
|
// Deprecated. As of version 12.2.x this field does nothing.
|
||||||
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
EnableOptimizations bool `ini:"enable_optimizations" json:"enableOptimizations,omitempty" yaml:"EnableOptimizations" toml:"EnableOptimizations"`
|
||||||
// EnableProtoJSON when this field is true
|
// EnableProtoJSON when this field is true
|
||||||
// enables the proto marshaler on given proto messages when calling the Context.JSON method.
|
// enables the proto marshaler on given proto messages when calling the Context.JSON method.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -103,7 +102,7 @@ func createGlobalConfiguration(t *testing.T) {
|
||||||
out, err := yaml.Marshal(&c)
|
out, err := yaml.Marshal(&c)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(filename, out, os.FileMode(0666))
|
err = os.WriteFile(filename, out, os.FileMode(0666))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err)
|
t.Fatalf("error while writing the global configuration field at: %s. Trace: %v\n", filename, err)
|
||||||
|
@ -131,7 +130,7 @@ func testConfigurationGlobal(t *testing.T, c Configurator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigurationYAML(t *testing.T) {
|
func TestConfigurationYAML(t *testing.T) {
|
||||||
yamlFile, ferr := ioutil.TempFile("", "configuration.yml")
|
yamlFile, ferr := os.CreateTemp("", "configuration.yml")
|
||||||
|
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
t.Fatal(ferr)
|
t.Fatal(ferr)
|
||||||
|
@ -264,7 +263,7 @@ Other:
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigurationTOML(t *testing.T) {
|
func TestConfigurationTOML(t *testing.T) {
|
||||||
tomlFile, ferr := ioutil.TempFile("", "configuration.toml")
|
tomlFile, ferr := os.CreateTemp("", "configuration.toml")
|
||||||
|
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
t.Fatal(ferr)
|
t.Fatal(ferr)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
"mime"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net"
|
"net"
|
||||||
|
@ -31,7 +30,6 @@ import (
|
||||||
|
|
||||||
"github.com/Shopify/goreferrer"
|
"github.com/Shopify/goreferrer"
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
gojson "github.com/goccy/go-json"
|
|
||||||
"github.com/iris-contrib/schema"
|
"github.com/iris-contrib/schema"
|
||||||
"github.com/mailru/easyjson"
|
"github.com/mailru/easyjson"
|
||||||
"github.com/mailru/easyjson/jwriter"
|
"github.com/mailru/easyjson/jwriter"
|
||||||
|
@ -100,7 +98,7 @@ type (
|
||||||
// is terminated and the error is received by the ReadJSONStream method,
|
// is terminated and the error is received by the ReadJSONStream method,
|
||||||
// otherwise it continues to read the next available object.
|
// otherwise it continues to read the next available object.
|
||||||
// Look the `Context.ReadJSONStream` method.
|
// Look the `Context.ReadJSONStream` method.
|
||||||
DecodeFunc func(ctx stdContext.Context, outPtr interface{}) error
|
DecodeFunc func(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.
|
||||||
|
@ -539,7 +537,6 @@ func (ctx *Context) Do(handlers Handlers) {
|
||||||
// Router is calling this function to add the route's handler.
|
// Router is calling this function to add the route's handler.
|
||||||
// If AddHandler called then the handlers will be inserted
|
// If AddHandler called then the handlers will be inserted
|
||||||
// to the end of the already-defined route's handler.
|
// to the end of the already-defined route's handler.
|
||||||
//
|
|
||||||
func (ctx *Context) AddHandler(handlers ...Handler) {
|
func (ctx *Context) AddHandler(handlers ...Handler) {
|
||||||
ctx.handlers = append(ctx.handlers, handlers...)
|
ctx.handlers = append(ctx.handlers, handlers...)
|
||||||
}
|
}
|
||||||
|
@ -601,12 +598,15 @@ func (ctx *Context) HandlerIndex(n int) (currentIndex int) {
|
||||||
// ctx.StopExecution()
|
// ctx.StopExecution()
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// This Get() will be executed in the same handler as `BeginRequest`,
|
// This Get() will be executed in the same handler as `BeginRequest`,
|
||||||
// internally controller checks for `ctx.StopExecution`.
|
// internally controller checks for `ctx.StopExecution`.
|
||||||
// So it will not be fired if BeginRequest called the `StopExecution`.
|
// So it will not be fired if BeginRequest called the `StopExecution`.
|
||||||
|
//
|
||||||
// func(c *UsersController) Get() []models.User {
|
// func(c *UsersController) Get() []models.User {
|
||||||
// return c.Service.GetAll()
|
// return c.Service.GetAll()
|
||||||
//}
|
// }
|
||||||
|
//
|
||||||
// Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
|
// Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
|
||||||
func (ctx *Context) Proceed(h Handler) bool {
|
func (ctx *Context) Proceed(h Handler) bool {
|
||||||
_, ok := ctx.ProceedAndReportIfStopped(h)
|
_, ok := ctx.ProceedAndReportIfStopped(h)
|
||||||
|
@ -841,8 +841,7 @@ func (ctx *Context) StopWithPlainError(statusCode int, err error) {
|
||||||
// it will also fire the specified error code handler.
|
// it will also fire the specified error code handler.
|
||||||
func (ctx *Context) StopWithJSON(statusCode int, jsonObject interface{}) error {
|
func (ctx *Context) StopWithJSON(statusCode int, jsonObject interface{}) error {
|
||||||
ctx.StopWithStatus(statusCode)
|
ctx.StopWithStatus(statusCode)
|
||||||
_, err := ctx.writeJSON(jsonObject, nil) // do not modify - see errors.DefaultContextErrorHandler.
|
return ctx.writeJSON(jsonObject, nil) // do not modify - see errors.DefaultContextErrorHandler.
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopWithProblem stops the handlers chain, writes the status code
|
// StopWithProblem stops the handlers chain, writes the status code
|
||||||
|
@ -854,8 +853,7 @@ func (ctx *Context) StopWithJSON(statusCode int, jsonObject interface{}) error {
|
||||||
func (ctx *Context) StopWithProblem(statusCode int, problem Problem) error {
|
func (ctx *Context) StopWithProblem(statusCode int, problem Problem) error {
|
||||||
ctx.StopWithStatus(statusCode)
|
ctx.StopWithStatus(statusCode)
|
||||||
problem.Status(statusCode)
|
problem.Status(statusCode)
|
||||||
_, err := ctx.Problem(problem)
|
return ctx.Problem(problem)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
@ -939,7 +937,7 @@ func (ctx *Context) RequestPath(escape bool) string {
|
||||||
|
|
||||||
const sufscheme = "://"
|
const sufscheme = "://"
|
||||||
|
|
||||||
// GetScheme returns the full scheme of the request URL (https://, http:// or ws:// and e.t.c.``).
|
// GetScheme returns the full scheme of the request URL (https://, http:// or ws:// and e.t.c.).
|
||||||
func GetScheme(r *http.Request) string {
|
func GetScheme(r *http.Request) string {
|
||||||
scheme := r.URL.Scheme
|
scheme := r.URL.Scheme
|
||||||
|
|
||||||
|
@ -1111,10 +1109,11 @@ func (ctx *Context) FullRequestURI() string {
|
||||||
// even if it's part of a private network.
|
// even if it's part of a private network.
|
||||||
//
|
//
|
||||||
// Look `Configuration.RemoteAddrHeaders`,
|
// Look `Configuration.RemoteAddrHeaders`,
|
||||||
// `Configuration.RemoteAddrHeadersForce`,
|
//
|
||||||
// `Configuration.WithRemoteAddrHeader(...)`,
|
// Configuration.RemoteAddrHeadersForce,
|
||||||
// `Configuration.WithoutRemoteAddrHeader(...)` and
|
// Configuration.WithRemoteAddrHeader(...),
|
||||||
// `Configuration.RemoteAddrPrivateSubnets` for more.
|
// Configuration.WithoutRemoteAddrHeader(...) and
|
||||||
|
// Configuration.RemoteAddrPrivateSubnetsW for more.
|
||||||
func (ctx *Context) RemoteAddr() string {
|
func (ctx *Context) RemoteAddr() string {
|
||||||
if remoteHeaders := ctx.app.ConfigurationReadOnly().GetRemoteAddrHeaders(); len(remoteHeaders) > 0 {
|
if remoteHeaders := ctx.app.ConfigurationReadOnly().GetRemoteAddrHeaders(); len(remoteHeaders) > 0 {
|
||||||
privateSubnets := ctx.app.ConfigurationReadOnly().GetRemoteAddrPrivateSubnets()
|
privateSubnets := ctx.app.ConfigurationReadOnly().GetRemoteAddrPrivateSubnets()
|
||||||
|
@ -1176,7 +1175,7 @@ func (ctx *Context) GetHeader(name string) string {
|
||||||
// try to find another way of detecting the type(i.e, content type),
|
// try to find another way of detecting the type(i.e, content type),
|
||||||
// there are many blogs that describe these problems and provide different kind of solutions,
|
// there are many blogs that describe these problems and provide different kind of solutions,
|
||||||
// it's always depending on the application you're building,
|
// it's always depending on the application you're building,
|
||||||
// this is the reason why this `IsAjax`` is simple enough for general purpose use.
|
// this is the reason why this `IsAjax` is simple enough for general purpose use.
|
||||||
//
|
//
|
||||||
// Read more at: https://developer.mozilla.org/en-US/docs/AJAX
|
// Read more at: https://developer.mozilla.org/en-US/docs/AJAX
|
||||||
// and https://xhr.spec.whatwg.org/
|
// and https://xhr.spec.whatwg.org/
|
||||||
|
@ -1557,9 +1556,11 @@ func (ctx *Context) URLParamEscape(name string) string {
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// n, err := context.URLParamInt("url_query_param_name")
|
// n, err := context.URLParamInt("url_query_param_name")
|
||||||
|
//
|
||||||
// if errors.Is(err, context.ErrNotFound) {
|
// if errors.Is(err, context.ErrNotFound) {
|
||||||
// // [handle error...]
|
// // [handle error...]
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// Another usage would be `err == context.ErrNotFound`
|
// Another usage would be `err == context.ErrNotFound`
|
||||||
// HOWEVER prefer use the new `errors.Is` as API details may change in the future.
|
// HOWEVER prefer use the new `errors.Is` as API details may change in the future.
|
||||||
var ErrNotFound = errors.New("not found")
|
var ErrNotFound = errors.New("not found")
|
||||||
|
@ -1816,7 +1817,7 @@ func GetForm(r *http.Request, postMaxMemory int64, resetBody bool) (form map[str
|
||||||
setBody(r, body) // so the ctx.request.Body works
|
setBody(r, body) // so the ctx.request.Body works
|
||||||
defer restoreBody() // so the next GetForm calls work.
|
defer restoreBody() // so the next GetForm calls work.
|
||||||
|
|
||||||
// r.Body = ioutil.NopCloser(io.TeeReader(r.Body, buf))
|
// r.Body = io.NopCloser(io.TeeReader(r.Body, buf))
|
||||||
} else {
|
} else {
|
||||||
resetBody = false
|
resetBody = false
|
||||||
}
|
}
|
||||||
|
@ -1828,7 +1829,7 @@ func GetForm(r *http.Request, postMaxMemory int64, resetBody bool) (form map[str
|
||||||
// subsequent calls have no effect, are idempotent.
|
// subsequent calls have no effect, are idempotent.
|
||||||
err := r.ParseMultipartForm(postMaxMemory)
|
err := r.ParseMultipartForm(postMaxMemory)
|
||||||
// if resetBody {
|
// if resetBody {
|
||||||
// r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyCopy))
|
// r.Body = io.NopCloser(bytes.NewBuffer(bodyCopy))
|
||||||
// }
|
// }
|
||||||
if err != nil && err != http.ErrNotMultipart {
|
if err != nil && err != http.ErrNotMultipart {
|
||||||
return nil, false
|
return nil, false
|
||||||
|
@ -2037,7 +2038,6 @@ func (ctx *Context) PostValueBool(name string) (bool, error) {
|
||||||
|
|
||||||
// FormFile returns the first uploaded file that received from the client.
|
// FormFile returns the first uploaded file that received from the client.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
|
@ -2284,7 +2284,7 @@ var emptyFunc = func() {}
|
||||||
|
|
||||||
// GetBody reads and returns the request body.
|
// GetBody reads and returns the request body.
|
||||||
func GetBody(r *http.Request, resetBody bool) ([]byte, func(), error) {
|
func GetBody(r *http.Request, resetBody bool) ([]byte, func(), error) {
|
||||||
data, err := ioutil.ReadAll(r.Body)
|
data, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -2301,7 +2301,7 @@ func GetBody(r *http.Request, resetBody bool) ([]byte, func(), error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setBody(r *http.Request, data []byte) {
|
func setBody(r *http.Request, data []byte) {
|
||||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(data))
|
r.Body = io.NopCloser(bytes.NewBuffer(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
const disableRequestBodyConsumptionContextKey = "iris.request.body.record"
|
const disableRequestBodyConsumptionContextKey = "iris.request.body.record"
|
||||||
|
@ -2385,10 +2385,6 @@ func (ctx *Context) UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) e
|
||||||
return ctx.app.Validate(outPtr)
|
return ctx.app.Validate(outPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) shouldOptimize() bool {
|
|
||||||
return ctx.app.ConfigurationReadOnly().GetEnableOptimizations()
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONReader holds the JSON decode options of the `Context.ReadJSON, ReadBody` methods.
|
// JSONReader holds the JSON decode options of the `Context.ReadJSON, ReadBody` methods.
|
||||||
type JSONReader struct { // Note(@kataras): struct instead of optional funcs to keep consistently with the encoder options.
|
type JSONReader struct { // Note(@kataras): struct instead of optional funcs to keep consistently with the encoder options.
|
||||||
// DisallowUnknownFields causes the json decoder to return an error when the destination
|
// DisallowUnknownFields causes the json decoder to return an error when the destination
|
||||||
|
@ -2413,123 +2409,31 @@ type JSONReader struct { // Note(@kataras): struct instead of optional funcs to
|
||||||
// {"username": "makis"}
|
// {"username": "makis"}
|
||||||
// {"username": "george"}
|
// {"username": "george"}
|
||||||
ArrayStream bool
|
ArrayStream bool
|
||||||
|
|
||||||
// Optional context cancelation of decoder when Optimize field is enabled.
|
|
||||||
// On ReadJSON method this is automatically binded to the request context.
|
|
||||||
Context stdContext.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type internalJSONDecoder interface {
|
var ReadJSON = func(ctx *Context, outPtr interface{}, opts ...JSONReader) error {
|
||||||
Token() (json.Token, error) // gojson.Token is an alias of this, so we are ok.
|
decoder := json.NewDecoder(ctx.request.Body)
|
||||||
More() bool
|
// decoder := gojson.NewDecoder(ctx.Request().Body)
|
||||||
DisallowUnknownFields()
|
if len(opts) > 0 {
|
||||||
}
|
options := opts[0]
|
||||||
|
|
||||||
type unmarshalerContext interface {
|
|
||||||
// UnmarshalJSON unmarshal json with context support.
|
|
||||||
UnmarshalJSON(stdContext.Context, []byte) error //lint:ignore stdmethods external pkg.
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapDecodeFunc(decodeFunc func(interface{}) error) DecodeFunc {
|
|
||||||
return func(_ stdContext.Context, outPtr interface{}) error {
|
|
||||||
return decodeFunc(outPtr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (options JSONReader) unmarshal(ctx stdContext.Context, body []byte, outPtr interface{}) error {
|
|
||||||
if options.Optimize {
|
|
||||||
if outPtr != nil {
|
|
||||||
if _, supportsContext := outPtr.(unmarshalerContext); !supportsContext {
|
|
||||||
return gojson.Unmarshal(body, outPtr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return gojson.UnmarshalContext(ctx, body, outPtr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Unmarshal(body, outPtr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (options JSONReader) getDecoder(r io.Reader, outPtr interface{}) (internalJSONDecoder, DecodeFunc) {
|
|
||||||
var (
|
|
||||||
decoder internalJSONDecoder
|
|
||||||
decodeFunc DecodeFunc
|
|
||||||
)
|
|
||||||
|
|
||||||
if options.Optimize {
|
|
||||||
dec := gojson.NewDecoder(r)
|
|
||||||
|
|
||||||
if outPtr != nil {
|
|
||||||
// If a custom type does not implement the unnmarshal json with context interface
|
|
||||||
// that is REQUIRED by the gojson, then fallback to the normal gojson decode without context support,
|
|
||||||
// so we protect compatibility against existing objects.
|
|
||||||
if _, supportsContext := outPtr.(unmarshalerContext); supportsContext {
|
|
||||||
decodeFunc = dec.DecodeContext
|
|
||||||
} else {
|
|
||||||
decodeFunc = wrapDecodeFunc(dec.Decode)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
decodeFunc = dec.DecodeContext
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder = dec
|
|
||||||
} else {
|
|
||||||
dec := json.NewDecoder(r)
|
|
||||||
decodeFunc = wrapDecodeFunc(dec.Decode)
|
|
||||||
decoder = dec
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.DisallowUnknownFields {
|
if options.DisallowUnknownFields {
|
||||||
decoder.DisallowUnknownFields()
|
decoder.DisallowUnknownFields()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return decoder, decodeFunc
|
if err := decoder.Decode(&outPtr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.app.Validate(outPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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/request-body/read-json/main.go
|
// Example: https://github.com/kataras/iris/blob/master/_examples/request-body/read-json/main.go
|
||||||
func (ctx *Context) ReadJSON(outPtr interface{}, opts ...JSONReader) error {
|
func (ctx *Context) ReadJSON(outPtr interface{}, opts ...JSONReader) error {
|
||||||
var options JSONReader
|
return ReadJSON(ctx, outPtr, opts...)
|
||||||
options.Optimize = ctx.shouldOptimize()
|
|
||||||
|
|
||||||
if len(opts) > 0 {
|
|
||||||
options = opts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.IsRecordingBody() {
|
|
||||||
body, restoreBody, err := GetBody(ctx.request, true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
restoreBody()
|
|
||||||
|
|
||||||
err = options.unmarshal(ctx.request.Context(), body, outPtr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, decodeFunc := options.getDecoder(ctx.request.Body, outPtr)
|
|
||||||
err := decodeFunc(ctx.request.Context(), outPtr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.app.Validate(outPtr)
|
|
||||||
|
|
||||||
/*
|
|
||||||
b, err := ctx.GetBody()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.Optimize {
|
|
||||||
return gojson.UnmarshalContext(ctx.request.Context(), b, outPtr)
|
|
||||||
} else {
|
|
||||||
return json.Unmarshal(b, outPtr)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadJSONStream is an alternative of ReadJSON which can reduce the memory load
|
// ReadJSONStream is an alternative of ReadJSON which can reduce the memory load
|
||||||
|
@ -2543,21 +2447,16 @@ func (ctx *Context) ReadJSON(outPtr interface{}, opts ...JSONReader) error {
|
||||||
//
|
//
|
||||||
// Example: https://github.com/kataras/iris/blob/master/_examples/request-body/read-json-stream/main.go
|
// Example: https://github.com/kataras/iris/blob/master/_examples/request-body/read-json-stream/main.go
|
||||||
func (ctx *Context) ReadJSONStream(onDecode func(DecodeFunc) error, opts ...JSONReader) error {
|
func (ctx *Context) ReadJSONStream(onDecode func(DecodeFunc) error, opts ...JSONReader) error {
|
||||||
var options JSONReader
|
decoder := json.NewDecoder(ctx.request.Body)
|
||||||
if len(opts) > 0 {
|
|
||||||
options = opts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, decodeFunc := options.getDecoder(ctx.request.Body, nil)
|
if len(opts) > 0 && opts[0].ArrayStream {
|
||||||
|
|
||||||
if options.ArrayStream {
|
|
||||||
_, err := decoder.Token() // read open bracket.
|
_, err := decoder.Token() // read open bracket.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for decoder.More() { // hile the array contains values.
|
for decoder.More() { // hile the array contains values.
|
||||||
if err = onDecode(decodeFunc); err != nil {
|
if err = onDecode(decoder.Decode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2568,7 +2467,7 @@ func (ctx *Context) ReadJSONStream(onDecode func(DecodeFunc) error, opts ...JSON
|
||||||
|
|
||||||
// while the array contains values
|
// while the array contains values
|
||||||
for decoder.More() {
|
for decoder.More() {
|
||||||
if err := onDecode(decodeFunc); err != nil {
|
if err := onDecode(decoder.Decode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2788,7 +2687,7 @@ func (ctx *Context) ReadMultipartRelated() (MultipartRelated, error) {
|
||||||
}
|
}
|
||||||
defer part.Close()
|
defer part.Close()
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(part)
|
b, err := io.ReadAll(part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MultipartRelated{}, fmt.Errorf("multipart related: next part: read: %w", err)
|
return MultipartRelated{}, fmt.Errorf("multipart related: next part: read: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -3149,6 +3048,7 @@ func (ctx *Context) SetLastModified(modtime time.Time) {
|
||||||
// that has to perform one or more client side preconditions before the actual check, e.g. `CheckIfModifiedSince`.
|
// that has to perform one or more client side preconditions before the actual check, e.g. `CheckIfModifiedSince`.
|
||||||
// Usage:
|
// Usage:
|
||||||
// ok, err := context.CheckIfModifiedSince(modTime)
|
// ok, err := context.CheckIfModifiedSince(modTime)
|
||||||
|
//
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// if errors.Is(err, context.ErrPreconditionFailed) {
|
// if errors.Is(err, context.ErrPreconditionFailed) {
|
||||||
// [handle missing client conditions,such as not valid request method...]
|
// [handle missing client conditions,such as not valid request method...]
|
||||||
|
@ -3232,9 +3132,9 @@ func (ctx *Context) WriteWithExpiration(body []byte, modtime time.Time) (int, er
|
||||||
//
|
//
|
||||||
// This function may be used in the following cases:
|
// This function may be used in the following cases:
|
||||||
//
|
//
|
||||||
// * if response body is too big (more than iris.LimitRequestBodySize(if set)).
|
// - if response body is too big (more than iris.LimitRequestBodySize(if set)).
|
||||||
// * if response body is streamed from slow external sources.
|
// - if response body is streamed from slow external sources.
|
||||||
// * if response body must be streamed to the client in chunks.
|
// - if response body must be streamed to the client in chunks.
|
||||||
// (aka `http server push`).
|
// (aka `http server push`).
|
||||||
func (ctx *Context) StreamWriter(writer func(w io.Writer) error) error {
|
func (ctx *Context) StreamWriter(writer func(w io.Writer) error) error {
|
||||||
cancelCtx := ctx.Request().Context()
|
cancelCtx := ctx.Request().Context()
|
||||||
|
@ -3287,10 +3187,12 @@ func (ctx *Context) ClientSupportsEncoding(encodings ...string) bool {
|
||||||
// will change the response writer to a compress writer instead.
|
// will change the response writer to a compress writer instead.
|
||||||
// All future write and rich write methods will respect this option.
|
// All future write and rich write methods will respect this option.
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// app.Use(func(ctx iris.Context){
|
// app.Use(func(ctx iris.Context){
|
||||||
// err := ctx.CompressWriter(true)
|
// err := ctx.CompressWriter(true)
|
||||||
// ctx.Next()
|
// ctx.Next()
|
||||||
// })
|
// })
|
||||||
|
//
|
||||||
// The recommendation is to compress data as much as possible and therefore to use this field,
|
// The recommendation is to compress data as much as possible and therefore to use this field,
|
||||||
// but some types of resources, such as jpeg images, are already compressed.
|
// but some types of resources, such as jpeg images, are already compressed.
|
||||||
// Sometimes, using additional compression doesn't reduce payload size and
|
// Sometimes, using additional compression doesn't reduce payload size and
|
||||||
|
@ -3350,11 +3252,14 @@ func (ctx *Context) CompressWriter(enable bool) error {
|
||||||
// All future calls of `ctx.GetBody/ReadXXX/UnmarshalBody` methods will respect this option.
|
// All future calls of `ctx.GetBody/ReadXXX/UnmarshalBody` methods will respect this option.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// app.Use(func(ctx iris.Context){
|
// app.Use(func(ctx iris.Context){
|
||||||
// err := ctx.CompressReader(true)
|
// err := ctx.CompressReader(true)
|
||||||
// ctx.Next()
|
// ctx.Next()
|
||||||
// })
|
// })
|
||||||
|
//
|
||||||
// More:
|
// More:
|
||||||
|
//
|
||||||
// if cr, ok := ctx.Request().Body.(*CompressReader); ok {
|
// if cr, ok := ctx.Request().Body.(*CompressReader); ok {
|
||||||
// cr.Src // the original request body
|
// cr.Src // the original request body
|
||||||
// cr.Encoding // the compression algorithm.
|
// cr.Encoding // the compression algorithm.
|
||||||
|
@ -3592,6 +3497,7 @@ func (ctx *Context) fireFallbackViewOnce(err ErrViewNotExist) error {
|
||||||
// is responsible to handle the error or render a different view.
|
// is responsible to handle the error or render a different view.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// FallbackView(iris.FallbackView("fallback.html"))
|
// FallbackView(iris.FallbackView("fallback.html"))
|
||||||
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
||||||
// OR
|
// OR
|
||||||
|
@ -3749,8 +3655,6 @@ type ProtoMarshalOptions = protojson.MarshalOptions
|
||||||
|
|
||||||
// JSON contains the options for the JSON (Context's) Renderer.
|
// JSON contains the options for the JSON (Context's) Renderer.
|
||||||
type JSON struct {
|
type JSON struct {
|
||||||
// http-specific
|
|
||||||
StreamingJSON bool `yaml:"StreamingJSON"`
|
|
||||||
// content-specific
|
// content-specific
|
||||||
UnescapeHTML bool `yaml:"UnescapeHTML"`
|
UnescapeHTML bool `yaml:"UnescapeHTML"`
|
||||||
Indent string `yaml:"Indent"`
|
Indent string `yaml:"Indent"`
|
||||||
|
@ -3772,8 +3676,7 @@ var DefaultJSONOptions = JSON{}
|
||||||
|
|
||||||
// IsDefault reports whether this JSON options structure holds the default values.
|
// IsDefault reports whether this JSON options structure holds the default values.
|
||||||
func (j *JSON) IsDefault() bool {
|
func (j *JSON) IsDefault() bool {
|
||||||
return j.StreamingJSON == DefaultJSONOptions.StreamingJSON &&
|
return j.UnescapeHTML == DefaultJSONOptions.UnescapeHTML &&
|
||||||
j.UnescapeHTML == DefaultJSONOptions.UnescapeHTML &&
|
|
||||||
j.Indent == DefaultJSONOptions.Indent &&
|
j.Indent == DefaultJSONOptions.Indent &&
|
||||||
j.Prefix == DefaultJSONOptions.Prefix &&
|
j.Prefix == DefaultJSONOptions.Prefix &&
|
||||||
j.ASCII == DefaultJSONOptions.ASCII &&
|
j.ASCII == DefaultJSONOptions.ASCII &&
|
||||||
|
@ -3858,28 +3761,24 @@ func (ctx *Context) handleSpecialJSONResponseValue(v interface{}, options *JSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
|
// WriteJSON marshals the given interface object and writes the JSON response to the 'writer'.
|
||||||
func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options *JSON, shouldOptimize bool) (int, error) {
|
var WriteJSON = func(ctx *Context, v interface{}, options *JSON) error {
|
||||||
if options.StreamingJSON {
|
if !options.Secure && !options.ASCII && options.Prefix == "" {
|
||||||
var err error
|
|
||||||
if shouldOptimize {
|
|
||||||
// jsoniterConfig := jsoniter.Config{
|
// jsoniterConfig := jsoniter.Config{
|
||||||
// EscapeHTML: !options.UnescapeHTML,
|
// EscapeHTML: !options.UnescapeHTML,
|
||||||
// IndentionStep: 4,
|
// IndentionStep: 4,
|
||||||
// }.Froze()
|
// }.Froze()
|
||||||
// enc := jsoniterConfig.NewEncoder(ctx.writer)
|
// enc := jsoniterConfig.NewEncoder(ctx.writer)
|
||||||
// err = enc.Encode(v)
|
// err = enc.Encode(v)
|
||||||
enc := gojson.NewEncoder(writer)
|
//
|
||||||
|
// enc := gojson.NewEncoder(ctx.writer)
|
||||||
|
// enc.SetEscapeHTML(!options.UnescapeHTML)
|
||||||
|
// enc.SetIndent(options.Prefix, options.Indent)
|
||||||
|
// err = enc.EncodeContext(ctx, v)
|
||||||
|
enc := json.NewEncoder(ctx.writer)
|
||||||
enc.SetEscapeHTML(!options.UnescapeHTML)
|
enc.SetEscapeHTML(!options.UnescapeHTML)
|
||||||
enc.SetIndent(options.Prefix, options.Indent)
|
enc.SetIndent(options.Prefix, options.Indent)
|
||||||
err = enc.EncodeContext(ctx, v)
|
|
||||||
} else {
|
|
||||||
enc := json.NewEncoder(writer)
|
|
||||||
enc.SetEscapeHTML(!options.UnescapeHTML)
|
|
||||||
enc.SetIndent(options.Prefix, options.Indent)
|
|
||||||
err = enc.Encode(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, err
|
return enc.Encode(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -3887,35 +3786,15 @@ func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
// Let's keep it as it is.
|
|
||||||
// if !shouldOptimize && options.Indent == "" {
|
|
||||||
// options.Indent = " "
|
|
||||||
// }
|
|
||||||
|
|
||||||
if indent := options.Indent; indent != "" {
|
if indent := options.Indent; indent != "" {
|
||||||
if shouldOptimize {
|
|
||||||
// result,err = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent
|
|
||||||
result, err = gojson.MarshalIndent(v, "", indent)
|
|
||||||
} else {
|
|
||||||
result, err = json.MarshalIndent(v, "", indent)
|
result, err = json.MarshalIndent(v, "", indent)
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, newLineB...)
|
result = append(result, newLineB...)
|
||||||
} else {
|
|
||||||
if shouldOptimize {
|
|
||||||
// result, err = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal
|
|
||||||
if ctx != nil {
|
|
||||||
result, err = gojson.MarshalContext(ctx, v)
|
|
||||||
} else {
|
|
||||||
result, err = gojson.Marshal(v)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
result, err = json.Marshal(v)
|
result, err = json.Marshal(v)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
prependSecure := false
|
prependSecure := false
|
||||||
|
@ -3960,7 +3839,8 @@ func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options
|
||||||
result = append(stringToBytes(prefix), result...)
|
result = append(stringToBytes(prefix), result...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return writer.Write(result)
|
_, err = ctx.Write(result)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://golang.org/src/strings/builder.go#L45
|
// See https://golang.org/src/strings/builder.go#L45
|
||||||
|
@ -4007,25 +3887,27 @@ func (ctx *Context) handleContextError(err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON marshals the given "v" value to JSON and writes the response to the client.
|
// JSON marshals the given "v" value to JSON and writes the response to the client.
|
||||||
// Look the Configuration.EnableProtoJSON/EnableEasyJSON and EnableOptimizations too.
|
// Look the Configuration.EnableProtoJSON and EnableEasyJSON too.
|
||||||
//
|
//
|
||||||
// It reports any JSON parser or write errors back to the caller.
|
// It reports any JSON parser or write errors back to the caller.
|
||||||
// Look the Application.SetContextErrorHandler to override the
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
// default status code 500 with a custom error response.
|
// default status code 500 with a custom error response.
|
||||||
//
|
//
|
||||||
// It can, optionally, accept the JSON structure which may hold customizations over the
|
// Customize the behavior of every `Context.JSON“ can be achieved
|
||||||
// final JSON response but keep in mind that the caller should NOT modify that JSON options
|
// by modifying the package-level `WriteJSON` function on program initilization.
|
||||||
// value in another goroutine while JSON method is still running.
|
func (ctx *Context) JSON(v interface{}, opts ...JSON) (err error) {
|
||||||
func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
|
|
||||||
var options *JSON
|
var options *JSON
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = &opts[0]
|
options = &opts[0]
|
||||||
|
} else {
|
||||||
|
// If no options are given safely read the already-initialized value.
|
||||||
|
options = &DefaultJSONOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
if n, err = ctx.writeJSON(v, options); err != nil {
|
if err = ctx.writeJSON(v, options); err != nil {
|
||||||
// if no options are given or OmitErrorHandler is true
|
// if no options are given or OmitErrorHandler is true
|
||||||
// then do call the error handler (which may lead to a cycle).
|
// then do call the error handler (which may lead to a cycle).
|
||||||
if options == nil || !options.OmitErrorHandler {
|
if !options.OmitErrorHandler {
|
||||||
ctx.handleContextError(err)
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4033,76 +3915,38 @@ func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) writeJSON(v interface{}, options *JSON) (int, error) {
|
func (ctx *Context) writeJSON(v interface{}, options *JSON) error {
|
||||||
ctx.ContentType(ContentJSONHeaderValue)
|
ctx.ContentType(ContentJSONHeaderValue)
|
||||||
|
|
||||||
// After content type given and before everything else, try handle proto or easyjson, no matter the performance mode.
|
// After content type given and before everything else, try handle proto or easyjson, no matter the performance mode.
|
||||||
if handled, n, err := ctx.handleSpecialJSONResponseValue(v, options); handled {
|
if handled, _, err := ctx.handleSpecialJSONResponseValue(v, options); handled {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldOptimize := ctx.shouldOptimize()
|
return WriteJSON(ctx, v, options)
|
||||||
if options == nil {
|
|
||||||
if shouldOptimize {
|
|
||||||
// If no options given and optimizations are enabled.
|
|
||||||
// write using the fast json marshaler with the http request context as soon as possible.
|
|
||||||
result, err := gojson.MarshalContext(ctx.request.Context(), v)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.Write(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else if no options given neither optimizations are enabled, then safely read the already-initialized object.
|
|
||||||
options = &DefaultJSONOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriteJSON(ctx, ctx.writer, v, options, shouldOptimize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var finishCallbackB = []byte(");")
|
var finishCallbackB = []byte(");")
|
||||||
|
|
||||||
// WriteJSONP marshals the given interface object and writes the JSON response to the writer.
|
// WriteJSONP marshals the given interface object and writes the JSONP response to the writer.
|
||||||
func WriteJSONP(writer io.Writer, v interface{}, options JSONP, optimize bool) (int, error) {
|
var WriteJSONP = func(ctx *Context, v interface{}, options *JSONP) (err error) {
|
||||||
if callback := options.Callback; callback != "" {
|
if callback := options.Callback; callback != "" {
|
||||||
n, err := writer.Write(stringToBytes(callback + "("))
|
_, err = ctx.Write(stringToBytes(callback + "("))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
defer writer.Write(finishCallbackB)
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
ctx.Write(finishCallbackB)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !optimize && options.Indent == "" {
|
err = WriteJSON(ctx, v, &JSON{
|
||||||
options.Indent = " "
|
Indent: options.Indent,
|
||||||
}
|
OmitErrorHandler: options.OmitErrorHandler,
|
||||||
|
})
|
||||||
if indent := options.Indent; indent != "" {
|
return err
|
||||||
marshalIndent := json.MarshalIndent
|
|
||||||
if optimize {
|
|
||||||
// marshalIndent = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent
|
|
||||||
marshalIndent = gojson.MarshalIndent
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := marshalIndent(v, "", indent)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
result = append(result, newLineB...)
|
|
||||||
return writer.Write(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
marshal := json.Marshal
|
|
||||||
if optimize {
|
|
||||||
// marshal = jsoniter.ConfigCompatibleWithStandardLibrary.Marshal
|
|
||||||
marshal = gojson.Marshal
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return writer.Write(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultJSONPOptions is the optional settings that are being used
|
// DefaultJSONPOptions is the optional settings that are being used
|
||||||
|
@ -4114,14 +3958,16 @@ var DefaultJSONPOptions = JSONP{}
|
||||||
// It reports any JSON parser or write errors back to the caller.
|
// It reports any JSON parser or write errors back to the caller.
|
||||||
// Look the Application.SetContextErrorHandler to override the
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
// default status code 500 with a custom error response.
|
// default status code 500 with a custom error response.
|
||||||
func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (n int, err error) {
|
func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (err error) {
|
||||||
options := DefaultJSONPOptions
|
var options *JSONP
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = &opts[0]
|
||||||
|
} else {
|
||||||
|
options = &DefaultJSONPOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentJavascriptHeaderValue)
|
ctx.ContentType(ContentJavascriptHeaderValue)
|
||||||
if n, err = WriteJSONP(ctx.writer, v, options, ctx.shouldOptimize()); err != nil {
|
if err = WriteJSONP(ctx, v, options); err != nil {
|
||||||
if !options.OmitErrorHandler {
|
if !options.OmitErrorHandler {
|
||||||
ctx.handleContextError(err)
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
|
@ -4174,32 +4020,21 @@ func (m xmlMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteXML marshals the given interface object and writes the XML response to the writer.
|
// WriteXML marshals the given interface object and writes the XML response to the writer.
|
||||||
func WriteXML(writer io.Writer, v interface{}, options XML, optimize bool) (int, error) {
|
var WriteXML = func(ctx *Context, v interface{}, options *XML) error {
|
||||||
if prefix := options.Prefix; prefix != "" {
|
if prefix := options.Prefix; prefix != "" {
|
||||||
n, err := writer.Write(stringToBytes(prefix))
|
_, err := ctx.Write(stringToBytes(prefix))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !optimize && options.Indent == "" {
|
encoder := xml.NewEncoder(ctx.writer)
|
||||||
options.Indent = " " // Two spaces for XML is the default indentation when not optimized.
|
encoder.Indent("", options.Indent)
|
||||||
|
if err := encoder.Encode(v); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if indent := options.Indent; indent != "" {
|
return encoder.Flush()
|
||||||
result, err := xml.MarshalIndent(v, "", indent)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
result = append(result, newLineB...)
|
|
||||||
return writer.Write(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := xml.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return writer.Write(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultXMLOptions is the optional settings that are being used
|
// DefaultXMLOptions is the optional settings that are being used
|
||||||
|
@ -4212,14 +4047,16 @@ var DefaultXMLOptions = XML{}
|
||||||
// It reports any XML parser or write errors back to the caller.
|
// It reports any XML parser or write errors back to the caller.
|
||||||
// Look the Application.SetContextErrorHandler to override the
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
// default status code 500 with a custom error response.
|
// default status code 500 with a custom error response.
|
||||||
func (ctx *Context) XML(v interface{}, opts ...XML) (n int, err error) {
|
func (ctx *Context) XML(v interface{}, opts ...XML) (err error) {
|
||||||
options := DefaultXMLOptions
|
var options *XML
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = &opts[0]
|
||||||
|
} else {
|
||||||
|
options = &DefaultXMLOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentXMLHeaderValue)
|
ctx.ContentType(ContentXMLHeaderValue)
|
||||||
if n, err = WriteXML(ctx.writer, v, options, ctx.shouldOptimize()); err != nil {
|
if err = WriteXML(ctx, v, options); err != nil {
|
||||||
if !options.OmitErrorHandler {
|
if !options.OmitErrorHandler {
|
||||||
ctx.handleContextError(err)
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
|
@ -4239,7 +4076,7 @@ func (ctx *Context) XML(v interface{}, opts ...XML) (n int, err error) {
|
||||||
// send a response of content type "application/problem+xml" instead.
|
// send a response of content type "application/problem+xml" instead.
|
||||||
//
|
//
|
||||||
// Read more at: https://github.com/kataras/iris/wiki/Routing-error-handlers
|
// Read more at: https://github.com/kataras/iris/wiki/Routing-error-handlers
|
||||||
func (ctx *Context) Problem(v interface{}, opts ...ProblemOptions) (int, error) {
|
func (ctx *Context) Problem(v interface{}, opts ...ProblemOptions) error {
|
||||||
options := DefaultProblemOptions
|
options := DefaultProblemOptions
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = opts[0]
|
||||||
|
@ -4276,13 +4113,14 @@ func (ctx *Context) Problem(v interface{}, opts ...ProblemOptions) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteMarkdown parses the markdown to html and writes these contents to the writer.
|
// WriteMarkdown parses the markdown to html and writes these contents to the writer.
|
||||||
func WriteMarkdown(writer io.Writer, markdownB []byte, options Markdown) (n int, err error) {
|
var WriteMarkdown = func(ctx *Context, markdownB []byte, options *Markdown) error {
|
||||||
buf := blackfriday.Run(markdownB)
|
buf := blackfriday.Run(markdownB)
|
||||||
if options.Sanitize {
|
if options.Sanitize {
|
||||||
buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
|
buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
return writer.Write(buf)
|
_, err := ctx.Write(buf)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultMarkdownOptions is the optional settings that are being used
|
// DefaultMarkdownOptions is the optional settings that are being used
|
||||||
|
@ -4294,14 +4132,16 @@ var DefaultMarkdownOptions = Markdown{}
|
||||||
// It reports any Markdown parser or write errors back to the caller.
|
// It reports any Markdown parser or write errors back to the caller.
|
||||||
// Look the Application.SetContextErrorHandler to override the
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
// default status code 500 with a custom error response.
|
// default status code 500 with a custom error response.
|
||||||
func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (n int, err error) {
|
func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (err error) {
|
||||||
options := DefaultMarkdownOptions
|
var options *Markdown
|
||||||
if len(opts) > 0 {
|
if len(opts) > 0 {
|
||||||
options = opts[0]
|
options = &opts[0]
|
||||||
|
} else {
|
||||||
|
options = &DefaultMarkdownOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ContentType(ContentHTMLHeaderValue)
|
ctx.ContentType(ContentHTMLHeaderValue)
|
||||||
if n, err = WriteMarkdown(ctx.writer, markdownB, options); err != nil {
|
if err = WriteMarkdown(ctx, markdownB, options); err != nil {
|
||||||
if !options.OmitErrorHandler {
|
if !options.OmitErrorHandler {
|
||||||
ctx.handleContextError(err)
|
ctx.handleContextError(err)
|
||||||
}
|
}
|
||||||
|
@ -4310,31 +4150,46 @@ func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (n int, err err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteYAML sends YAML response to the client.
|
||||||
|
var WriteYAML = func(ctx *Context, v interface{}, indentSpace int) error {
|
||||||
|
encoder := yaml.NewEncoder(ctx.writer)
|
||||||
|
encoder.SetIndent(indentSpace)
|
||||||
|
|
||||||
|
if err := encoder.Encode(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// YAML marshals the given "v" value using the yaml marshaler and writes the result to the client.
|
// YAML marshals the given "v" value using the yaml marshaler and writes the result to the client.
|
||||||
//
|
//
|
||||||
// It reports any YAML parser or write errors back to the caller.
|
// It reports any YAML parser or write errors back to the caller.
|
||||||
// Look the Application.SetContextErrorHandler to override the
|
// Look the Application.SetContextErrorHandler to override the
|
||||||
// default status code 500 with a custom error response.
|
// default status code 500 with a custom error response.
|
||||||
func (ctx *Context) YAML(v interface{}) (int, error) {
|
func (ctx *Context) YAML(v interface{}) error {
|
||||||
out, err := yaml.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
ctx.handleContextError(err)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.ContentType(ContentYAMLHeaderValue)
|
ctx.ContentType(ContentYAMLHeaderValue)
|
||||||
n, err := ctx.Write(out)
|
|
||||||
|
err := WriteYAML(ctx, v, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.handleContextError(err)
|
ctx.handleContextError(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TextYAML calls the Context.YAML method but with the text/yaml content type instead.
|
// TextYAML calls the Context.YAML method but with the text/yaml content type instead.
|
||||||
func (ctx *Context) TextYAML(v interface{}) (int, error) {
|
func (ctx *Context) TextYAML(v interface{}) error {
|
||||||
ctx.contentTypeOnce(ContentYAMLTextHeaderValue, "")
|
ctx.ContentType(ContentYAMLTextHeaderValue)
|
||||||
return ctx.YAML(v)
|
|
||||||
|
err := WriteYAML(ctx, v, 4)
|
||||||
|
if err != nil {
|
||||||
|
ctx.handleContextError(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protobuf marshals the given "v" value of proto Message and writes its result to the client.
|
// Protobuf marshals the given "v" value of proto Message and writes its result to the client.
|
||||||
|
@ -4583,19 +4438,54 @@ func (ctx *Context) Negotiate(v interface{}) (int, error) {
|
||||||
case ContentTextHeaderValue, ContentHTMLHeaderValue:
|
case ContentTextHeaderValue, ContentHTMLHeaderValue:
|
||||||
return ctx.WriteString(v.(string))
|
return ctx.WriteString(v.(string))
|
||||||
case ContentMarkdownHeaderValue:
|
case ContentMarkdownHeaderValue:
|
||||||
return ctx.Markdown(v.([]byte))
|
err := ctx.Markdown(v.([]byte))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentJSONHeaderValue:
|
case ContentJSONHeaderValue:
|
||||||
return ctx.JSON(v)
|
err := ctx.JSON(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentJSONProblemHeaderValue, ContentXMLProblemHeaderValue:
|
case ContentJSONProblemHeaderValue, ContentXMLProblemHeaderValue:
|
||||||
return ctx.Problem(v)
|
err := ctx.Problem(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentJavascriptHeaderValue:
|
case ContentJavascriptHeaderValue:
|
||||||
return ctx.JSONP(v)
|
err := ctx.JSONP(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
|
case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
|
||||||
return ctx.XML(v)
|
err := ctx.XML(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentYAMLHeaderValue:
|
case ContentYAMLHeaderValue:
|
||||||
return ctx.YAML(v)
|
err := ctx.YAML(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentYAMLTextHeaderValue:
|
case ContentYAMLTextHeaderValue:
|
||||||
return ctx.TextYAML(v)
|
err := ctx.TextYAML(v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.writer.Written(), nil
|
||||||
case ContentProtobufHeaderValue:
|
case ContentProtobufHeaderValue:
|
||||||
msg, ok := v.(proto.Message)
|
msg, ok := v.(proto.Message)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -5438,15 +5328,15 @@ const cookieOptionsContextKey = "iris.cookie.options"
|
||||||
// cookies sent or received from the next Handler in the chain.
|
// cookies sent or received from the next Handler in the chain.
|
||||||
//
|
//
|
||||||
// Available builtin Cookie options are:
|
// Available builtin Cookie options are:
|
||||||
// * CookieAllowReclaim
|
// - CookieAllowReclaim
|
||||||
// * CookieAllowSubdomains
|
// - CookieAllowSubdomains
|
||||||
// * CookieSecure
|
// - CookieSecure
|
||||||
// * CookieHTTPOnly
|
// - CookieHTTPOnly
|
||||||
// * CookieSameSite
|
// - CookieSameSite
|
||||||
// * CookiePath
|
// - CookiePath
|
||||||
// * CookieCleanPath
|
// - CookieCleanPath
|
||||||
// * CookieExpires
|
// - CookieExpires
|
||||||
// * CookieEncoding
|
// - CookieEncoding
|
||||||
//
|
//
|
||||||
// Example at: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
// Example at: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
|
||||||
func (ctx *Context) AddCookieOptions(options ...CookieOption) {
|
func (ctx *Context) AddCookieOptions(options ...CookieOption) {
|
||||||
|
@ -5554,6 +5444,7 @@ var SetCookieKVExpiration = 8760 * time.Hour
|
||||||
// (note that client should be responsible for that if server sent an empty cookie's path, all browsers are compatible)
|
// (note that client should be responsible for that if server sent an empty cookie's path, all browsers are compatible)
|
||||||
// ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
|
// ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
|
||||||
// More:
|
// More:
|
||||||
|
//
|
||||||
// iris.CookieExpires(time.Duration)
|
// iris.CookieExpires(time.Duration)
|
||||||
// iris.CookieHTTPOnly(false)
|
// iris.CookieHTTPOnly(false)
|
||||||
//
|
//
|
||||||
|
|
|
@ -166,10 +166,12 @@ func (u *SimpleUser) GetField(key string) (interface{}, error) {
|
||||||
|
|
||||||
// UserMap can be used to convert a common map[string]interface{} to a User.
|
// UserMap can be used to convert a common map[string]interface{} to a User.
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// user := map[string]interface{}{
|
// user := map[string]interface{}{
|
||||||
// "username": "kataras",
|
// "username": "kataras",
|
||||||
// "age" : 27,
|
// "age" : 27,
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// ctx.SetUser(user)
|
// ctx.SetUser(user)
|
||||||
// OR
|
// OR
|
||||||
// user := UserStruct{....}
|
// user := UserStruct{....}
|
||||||
|
|
|
@ -275,7 +275,6 @@ type Filter func(*Context) bool
|
||||||
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
// Handlers here should act like middleware, they should contain `ctx.Next` to proceed
|
||||||
// to the next handler of the chain. Those "handlers" are registered to the per-request context.
|
// to the next handler of the chain. Those "handlers" are registered to the per-request context.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// It checks the "filter" and if passed then
|
// It checks the "filter" and if passed then
|
||||||
// it, correctly, executes the "handlers".
|
// it, correctly, executes the "handlers".
|
||||||
//
|
//
|
||||||
|
|
|
@ -131,6 +131,7 @@ func (r *RequestParams) GetIntUnslashed(key string) (int, bool) {
|
||||||
// Key is the specific type, which should be unique.
|
// Key is the specific type, which should be unique.
|
||||||
// The value is a function which accepts the parameter index
|
// The value is a function which accepts the parameter index
|
||||||
// and it should return the value as the parameter type evaluator expects it.
|
// and it should return the value as the parameter type evaluator expects it.
|
||||||
|
//
|
||||||
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
|
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
|
||||||
// return func(ctx *Context) <T> {
|
// return func(ctx *Context) <T> {
|
||||||
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
|
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
|
||||||
|
@ -261,7 +262,9 @@ var ParamResolvers = map[reflect.Type]func(paramIndex int) interface{}{
|
||||||
// and the parameter's index based on the registered path.
|
// and the parameter's index based on the registered path.
|
||||||
// Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 0)
|
// Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 0)
|
||||||
// Inside a Handler: nameResolver.Call(ctx)[0]
|
// Inside a Handler: nameResolver.Call(ctx)[0]
|
||||||
|
//
|
||||||
// it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
|
// it will return the reflect.Value Of the exact type of the parameter(based on the path parameters and macros).
|
||||||
|
//
|
||||||
// It is only useful for dynamic binding of the parameter, it is used on "hero" package and it should be modified
|
// It is only useful for dynamic binding of the parameter, it is used on "hero" package and it should be modified
|
||||||
// only when Macros are modified in such way that the default selections for the available go std types are not enough.
|
// only when Macros are modified in such way that the default selections for the available go std types are not enough.
|
||||||
//
|
//
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -32,7 +32,7 @@ func releaseResponseRecorder(w *ResponseRecorder) {
|
||||||
// A ResponseRecorder is used mostly for testing
|
// A ResponseRecorder is used mostly for testing
|
||||||
// in order to record and modify, if necessary, the body and status code and headers.
|
// in order to record and modify, if necessary, the body and status code and headers.
|
||||||
//
|
//
|
||||||
// See `context.Recorder`` method too.
|
// See `context.Recorder“ method too.
|
||||||
type ResponseRecorder struct {
|
type ResponseRecorder struct {
|
||||||
ResponseWriter
|
ResponseWriter
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ func (w *ResponseRecorder) Result() *http.Response { // a modified copy of net/h
|
||||||
}
|
}
|
||||||
res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
|
res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
|
||||||
if w.chunks != nil {
|
if w.chunks != nil {
|
||||||
res.Body = ioutil.NopCloser(bytes.NewReader(w.chunks))
|
res.Body = io.NopCloser(bytes.NewReader(w.chunks))
|
||||||
} else {
|
} else {
|
||||||
res.Body = http.NoBody
|
res.Body = http.NoBody
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ func StatusText(code int) string {
|
||||||
// Read more at `iris/Configuration#DisableAutoFireStatusCode` and
|
// Read more at `iris/Configuration#DisableAutoFireStatusCode` and
|
||||||
// `iris/core/router/Party#OnAnyErrorCode` for relative information.
|
// `iris/core/router/Party#OnAnyErrorCode` for relative information.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Modify this variable when your Iris server or/and client
|
// Modify this variable when your Iris server or/and client
|
||||||
// not follows the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
// not follows the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
var StatusCodeNotSuccessful = func(statusCode int) bool { return statusCode >= 400 }
|
var StatusCodeNotSuccessful = func(statusCode int) bool { return statusCode >= 400 }
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.
|
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.
|
||||||
//
|
//
|
||||||
// Supported form types:
|
// Supported form types:
|
||||||
|
//
|
||||||
// .FromStd(h http.Handler)
|
// .FromStd(h http.Handler)
|
||||||
// .FromStd(func(w http.ResponseWriter, r *http.Request))
|
// .FromStd(func(w http.ResponseWriter, r *http.Request))
|
||||||
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
|
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
|
||||||
|
|
|
@ -730,7 +730,6 @@ func (e Entry) Value() interface{} {
|
||||||
// Save same as `Set`
|
// Save same as `Set`
|
||||||
// However, if "immutable" is true then saves it as immutable (same as `SetImmutable`).
|
// However, if "immutable" is true then saves it as immutable (same as `SetImmutable`).
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Returns the entry and true if it was just inserted, meaning that
|
// Returns the entry and true if it was just inserted, meaning that
|
||||||
// it will return the entry and a false boolean if the entry exists and it has been updated.
|
// it will return the entry and a false boolean if the entry exists and it has been updated.
|
||||||
func (r *Store) Save(key string, value interface{}, immutable bool) (Entry, bool) {
|
func (r *Store) Save(key string, value interface{}, immutable bool) (Entry, bool) {
|
||||||
|
|
|
@ -377,6 +377,7 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
|
||||||
// (see ConfigureContainer().RegisterDependency)
|
// (see ConfigureContainer().RegisterDependency)
|
||||||
// or leave the framework to parse the request and fill the values accordingly.
|
// or leave the framework to parse the request and fill the values accordingly.
|
||||||
// The output of the "handlersFn" can be any output result:
|
// The output of the "handlersFn" can be any output result:
|
||||||
|
//
|
||||||
// custom structs <T>, string, []byte, int, error,
|
// custom structs <T>, string, []byte, int, error,
|
||||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||||
//
|
//
|
||||||
|
@ -474,6 +475,7 @@ func (api *APIBuilder) AllowMethods(methods ...string) Party {
|
||||||
// For example, if for some reason the desired result is the (done or all) handlers to be executed no matter what
|
// For example, if for some reason the desired result is the (done or all) handlers to be executed no matter what
|
||||||
// even if no `ctx.Next()` is called in the previous handlers, including the begin(`Use`),
|
// even if no `ctx.Next()` is called in the previous handlers, including the begin(`Use`),
|
||||||
// the main(`Handle`) and the done(`Done`) handlers themselves, then:
|
// the main(`Handle`) and the done(`Done`) handlers themselves, then:
|
||||||
|
//
|
||||||
// Party#SetExecutionRules(iris.ExecutionRules {
|
// Party#SetExecutionRules(iris.ExecutionRules {
|
||||||
// Begin: iris.ExecutionOptions{Force: true},
|
// Begin: iris.ExecutionOptions{Force: true},
|
||||||
// Main: iris.ExecutionOptions{Force: true},
|
// Main: iris.ExecutionOptions{Force: true},
|
||||||
|
@ -567,8 +569,11 @@ func (api *APIBuilder) handle(errorCode int, method string, relativePath string,
|
||||||
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
|
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
|
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
|
||||||
|
//
|
||||||
// At the other side, with `Handle` we've had to write:
|
// At the other side, with `Handle` we've had to write:
|
||||||
|
//
|
||||||
// app.Handle("GET", "/user", userHandler)
|
// app.Handle("GET", "/user", userHandler)
|
||||||
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
|
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
|
||||||
// app.Handle("GET", "/user/me", userMeHandler)
|
// app.Handle("GET", "/user/me", userMeHandler)
|
||||||
|
@ -904,6 +909,7 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
|
||||||
// Note: `iris#Party` and `core/router#Party` describes the exactly same interface.
|
// Note: `iris#Party` and `core/router#Party` describes the exactly same interface.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// app.PartyFunc("/users", func(u iris.Party){
|
// app.PartyFunc("/users", func(u iris.Party){
|
||||||
// u.Use(authMiddleware, logMiddleware)
|
// u.Use(authMiddleware, logMiddleware)
|
||||||
// u.Get("/", getAllUsers)
|
// u.Get("/", getAllUsers)
|
||||||
|
@ -949,14 +955,19 @@ type (
|
||||||
// Useful when the api's dependencies amount are too much to pass on a function.
|
// Useful when the api's dependencies amount are too much to pass on a function.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
|
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
|
||||||
|
//
|
||||||
// Where UsersAPI looks like:
|
// Where UsersAPI looks like:
|
||||||
|
//
|
||||||
// type UsersAPI struct { [...] }
|
// type UsersAPI struct { [...] }
|
||||||
// func(api *UsersAPI) Configure(router iris.Party) {
|
// func(api *UsersAPI) Configure(router iris.Party) {
|
||||||
// router.Get("/{id:uuid}", api.getUser)
|
// router.Get("/{id:uuid}", api.getUser)
|
||||||
// [...]
|
// [...]
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// Usage with (static) dependencies:
|
// Usage with (static) dependencies:
|
||||||
|
//
|
||||||
// app.RegisterDependency(userRepo, ...)
|
// app.RegisterDependency(userRepo, ...)
|
||||||
// app.PartyConfigure("/users", new(api.UsersAPI))
|
// app.PartyConfigure("/users", new(api.UsersAPI))
|
||||||
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
|
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
|
||||||
|
@ -1626,6 +1637,7 @@ func (api *APIBuilder) RegisterView(viewEngine context.ViewEngine) {
|
||||||
|
|
||||||
// FallbackView registers one or more fallback views for a template or a template layout.
|
// FallbackView registers one or more fallback views for a template or a template layout.
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// FallbackView(iris.FallbackView("fallback.html"))
|
// FallbackView(iris.FallbackView("fallback.html"))
|
||||||
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
|
||||||
// OR
|
// OR
|
||||||
|
@ -1653,6 +1665,7 @@ func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
|
||||||
// app := iris.New()
|
// app := iris.New()
|
||||||
// app.RegisterView(iris.$VIEW_ENGINE("./views", ".$extension"))
|
// app.RegisterView(iris.$VIEW_ENGINE("./views", ".$extension"))
|
||||||
// my := app.Party("/my").Layout("layouts/mylayout.html")
|
// my := app.Party("/my").Layout("layouts/mylayout.html")
|
||||||
|
//
|
||||||
// my.Get("/", func(ctx iris.Context) {
|
// my.Get("/", func(ctx iris.Context) {
|
||||||
// ctx.View("page1.html")
|
// ctx.View("page1.html")
|
||||||
// })
|
// })
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/kataras/golog"
|
"github.com/kataras/golog"
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
|
||||||
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
|
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
|
||||||
// the below piece of code is external, as an answer to a stackoverflow question.
|
// the below piece of code is external, as an answer to a stackoverflow question.
|
||||||
//
|
//
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -1041,7 +1040,7 @@ func cacheFiles(ctx stdContext.Context, fs http.FileSystem, names []string, comp
|
||||||
|
|
||||||
fi := newFileInfo(path.Base(name), inf.Mode(), inf.ModTime())
|
fi := newFileInfo(path.Base(name), inf.Mode(), inf.ModTime())
|
||||||
|
|
||||||
contents, err := ioutil.ReadAll(f)
|
contents, err := io.ReadAll(f)
|
||||||
f.Close()
|
f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
|
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// Party#SetExecutionRules(ExecutionRules {
|
// Party#SetExecutionRules(ExecutionRules {
|
||||||
// Done: ExecutionOptions{Force: true},
|
// Done: ExecutionOptions{Force: true},
|
||||||
// })
|
// })
|
||||||
|
|
|
@ -491,8 +491,9 @@ func (r *Route) GetTitle() string {
|
||||||
// Should be called after `Build` state.
|
// Should be called after `Build` state.
|
||||||
//
|
//
|
||||||
// It prints the @method: @path (@description) (@route_rel_location)
|
// It prints the @method: @path (@description) (@route_rel_location)
|
||||||
// * @handler_name (@handler_rel_location)
|
// - @handler_name (@handler_rel_location)
|
||||||
// * @second_handler ...
|
// - @second_handler ...
|
||||||
|
//
|
||||||
// If route and handler line:number locations are equal then the second is ignored.
|
// If route and handler line:number locations are equal then the second is ignored.
|
||||||
func (r *Route) Trace(w io.Writer, stoppedIndex int) {
|
func (r *Route) Trace(w io.Writer, stoppedIndex int) {
|
||||||
title := r.GetTitle()
|
title := r.GetTitle()
|
||||||
|
|
7
doc.go
7
doc.go
|
@ -36,11 +36,11 @@ Source code and other details for the project are available at GitHub:
|
||||||
|
|
||||||
https://github.com/kataras/iris
|
https://github.com/kataras/iris
|
||||||
|
|
||||||
Current Version
|
# Current Version
|
||||||
|
|
||||||
12.2.0-beta3
|
12.2.0-beta4
|
||||||
|
|
||||||
Installation
|
# Installation
|
||||||
|
|
||||||
The only requirement is the Go Programming Language, at least version 1.18.
|
The only requirement is the Go Programming Language, at least version 1.18.
|
||||||
|
|
||||||
|
@ -62,6 +62,5 @@ Middleware:
|
||||||
Home Page:
|
Home Page:
|
||||||
|
|
||||||
https://iris-go.com
|
https://iris-go.com
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package iris
|
package iris
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -15,7 +15,6 @@ require (
|
||||||
github.com/fatih/structs v1.1.0
|
github.com/fatih/structs v1.1.0
|
||||||
github.com/flosch/pongo2/v4 v4.0.2
|
github.com/flosch/pongo2/v4 v4.0.2
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5
|
|
||||||
github.com/golang/snappy v0.0.4
|
github.com/golang/snappy v0.0.4
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/securecookie v1.1.1
|
github.com/gorilla/securecookie v1.1.1
|
||||||
|
|
2
go.sum
generated
2
go.sum
generated
|
@ -62,8 +62,6 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5 h1:aeyOtISssR4sP36FAC9LV96PQqxzcbhz54EWv9U+ZGc=
|
|
||||||
github.com/goccy/go-json v0.9.8-0.20220506185958-23bd66f4c0d5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
|
|
@ -327,22 +327,27 @@ func Handler(fn interface{}) context.Handler {
|
||||||
// as middleware or as simple route handler or subdomain's handler.
|
// as middleware or as simple route handler or subdomain's handler.
|
||||||
//
|
//
|
||||||
// func(...<T>) iris.Handler
|
// func(...<T>) iris.Handler
|
||||||
|
//
|
||||||
// - if <T> are all static dependencies then
|
// - if <T> are all static dependencies then
|
||||||
// there is no reflection involved at serve-time.
|
// there is no reflection involved at serve-time.
|
||||||
//
|
//
|
||||||
// func(pathParameter string, ...<T>)
|
// func(pathParameter string, ...<T>)
|
||||||
|
//
|
||||||
// - one or more path parameters (e.g. :uid, :string, :int, :path, :uint64)
|
// - one or more path parameters (e.g. :uid, :string, :int, :path, :uint64)
|
||||||
// are automatically binded to the first input Go standard types (string, int, uint64 and e.t.c.)
|
// are automatically binded to the first input Go standard types (string, int, uint64 and e.t.c.)
|
||||||
//
|
//
|
||||||
// func(<T>) error
|
// func(<T>) error
|
||||||
|
//
|
||||||
// - if a function returns an error then this error's text is sent to the client automatically.
|
// - if a function returns an error then this error's text is sent to the client automatically.
|
||||||
//
|
//
|
||||||
// func(<T>) <R>
|
// func(<T>) <R>
|
||||||
|
//
|
||||||
// - The result of the function is a dependency too.
|
// - The result of the function is a dependency too.
|
||||||
// If <R> is a request-scope dependency (dynamic) then
|
// If <R> is a request-scope dependency (dynamic) then
|
||||||
// this function will be called at every request.
|
// this function will be called at every request.
|
||||||
//
|
//
|
||||||
// func(<T>) <R>
|
// func(<T>) <R>
|
||||||
|
//
|
||||||
// - If <R> is static dependency (e.g. a database or a service) then its result
|
// - If <R> is static dependency (e.g. a database or a service) then its result
|
||||||
// can be used as a static dependency to the next dependencies or to the controller/function itself.
|
// can be used as a static dependency to the next dependencies or to the controller/function itself.
|
||||||
func (c *Container) Handler(fn interface{}) context.Handler {
|
func (c *Container) Handler(fn interface{}) context.Handler {
|
||||||
|
|
|
@ -27,11 +27,9 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
|
||||||
|
|
||||||
switch context.TrimHeaderValue(ctx.GetContentType()) {
|
switch context.TrimHeaderValue(ctx.GetContentType()) {
|
||||||
case context.ContentXMLHeaderValue, context.ContentXMLUnreadableHeaderValue:
|
case context.ContentXMLHeaderValue, context.ContentXMLUnreadableHeaderValue:
|
||||||
_, err := ctx.XML(v)
|
return ctx.XML(v)
|
||||||
return err
|
|
||||||
case context.ContentYAMLHeaderValue:
|
case context.ContentYAMLHeaderValue:
|
||||||
_, err := ctx.YAML(v)
|
return ctx.YAML(v)
|
||||||
return err
|
|
||||||
case context.ContentProtobufHeaderValue:
|
case context.ContentProtobufHeaderValue:
|
||||||
msg, ok := v.(proto.Message)
|
msg, ok := v.(proto.Message)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -45,8 +43,7 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
|
||||||
return err
|
return err
|
||||||
default:
|
default:
|
||||||
// otherwise default to JSON.
|
// otherwise default to JSON.
|
||||||
_, err := ctx.JSON(v)
|
return ctx.JSON(v)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (e err) Dispatch(ctx iris.Context) {
|
||||||
// write the status code based on the err's StatusCode.
|
// write the status code based on the err's StatusCode.
|
||||||
ctx.StatusCode(e.Status)
|
ctx.StatusCode(e.Status)
|
||||||
// send to the client the whole object as json
|
// send to the client the whole object as json
|
||||||
_, _ = ctx.JSON(e)
|
_ = ctx.JSON(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCustomErrorAsDispatcher() err {
|
func GetCustomErrorAsDispatcher() err {
|
||||||
|
|
|
@ -98,8 +98,11 @@ func DefaultConfiguration() *Configuration {
|
||||||
|
|
||||||
// New Prepares and returns a new test framework based on the "app".
|
// New Prepares and returns a new test framework based on the "app".
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// httptest.New(t, app)
|
// httptest.New(t, app)
|
||||||
|
//
|
||||||
// With options:
|
// With options:
|
||||||
|
//
|
||||||
// httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true))
|
// httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true))
|
||||||
//
|
//
|
||||||
// Example at: https://github.com/kataras/iris/tree/master/_examples/testing/httptest.
|
// Example at: https://github.com/kataras/iris/tree/master/_examples/testing/httptest.
|
||||||
|
|
|
@ -152,7 +152,7 @@ func (loc *Locale) Tag() *language.Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Language should return the exact languagecode of this `Locale`
|
// Language should return the exact languagecode of this `Locale`
|
||||||
//that the user provided on `New` function.
|
// that the user provided on `New` function.
|
||||||
//
|
//
|
||||||
// Same as `Tag().String()` but it's static.
|
// Same as `Tag().String()` but it's static.
|
||||||
func (loc *Locale) Language() string {
|
func (loc *Locale) Language() string {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package i18n
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ func Glob(globPattern string, options LoaderConfig) Loader {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return load(assetNames, ioutil.ReadFile, options)
|
return load(assetNames, os.ReadFile, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assets accepts a function that returns a list of filenames (physical or virtual),
|
// Assets accepts a function that returns a list of filenames (physical or virtual),
|
||||||
|
|
2
iris.go
2
iris.go
|
@ -299,6 +299,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
||||||
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
|
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
|
||||||
//
|
//
|
||||||
// Adding custom levels requires import of the `github.com/kataras/golog` package:
|
// Adding custom levels requires import of the `github.com/kataras/golog` package:
|
||||||
|
//
|
||||||
// First we create our level to a golog.Level
|
// First we create our level to a golog.Level
|
||||||
// in order to be used in the Log functions.
|
// in order to be used in the Log functions.
|
||||||
// var SuccessLevel golog.Level = 6
|
// var SuccessLevel golog.Level = 6
|
||||||
|
@ -309,6 +310,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
||||||
// // ColorfulText (Green Color[SUCC])
|
// // ColorfulText (Green Color[SUCC])
|
||||||
// ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
|
// ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// app.Logger().SetLevel("success")
|
// app.Logger().SetLevel("success")
|
||||||
// app.Logger().Logf(SuccessLevel, "a custom leveled log message")
|
// app.Logger().Logf(SuccessLevel, "a custom leveled log message")
|
||||||
|
|
|
@ -237,7 +237,7 @@ type (
|
||||||
Step3 interface {
|
Step3 interface {
|
||||||
// Health enables the /health route.
|
// Health enables the /health route.
|
||||||
// If "env" and "developer" are given, these fields will be populated to the client
|
// If "env" and "developer" are given, these fields will be populated to the client
|
||||||
// through headers and environemnt on health route.
|
// through headers and environment on health route.
|
||||||
Health(b bool, env, developer string) Step4
|
Health(b bool, env, developer string) Step4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ import (
|
||||||
// Note that the builtin macros return error too, but they're handled
|
// Note that the builtin macros return error too, but they're handled
|
||||||
// by the `else` literal (error code). To change this behavior
|
// by the `else` literal (error code). To change this behavior
|
||||||
// and send a custom error response you have to register it:
|
// and send a custom error response you have to register it:
|
||||||
|
//
|
||||||
// app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error)).
|
// app.Macros().Get("uuid").HandleError(func(ctx iris.Context, paramIndex int, err error)).
|
||||||
|
//
|
||||||
// You can also set custom macros by `app.Macros().Register`.
|
// You can also set custom macros by `app.Macros().Register`.
|
||||||
//
|
//
|
||||||
// See macro.HandleError to set it.
|
// See macro.HandleError to set it.
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -324,7 +323,7 @@ func BenchmarkAccessLogAfterPrint(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
|
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
|
||||||
ac := New(ioutil.Discard)
|
ac := New(io.Discard)
|
||||||
ac.Clock = TClock(time.Time{})
|
ac.Clock = TClock(time.Time{})
|
||||||
ac.BytesReceived = false
|
ac.BytesReceived = false
|
||||||
ac.BytesReceivedBody = false
|
ac.BytesReceivedBody = false
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Log represents the log data specifically for the accesslog middleware.
|
// Log represents the log data specifically for the accesslog middleware.
|
||||||
|
//
|
||||||
//easyjson:json
|
//easyjson:json
|
||||||
type Log struct {
|
type Log struct {
|
||||||
// The AccessLog instance this Log was created of.
|
// The AccessLog instance this Log was created of.
|
||||||
|
|
|
@ -52,6 +52,7 @@ type ErrorHandler func(ctx *context.Context, err error)
|
||||||
// The only required value is the Allow field.
|
// The only required value is the Allow field.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// opts := Options { ... }
|
// opts := Options { ... }
|
||||||
// auth := New(opts)
|
// auth := New(opts)
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
@ -171,6 +172,7 @@ type BasicAuth struct {
|
||||||
// The result should be used to wrap an existing handler or the HTTP application's root router.
|
// The result should be used to wrap an existing handler or the HTTP application's root router.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
|
//
|
||||||
// opts := basicauth.Options{
|
// opts := basicauth.Options{
|
||||||
// Realm: basicauth.DefaultRealm,
|
// Realm: basicauth.DefaultRealm,
|
||||||
// ErrorHandler: basicauth.DefaultErrorHandler,
|
// ErrorHandler: basicauth.DefaultErrorHandler,
|
||||||
|
@ -238,12 +240,14 @@ func New(opts Options) context.Handler {
|
||||||
// are required as they are compared against the user input
|
// are required as they are compared against the user input
|
||||||
// when access to protected resource is requested.
|
// when access to protected resource is requested.
|
||||||
// A user list can defined with one of the following values:
|
// A user list can defined with one of the following values:
|
||||||
|
//
|
||||||
// map[string]string form of: {username:password, ...}
|
// map[string]string form of: {username:password, ...}
|
||||||
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
||||||
// []T which T completes the User interface, where T is a struct value
|
// []T which T completes the User interface, where T is a struct value
|
||||||
// []T which T contains at least Username and Password fields.
|
// []T which T contains at least Username and Password fields.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// auth := Default(map[string]string{
|
// auth := Default(map[string]string{
|
||||||
// "admin": "admin",
|
// "admin": "admin",
|
||||||
// "john": "p@ss",
|
// "john": "p@ss",
|
||||||
|
@ -260,6 +264,7 @@ func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
||||||
// a filename to load the users from.
|
// a filename to load the users from.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// auth := Load("users.yml")
|
// auth := Load("users.yml")
|
||||||
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
|
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
|
||||||
opts := Options{
|
opts := Options{
|
||||||
|
|
|
@ -3,7 +3,7 @@ package basicauth
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ import (
|
||||||
// ReadFile can be used to customize the way the
|
// ReadFile can be used to customize the way the
|
||||||
// AllowUsersFile function is loading the filename from.
|
// AllowUsersFile function is loading the filename from.
|
||||||
// Example of usage: embedded users.yml file.
|
// Example of usage: embedded users.yml file.
|
||||||
// Defaults to the `ioutil.ReadFile` which reads the file from the physical disk.
|
// Defaults to the `os.ReadFile` which reads the file from the physical disk.
|
||||||
var ReadFile = ioutil.ReadFile
|
var ReadFile = os.ReadFile
|
||||||
|
|
||||||
// User is a partial part of the iris.User interface.
|
// User is a partial part of the iris.User interface.
|
||||||
// It's used to declare a static slice of registered User for authentication.
|
// It's used to declare a static slice of registered User for authentication.
|
||||||
|
@ -48,6 +48,7 @@ type UserAuthOption func(*UserAuthOptions)
|
||||||
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
|
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// Default(..., BCRYPT) OR
|
// Default(..., BCRYPT) OR
|
||||||
// Load(..., BCRYPT) OR
|
// Load(..., BCRYPT) OR
|
||||||
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
||||||
|
@ -75,6 +76,7 @@ func toUserAuthOptions(opts []UserAuthOption) (options UserAuthOptions) {
|
||||||
|
|
||||||
// AllowUsers is an AuthFunc which authenticates user input based on a (static) user list.
|
// AllowUsers is an AuthFunc which authenticates user input based on a (static) user list.
|
||||||
// The "users" input parameter can be one of the following forms:
|
// The "users" input parameter can be one of the following forms:
|
||||||
|
//
|
||||||
// map[string]string e.g. {username: password, username: password...}.
|
// map[string]string e.g. {username: password, username: password...}.
|
||||||
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
||||||
// []T which T completes the User interface.
|
// []T which T completes the User interface.
|
||||||
|
@ -155,7 +157,9 @@ func userMap(usernamePassword map[string]string, opts ...UserAuthOption) AuthFun
|
||||||
// loaded from a file on initialization.
|
// loaded from a file on initialization.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
|
//
|
||||||
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
||||||
|
//
|
||||||
// The users.yml file looks like the following:
|
// The users.yml file looks like the following:
|
||||||
// - username: kataras
|
// - username: kataras
|
||||||
// password: kataras_pass
|
// password: kataras_pass
|
||||||
|
|
|
@ -2,7 +2,6 @@ package basicauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -164,7 +163,7 @@ func TestAllowUsers(t *testing.T) {
|
||||||
|
|
||||||
// Test YAML user loading with b-encrypted passwords.
|
// Test YAML user loading with b-encrypted passwords.
|
||||||
func TestAllowUsersFile(t *testing.T) {
|
func TestAllowUsersFile(t *testing.T) {
|
||||||
f, err := ioutil.TempFile("", "*users.yml")
|
f, err := os.CreateTemp("", "*users.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ type (
|
||||||
// please refer to: https://github.com/iris-contrib/middleware repository instead.
|
// please refer to: https://github.com/iris-contrib/middleware repository instead.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
|
//
|
||||||
// import "github.com/kataras/iris/v12/middleware/cors"
|
// import "github.com/kataras/iris/v12/middleware/cors"
|
||||||
// import "github.com/kataras/iris/v12/x/errors"
|
// import "github.com/kataras/iris/v12/x/errors"
|
||||||
//
|
//
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// The Iris server SHOULD run under HTTP/2 and clients too.
|
// The Iris server SHOULD run under HTTP/2 and clients too.
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
||||||
// [...]
|
// [...]
|
||||||
// app := iris.New()
|
// app := iris.New()
|
||||||
|
|
|
@ -3,7 +3,7 @@ package hcaptcha
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -70,7 +70,9 @@ func New(secret string, options ...Option) context.Handler {
|
||||||
|
|
||||||
// Handler is the HTTP route middleware featured hcaptcha validation.
|
// Handler is the HTTP route middleware featured hcaptcha validation.
|
||||||
// It calls the `SiteVerify` method and fires the "next" when user completed the hcaptcha successfully,
|
// It calls the `SiteVerify` method and fires the "next" when user completed the hcaptcha successfully,
|
||||||
|
//
|
||||||
// otherwise it calls the Client's `FailureHandler`.
|
// otherwise it calls the Client's `FailureHandler`.
|
||||||
|
//
|
||||||
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
||||||
// is saved on the Request's Context (see `GetResponseFromContext`).
|
// is saved on the Request's Context (see `GetResponseFromContext`).
|
||||||
func (c *Client) Handler(ctx *context.Context) {
|
func (c *Client) Handler(ctx *context.Context) {
|
||||||
|
@ -113,7 +115,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||||
|
|
|
@ -62,22 +62,29 @@ type Verifier struct {
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// verifier := NewVerifier(HS256, secret)
|
// verifier := NewVerifier(HS256, secret)
|
||||||
|
//
|
||||||
// OR
|
// OR
|
||||||
|
//
|
||||||
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
||||||
//
|
//
|
||||||
// claimsGetter := func() interface{} { return new(userClaims) }
|
// claimsGetter := func() interface{} { return new(userClaims) }
|
||||||
// middleware := verifier.Verify(claimsGetter)
|
// middleware := verifier.Verify(claimsGetter)
|
||||||
|
//
|
||||||
// OR
|
// OR
|
||||||
|
//
|
||||||
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
||||||
//
|
//
|
||||||
// Register the middleware, e.g.
|
// Register the middleware, e.g.
|
||||||
|
//
|
||||||
// app.Use(middleware)
|
// app.Use(middleware)
|
||||||
//
|
//
|
||||||
// Get the claims:
|
// Get the claims:
|
||||||
|
//
|
||||||
// claims := jwt.Get(ctx).(*userClaims)
|
// claims := jwt.Get(ctx).(*userClaims)
|
||||||
// username := claims.Username
|
// username := claims.Username
|
||||||
//
|
//
|
||||||
// Get the context user:
|
// Get the context user:
|
||||||
|
//
|
||||||
// username, err := ctx.User().GetUsername()
|
// username, err := ctx.User().GetUsername()
|
||||||
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
|
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
|
||||||
if signatureAlg == HS256 {
|
if signatureAlg == HS256 {
|
||||||
|
|
|
@ -166,6 +166,7 @@ func Query(paramName string) Option {
|
||||||
// to determinate the method to override with.
|
// to determinate the method to override with.
|
||||||
//
|
//
|
||||||
// Use cases:
|
// Use cases:
|
||||||
|
//
|
||||||
// 1. When need to check only for headers and ignore other fields:
|
// 1. When need to check only for headers and ignore other fields:
|
||||||
// New(Only(Headers("X-Custom-Header")))
|
// New(Only(Headers("X-Custom-Header")))
|
||||||
//
|
//
|
||||||
|
@ -185,7 +186,6 @@ func Only(o ...Option) Option {
|
||||||
// that do not support certain HTTP operations such as DELETE or PUT for security reasons.
|
// that do not support certain HTTP operations such as DELETE or PUT for security reasons.
|
||||||
// This wrapper will accept a method, based on criteria, to override the POST method with.
|
// This wrapper will accept a method, based on criteria, to override the POST method with.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Read more at:
|
// Read more at:
|
||||||
// https://github.com/kataras/iris/issues/1325
|
// https://github.com/kataras/iris/issues/1325
|
||||||
func New(opt ...Option) router.WrapperFunc {
|
func New(opt ...Option) router.WrapperFunc {
|
||||||
|
|
|
@ -34,11 +34,12 @@ type Options struct {
|
||||||
// for security reasons.
|
// for security reasons.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
|
//
|
||||||
// app.Get("/health", modrevision.New(modrevision.Options{
|
// app.Get("/health", modrevision.New(modrevision.Options{
|
||||||
// ServerName: "Iris Server",
|
// ServerName: "Iris Server",
|
||||||
// Env: "development",
|
// Env: "development",
|
||||||
// Developer: "kataras",
|
// Developer: "kataras",
|
||||||
// TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
// TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||||
// }))
|
// }))
|
||||||
func New(opts Options) context.Handler {
|
func New(opts Options) context.Handler {
|
||||||
buildTime, buildRevision := context.BuildTime, context.BuildRevision
|
buildTime, buildRevision := context.BuildTime, context.BuildRevision
|
||||||
|
|
|
@ -41,6 +41,7 @@ var profileDescriptions = map[string]string{
|
||||||
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.
|
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.
|
||||||
// Note: Route MUST have the last named parameter wildcard named '{action:path}'.
|
// Note: Route MUST have the last named parameter wildcard named '{action:path}'.
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
||||||
func New() context.Handler {
|
func New() context.Handler {
|
||||||
return func(ctx *context.Context) {
|
return func(ctx *context.Context) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package recaptcha
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -50,7 +50,9 @@ func New(secret string) context.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiteVerify accepts context and the secret key(https://www.google.com/recaptcha)
|
// SiteVerify accepts context and the secret key(https://www.google.com/recaptcha)
|
||||||
|
//
|
||||||
// and returns the google's recaptcha response, if `response.Success` is true
|
// and returns the google's recaptcha response, if `response.Success` is true
|
||||||
|
//
|
||||||
// then validation passed.
|
// then validation passed.
|
||||||
//
|
//
|
||||||
// Use `New` for middleware use instead.
|
// Use `New` for middleware use instead.
|
||||||
|
@ -74,7 +76,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := io.ReadAll(r.Body)
|
||||||
r.Body.Close()
|
r.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||||
|
@ -113,6 +115,7 @@ var recaptchaForm = `<form action="%s" method="POST">
|
||||||
// Example Code:
|
// Example Code:
|
||||||
//
|
//
|
||||||
// Method: "POST" | Path: "/contact"
|
// Method: "POST" | Path: "/contact"
|
||||||
|
//
|
||||||
// func postContact(ctx *context.Context) {
|
// func postContact(ctx *context.Context) {
|
||||||
// // [...]
|
// // [...]
|
||||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||||
|
@ -125,6 +128,7 @@ var recaptchaForm = `<form action="%s" method="POST">
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Method: "GET" | Path: "/contact"
|
// Method: "GET" | Path: "/contact"
|
||||||
|
//
|
||||||
// func getContact(ctx *context.Context) {
|
// func getContact(ctx *context.Context) {
|
||||||
// // render the recaptcha form
|
// // render the recaptcha form
|
||||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||||
|
|
|
@ -384,9 +384,11 @@ func (c *ControllerActivator) handleHTTPError(funcName string) *router.Route {
|
||||||
//
|
//
|
||||||
// Just like `Party#HandleMany`:, it returns the `[]*router.Routes`.
|
// Just like `Party#HandleMany`:, it returns the `[]*router.Routes`.
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
|
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
|
||||||
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
|
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// HandleMany will override any routes of this "funcName".
|
// HandleMany will override any routes of this "funcName".
|
||||||
func (c *ControllerActivator) HandleMany(method, path, funcName string, middleware ...context.Handler) []*router.Route {
|
func (c *ControllerActivator) HandleMany(method, path, funcName string, middleware ...context.Handler) []*router.Route {
|
||||||
return c.handleMany(method, path, funcName, true, middleware...)
|
return c.handleMany(method, path, funcName, true, middleware...)
|
||||||
|
|
|
@ -86,6 +86,7 @@ func New(party router.Party) *Application {
|
||||||
// this function simply calls the `New(party)` and its `.Configure(configurators...)`.
|
// this function simply calls the `New(party)` and its `.Configure(configurators...)`.
|
||||||
//
|
//
|
||||||
// A call of `mvc.New(app.Party("/path").Configure(buildMyMVC)` is equal to
|
// A call of `mvc.New(app.Party("/path").Configure(buildMyMVC)` is equal to
|
||||||
|
//
|
||||||
// `mvc.Configure(app.Party("/path"), buildMyMVC)`.
|
// `mvc.Configure(app.Party("/path"), buildMyMVC)`.
|
||||||
//
|
//
|
||||||
// Read more at `New() Application` and `Application#Configure` methods.
|
// Read more at `New() Application` and `Application#Configure` methods.
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
// It requires a specific "version" constraint for a Controller,
|
// It requires a specific "version" constraint for a Controller,
|
||||||
// e.g. ">1.0.0 <=2.0.0".
|
// e.g. ">1.0.0 <=2.0.0".
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// m := mvc.New(dataRouter)
|
// m := mvc.New(dataRouter)
|
||||||
// m.Handle(new(v1Controller), mvc.Version("1.0.0"), mvc.Deprecated(mvc.DeprecationOptions{}))
|
// m.Handle(new(v1Controller), mvc.Version("1.0.0"), mvc.Deprecated(mvc.DeprecationOptions{}))
|
||||||
// m.Handle(new(v2Controller), mvc.Version("2.3.0"))
|
// m.Handle(new(v2Controller), mvc.Version("2.3.0"))
|
||||||
|
|
|
@ -78,8 +78,13 @@ func (c Config) Validate() Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.SessionIDGenerator == nil {
|
if c.SessionIDGenerator == nil {
|
||||||
c.SessionIDGenerator = func(*context.Context) string {
|
c.SessionIDGenerator = func(ctx *context.Context) string {
|
||||||
id, _ := uuid.NewRandom()
|
id, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
ctx.StopWithError(400, err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return id.String()
|
return id.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,24 +94,28 @@ func (s *mem) OnUpdateExpiration(string, time.Duration) error { return nil }
|
||||||
// immutable depends on the store, it may not implement it at all.
|
// immutable depends on the store, it may not implement it at all.
|
||||||
func (s *mem) Set(sid string, key string, value interface{}, _ time.Duration, immutable bool) error {
|
func (s *mem) Set(sid string, key string, value interface{}, _ time.Duration, immutable bool) error {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
s.values[sid].Save(key, value, immutable)
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
store.Save(key, value, immutable)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Get(sid string, key string) interface{} {
|
func (s *mem) Get(sid string, key string) interface{} {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
v := s.values[sid].Get(key)
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return store.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
return v
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
||||||
s.mu.RLock()
|
v := s.Get(sid, key)
|
||||||
v := s.values[sid].Get(key)
|
|
||||||
s.mu.RUnlock()
|
|
||||||
if v != nil {
|
if v != nil {
|
||||||
reflect.ValueOf(outPtr).Set(reflect.ValueOf(v))
|
reflect.ValueOf(outPtr).Set(reflect.ValueOf(v))
|
||||||
}
|
}
|
||||||
|
@ -119,29 +123,45 @@ func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Visit(sid string, cb func(key string, value interface{})) error {
|
func (s *mem) Visit(sid string, cb func(key string, value interface{})) error {
|
||||||
s.values[sid].Visit(cb)
|
s.mu.RLock()
|
||||||
|
store, ok := s.values[sid]
|
||||||
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
store.Visit(cb)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Len(sid string) int {
|
func (s *mem) Len(sid string) int {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
n := s.values[sid].Len()
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return store.Len()
|
||||||
|
}
|
||||||
|
|
||||||
return n
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Delete(sid string, key string) (deleted bool) {
|
func (s *mem) Delete(sid string, key string) (deleted bool) {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
deleted = s.values[sid].Remove(key)
|
store, ok := s.values[sid]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
deleted = store.Remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mem) Clear(sid string) error {
|
func (s *mem) Clear(sid string) error {
|
||||||
s.mu.Lock()
|
s.mu.RLock()
|
||||||
s.values[sid].Reset()
|
store, ok := s.values[sid]
|
||||||
s.mu.Unlock()
|
s.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
store.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -150,7 +170,6 @@ func (s *mem) Release(sid string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
delete(s.values, sid)
|
delete(s.values, sid)
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ func (p *provider) newSession(man *Sessions, sid string, expires time.Duration)
|
||||||
sid: sid,
|
sid: sid,
|
||||||
Man: man,
|
Man: man,
|
||||||
provider: p,
|
provider: p,
|
||||||
flashes: make(map[string]*flashMessage),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onExpire := func() {
|
onExpire := func() {
|
||||||
|
@ -99,6 +98,7 @@ func (p *provider) EndRequest(ctx *context.Context, session *Session) {
|
||||||
// ErrNotFound may be returned from `UpdateExpiration` of a non-existing or
|
// ErrNotFound may be returned from `UpdateExpiration` of a non-existing or
|
||||||
// invalid session entry from memory storage or databases.
|
// invalid session entry from memory storage or databases.
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// if err != nil && err.Is(err, sessions.ErrNotFound) {
|
// if err != nil && err.Is(err, sessions.ErrNotFound) {
|
||||||
// [handle error...]
|
// [handle error...]
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -76,6 +76,7 @@ func (s *Session) runFlashGC() {
|
||||||
delete(s.flashes, key)
|
delete(s.flashes, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,6 +559,10 @@ func (s *Session) SetImmutable(key string, value interface{}) {
|
||||||
// If you want to define more than one flash messages, you will have to use different keys.
|
// If you want to define more than one flash messages, you will have to use different keys.
|
||||||
func (s *Session) SetFlash(key string, value interface{}) {
|
func (s *Session) SetFlash(key string, value interface{}) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
if s.flashes == nil {
|
||||||
|
s.flashes = make(map[string]*flashMessage)
|
||||||
|
}
|
||||||
|
|
||||||
s.flashes[key] = &flashMessage{value: value}
|
s.flashes[key] = &flashMessage{value: value}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ func testSessions(t *testing.T, app *iris.Application) {
|
||||||
s := sessions.Get(ctx)
|
s := sessions.Get(ctx)
|
||||||
sessValues := s.GetAll()
|
sessValues := s.GetAll()
|
||||||
|
|
||||||
_, err := ctx.JSON(sessValues)
|
err := ctx.JSON(sessValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -141,8 +141,7 @@ func TestFlashMessages(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
writeValues := func(ctx *context.Context, values map[string]interface{}) error {
|
writeValues := func(ctx *context.Context, values map[string]interface{}) error {
|
||||||
_, err := ctx.JSON(values)
|
return ctx.JSON(values)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Post("/set", func(ctx *context.Context) {
|
app.Post("/set", func(ctx *context.Context) {
|
||||||
|
|
|
@ -30,9 +30,12 @@ type Group struct {
|
||||||
// any changes to its parent won't affect this one (e.g. register global middlewares afterwards).
|
// any changes to its parent won't affect this one (e.g. register global middlewares afterwards).
|
||||||
//
|
//
|
||||||
// A version is extracted through the versioning.GetVersion function:
|
// A version is extracted through the versioning.GetVersion function:
|
||||||
|
//
|
||||||
// Accept-Version: 1.0.0
|
// Accept-Version: 1.0.0
|
||||||
// Accept: application/json; version=1.0.0
|
// Accept: application/json; version=1.0.0
|
||||||
|
//
|
||||||
// You can customize it by setting a version based on the request context:
|
// You can customize it by setting a version based on the request context:
|
||||||
|
//
|
||||||
// api.Use(func(ctx *context.Context) {
|
// api.Use(func(ctx *context.Context) {
|
||||||
// if version := ctx.URLParam("version"); version != "" {
|
// if version := ctx.URLParam("version"); version != "" {
|
||||||
// SetVersion(ctx, version)
|
// SetVersion(ctx, version)
|
||||||
|
@ -40,11 +43,14 @@ type Group struct {
|
||||||
//
|
//
|
||||||
// ctx.Next()
|
// ctx.Next()
|
||||||
// })
|
// })
|
||||||
|
//
|
||||||
// OR:
|
// OR:
|
||||||
|
//
|
||||||
// api.Use(versioning.FromQuery("version", ""))
|
// api.Use(versioning.FromQuery("version", ""))
|
||||||
//
|
//
|
||||||
// Examples at: _examples/routing/versioning
|
// Examples at: _examples/routing/versioning
|
||||||
// Usage:
|
// Usage:
|
||||||
|
//
|
||||||
// app := iris.New()
|
// app := iris.New()
|
||||||
// api := app.Party("/api")
|
// api := app.Party("/api")
|
||||||
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
|
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
|
||||||
|
@ -61,8 +67,10 @@ type Group struct {
|
||||||
// A Range can consist of multiple ranges separated by space:
|
// A Range can consist of multiple ranges separated by space:
|
||||||
// Ranges can be linked by logical AND:
|
// Ranges can be linked by logical AND:
|
||||||
// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7"
|
// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7"
|
||||||
|
//
|
||||||
// but not "1.0.0" or "2.0.0"
|
// but not "1.0.0" or "2.0.0"
|
||||||
// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0
|
// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0
|
||||||
|
//
|
||||||
// except 2.0.3-beta.2
|
// except 2.0.3-beta.2
|
||||||
//
|
//
|
||||||
// Ranges can also be linked by logical OR:
|
// Ranges can also be linked by logical OR:
|
||||||
|
@ -73,6 +81,7 @@ type Group struct {
|
||||||
// Ranges can be combined by both AND and OR
|
// Ranges can be combined by both AND and OR
|
||||||
//
|
//
|
||||||
// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`,
|
// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`,
|
||||||
|
//
|
||||||
// but not `4.2.1`, `2.1.1`
|
// but not `4.2.1`, `2.1.1`
|
||||||
func NewGroup(r API, version string) *Group {
|
func NewGroup(r API, version string) *Group {
|
||||||
version = strings.ReplaceAll(version, ",", " ")
|
version = strings.ReplaceAll(version, ",", " ")
|
||||||
|
|
|
@ -187,11 +187,13 @@ func GetVersion(ctx *context.Context) string {
|
||||||
// It can be used inside a middleware.
|
// It can be used inside a middleware.
|
||||||
// Example of how you can change the default behavior to extract a requested version (which is by headers)
|
// Example of how you can change the default behavior to extract a requested version (which is by headers)
|
||||||
// from a "version" url parameter instead:
|
// from a "version" url parameter instead:
|
||||||
|
//
|
||||||
// func(ctx iris.Context) { // &version=1
|
// func(ctx iris.Context) { // &version=1
|
||||||
// version := ctx.URLParamDefault("version", "1.0.0")
|
// version := ctx.URLParamDefault("version", "1.0.0")
|
||||||
// versioning.SetVersion(ctx, version)
|
// versioning.SetVersion(ctx, version)
|
||||||
// ctx.Next()
|
// ctx.Next()
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// See `GetVersion` too.
|
// See `GetVersion` too.
|
||||||
func SetVersion(ctx *context.Context, constraint string) {
|
func SetVersion(ctx *context.Context, constraint string) {
|
||||||
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
|
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
|
||||||
|
@ -205,6 +207,7 @@ type AliasMap = map[string]string
|
||||||
// for the children Parties(routers). It's respected by versioning Groups.
|
// for the children Parties(routers). It's respected by versioning Groups.
|
||||||
//
|
//
|
||||||
// Example Code:
|
// Example Code:
|
||||||
|
//
|
||||||
// app := iris.New()
|
// app := iris.New()
|
||||||
//
|
//
|
||||||
// api := app.Party("/api")
|
// api := app.Party("/api")
|
||||||
|
|
|
@ -50,6 +50,7 @@ type (
|
||||||
// through a Context or within filter functions.
|
// through a Context or within filter functions.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// AsValue("my string")
|
// AsValue("my string")
|
||||||
//
|
//
|
||||||
// Shortcut for `pongo2.AsValue`.
|
// Shortcut for `pongo2.AsValue`.
|
||||||
|
|
|
@ -2,7 +2,7 @@ package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -80,7 +80,7 @@ func asset(fs http.FileSystem, name string) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contents, err := ioutil.ReadAll(f)
|
contents, err := io.ReadAll(f)
|
||||||
f.Close()
|
f.Close()
|
||||||
return contents, err
|
return contents, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,7 @@ func (s *HTMLEngine) Reload(developmentMode bool) *HTMLEngine {
|
||||||
//
|
//
|
||||||
// missingkey: Control the behavior during execution if a map is
|
// missingkey: Control the behavior during execution if a map is
|
||||||
// indexed with a key that is not present in the map.
|
// indexed with a key that is not present in the map.
|
||||||
|
//
|
||||||
// "missingkey=default" or "missingkey=invalid"
|
// "missingkey=default" or "missingkey=invalid"
|
||||||
// The default behavior: Do nothing and continue execution.
|
// The default behavior: Do nothing and continue execution.
|
||||||
// If printed, the result of the index operation is the string
|
// If printed, the result of the index operation is the string
|
||||||
|
@ -148,7 +149,6 @@ func (s *HTMLEngine) Reload(developmentMode bool) *HTMLEngine {
|
||||||
// The operation returns the zero value for the map type's element.
|
// The operation returns the zero value for the map type's element.
|
||||||
// "missingkey=error"
|
// "missingkey=error"
|
||||||
// Execution stops immediately with an error.
|
// Execution stops immediately with an error.
|
||||||
//
|
|
||||||
func (s *HTMLEngine) Option(opt ...string) *HTMLEngine {
|
func (s *HTMLEngine) Option(opt ...string) *HTMLEngine {
|
||||||
s.rmu.Lock()
|
s.rmu.Lock()
|
||||||
s.options = append(s.options, opt...)
|
s.options = append(s.options, opt...)
|
||||||
|
@ -172,6 +172,7 @@ func (s *HTMLEngine) Delims(left, right string) *HTMLEngine {
|
||||||
// for the template file with its extension.
|
// for the template file with its extension.
|
||||||
//
|
//
|
||||||
// Example: HTML("./templates", ".html").Layout("layouts/mainLayout.html")
|
// Example: HTML("./templates", ".html").Layout("layouts/mainLayout.html")
|
||||||
|
//
|
||||||
// // mainLayout.html is inside: "./templates/layouts/".
|
// // mainLayout.html is inside: "./templates/layouts/".
|
||||||
//
|
//
|
||||||
// Note: Layout can be changed for a specific call
|
// Note: Layout can be changed for a specific call
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -281,7 +280,7 @@ func (c *Client) Do(ctx context.Context, method, urlpath string, payload interfa
|
||||||
// DrainResponseBody drains response body and close it, allowing the transport to reuse TCP connections.
|
// DrainResponseBody drains response body and close it, allowing the transport to reuse TCP connections.
|
||||||
// It's automatically called on Client.ReadXXX methods on the end.
|
// It's automatically called on Client.ReadXXX methods on the end.
|
||||||
func (c *Client) DrainResponseBody(resp *http.Response) {
|
func (c *Client) DrainResponseBody(resp *http.Response) {
|
||||||
_, _ = io.Copy(ioutil.Discard, resp.Body)
|
_, _ = io.Copy(io.Discard, resp.Body)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +397,7 @@ func (c *Client) ReadJSON(ctx context.Context, dest interface{}, method, urlpath
|
||||||
}
|
}
|
||||||
|
|
||||||
// DBUG
|
// DBUG
|
||||||
// b, _ := ioutil.ReadAll(resp.Body)
|
// b, _ := io.ReadAll(resp.Body)
|
||||||
// println(string(b))
|
// println(string(b))
|
||||||
// return json.Unmarshal(b, &dest)
|
// return json.Unmarshal(b, &dest)
|
||||||
|
|
||||||
|
@ -418,7 +417,7 @@ func (c *Client) ReadPlain(ctx context.Context, dest interface{}, method, urlpat
|
||||||
return ExtractError(resp)
|
return ExtractError(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -495,7 +494,7 @@ func BindResponse(resp *http.Response, dest interface{}) (err error) {
|
||||||
case contentTypeJSON: // the most common scenario on successful responses.
|
case contentTypeJSON: // the most common scenario on successful responses.
|
||||||
return json.NewDecoder(resp.Body).Decode(&dest)
|
return json.NewDecoder(resp.Body).Decode(&dest)
|
||||||
case contentTypePlainText:
|
case contentTypePlainText:
|
||||||
b, err := ioutil.ReadAll(resp.Body)
|
b, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -39,7 +39,7 @@ func (e APIError) Error() string {
|
||||||
|
|
||||||
// ExtractError returns the response wrapped inside an APIError.
|
// ExtractError returns the response wrapped inside an APIError.
|
||||||
func ExtractError(resp *http.Response) APIError {
|
func ExtractError(resp *http.Response) APIError {
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
return APIError{
|
return APIError{
|
||||||
Response: resp,
|
Response: resp,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user