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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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) {
m.Router.Use(cache.Handler(10*time.Second))
})
```
```go
@ -32,10 +34,12 @@ mvc.Configure(userRouter, ...)
```go
// 4
// same:
app.PartyFunc("/user", func(r iris.Party){
r.Use(cache.Handler(10*time.Second))
mvc.Configure(r, ...)
})
```
If you want to use a middleware for a single route,
@ -48,6 +52,7 @@ then you just call it on the method:
var myMiddleware := myMiddleware.New(...) // this should return an iris/context.Handler
type UserController struct{}
func (c *UserController) GetSomething(ctx iris.Context) {
// ctx.Proceed checks if myMiddleware called `ctx.Next()`
// inside it and returns true if so, otherwise false.
@ -58,6 +63,7 @@ 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.
@ -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

@ -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

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

View File

@ -3,7 +3,7 @@ package client
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
)
@ -27,7 +27,7 @@ func (t *handlerTransport) RoundTrip(req *http.Request) (*http.Response, error)
reqCopy.TransferEncoding = []string{"chunked"}
}
} else {
reqCopy.Body = ioutil.NopCloser(bytes.NewReader(nil))
reqCopy.Body = io.NopCloser(bytes.NewReader(nil))
}
if reqCopy.RequestURI == "" {
@ -50,7 +50,7 @@ func (t *handlerTransport) RoundTrip(req *http.Request) (*http.Response, error)
}
if recorder.Body != nil {
resp.Body = ioutil.NopCloser(recorder.Body)
resp.Body = io.NopCloser(recorder.Body)
}
return &resp, nil

View File

@ -67,6 +67,7 @@ func RateLimit(requestsPerSecond int) Option {
// and right after a response from the server is received.
//
// Example Output for request:
//
// [DBUG] 2022/03/01 21:54 Iris HTTP Client: POST / HTTP/1.1
// Host: 127.0.0.1:50948
// User-Agent: Go-http-client/1.1
@ -78,6 +79,7 @@ func RateLimit(requestsPerSecond int) Option {
// {"firstname":"Makis"}
//
// Example Output for response:
//
// [DBUG] 2022/03/01 21:54 Iris HTTP Client: HTTP/1.1 200 OK
// Content-Length: 27
// Content-Type: application/json; charset=utf-8

View File

@ -56,6 +56,7 @@ var errorCodeMap = make(map[ErrorCodeName]ErrorCode)
// See "RegisterErrorCode" and "RegisterErrorCodeMap" for alternatives.
//
// Example:
//
// var (
// NotFound = errors.E("NOT_FOUND", http.StatusNotFound)
// )
@ -238,6 +239,7 @@ var (
// Error represents the JSON form of "http wire errors".
//
// Examples can be found at:
//
// https://github.com/kataras/iris/tree/master/_examples/routing/http-wire-errors.
type Error struct {
ErrorCode ErrorCode `json:"http_error_code" yaml:"HTTPErrorCode"`

View File

@ -13,6 +13,7 @@ import (
// A validation error(s) can be given by ErrorCodeName's Validation or Err methods.
//
// Example can be found at:
//
// https://github.com/kataras/iris/tree/master/_examples/routing/http-wire-errors/custom-validation-errors
type ValidationError interface {
error