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
@ -38,7 +39,7 @@ func main() {
}
```
<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
//
// 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
//
// 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
//
// 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
//
// 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
//
// 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
//
// 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,6 +30,7 @@ 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()
//
@ -38,6 +39,7 @@ type UsersController struct {
// }
// 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) {
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){
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,7 +52,8 @@ 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) {
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)
@ -57,7 +62,8 @@ func (c *UserController) GetSomething(ctx iris.Context) {
}
// 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

@ -35,7 +35,9 @@ func pong(ctx iris.Context) {
| | |
| | |
DEV | | | PROD
-------------------+---------------------+ | +----------------------+-------------------
| | |
| | |
+---+-----+ +----------------v------------------+ +----+----+
@ -64,6 +66,7 @@ func pong(ctx iris.Context) {
| | /greet?name=kataras | |
| +-----------+-----------+ |
| | |
+------------------+--------+ +------------+------------+ +-------+------------------+
| model.Response (JSON) | | Response (JSON, error) | | Bad Request |
+---------------------------+ +-------------------------+ +--------------------------+

View File

@ -23,6 +23,7 @@ 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()
//
@ -31,6 +32,7 @@ type MovieController struct {
// }
// 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,7 +7,8 @@ import (
"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(ctx iris.Context)
- Build should builds the handler, it's being called on router's BuildRouter.

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 {
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
//
// 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
//
// 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
//
// 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
//
// 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
//
// 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,6 +13,7 @@ import (
// The cases are filtered in order of their registration.
//
// Example Code:
//
// switcher := Switch(Hosts{
// "mydomain.com": app,
// "test.mydomain.com": testSubdomainApp,

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,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.
//
// Usage Example:
//
// api := app.Party("/api")
// api.EnsureStaticBindings().RegisterDependency(
// NewAuthProviderErrorHandler(),

1
cache/browser.go vendored
View File

@ -49,6 +49,7 @@ 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)
// [...]

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,6 +22,7 @@ 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.

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)

View File

@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net"
@ -31,7 +30,6 @@ import (
"github.com/Shopify/goreferrer"
"github.com/fatih/structs"
gojson "github.com/goccy/go-json"
"github.com/iris-contrib/schema"
"github.com/mailru/easyjson"
"github.com/mailru/easyjson/jwriter"
@ -100,7 +98,7 @@ type (
// is terminated and the error is received by the ReadJSONStream method,
// otherwise it continues to read the next available object.
// 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.
@ -539,7 +537,6 @@ func (ctx *Context) Do(handlers Handlers) {
// Router is calling this function to add the route's handler.
// If AddHandler called then the handlers will be inserted
// to the end of the already-defined route's handler.
//
func (ctx *Context) AddHandler(handlers ...Handler) {
ctx.handlers = append(ctx.handlers, handlers...)
}
@ -601,12 +598,15 @@ func (ctx *Context) HandlerIndex(n int) (currentIndex int) {
// ctx.StopExecution()
// }
// }
//
// This Get() will be executed in the same handler as `BeginRequest`,
// internally controller checks for `ctx.StopExecution`.
// So it will not be fired if BeginRequest called the `StopExecution`.
//
// func(c *UsersController) Get() []models.User {
// return c.Service.GetAll()
//}
// }
//
// Alternative way is `!ctx.IsStopped()` if middleware make use of the `ctx.StopExecution()` on failure.
func (ctx *Context) Proceed(h Handler) bool {
_, 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.
func (ctx *Context) StopWithJSON(statusCode int, jsonObject interface{}) error {
ctx.StopWithStatus(statusCode)
_, err := ctx.writeJSON(jsonObject, nil) // do not modify - see errors.DefaultContextErrorHandler.
return err
return ctx.writeJSON(jsonObject, nil) // do not modify - see errors.DefaultContextErrorHandler.
}
// 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 {
ctx.StopWithStatus(statusCode)
problem.Status(statusCode)
_, err := ctx.Problem(problem)
return err
return ctx.Problem(problem)
}
// +------------------------------------------------------------+
@ -939,7 +937,7 @@ func (ctx *Context) RequestPath(escape bool) string {
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 {
scheme := r.URL.Scheme
@ -1111,10 +1109,11 @@ func (ctx *Context) FullRequestURI() string {
// even if it's part of a private network.
//
// Look `Configuration.RemoteAddrHeaders`,
// `Configuration.RemoteAddrHeadersForce`,
// `Configuration.WithRemoteAddrHeader(...)`,
// `Configuration.WithoutRemoteAddrHeader(...)` and
// `Configuration.RemoteAddrPrivateSubnets` for more.
//
// Configuration.RemoteAddrHeadersForce,
// Configuration.WithRemoteAddrHeader(...),
// Configuration.WithoutRemoteAddrHeader(...) and
// Configuration.RemoteAddrPrivateSubnetsW for more.
func (ctx *Context) RemoteAddr() string {
if remoteHeaders := ctx.app.ConfigurationReadOnly().GetRemoteAddrHeaders(); len(remoteHeaders) > 0 {
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),
// there are many blogs that describe these problems and provide different kind of solutions,
// 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
// and https://xhr.spec.whatwg.org/
@ -1557,9 +1556,11 @@ func (ctx *Context) URLParamEscape(name string) string {
// Example:
//
// n, err := context.URLParamInt("url_query_param_name")
//
// if errors.Is(err, context.ErrNotFound) {
// // [handle error...]
// }
//
// Another usage would be `err == context.ErrNotFound`
// HOWEVER prefer use the new `errors.Is` as API details may change in the future.
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
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 {
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.
err := r.ParseMultipartForm(postMaxMemory)
// if resetBody {
// r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyCopy))
// r.Body = io.NopCloser(bytes.NewBuffer(bodyCopy))
// }
if err != nil && err != http.ErrNotMultipart {
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.
//
//
// 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.
//
@ -2284,7 +2284,7 @@ var emptyFunc = func() {}
// GetBody reads and returns the request body.
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 {
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) {
r.Body = ioutil.NopCloser(bytes.NewBuffer(data))
r.Body = io.NopCloser(bytes.NewBuffer(data))
}
const disableRequestBodyConsumptionContextKey = "iris.request.body.record"
@ -2385,10 +2385,6 @@ func (ctx *Context) UnmarshalBody(outPtr interface{}, unmarshaler Unmarshaler) e
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.
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
@ -2413,123 +2409,31 @@ type JSONReader struct { // Note(@kataras): struct instead of optional funcs to
// {"username": "makis"}
// {"username": "george"}
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 {
Token() (json.Token, error) // gojson.Token is an alias of this, so we are ok.
More() bool
DisallowUnknownFields()
}
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
}
var ReadJSON = func(ctx *Context, outPtr interface{}, opts ...JSONReader) error {
decoder := json.NewDecoder(ctx.request.Body)
// decoder := gojson.NewDecoder(ctx.Request().Body)
if len(opts) > 0 {
options := opts[0]
if options.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.
//
// Example: https://github.com/kataras/iris/blob/master/_examples/request-body/read-json/main.go
func (ctx *Context) ReadJSON(outPtr interface{}, opts ...JSONReader) error {
var options JSONReader
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)
}
*/
return ReadJSON(ctx, outPtr, opts...)
}
// 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
func (ctx *Context) ReadJSONStream(onDecode func(DecodeFunc) error, opts ...JSONReader) error {
var options JSONReader
if len(opts) > 0 {
options = opts[0]
}
decoder := json.NewDecoder(ctx.request.Body)
decoder, decodeFunc := options.getDecoder(ctx.request.Body, nil)
if options.ArrayStream {
if len(opts) > 0 && opts[0].ArrayStream {
_, err := decoder.Token() // read open bracket.
if err != nil {
return err
}
for decoder.More() { // hile the array contains values.
if err = onDecode(decodeFunc); err != nil {
if err = onDecode(decoder.Decode); err != nil {
return err
}
}
@ -2568,7 +2467,7 @@ func (ctx *Context) ReadJSONStream(onDecode func(DecodeFunc) error, opts ...JSON
// while the array contains values
for decoder.More() {
if err := onDecode(decodeFunc); err != nil {
if err := onDecode(decoder.Decode); err != nil {
return err
}
}
@ -2788,7 +2687,7 @@ func (ctx *Context) ReadMultipartRelated() (MultipartRelated, error) {
}
defer part.Close()
b, err := ioutil.ReadAll(part)
b, err := io.ReadAll(part)
if err != nil {
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`.
// Usage:
// ok, err := context.CheckIfModifiedSince(modTime)
//
// if err != nil {
// if errors.Is(err, context.ErrPreconditionFailed) {
// [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:
//
// * if response body is too big (more than iris.LimitRequestBodySize(if set)).
// * if response body is streamed from slow external sources.
// * if response body must be streamed to the client in chunks.
// - if response body is too big (more than iris.LimitRequestBodySize(if set)).
// - if response body is streamed from slow external sources.
// - if response body must be streamed to the client in chunks.
// (aka `http server push`).
func (ctx *Context) StreamWriter(writer func(w io.Writer) error) error {
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.
// All future write and rich write methods will respect this option.
// Usage:
//
// app.Use(func(ctx iris.Context){
// err := ctx.CompressWriter(true)
// ctx.Next()
// })
//
// 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.
// 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.
//
// Usage:
//
// app.Use(func(ctx iris.Context){
// err := ctx.CompressReader(true)
// ctx.Next()
// })
//
// More:
//
// if cr, ok := ctx.Request().Body.(*CompressReader); ok {
// cr.Src // the original request body
// 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.
//
// Usage:
//
// FallbackView(iris.FallbackView("fallback.html"))
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
// OR
@ -3749,8 +3655,6 @@ type ProtoMarshalOptions = protojson.MarshalOptions
// JSON contains the options for the JSON (Context's) Renderer.
type JSON struct {
// http-specific
StreamingJSON bool `yaml:"StreamingJSON"`
// content-specific
UnescapeHTML bool `yaml:"UnescapeHTML"`
Indent string `yaml:"Indent"`
@ -3772,8 +3676,7 @@ var DefaultJSONOptions = JSON{}
// IsDefault reports whether this JSON options structure holds the default values.
func (j *JSON) IsDefault() bool {
return j.StreamingJSON == DefaultJSONOptions.StreamingJSON &&
j.UnescapeHTML == DefaultJSONOptions.UnescapeHTML &&
return j.UnescapeHTML == DefaultJSONOptions.UnescapeHTML &&
j.Indent == DefaultJSONOptions.Indent &&
j.Prefix == DefaultJSONOptions.Prefix &&
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'.
func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options *JSON, shouldOptimize bool) (int, error) {
if options.StreamingJSON {
var err error
if shouldOptimize {
var WriteJSON = func(ctx *Context, v interface{}, options *JSON) error {
if !options.Secure && !options.ASCII && options.Prefix == "" {
// jsoniterConfig := jsoniter.Config{
// EscapeHTML: !options.UnescapeHTML,
// IndentionStep: 4,
// }.Froze()
// enc := jsoniterConfig.NewEncoder(ctx.writer)
// 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.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 (
@ -3887,35 +3786,15 @@ func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options
err error
)
// Let's keep it as it is.
// if !shouldOptimize && options.Indent == "" {
// options.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 = 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 {
result, err = json.Marshal(v)
}
}
if err != nil {
return 0, err
return err
}
prependSecure := false
@ -3960,7 +3839,8 @@ func WriteJSON(ctx stdContext.Context, writer io.Writer, v interface{}, options
result = append(stringToBytes(prefix), result...)
}
return writer.Write(result)
_, err = ctx.Write(result)
return err
}
// 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.
// 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.
// Look the Application.SetContextErrorHandler to override the
// default status code 500 with a custom error response.
//
// It can, optionally, accept the JSON structure which may hold customizations over the
// final JSON response but keep in mind that the caller should NOT modify that JSON options
// value in another goroutine while JSON method is still running.
func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
// Customize the behavior of every `Context.JSON“ can be achieved
// by modifying the package-level `WriteJSON` function on program initilization.
func (ctx *Context) JSON(v interface{}, opts ...JSON) (err error) {
var options *JSON
if len(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
// then do call the error handler (which may lead to a cycle).
if options == nil || !options.OmitErrorHandler {
if !options.OmitErrorHandler {
ctx.handleContextError(err)
}
}
@ -4033,76 +3915,38 @@ func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
return
}
func (ctx *Context) writeJSON(v interface{}, options *JSON) (int, error) {
func (ctx *Context) writeJSON(v interface{}, options *JSON) error {
ctx.ContentType(ContentJSONHeaderValue)
// 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 {
return n, err
if handled, _, err := ctx.handleSpecialJSONResponseValue(v, options); handled {
return err
}
shouldOptimize := ctx.shouldOptimize()
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)
return WriteJSON(ctx, v, options)
}
var finishCallbackB = []byte(");")
// WriteJSONP marshals the given interface object and writes the JSON response to the writer.
func WriteJSONP(writer io.Writer, v interface{}, options JSONP, optimize bool) (int, error) {
// WriteJSONP marshals the given interface object and writes the JSONP response to the writer.
var WriteJSONP = func(ctx *Context, v interface{}, options *JSONP) (err error) {
if callback := options.Callback; callback != "" {
n, err := writer.Write(stringToBytes(callback + "("))
_, err = ctx.Write(stringToBytes(callback + "("))
if err != nil {
return n, err
return err
}
defer writer.Write(finishCallbackB)
defer func() {
if err == nil {
ctx.Write(finishCallbackB)
}
}()
}
if !optimize && options.Indent == "" {
options.Indent = " "
}
if indent := options.Indent; indent != "" {
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)
err = WriteJSON(ctx, v, &JSON{
Indent: options.Indent,
OmitErrorHandler: options.OmitErrorHandler,
})
return err
}
// 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.
// Look the Application.SetContextErrorHandler to override the
// default status code 500 with a custom error response.
func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (n int, err error) {
options := DefaultJSONPOptions
func (ctx *Context) JSONP(v interface{}, opts ...JSONP) (err error) {
var options *JSONP
if len(opts) > 0 {
options = opts[0]
options = &opts[0]
} else {
options = &DefaultJSONPOptions
}
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 {
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.
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 != "" {
n, err := writer.Write(stringToBytes(prefix))
_, err := ctx.Write(stringToBytes(prefix))
if err != nil {
return n, err
return err
}
}
if !optimize && options.Indent == "" {
options.Indent = " " // Two spaces for XML is the default indentation when not optimized.
encoder := xml.NewEncoder(ctx.writer)
encoder.Indent("", options.Indent)
if err := encoder.Encode(v); err != nil {
return err
}
if indent := options.Indent; indent != "" {
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)
return encoder.Flush()
}
// 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.
// Look the Application.SetContextErrorHandler to override the
// default status code 500 with a custom error response.
func (ctx *Context) XML(v interface{}, opts ...XML) (n int, err error) {
options := DefaultXMLOptions
func (ctx *Context) XML(v interface{}, opts ...XML) (err error) {
var options *XML
if len(opts) > 0 {
options = opts[0]
options = &opts[0]
} else {
options = &DefaultXMLOptions
}
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 {
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.
//
// 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
if len(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.
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)
if options.Sanitize {
buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
}
return writer.Write(buf)
_, err := ctx.Write(buf)
return err
}
// 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.
// Look the Application.SetContextErrorHandler to override the
// default status code 500 with a custom error response.
func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (n int, err error) {
options := DefaultMarkdownOptions
func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (err error) {
var options *Markdown
if len(opts) > 0 {
options = opts[0]
options = &opts[0]
} else {
options = &DefaultMarkdownOptions
}
ctx.ContentType(ContentHTMLHeaderValue)
if n, err = WriteMarkdown(ctx.writer, markdownB, options); err != nil {
if err = WriteMarkdown(ctx, markdownB, options); err != nil {
if !options.OmitErrorHandler {
ctx.handleContextError(err)
}
@ -4310,31 +4150,46 @@ func (ctx *Context) Markdown(markdownB []byte, opts ...Markdown) (n int, err err
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.
//
// It reports any YAML parser or write errors back to the caller.
// Look the Application.SetContextErrorHandler to override the
// default status code 500 with a custom error response.
func (ctx *Context) YAML(v interface{}) (int, error) {
out, err := yaml.Marshal(v)
if err != nil {
ctx.handleContextError(err)
return 0, err
}
func (ctx *Context) YAML(v interface{}) error {
ctx.ContentType(ContentYAMLHeaderValue)
n, err := ctx.Write(out)
err := WriteYAML(ctx, v, 0)
if err != nil {
ctx.handleContextError(err)
return err
}
return n, err
return nil
}
// TextYAML calls the Context.YAML method but with the text/yaml content type instead.
func (ctx *Context) TextYAML(v interface{}) (int, error) {
ctx.contentTypeOnce(ContentYAMLTextHeaderValue, "")
return ctx.YAML(v)
func (ctx *Context) TextYAML(v interface{}) error {
ctx.ContentType(ContentYAMLTextHeaderValue)
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.
@ -4583,19 +4438,54 @@ func (ctx *Context) Negotiate(v interface{}) (int, error) {
case ContentTextHeaderValue, ContentHTMLHeaderValue:
return ctx.WriteString(v.(string))
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:
return ctx.JSON(v)
err := ctx.JSON(v)
if err != nil {
return 0, err
}
return ctx.writer.Written(), nil
case ContentJSONProblemHeaderValue, ContentXMLProblemHeaderValue:
return ctx.Problem(v)
err := ctx.Problem(v)
if err != nil {
return 0, err
}
return ctx.writer.Written(), nil
case ContentJavascriptHeaderValue:
return ctx.JSONP(v)
err := ctx.JSONP(v)
if err != nil {
return 0, err
}
return ctx.writer.Written(), nil
case ContentXMLHeaderValue, ContentXMLUnreadableHeaderValue:
return ctx.XML(v)
err := ctx.XML(v)
if err != nil {
return 0, err
}
return ctx.writer.Written(), nil
case ContentYAMLHeaderValue:
return ctx.YAML(v)
err := ctx.YAML(v)
if err != nil {
return 0, err
}
return ctx.writer.Written(), nil
case ContentYAMLTextHeaderValue:
return ctx.TextYAML(v)
err := ctx.TextYAML(v)
if err != nil {
return 0, err
}
return ctx.writer.Written(), nil
case ContentProtobufHeaderValue:
msg, ok := v.(proto.Message)
if !ok {
@ -5438,15 +5328,15 @@ const cookieOptionsContextKey = "iris.cookie.options"
// cookies sent or received from the next Handler in the chain.
//
// Available builtin Cookie options are:
// * CookieAllowReclaim
// * CookieAllowSubdomains
// * CookieSecure
// * CookieHTTPOnly
// * CookieSameSite
// * CookiePath
// * CookieCleanPath
// * CookieExpires
// * CookieEncoding
// - CookieAllowReclaim
// - CookieAllowSubdomains
// - CookieSecure
// - CookieHTTPOnly
// - CookieSameSite
// - CookiePath
// - CookieCleanPath
// - CookieExpires
// - CookieEncoding
//
// Example at: https://github.com/kataras/iris/tree/master/_examples/cookies/securecookie
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)
// ctx.SetCookieKV(name, value, iris.CookieCleanPath/iris.CookiePath(""))
// More:
//
// iris.CookieExpires(time.Duration)
// iris.CookieHTTPOnly(false)
//

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,
// }
//
// 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,6 +131,7 @@ 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>)
@ -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 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,6 +10,7 @@ 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))

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,6 +377,7 @@ 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.
//
@ -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
// 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},
@ -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.
//
// Usage:
//
// 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)
@ -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.
//
// Usage:
//
// app.PartyFunc("/users", func(u iris.Party){
// u.Use(authMiddleware, logMiddleware)
// u.Get("/", getAllUsers)
@ -949,14 +955,19 @@ type (
// Useful when the api's dependencies amount are too much to pass on a function.
//
// Usage:
//
// 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)
// [...]
// }
//
// Usage with (static) dependencies:
//
// app.RegisterDependency(userRepo, ...)
// app.PartyConfigure("/users", new(api.UsersAPI))
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.
// Usage:
//
// FallbackView(iris.FallbackView("fallback.html"))
// FallbackView(iris.FallbackViewLayout("layouts/fallback.html"))
// OR
@ -1653,6 +1665,7 @@ 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")
// })

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,6 +6,7 @@ import (
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
// Usage:
//
// Party#SetExecutionRules(ExecutionRules {
// Done: ExecutionOptions{Force: true},
// })

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()

7
doc.go
View File

@ -36,11 +36,11 @@ Source code and other details for the project are available at GitHub:
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.
@ -62,6 +62,5 @@ Middleware:
Home Page:
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

@ -327,22 +327,27 @@ func Handler(fn interface{}) context.Handler {
// as middleware or as simple route handler or subdomain's handler.
//
// func(...<T>) iris.Handler
//
// - if <T> are all static dependencies then
// there is no reflection involved at serve-time.
//
// 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
//
// - if a function returns an error then this error's text is sent to the client automatically.
//
// 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>
//
// - 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,8 +98,11 @@ func DefaultConfiguration() *Configuration {
// New Prepares and returns a new test framework based on the "app".
// Usage:
//
// httptest.New(t, app)
//
// With options:
//
// 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.

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),

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")

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)).
//
// 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,6 +52,7 @@ type ErrorHandler func(ctx *context.Context, err error)
// The only required value is the Allow field.
//
// Usage:
//
// opts := Options { ... }
// auth := New(opts)
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.
//
// Example Code:
//
// opts := basicauth.Options{
// Realm: basicauth.DefaultRealm,
// ErrorHandler: basicauth.DefaultErrorHandler,
@ -238,12 +240,14 @@ 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.
//
// Usage:
//
// auth := Default(map[string]string{
// "admin": "admin",
// "john": "p@ss",
@ -260,6 +264,7 @@ func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
// a filename to load the users from.
//
// Usage:
//
// auth := Load("users.yml")
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
opts := Options{

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,6 +48,7 @@ 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
@ -75,6 +76,7 @@ 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.
@ -155,7 +157,9 @@ func userMap(usernamePassword map[string]string, opts ...UserAuthOption) AuthFun
// loaded from a file on initialization.
//
// Example Code:
//
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
//
// The users.yml file looks like the following:
// - username: kataras
// password: kataras_pass

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,6 +85,7 @@ 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"
//

View File

@ -13,6 +13,7 @@ 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()

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`.
//
// 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

@ -62,22 +62,29 @@ type Verifier struct {
// Usage:
//
// verifier := NewVerifier(HS256, secret)
//
// OR
//
// 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)
//
// Get the claims:
//
// claims := jwt.Get(ctx).(*userClaims)
// username := claims.Username
//
// Get the context user:
//
// username, err := ctx.User().GetUsername()
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
if signatureAlg == HS256 {

View File

@ -166,6 +166,7 @@ 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")))
//
@ -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,11 +34,12 @@ 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),
// TimeLocation: time.FixedZone("Greece/Athens", 7200),
// }))
func New(opts Options) context.Handler {
buildTime, buildRevision := context.BuildTime, context.BuildRevision

View File

@ -41,6 +41,7 @@ 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())
func New() context.Handler {
return func(ctx *context.Context) {

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
//
// 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,6 +115,7 @@ var recaptchaForm = `<form action="%s" method="POST">
// Example Code:
//
// Method: "POST" | Path: "/contact"
//
// func postContact(ctx *context.Context) {
// // [...]
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
@ -125,6 +128,7 @@ var recaptchaForm = `<form action="%s" method="POST">
// }
//
// Method: "GET" | Path: "/contact"
//
// func getContact(ctx *context.Context) {
// // render the recaptcha form
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))

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")
// }
//
// 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,6 +86,7 @@ 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)`.
//
// Read more at `New() Application` and `Application#Configure` methods.

View File

@ -10,8 +10,8 @@ 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"))

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,6 +98,7 @@ 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...]
// }

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,9 +30,12 @@ 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)
@ -40,11 +43,14 @@ type Group struct {
//
// ctx.Next()
// })
//
// OR:
//
// 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")
@ -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:
@ -73,6 +81,7 @@ 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`,
//
// 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()
// }
//
// See `GetVersion` too.
func SetVersion(ctx *context.Context, constraint string) {
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.
//
// Example Code:
//
// app := iris.New()
//
// api := app.Party("/api")

View File

@ -50,6 +50,7 @@ type (
// through a Context or within filter functions.
//
// Example:
//
// AsValue("my string")
//
// Shortcut for `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
}

View File

@ -140,6 +140,7 @@ func (s *HTMLEngine) Reload(developmentMode bool) *HTMLEngine {
//
// missingkey: Control the behavior during execution if a map is
// indexed with a key that is not present in the map.
//
// "missingkey=default" or "missingkey=invalid"
// The default behavior: Do nothing and continue execution.
// 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.
// "missingkey=error"
// Execution stops immediately with an error.
//
func (s *HTMLEngine) Option(opt ...string) *HTMLEngine {
s.rmu.Lock()
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.
//
// Example: HTML("./templates", ".html").Layout("layouts/mainLayout.html")
//
// // mainLayout.html is inside: "./templates/layouts/".
//
// Note: Layout can be changed for a specific call

View File

@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"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.
// It's automatically called on Client.ReadXXX methods on the end.
func (c *Client) DrainResponseBody(resp *http.Response) {
_, _ = io.Copy(ioutil.Discard, resp.Body)
_, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}
@ -398,7 +397,7 @@ func (c *Client) ReadJSON(ctx context.Context, dest interface{}, method, urlpath
}
// DBUG
// b, _ := ioutil.ReadAll(resp.Body)
// b, _ := io.ReadAll(resp.Body)
// println(string(b))
// return json.Unmarshal(b, &dest)
@ -418,7 +417,7 @@ func (c *Client) ReadPlain(ctx context.Context, dest interface{}, method, urlpat
return ExtractError(resp)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
@ -495,7 +494,7 @@ func BindResponse(resp *http.Response, dest interface{}) (err error) {
case contentTypeJSON: // the most common scenario on successful responses.
return json.NewDecoder(resp.Body).Decode(&dest)
case contentTypePlainText:
b, err := ioutil.ReadAll(resp.Body)
b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

View File

@ -2,7 +2,7 @@ package client
import (
"encoding/json"
"io/ioutil"
"io"
"net/http"
"strings"
)
@ -39,7 +39,7 @@ func (e APIError) Error() string {
// ExtractError returns the response wrapped inside an APIError.
func ExtractError(resp *http.Response) APIError {
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
return APIError{
Response: resp,

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