replace ioutil with io package and other minor improvements

This commit is contained in:
Gerasimos (Makis) Maropoulos 2022-06-17 22:03:18 +03:00
parent 20d2855a66
commit ef2643b046
No known key found for this signature in database
GPG Key ID: 3595CBE7F3B4082E
108 changed files with 1069 additions and 1021 deletions

View File

@ -28,6 +28,7 @@ The codebase for Dependency Injection, Internationalization and localization and
## 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.
- 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.

View File

@ -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
modification, are permitted provided that the following conditions are

View File

@ -19,7 +19,8 @@
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
package main
@ -27,18 +28,18 @@ package main
import "github.com/kataras/iris/v12"
func main() {
app := iris.New()
app.Use(iris.Compression)
app := iris.New()
app.Use(iris.Compression)
app.Get("/", func(ctx iris.Context) {
ctx.HTML("Hello <strong>%s</strong>!", "World")
})
app.Get("/", func(ctx iris.Context) {
ctx.HTML("Hello <strong>%s</strong>!", "World")
})
app.Listen(":8080")
app.Listen(":8080")
}
```
<details><summary>More with simple Handler</summary>
<!-- <details><summary>More with simple Handler</summary>
```go
package main
@ -178,6 +179,34 @@ func main() {
<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.
[![](https://iris-go.com/images/reviews.gif)](https://iris-go.com/testimonials/)

View File

@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
@ -105,5 +104,5 @@ func BindResponse(resp *http.Response, dest interface{}) error {
func RawResponse(resp *http.Response) ([]byte, error) {
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
return io.ReadAll(resp.Body)
}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"github.com/kataras/iris/v12/context"
@ -51,7 +51,7 @@ func getExample() {
}
defer cr.Close()
body, err := ioutil.ReadAll(cr)
body, err := io.ReadAll(cr)
if err != nil {
panic(err)
}
@ -103,7 +103,7 @@ func postExample() {
}
defer cr.Close()
body, err := ioutil.ReadAll(cr)
body, err := io.ReadAll(cr)
if err != nil {
panic(err)
}

View File

@ -5,7 +5,7 @@ import (
"compress/gzip"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
)
@ -42,7 +42,7 @@ func getExample() {
}
defer r.Close()
body, err := ioutil.ReadAll(r)
body, err := io.ReadAll(r)
if err != nil {
panic(err)
}
@ -93,7 +93,7 @@ func postExample() {
}
defer r.Close()
body, err := ioutil.ReadAll(r)
body, err := io.ReadAll(r)
if err != nil {
panic(err)
}

View File

@ -11,8 +11,8 @@ import (
const addr = "127.0.0.1:8080"
/*
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
$ ./myapp.exe # run the app
$ go build -mod=mod -ldflags -H=windowsgui -o myapp.exe
$ ./myapp.exe # run the app
*/
func main() {
go runServer()

View File

@ -8,8 +8,8 @@ import (
const addr = "127.0.0.1:8080"
/*
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
$ ./myapp.exe # run
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
$ ./myapp.exe # run
*/
func main() {
go runServer()

View File

@ -8,21 +8,21 @@ import (
const addr = "127.0.0.1:8080"
/*
# Windows requires special linker flags for GUI apps.
# It's also recommended to use TDM-GCC-64 compiler for CGo.
# http://tdm-gcc.tdragon.net/download
#
#
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
$ ./myapp.exe # run
#
# MacOS uses app bundles for GUI apps
$ mkdir -p example.app/Contents/MacOS
$ go build -o example.app/Contents/MacOS/example
$ 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"
# please refer to: https://github.com/webview/webview/issues/188
# Windows requires special linker flags for GUI apps.
# It's also recommended to use TDM-GCC-64 compiler for CGo.
# http://tdm-gcc.tdragon.net/download
#
#
$ go build -mod=mod -ldflags="-H windowsgui" -o myapp.exe # build for windows
$ ./myapp.exe # run
#
# MacOS uses app bundles for GUI apps
$ mkdir -p example.app/Contents/MacOS
$ go build -o example.app/Contents/MacOS/example
$ 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"
# please refer to: https://github.com/webview/webview/issues/188
*/
func main() {
go runServer()

View File

@ -1,7 +1,7 @@
package main
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
@ -47,7 +47,7 @@ func (r resource) loadFromBase(dir string, strip string) string {
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
b, err := os.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}

View File

@ -1,6 +1,6 @@
// 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/favicon.ico
// assets/js/main.js
@ -11,7 +11,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -1,7 +1,7 @@
package main
import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
@ -46,7 +46,7 @@ func (r resource) loadFromBase(dir string) string {
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
b, err := os.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}

View File

@ -1,6 +1,6 @@
// 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/favicon.ico
// ../embedding-files-into-app/assets/js/main.js
@ -11,7 +11,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
@ -348,7 +349,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -2,7 +2,7 @@ package main
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
@ -48,7 +48,7 @@ func (r resource) loadFromBase(dir string) string {
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
b, err := os.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}

View File

@ -1,6 +1,6 @@
// 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/dirs/dir1/text.txt
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
@ -19,7 +19,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -1,6 +1,6 @@
// 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/dirs/dir1/text.txt
// ../http2push/assets/app2/app2app3/dirs/dir2/text.txt
@ -19,7 +19,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -464,11 +463,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
@ -546,7 +547,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -1,6 +1,6 @@
// 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/css/main.css
// public/index.html
@ -11,7 +11,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -288,11 +287,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
@ -346,7 +347,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -12,7 +12,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
@ -377,7 +378,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -1,7 +1,7 @@
package main
import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
@ -41,7 +41,7 @@ func (r resource) loadFromBase(dir string) string {
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
b, err := os.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}

View File

@ -1,8 +1,8 @@
package main
import (
"io/ioutil"
"net"
"os"
"path/filepath"
"testing"
@ -40,7 +40,7 @@ func (r resource) loadFromBase(dir string) string {
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
b, err := os.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}

View File

@ -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".
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
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
import (

View File

@ -5,15 +5,15 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"os"
pb "github.com/kataras/iris/v12/_examples/mvc/grpc-compatible/helloworld"
)
func main() {
b, err := ioutil.ReadFile("../server.crt")
b, err := os.ReadFile("../server.crt")
if err != nil {
log.Fatal(err)
}

View File

@ -30,14 +30,16 @@ type UsersController struct {
// curl -i -u admin:password http://localhost:8080/users
//
// The correct way if you have sensitive data:
// func (c *UsersController) Get() (results []viewmodels.User) {
// data := c.Service.GetAll()
//
// for _, user := range data {
// results = append(results, viewmodels.User{user})
// }
// return
// }
// func (c *UsersController) Get() (results []viewmodels.User) {
// data := c.Service.GetAll()
//
// for _, user := range data {
// results = append(results, viewmodels.User{user})
// }
// return
// }
//
// otherwise just return the datamodels.
func (c *UsersController) Get() (results []datamodels.User) {
return c.Service.GetAll()

View File

@ -9,9 +9,11 @@ else as well, otherwise I am going with the first one:
```go
// 1
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
m.Router.Use(cache.Handler(10*time.Second))
})
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
m.Router.Use(cache.Handler(10*time.Second))
})
```
```go
@ -32,10 +34,12 @@ mvc.Configure(userRouter, ...)
```go
// 4
// same:
app.PartyFunc("/user", func(r iris.Party){
r.Use(cache.Handler(10*time.Second))
mvc.Configure(r, ...)
})
app.PartyFunc("/user", func(r iris.Party){
r.Use(cache.Handler(10*time.Second))
mvc.Configure(r, ...)
})
```
If you want to use a middleware for a single route,
@ -48,16 +52,18 @@ then you just call it on the method:
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
type UserController struct{}
func (c *UserController) GetSomething(ctx iris.Context) {
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
// inside it and returns true if so, otherwise false.
nextCalled := ctx.Proceed(myMiddleware)
if !nextCalled {
return
}
// else do the job here, it's allowed
}
func (c *UserController) GetSomething(ctx iris.Context) {
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
// inside it and returns true if so, otherwise false.
nextCalled := ctx.Proceed(myMiddleware)
if !nextCalled {
return
}
// else do the job here, it's allowed
}
```
And last, if you want to add a middleware on a specific method

View File

@ -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.
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
import (

View File

@ -28,42 +28,45 @@ func pong(ctx iris.Context) {
}
/*
+-------------------+
| Env (DEV, PROD) |
+---------+---------+
| | |
| | |
| | |
DEV | | | PROD
+-------------------+
| Env (DEV, PROD) |
+---------+---------+
| | |
| | |
| | |
DEV | | | PROD
-------------------+---------------------+ | +----------------------+-------------------
| | |
| | |
+---+-----+ +----------------v------------------+ +----+----+
| sqlite | | NewDB(Env) DB | | mysql |
+---+-----+ +----------------+---+--------------+ +----+----+
| | | |
| | | |
| | | |
+--------------+-----+ +-------------------v---v-----------------+ +----+------+
| greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter |
+--------------+-----+ +---------------------------+-------------+ +----+------+
| | |
| | |
| +-----------------------------------------+ |
| | GreetController | | |
| | | | |
| | - Service GreetService <-- | |
| | | |
| +-------------------+---------------------+ |
| | |
| | |
| | |
| +-----------+-----------+ |
| | HTTP Request | |
| +-----------------------+ |
| | /greet?name=kataras | |
| +-----------+-----------+ |
| | |
| | |
| | |
+---+-----+ +----------------v------------------+ +----+----+
| sqlite | | NewDB(Env) DB | | mysql |
+---+-----+ +----------------+---+--------------+ +----+----+
| | | |
| | | |
| | | |
+--------------+-----+ +-------------------v---v-----------------+ +----+------+
| greeterWithLogging | | NewGreetService(Env, DB) GreetService | | greeter |
+--------------+-----+ +---------------------------+-------------+ +----+------+
| | |
| | |
| +-----------------------------------------+ |
| | GreetController | | |
| | | | |
| | - Service GreetService <-- | |
| | | |
| +-------------------+---------------------+ |
| | |
| | |
| | |
| +-----------+-----------+ |
| | HTTP Request | |
| +-----------------------+ |
| | /greet?name=kataras | |
| +-----------+-----------+ |
| | |
+------------------+--------+ +------------+------------+ +-------+------------------+
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
+---------------------------+ +-------------------------+ +--------------------------+

View File

@ -23,14 +23,16 @@ type MovieController struct {
// curl -i http://localhost:8080/movies
//
// The correct way if you have sensitive data:
// func (c *MovieController) Get() (results []viewmodels.Movie) {
// data := c.Service.GetAll()
//
// for _, movie := range data {
// results = append(results, viewmodels.Movie{movie})
// }
// return
// }
// func (c *MovieController) Get() (results []viewmodels.Movie) {
// data := c.Service.GetAll()
//
// for _, movie := range data {
// results = append(results, viewmodels.Movie{movie})
// }
// return
// }
//
// otherwise just return the datamodels.
func (c *MovieController) Get() (results []datamodels.Movie) {
return c.Service.GetAll()

View File

@ -18,7 +18,7 @@ func (srv *Server) buildRouter() {
ServerName: srv.config.ServerName,
Env: srv.config.Env,
Developer: "kataras",
TimeLocation: time.FixedZone("Greece/Athens", 10800),
TimeLocation: time.FixedZone("Greece/Athens", 7200),
}))
api := srv.Party("/api")

View File

@ -8,7 +8,7 @@ func main() {
app := iris.New()
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.
if err != nil {
ctx.StopWithError(iris.StatusInternalServerError, err)

View File

@ -4,7 +4,7 @@ import (
"bytes"
"compress/gzip"
"encoding/xml"
"io/ioutil"
"io"
"testing"
"github.com/kataras/iris/v12"
@ -69,7 +69,7 @@ func TestContentNegotiation(t *testing.T) {
t.Fatal(err)
}
rawResponse, err := ioutil.ReadAll(zr)
rawResponse, err := io.ReadAll(zr)
if err != nil {
t.Fatal(err)
}

View File

@ -7,14 +7,15 @@ import (
"github.com/kataras/iris/v12/core/router"
)
/* A Router should contain all three of the following methods:
- HandleRequest should handle the request based on the Context.
HandleRequest(ctx iris.Context)
- Build should builds the handler, it's being called on router's BuildRouter.
Build(provider router.RoutesProvider) error
- RouteExists reports whether a particular route exists.
RouteExists(ctx iris.Context, method, path string) bool
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
/*
A Router should contain all three of the following methods:
- HandleRequest should handle the request based on the Context.
HandleRequest(ctx iris.Context)
- Build should builds the handler, it's being called on router's BuildRouter.
Build(provider router.RoutesProvider) error
- RouteExists reports whether a particular route exists.
RouteExists(ctx iris.Context, method, path string) bool
- FireErrorCode(ctx iris.Context) should handle the given ctx.GetStatusCode().
For a more detailed, complete and useful example
you can take a look at the iris' router itself which is located at:

View File

@ -1,7 +1,7 @@
package main
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
@ -29,7 +29,7 @@ func (r resource) loadFromBase(dir string) string {
fullpath := filepath.Join(dir, filename)
b, err := ioutil.ReadFile(fullpath)
b, err := os.ReadFile(fullpath)
if err != nil {
panic(fullpath + " failed with error: " + err.Error())
}

View File

@ -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,
but with the `ExecutionRules` we can change this default behavior.
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
to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers:
app.SetExecutionRules(iris.ExecutionRules {
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
})
app.SetExecutionRules(iris.ExecutionRules {
Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use)
Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...)
Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done)
})
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).
@ -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
with `Party#SetExecutionRules(iris.ExecutionRules{})`.
*/
package main

View File

@ -1,7 +1,6 @@
package main
import (
"io/ioutil"
"os"
"testing"
"time"
@ -14,7 +13,7 @@ import (
// The rest possible checks is up to you, take it as as an exercise!
func TestURLShortener(t *testing.T) {
// temp db file
f, err := ioutil.TempFile("", "shortener")
f, err := os.CreateTemp("", "shortener")
if err != nil {
t.Fatalf("creating temp file for database failed: %v", err)
}

View File

@ -1,6 +1,6 @@
// 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/mylayout.html
// templates/page1.html
@ -12,7 +12,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -10,7 +10,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
@ -323,7 +324,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -13,7 +13,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -332,11 +331,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
@ -394,7 +395,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -12,7 +12,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -310,11 +309,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
@ -371,7 +372,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -10,7 +10,6 @@ import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@ -266,11 +265,13 @@ var _bindata = map[string]func() (*asset, error){
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
//
// data/
// foo.txt
// img/
// a.png
// b.png
//
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error
@ -321,7 +322,7 @@ func RestoreAsset(dir, name string) error {
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}

View File

@ -12,7 +12,6 @@ package main
import (
"flag"
"io/ioutil"
"log"
"os"
"strconv"
@ -53,7 +52,7 @@ func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
if !fi.ModTime().After(lastMod) {
return nil, lastMod, nil
}
p, err := ioutil.ReadFile(filename)
p, err := os.ReadFile(filename)
if err != nil {
return nil, fi.ModTime(), err
}

View File

@ -13,12 +13,13 @@ import (
// The cases are filtered in order of their registration.
//
// Example Code:
// switcher := Switch(Hosts{
// "mydomain.com": app,
// "test.mydomain.com": testSubdomainApp,
// "otherdomain.com": "appName",
// })
// switcher.Listen(":80")
//
// switcher := Switch(Hosts{
// "mydomain.com": app,
// "test.mydomain.com": testSubdomainApp,
// "otherdomain.com": "appName",
// })
// switcher.Listen(":80")
//
// Note that this is NOT an alternative for a load balancer.
// The filters are executed by registration order and a matched Application

View File

@ -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)
// and panics if the error is non-nil. It is intended for use in variable
// initializations such as
//
// var s = auth.Must(auth.New[MyUser](config))
func Must[T User](s *Auth[T], err error) *Auth[T] {
if err != nil {
@ -142,12 +143,13 @@ 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.
//
// Usage Example:
// api := app.Party("/api")
// api.EnsureStaticBindings().RegisterDependency(
// NewAuthProviderErrorHandler(),
// NewAuthCustomerProvider,
// auth.Must(auth.New[Customer](authConfig)).WithProviderAndErrorHandler,
// )
//
// api := app.Party("/api")
// api.EnsureStaticBindings().RegisterDependency(
// NewAuthProviderErrorHandler(),
// NewAuthCustomerProvider,
// auth.Must(auth.New[Customer](authConfig)).WithProviderAndErrorHandler,
// )
func (s *Auth[T]) WithProviderAndErrorHandler(provider Provider[T], errHandler ErrorHandler) *Auth[T] {
if provider != nil {
for i := range s.providers {

9
cache/browser.go vendored
View File

@ -49,10 +49,11 @@ var NoCache = func(ctx *context.Context) {
// 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:
// cacheMiddleware := cache.StaticCache(...)
// func(ctx iris.Context){
// cacheMiddleware(ctx)
// [...]
// }
//
// func(ctx iris.Context){
// cacheMiddleware(ctx)
// [...]
// }
var StaticCache = func(cacheDur time.Duration) context.Handler {
if int64(cacheDur) <= 0 {
return NoCache

View File

@ -2,7 +2,7 @@ package client
import (
"bytes"
"io/ioutil"
"io"
"net/http"
"time"
@ -17,8 +17,8 @@ import (
// register one client handler per route.
//
// 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 {
// bodyHandler the original route's 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
ctx.ContentType(response.Header.Get(cfg.ContentTypeHeader))
ctx.StatusCode(response.StatusCode)
responseBody, err := ioutil.ReadAll(response.Body)
responseBody, err := io.ReadAll(response.Body)
response.Body.Close()
if err != nil {
return

View File

@ -22,12 +22,13 @@ type PreValidator func(*context.Context) bool
//
// 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
// 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,
// also the PostValidator should return true to store the cached response.
// Last, a PostValidator accepts a context
// in order to be able to catch the original handler's response,
// the PreValidator checks only for request.
//
// 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,
// also the PostValidator should return true to store the cached response.
// Last, a PostValidator accepts a context
// in order to be able to catch the original handler's response,
// the PreValidator checks only for request.
//
// If a function of type of PostValidator returns true then the (shared-always) cache is allowed to be stored.
type PostValidator func(*context.Context) bool

View File

@ -2,7 +2,6 @@ package iris
import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
@ -65,7 +64,7 @@ func parseYAML(filename string) (Configuration, error) {
}
// read the raw contents of the file
data, err := ioutil.ReadFile(yamlAbsPath)
data, err := os.ReadFile(yamlAbsPath)
if err != nil {
return c, fmt.Errorf("parse yaml: %w", err)
}
@ -112,7 +111,6 @@ func YAML(filename string) Configuration {
// Read more about toml's implementation at:
// https://github.com/toml-lang/toml
//
//
// Accepts the absolute path of the configuration file.
// 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.
@ -144,7 +142,7 @@ func TOML(filename string) Configuration {
}
// read the raw contents of the file
data, err := ioutil.ReadFile(tomlAbsPath)
data, err := os.ReadFile(tomlAbsPath)
if err != nil {
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.
//
// 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"`
// EnableProtoJSON when this field is true
// enables the proto marshaler on given proto messages when calling the Context.JSON method.

View File

@ -1,7 +1,6 @@
package iris
import (
"io/ioutil"
"os"
"reflect"
"testing"
@ -103,7 +102,7 @@ func createGlobalConfiguration(t *testing.T) {
out, err := yaml.Marshal(&c)
if err == nil {
err = ioutil.WriteFile(filename, out, os.FileMode(0666))
err = os.WriteFile(filename, out, os.FileMode(0666))
}
if err != nil {
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) {
yamlFile, ferr := ioutil.TempFile("", "configuration.yml")
yamlFile, ferr := os.CreateTemp("", "configuration.yml")
if ferr != nil {
t.Fatal(ferr)
@ -264,7 +263,7 @@ Other:
}
func TestConfigurationTOML(t *testing.T) {
tomlFile, ferr := ioutil.TempFile("", "configuration.toml")
tomlFile, ferr := os.CreateTemp("", "configuration.toml")
if ferr != nil {
t.Fatal(ferr)

File diff suppressed because it is too large Load Diff

View File

@ -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.
// Usage:
// user := map[string]interface{}{
// "username": "kataras",
// "age" : 27,
// }
//
// user := map[string]interface{}{
// "username": "kataras",
// "age" : 27,
// }
//
// ctx.SetUser(user)
// OR
// user := UserStruct{....}

View File

@ -275,7 +275,6 @@ type Filter func(*Context) bool
// 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.
//
//
// It checks the "filter" and if passed then
// it, correctly, executes the "handlers".
//

View File

@ -131,11 +131,12 @@ func (r *RequestParams) GetIntUnslashed(key string) (int, bool) {
// Key is the specific type, which should be unique.
// The value is a function which accepts the parameter index
// and it should return the value as the parameter type evaluator expects it.
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
// return func(ctx *Context) <T> {
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
// }
// }
//
// i.e [reflect.TypeOf("string")] = func(paramIndex int) interface{} {
// return func(ctx *Context) <T> {
// return ctx.Params().GetEntryAt(paramIndex).ValueRaw.(<T>)
// }
// }
//
// Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
// Checks for total available request parameters length
@ -261,7 +262,9 @@ var ParamResolvers = map[reflect.Type]func(paramIndex int) interface{}{
// and the parameter's index based on the registered path.
// Usage: nameResolver := ParamResolverByKindAndKey(reflect.TypeOf(""), 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
// only when Macros are modified in such way that the default selections for the available go std types are not enough.
//

View File

@ -4,7 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/textproto"
"strconv"
@ -32,7 +32,7 @@ func releaseResponseRecorder(w *ResponseRecorder) {
// A ResponseRecorder is used mostly for testing
// 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 {
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))
if w.chunks != nil {
res.Body = ioutil.NopCloser(bytes.NewReader(w.chunks))
res.Body = io.NopCloser(bytes.NewReader(w.chunks))
} else {
res.Body = http.NoBody
}

View File

@ -111,7 +111,6 @@ func StatusText(code int) string {
// Read more at `iris/Configuration#DisableAutoFireStatusCode` and
// `iris/core/router/Party#OnAnyErrorCode` for relative information.
//
//
// Modify this variable when your Iris server or/and client
// not follows the RFC: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
var StatusCodeNotSuccessful = func(statusCode int) bool { return statusCode >= 400 }

View File

@ -10,9 +10,10 @@ import (
// FromStd converts native http.Handler & http.HandlerFunc to context.Handler.
//
// Supported form types:
// .FromStd(h http.Handler)
// .FromStd(func(w http.ResponseWriter, r *http.Request))
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
//
// .FromStd(h http.Handler)
// .FromStd(func(w http.ResponseWriter, r *http.Request))
// .FromStd(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc))
func FromStd(handler interface{}) context.Handler {
switch h := handler.(type) {
case context.Handler:

View File

@ -730,7 +730,6 @@ func (e Entry) Value() interface{} {
// Save same as `Set`
// 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
// 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) {

View File

@ -377,8 +377,9 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
// (see ConfigureContainer().RegisterDependency)
// or leave the framework to parse the request and fill the values accordingly.
// The output of the "handlersFn" can be any output result:
// custom structs <T>, string, []byte, int, error,
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
//
// custom structs <T>, string, []byte, int, error,
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
//
// If more than one handler function is registered
// then the execution happens without the nessecity of the `Context.Next` method,
@ -390,22 +391,22 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
// The client's request body and server's response body Go types.
// Could be any data structure.
//
// type (
// request struct {
// Firstname string `json:"firstname"`
// Lastname string `json:"lastname"`
// }
// type (
// request struct {
// Firstname string `json:"firstname"`
// Lastname string `json:"lastname"`
// }
//
// response struct {
// ID uint64 `json:"id"`
// Message string `json:"message"`
// }
// )
// response struct {
// ID uint64 `json:"id"`
// Message string `json:"message"`
// }
// )
//
// Register the route hander.
//
// HTTP VERB ROUTE PATH ROUTE HANDLER
// app.HandleFunc("PUT", "/users/{id:uint64}", updateUser)
// HTTP VERB ROUTE PATH ROUTE HANDLER
// app.HandleFunc("PUT", "/users/{id:uint64}", updateUser)
//
// Code the route handler function.
// Path parameters and request body are binded
@ -413,26 +414,26 @@ func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) {
// The "id" uint64 binds to "{id:uint64}" route path parameter and
// the "input" binds to client request data such as JSON.
//
// func updateUser(id uint64, input request) response {
// // [custom logic...]
// func updateUser(id uint64, input request) response {
// // [custom logic...]
//
// return response{
// ID:id,
// Message: "User updated successfully",
// }
// }
// return response{
// ID:id,
// Message: "User updated successfully",
// }
// }
//
// Simulate a client request which sends data
// to the server and prints out the response.
//
// curl --request PUT -d '{"firstname":"John","lastname":"Doe"}' \
// -H "Content-Type: application/json" \
// http://localhost:8080/users/42
// curl --request PUT -d '{"firstname":"John","lastname":"Doe"}' \
// -H "Content-Type: application/json" \
// http://localhost:8080/users/42
//
// {
// "id": 42,
// "message": "User updated successfully"
// }
// {
// "id": 42,
// "message": "User updated successfully"
// }
//
// See the `ConfigureContainer` for more features regrading
// the dependency injection, mvc and function handlers.
@ -474,11 +475,12 @@ 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
// 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:
// Party#SetExecutionRules(iris.ExecutionRules {
// Begin: iris.ExecutionOptions{Force: true},
// Main: iris.ExecutionOptions{Force: true},
// Done: iris.ExecutionOptions{Force: true},
// })
//
// Party#SetExecutionRules(iris.ExecutionRules {
// Begin: iris.ExecutionOptions{Force: true},
// Main: iris.ExecutionOptions{Force: true},
// Done: iris.ExecutionOptions{Force: true},
// })
//
// Note that if : true then the only remained way to "break" the handler chain is by `ctx.StopExecution()` now that `ctx.Next()` does not matter.
//
@ -567,11 +569,14 @@ func (api *APIBuilder) handle(errorCode int, method string, relativePath string,
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
//
// 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:
// app.Handle("GET", "/user", userHandler)
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
// app.Handle("GET", "/user/me", userMeHandler)
//
// app.Handle("GET", "/user", userHandler)
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
// app.Handle("GET", "/user/me", userMeHandler)
//
// app.HandleMany("GET POST", "/path", handler)
func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti string, handlers ...context.Handler) (routes []*Route) {
@ -606,7 +611,7 @@ func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti stri
//
// Alternatively, to get just the handler for that look the FileServer function instead.
//
// api.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{IndexName: "/index.html", Compress: true})
// api.HandleDir("/static", iris.Dir("./assets"), iris.DirOptions{IndexName: "/index.html", Compress: true})
//
// Returns all the registered routes, including GET index and path patterm and HEAD.
//
@ -904,12 +909,13 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
// Note: `iris#Party` and `core/router#Party` describes the exactly same interface.
//
// Usage:
// app.PartyFunc("/users", func(u iris.Party){
// u.Use(authMiddleware, logMiddleware)
// u.Get("/", getAllUsers)
// u.Post("/", createOrUpdateUser)
// u.Delete("/", deleteUser)
// })
//
// app.PartyFunc("/users", func(u iris.Party){
// u.Use(authMiddleware, logMiddleware)
// u.Get("/", getAllUsers)
// u.Post("/", createOrUpdateUser)
// u.Delete("/", deleteUser)
// })
//
// Look `Party` for more.
func (api *APIBuilder) PartyFunc(relativePath string, partyBuilderFunc func(p Party)) Party {
@ -949,16 +955,21 @@ type (
// Useful when the api's dependencies amount are too much to pass on a function.
//
// Usage:
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
//
// app.PartyConfigure("/users", &api.UsersAPI{UserRepository: ..., ...})
//
// Where UsersAPI looks like:
// type UsersAPI struct { [...] }
// func(api *UsersAPI) Configure(router iris.Party) {
// router.Get("/{id:uuid}", api.getUser)
// [...]
// }
//
// type UsersAPI struct { [...] }
// func(api *UsersAPI) Configure(router iris.Party) {
// router.Get("/{id:uuid}", api.getUser)
// [...]
// }
//
// Usage with (static) dependencies:
// app.RegisterDependency(userRepo, ...)
// app.PartyConfigure("/users", new(api.UsersAPI))
//
// app.RegisterDependency(userRepo, ...)
// app.PartyConfigure("/users", new(api.UsersAPI))
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
var child Party
@ -1626,15 +1637,16 @@ func (api *APIBuilder) RegisterView(viewEngine context.ViewEngine) {
// FallbackView registers one or more fallback views for a template or a template layout.
// Usage:
// FallbackView(iris.FallbackView("fallback.html"))
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
// OR
// FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
// err.Name is the previous template name.
// err.IsLayout reports whether the failure came from the layout template.
// err.Data is the template data provided to the previous View call.
// [...custom logic e.g. ctx.View("fallback", err.Data)]
// })
//
// FallbackView(iris.FallbackView("fallback.html"))
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
// OR
// FallbackView(iris.FallbackViewFunc(ctx iris.Context, err iris.ErrViewNotExist) error {
// err.Name is the previous template name.
// err.IsLayout reports whether the failure came from the layout template.
// err.Data is the template data provided to the previous View call.
// [...custom logic e.g. ctx.View("fallback", err.Data)]
// })
func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
handler := func(ctx *context.Context) {
ctx.FallbackView(provider)
@ -1653,9 +1665,10 @@ func (api *APIBuilder) FallbackView(provider context.FallbackViewProvider) {
// app := iris.New()
// app.RegisterView(iris.$VIEW_ENGINE("./views", ".$extension"))
// my := app.Party("/my").Layout("layouts/mylayout.html")
// my.Get("/", func(ctx iris.Context) {
// ctx.View("page1.html")
// })
//
// my.Get("/", func(ctx iris.Context) {
// ctx.View("page1.html")
// })
//
// Examples: https://github.com/kataras/iris/tree/master/_examples/view
func (api *APIBuilder) Layout(tmplLayoutFile string) Party {

View File

@ -12,7 +12,6 @@ import (
"github.com/kataras/golog"
)
//
// randStringBytesMaskImprSrc helps us to generate random paths for the test,
// the below piece of code is external, as an answer to a stackoverflow question.
//

View File

@ -7,7 +7,6 @@ import (
"html"
"html/template"
"io"
"io/ioutil"
"net/http"
"net/url"
"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())
contents, err := ioutil.ReadAll(f)
contents, err := io.ReadAll(f)
f.Close()
if err != nil {
return err

View File

@ -6,9 +6,10 @@ import (
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
// Usage:
// Party#SetExecutionRules(ExecutionRules {
// Done: ExecutionOptions{Force: true},
// })
//
// Party#SetExecutionRules(ExecutionRules {
// Done: ExecutionOptions{Force: true},
// })
//
// See `Party#SetExecutionRules` for more.
type ExecutionRules struct {

View File

@ -560,9 +560,9 @@ func init() {
// system's mime.types file(s) if available under one or more of these
// names:
//
// /etc/mime.types
// /etc/apache2/mime.types
// /etc/apache/mime.types
// /etc/mime.types
// /etc/apache2/mime.types
// /etc/apache/mime.types
//
// On Windows, MIME types are extracted from the registry.
//

View File

@ -491,8 +491,9 @@ func (r *Route) GetTitle() string {
// Should be called after `Build` state.
//
// It prints the @method: @path (@description) (@route_rel_location)
// * @handler_name (@handler_rel_location)
// * @second_handler ...
// - @handler_name (@handler_rel_location)
// - @second_handler ...
//
// If route and handler line:number locations are equal then the second is ignored.
func (r *Route) Trace(w io.Writer, stoppedIndex int) {
title := r.GetTitle()

21
doc.go
View File

@ -34,34 +34,33 @@ Easy to learn for new gophers and advanced features for experienced, it goes as
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.
$ go get github.com/kataras/iris/v12@master
$ go get github.com/kataras/iris/v12@master
Wiki:
https://github.com/kataras/iris/wiki
https://github.com/kataras/iris/wiki
Examples:
https://github.com/kataras/iris/tree/master/_examples
https://github.com/kataras/iris/tree/master/_examples
Middleware:
https://github.com/kataras/iris/tree/master/middleware
https://github.com/iris-contrib/middleware
https://github.com/kataras/iris/tree/master/middleware
https://github.com/iris-contrib/middleware
Home Page:
https://iris-go.com
https://iris-go.com
*/
package iris

1
go.mod
View File

@ -15,7 +15,6 @@ require (
github.com/fatih/structs v1.1.0
github.com/flosch/pongo2/v4 v4.0.2
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/google/uuid v1.3.0
github.com/gorilla/securecookie v1.1.1

2
go.sum generated
View File

@ -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/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
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.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=

View File

@ -326,23 +326,28 @@ func Handler(fn interface{}) context.Handler {
// It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application,
// 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
// 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)
// 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.
//
// func(<T>) <R>
// func(<T>) <R>
//
// - The result of the function is a dependency too.
// If <R> is a request-scope dependency (dynamic) then
// 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
// 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 {

View File

@ -27,11 +27,9 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
switch context.TrimHeaderValue(ctx.GetContentType()) {
case context.ContentXMLHeaderValue, context.ContentXMLUnreadableHeaderValue:
_, err := ctx.XML(v)
return err
return ctx.XML(v)
case context.ContentYAMLHeaderValue:
_, err := ctx.YAML(v)
return err
return ctx.YAML(v)
case context.ContentProtobufHeaderValue:
msg, ok := v.(proto.Message)
if !ok {
@ -45,8 +43,7 @@ func defaultResultHandler(ctx *context.Context, v interface{}) error {
return err
default:
// otherwise default to JSON.
_, err := ctx.JSON(v)
return err
return ctx.JSON(v)
}
}

View File

@ -92,7 +92,7 @@ func (e err) Dispatch(ctx iris.Context) {
// write the status code based on the err's StatusCode.
ctx.StatusCode(e.Status)
// send to the client the whole object as json
_, _ = ctx.JSON(e)
_ = ctx.JSON(e)
}
func GetCustomErrorAsDispatcher() err {

View File

@ -98,9 +98,12 @@ func DefaultConfiguration() *Configuration {
// New Prepares and returns a new test framework based on the "app".
// Usage:
// httptest.New(t, app)
//
// httptest.New(t, app)
//
// 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.
func New(t *testing.T, app *iris.Application, setters ...OptionSetter) *httpexpect.Expect {

View File

@ -152,7 +152,7 @@ func (loc *Locale) Tag() *language.Tag {
}
// 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.
func (loc *Locale) Language() string {

View File

@ -3,7 +3,7 @@ package i18n
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@ -33,7 +33,7 @@ func Glob(globPattern string, options LoaderConfig) Loader {
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),

20
iris.go
View File

@ -299,6 +299,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
//
// Adding custom levels requires import of the `github.com/kataras/golog` package:
//
// First we create our level to a golog.Level
// in order to be used in the Log functions.
// var SuccessLevel golog.Level = 6
@ -309,6 +310,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
// // ColorfulText (Green Color[SUCC])
// ColorfulText: "\x1b[32m[SUCC]\x1b[0m",
// }
//
// Usage:
// app.Logger().SetLevel("success")
// app.Logger().Logf(SuccessLevel, "a custom leveled log message")
@ -437,12 +439,12 @@ func (app *Application) GetContextPool() *context.Pool {
//
// ExampleCode:
//
// type contextErrorHandler struct{}
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
// errors.InvalidArgument.Err(ctx, err)
// }
// ...
// app.SetContextErrorHandler(new(contextErrorHandler))
// type contextErrorHandler struct{}
// func (e *contextErrorHandler) HandleContextError(ctx iris.Context, err error) {
// errors.InvalidArgument.Err(ctx, err)
// }
// ...
// app.SetContextErrorHandler(new(contextErrorHandler))
func (app *Application) SetContextErrorHandler(errHandler context.ErrorHandler) *Application {
app.contextErrorHandler = errHandler
return app
@ -653,9 +655,9 @@ func (app *Application) Shutdown(ctx stdContext.Context) error {
//
// import "github.com/kataras/iris/v12/core/errgroup"
//
// errgroup.Walk(app.Build(), func(typ interface{}, err error) {
// app.Logger().Errorf("%s: %s", typ, err)
// })
// errgroup.Walk(app.Build(), func(typ interface{}, err error) {
// app.Logger().Errorf("%s: %s", typ, err)
// })
func (app *Application) Build() error {
if app.builded {
return nil

View File

@ -237,7 +237,7 @@ type (
Step3 interface {
// Health enables the /health route.
// 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
}

View File

@ -18,7 +18,9 @@ import (
// Note that the builtin macros return error too, but they're handled
// by the `else` literal (error code). To change this behavior
// 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`.
//
// See macro.HandleError to set it.

View File

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
@ -324,7 +323,7 @@ func BenchmarkAccessLogAfterPrint(b *testing.B) {
}
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
ac := New(ioutil.Discard)
ac := New(io.Discard)
ac.Clock = TClock(time.Time{})
ac.BytesReceived = false
ac.BytesReceivedBody = false

View File

@ -11,6 +11,7 @@ import (
)
// Log represents the log data specifically for the accesslog middleware.
//
//easyjson:json
type Log struct {
// The AccessLog instance this Log was created of.

View File

@ -52,8 +52,9 @@ type ErrorHandler func(ctx *context.Context, err error)
// The only required value is the Allow field.
//
// Usage:
// opts := Options { ... }
// auth := New(opts)
//
// opts := Options { ... }
// auth := New(opts)
type Options struct {
// Realm directive, read http://tools.ietf.org/html/rfc2617#section-1.2 for details.
// E.g. "Authorization Required".
@ -171,17 +172,18 @@ type BasicAuth struct {
// The result should be used to wrap an existing handler or the HTTP application's root router.
//
// Example Code:
// opts := basicauth.Options{
// Realm: basicauth.DefaultRealm,
// ErrorHandler: basicauth.DefaultErrorHandler,
// MaxAge: 2 * time.Hour,
// GC: basicauth.GC{
// Every: 3 * time.Hour,
// },
// Allow: basicauth.AllowUsers(users),
// }
// auth := basicauth.New(opts)
// app.Use(auth)
//
// opts := basicauth.Options{
// Realm: basicauth.DefaultRealm,
// ErrorHandler: basicauth.DefaultErrorHandler,
// MaxAge: 2 * time.Hour,
// GC: basicauth.GC{
// Every: 3 * time.Hour,
// },
// Allow: basicauth.AllowUsers(users),
// }
// auth := basicauth.New(opts)
// app.Use(auth)
//
// Access the user in the route handler with: ctx.User().GetRaw().(*myCustomType).
//
@ -238,16 +240,18 @@ func New(opts Options) context.Handler {
// are required as they are compared against the user input
// when access to protected resource is requested.
// A user list can defined with one of the following values:
// map[string]string form of: {username:password, ...}
// 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 contains at least Username and Password fields.
//
// map[string]string form of: {username:password, ...}
// 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 contains at least Username and Password fields.
//
// Usage:
// auth := Default(map[string]string{
// "admin": "admin",
// "john": "p@ss",
// })
//
// auth := Default(map[string]string{
// "admin": "admin",
// "john": "p@ss",
// })
func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
opts := Options{
Realm: DefaultRealm,
@ -260,7 +264,8 @@ func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
// a filename to load the users from.
//
// Usage:
// auth := Load("users.yml")
//
// auth := Load("users.yml")
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
opts := Options{
Realm: DefaultRealm,

View File

@ -3,7 +3,7 @@ package basicauth
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
@ -16,8 +16,8 @@ import (
// ReadFile can be used to customize the way the
// AllowUsersFile function is loading the filename from.
// Example of usage: embedded users.yml file.
// Defaults to the `ioutil.ReadFile` which reads the file from the physical disk.
var ReadFile = ioutil.ReadFile
// Defaults to the `os.ReadFile` which reads the file from the physical disk.
var ReadFile = os.ReadFile
// User is a partial part of the iris.User interface.
// It's used to declare a static slice of registered User for authentication.
@ -48,10 +48,11 @@ type UserAuthOption func(*UserAuthOptions)
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
//
// Usage:
// Default(..., BCRYPT) OR
// Load(..., BCRYPT) OR
// Options.Allow = AllowUsers(..., BCRYPT) OR
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
//
// Default(..., BCRYPT) OR
// Load(..., BCRYPT) OR
// Options.Allow = AllowUsers(..., BCRYPT) OR
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
func BCRYPT(opts *UserAuthOptions) {
opts.ComparePassword = func(stored, userPassword string) bool {
err := bcrypt.CompareHashAndPassword([]byte(stored), []byte(userPassword))
@ -75,10 +76,11 @@ func toUserAuthOptions(opts []UserAuthOption) (options UserAuthOptions) {
// 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:
// map[string]string e.g. {username: password, username: password...}.
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
// []T which T completes the User interface.
// []T which T contains at least Username and Password fields.
//
// map[string]string e.g. {username: password, username: password...}.
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
// []T which T completes the User interface.
// []T which T contains at least Username and Password fields.
//
// Usage:
// New(Options{Allow: AllowUsers(..., [BCRYPT])})
@ -155,15 +157,17 @@ func userMap(usernamePassword map[string]string, opts ...UserAuthOption) AuthFun
// loaded from a file on initialization.
//
// Example Code:
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
//
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
//
// The users.yml file looks like the following:
// - username: kataras
// password: kataras_pass
// age: 27
// role: admin
// - username: makis
// password: makis_password
// ...
// - username: kataras
// password: kataras_pass
// age: 27
// role: admin
// - username: makis
// password: makis_password
// ...
func AllowUsersFile(jsonOrYamlFilename string, opts ...UserAuthOption) AuthFunc {
var (
usernamePassword map[string]string

View File

@ -2,7 +2,6 @@ package basicauth
import (
"errors"
"io/ioutil"
"os"
"reflect"
"testing"
@ -164,7 +163,7 @@ func TestAllowUsers(t *testing.T) {
// Test YAML user loading with b-encrypted passwords.
func TestAllowUsersFile(t *testing.T) {
f, err := ioutil.TempFile("", "*users.yml")
f, err := os.CreateTemp("", "*users.yml")
if err != nil {
t.Fatal(err)
}

View File

@ -85,17 +85,18 @@ type (
// please refer to: https://github.com/iris-contrib/middleware repository instead.
//
// Example Code:
// import "github.com/kataras/iris/v12/middleware/cors"
// import "github.com/kataras/iris/v12/x/errors"
//
// app.UseRouter(cors.New().
// HandleErrorFunc(func(ctx iris.Context, err error) {
// errors.FailedPrecondition.Err(ctx, err)
// }).
// ExtractOriginFunc(cors.StrictOriginExtractor).
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
// AllowOrigin("domain1.com,domain2.com,domain3.com").
// Handler())
// import "github.com/kataras/iris/v12/middleware/cors"
// import "github.com/kataras/iris/v12/x/errors"
//
// app.UseRouter(cors.New().
// HandleErrorFunc(func(ctx iris.Context, err error) {
// errors.FailedPrecondition.Err(ctx, err)
// }).
// ExtractOriginFunc(cors.StrictOriginExtractor).
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
// AllowOrigin("domain1.com,domain2.com,domain3.com").
// Handler())
func New() *CORS {
return &CORS{
extractOriginFunc: DefaultOriginExtractor,

View File

@ -13,11 +13,12 @@ import (
// The Iris server SHOULD run under HTTP/2 and clients too.
//
// Usage:
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
// [...]
// app := iris.New()
// grpcServer := grpc.NewServer()
// app.WrapRouter(grpcWrapper.New(grpcServer))
//
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
// [...]
// app := iris.New()
// grpcServer := grpc.NewServer()
// app.WrapRouter(grpcWrapper.New(grpcServer))
func New(grpcServer http.Handler) router.WrapperFunc {
return func(w http.ResponseWriter, r *http.Request, mux http.HandlerFunc) {
if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {

View File

@ -3,7 +3,7 @@ package hcaptcha
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
@ -70,7 +70,9 @@ func New(secret string, options ...Option) context.Handler {
// Handler is the HTTP route middleware featured hcaptcha validation.
// 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`)
// is saved on the Request's Context (see `GetResponseFromContext`).
func (c *Client) Handler(ctx *context.Context) {
@ -113,7 +115,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
return
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
response.ErrorCodes = append(response.ErrorCodes, err.Error())

View File

@ -55,14 +55,14 @@ var _ jwt.Blocklist = (*Blocklist)(nil)
//
// Usage:
//
// blocklist := NewBlocklist()
// blocklist.ClientOptions.Addr = ...
// err := blocklist.Connect()
// blocklist := NewBlocklist()
// blocklist.ClientOptions.Addr = ...
// err := blocklist.Connect()
//
// And register it:
//
// verifier := jwt.NewVerifier(...)
// verifier.Blocklist = blocklist
// verifier := jwt.NewVerifier(...)
// verifier.Blocklist = blocklist
func NewBlocklist() *Blocklist {
return &Blocklist{
GetKey: defaultGetKey,

View File

@ -31,8 +31,8 @@ type Signer struct {
//
// Usage:
//
// signer := NewSigner(HS256, secret, 15*time.Minute)
// token, err := signer.Sign(userClaims{Username: "kataras"})
// signer := NewSigner(HS256, secret, 15*time.Minute)
// token, err := signer.Sign(userClaims{Username: "kataras"})
func NewSigner(signatureAlg Alg, signatureKey interface{}, maxAge time.Duration) *Signer {
if signatureAlg == HS256 {
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.

View File

@ -61,24 +61,31 @@ type Verifier struct {
//
// Usage:
//
// verifier := NewVerifier(HS256, secret)
// OR
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
// verifier := NewVerifier(HS256, secret)
//
// claimsGetter := func() interface{} { return new(userClaims) }
// middleware := verifier.Verify(claimsGetter)
// OR
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
//
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
//
// claimsGetter := func() interface{} { return new(userClaims) }
// middleware := verifier.Verify(claimsGetter)
//
// OR
//
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
//
// Register the middleware, e.g.
// app.Use(middleware)
//
// app.Use(middleware)
//
// Get the claims:
// claims := jwt.Get(ctx).(*userClaims)
// username := claims.Username
//
// claims := jwt.Get(ctx).(*userClaims)
// username := claims.Username
//
// Get the context user:
// username, err := ctx.User().GetUsername()
//
// username, err := ctx.User().GetUsername()
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
if signatureAlg == HS256 {
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.

View File

@ -166,11 +166,12 @@ func Query(paramName string) Option {
// to determinate the method to override with.
//
// Use cases:
// 1. When need to check only for headers and ignore other fields:
// New(Only(Headers("X-Custom-Header")))
//
// 2. When need to check only for (first) form field and (second) custom getter:
// New(Only(FormField("fieldName"), Getter(...)))
// 1. When need to check only for headers and ignore other fields:
// New(Only(Headers("X-Custom-Header")))
//
// 2. When need to check only for (first) form field and (second) custom getter:
// New(Only(FormField("fieldName"), Getter(...)))
func Only(o ...Option) Option {
return func(opts *options) {
opts.getters = opts.getters[0:0]
@ -185,7 +186,6 @@ func Only(o ...Option) Option {
// 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.
//
//
// Read more at:
// https://github.com/kataras/iris/issues/1325
func New(opt ...Option) router.WrapperFunc {

View File

@ -34,12 +34,13 @@ type Options struct {
// for security reasons.
//
// Example Code:
// app.Get("/health", modrevision.New(modrevision.Options{
// ServerName: "Iris Server",
// Env: "development",
// Developer: "kataras",
// TimeLocation: time.FixedZone("Greece/Athens", 10800),
// }))
//
// app.Get("/health", modrevision.New(modrevision.Options{
// ServerName: "Iris Server",
// Env: "development",
// Developer: "kataras",
// TimeLocation: time.FixedZone("Greece/Athens", 7200),
// }))
func New(opts Options) context.Handler {
buildTime, buildRevision := context.BuildTime, context.BuildRevision
if opts.UnixTime {

View File

@ -41,7 +41,8 @@ var profileDescriptions = map[string]string{
// 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}'.
// 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 {
return func(ctx *context.Context) {
if action := ctx.Params().Get("action"); action != "" {

View File

@ -3,7 +3,7 @@ package recaptcha
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net/url"
"time"
@ -50,7 +50,9 @@ func New(secret string) context.Handler {
}
// 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.
//
// Use `New` for middleware use instead.
@ -74,7 +76,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
return
}
body, err := ioutil.ReadAll(r.Body)
body, err := io.ReadAll(r.Body)
r.Body.Close()
if err != nil {
response.ErrorCodes = append(response.ErrorCodes, err.Error())
@ -113,22 +115,24 @@ var recaptchaForm = `<form action="%s" method="POST">
// Example Code:
//
// Method: "POST" | Path: "/contact"
// func postContact(ctx *context.Context) {
// // [...]
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
//
// if response.Success {
// // [your action here, i.e sendEmail(...)]
// }
// func postContact(ctx *context.Context) {
// // [...]
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
//
// ctx.JSON(response)
// }
// if response.Success {
// // [your action here, i.e sendEmail(...)]
// }
//
// ctx.JSON(response)
// }
//
// Method: "GET" | Path: "/contact"
// func getContact(ctx *context.Context) {
// // render the recaptcha form
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
// }
//
// func getContact(ctx *context.Context) {
// // render the recaptcha form
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
// }
func GetFormHTML(dataSiteKey string, postActionRelativePath string) string {
return fmt.Sprintf(recaptchaForm, postActionRelativePath, dataSiteKey)
}

View File

@ -384,9 +384,11 @@ func (c *ControllerActivator) handleHTTPError(funcName string) *router.Route {
//
// Just like `Party#HandleMany`:, it returns the `[]*router.Routes`.
// Usage:
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
// }
//
// func (*Controller) BeforeActivation(b mvc.BeforeActivation) {
// b.HandleMany("GET", "/path /path1" /path2", "HandlePath")
// }
//
// HandleMany will override any routes of this "funcName".
func (c *ControllerActivator) HandleMany(method, path, funcName string, middleware ...context.Handler) []*router.Route {
return c.handleMany(method, path, funcName, true, middleware...)

View File

@ -86,7 +86,8 @@ func New(party router.Party) *Application {
// this function simply calls the `New(party)` and its `.Configure(configurators...)`.
//
// 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.
func Configure(party router.Party, configurators ...func(*Application)) *Application {

View File

@ -10,13 +10,13 @@ import (
// It requires a specific "version" constraint for a Controller,
// e.g. ">1.0.0 <=2.0.0".
//
//
// Usage:
// m := mvc.New(dataRouter)
// 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(v3Controller), mvc.Version(">=3.0.0 <4.0.0"))
// m.Handle(new(noVersionController))
//
// m := mvc.New(dataRouter)
// 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(v3Controller), mvc.Version(">=3.0.0 <4.0.0"))
// m.Handle(new(noVersionController))
//
// See the `versioning` package's documentation for more information on
// how the version is extracted from incoming requests.

View File

@ -78,8 +78,13 @@ func (c Config) Validate() Config {
}
if c.SessionIDGenerator == nil {
c.SessionIDGenerator = func(*context.Context) string {
id, _ := uuid.NewRandom()
c.SessionIDGenerator = func(ctx *context.Context) string {
id, err := uuid.NewRandom()
if err != nil {
ctx.StopWithError(400, err)
return ""
}
return id.String()
}
}

View File

@ -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.
func (s *mem) Set(sid string, key string, value interface{}, _ time.Duration, immutable bool) error {
s.mu.RLock()
s.values[sid].Save(key, value, immutable)
store, ok := s.values[sid]
s.mu.RUnlock()
if ok {
store.Save(key, value, immutable)
}
return nil
}
func (s *mem) Get(sid string, key string) interface{} {
s.mu.RLock()
v := s.values[sid].Get(key)
store, ok := s.values[sid]
s.mu.RUnlock()
if ok {
return store.Get(key)
}
return v
return nil
}
func (s *mem) Decode(sid string, key string, outPtr interface{}) error {
s.mu.RLock()
v := s.values[sid].Get(key)
s.mu.RUnlock()
v := s.Get(sid, key)
if v != nil {
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 {
s.values[sid].Visit(cb)
s.mu.RLock()
store, ok := s.values[sid]
s.mu.RUnlock()
if ok {
store.Visit(cb)
}
return nil
}
func (s *mem) Len(sid string) int {
s.mu.RLock()
n := s.values[sid].Len()
store, ok := s.values[sid]
s.mu.RUnlock()
if ok {
return store.Len()
}
return n
return 0
}
func (s *mem) Delete(sid string, key string) (deleted bool) {
s.mu.RLock()
deleted = s.values[sid].Remove(key)
store, ok := s.values[sid]
s.mu.RUnlock()
if ok {
deleted = store.Remove(key)
}
return
}
func (s *mem) Clear(sid string) error {
s.mu.Lock()
s.values[sid].Reset()
s.mu.Unlock()
s.mu.RLock()
store, ok := s.values[sid]
s.mu.RUnlock()
if ok {
store.Reset()
}
return nil
}
@ -150,7 +170,6 @@ func (s *mem) Release(sid string) error {
s.mu.Lock()
delete(s.values, sid)
s.mu.Unlock()
return nil
}

View File

@ -50,7 +50,6 @@ func (p *provider) newSession(man *Sessions, sid string, expires time.Duration)
sid: sid,
Man: man,
provider: p,
flashes: make(map[string]*flashMessage),
}
onExpire := func() {
@ -99,9 +98,10 @@ func (p *provider) EndRequest(ctx *context.Context, session *Session) {
// ErrNotFound may be returned from `UpdateExpiration` of a non-existing or
// invalid session entry from memory storage or databases.
// Usage:
// if err != nil && err.Is(err, sessions.ErrNotFound) {
// [handle error...]
// }
//
// if err != nil && err.Is(err, sessions.ErrNotFound) {
// [handle error...]
// }
var ErrNotFound = errors.New("session not found")
// UpdateExpiration resets the expiration of a session.

View File

@ -76,6 +76,7 @@ func (s *Session) runFlashGC() {
delete(s.flashes, key)
}
}
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.
func (s *Session) SetFlash(key string, value interface{}) {
s.mu.Lock()
if s.flashes == nil {
s.flashes = make(map[string]*flashMessage)
}
s.flashes[key] = &flashMessage{value: value}
s.mu.Unlock()
}

View File

@ -35,7 +35,7 @@ func testSessions(t *testing.T, app *iris.Application) {
s := sessions.Get(ctx)
sessValues := s.GetAll()
_, err := ctx.JSON(sessValues)
err := ctx.JSON(sessValues)
if err != nil {
t.Fatal(err)
}
@ -141,8 +141,7 @@ func TestFlashMessages(t *testing.T) {
}
writeValues := func(ctx *context.Context, values map[string]interface{}) error {
_, err := ctx.JSON(values)
return err
return ctx.JSON(values)
}
app.Post("/set", func(ctx *context.Context) {

View File

@ -30,25 +30,31 @@ type Group struct {
// 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:
// Accept-Version: 1.0.0
// Accept: application/json; version=1.0.0
// You can customize it by setting a version based on the request context:
// api.Use(func(ctx *context.Context) {
// if version := ctx.URLParam("version"); version != "" {
// SetVersion(ctx, version)
// }
//
// ctx.Next()
// })
// Accept-Version: 1.0.0
// Accept: application/json; version=1.0.0
//
// You can customize it by setting a version based on the request context:
//
// api.Use(func(ctx *context.Context) {
// if version := ctx.URLParam("version"); version != "" {
// SetVersion(ctx, version)
// }
//
// ctx.Next()
// })
//
// OR:
// api.Use(versioning.FromQuery("version", ""))
//
// api.Use(versioning.FromQuery("version", ""))
//
// Examples at: _examples/routing/versioning
// Usage:
// app := iris.New()
// api := app.Party("/api")
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
// v1.Get/Post/Put/Delete...
//
// app := iris.New()
// api := app.Party("/api")
// v1 := versioning.NewGroup(api, ">=1.0.0 <2.0.0")
// v1.Get/Post/Put/Delete...
//
// Valid ranges are:
// - "<1.0.0"
@ -61,8 +67,10 @@ type Group struct {
// A Range can consist of multiple ranges separated by space:
// 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"
//
// 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
//
// except 2.0.3-beta.2
//
// Ranges can also be linked by logical OR:
@ -72,7 +80,8 @@ type Group struct {
//
// 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`
func NewGroup(r API, version string) *Group {
version = strings.ReplaceAll(version, ",", " ")

View File

@ -187,11 +187,13 @@ func GetVersion(ctx *context.Context) string {
// 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)
// from a "version" url parameter instead:
// func(ctx iris.Context) { // &version=1
// version := ctx.URLParamDefault("version", "1.0.0")
// versioning.SetVersion(ctx, version)
// ctx.Next()
// }
//
// func(ctx iris.Context) { // &version=1
// version := ctx.URLParamDefault("version", "1.0.0")
// versioning.SetVersion(ctx, version)
// ctx.Next()
// }
//
// See `GetVersion` too.
func SetVersion(ctx *context.Context, constraint string) {
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
@ -205,23 +207,24 @@ type AliasMap = map[string]string
// for the children Parties(routers). It's respected by versioning Groups.
//
// Example Code:
// app := iris.New()
//
// api := app.Party("/api")
// api.Use(Aliases(map[string]string{
// versioning.Empty: "1.0.0", // when no version was provided by the client.
// "beta": "4.0.0",
// "stage": "5.0.0-alpha"
// }))
// app := iris.New()
//
// v1 := NewGroup(api, ">=1.0.0 < 2.0.0")
// v1.Get/Post...
// api := app.Party("/api")
// api.Use(Aliases(map[string]string{
// versioning.Empty: "1.0.0", // when no version was provided by the client.
// "beta": "4.0.0",
// "stage": "5.0.0-alpha"
// }))
//
// v4 := NewGroup(api, ">=4.0.0 < 5.0.0")
// v4.Get/Post...
// v1 := NewGroup(api, ">=1.0.0 < 2.0.0")
// v1.Get/Post...
//
// stage := NewGroup(api, "5.0.0-alpha")
// stage.Get/Post...
// v4 := NewGroup(api, ">=4.0.0 < 5.0.0")
// v4.Get/Post...
//
// stage := NewGroup(api, "5.0.0-alpha")
// stage.Get/Post...
func Aliases(aliases AliasMap) context.Handler {
cp := make(AliasMap, len(aliases)) // copy the map here so we are safe of later modifications by end-dev.
for k, v := range aliases {

View File

@ -50,7 +50,8 @@ type (
// through a Context or within filter functions.
//
// Example:
// AsValue("my string")
//
// AsValue("my string")
//
// Shortcut for `pongo2.AsValue`.
var AsValue = pongo2.AsValue

View File

@ -2,7 +2,7 @@ package view
import (
"fmt"
"io/ioutil"
"io"
"net/http"
"path"
"path/filepath"
@ -80,7 +80,7 @@ func asset(fs http.FileSystem, name string) ([]byte, error) {
return nil, err
}
contents, err := ioutil.ReadAll(f)
contents, err := io.ReadAll(f)
f.Close()
return contents, err
}

Some files were not shown because too many files have changed in this diff Show More