mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
replace ioutil with io package and other minor improvements
This commit is contained in:
parent
20d2855a66
commit
ef2643b046
|
@ -28,6 +28,7 @@ The codebase for Dependency Injection, Internationalization and localization and
|
|||
|
||||
## Fixes and Improvements
|
||||
|
||||
- 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.
|
||||
|
|
5
LICENSE
5
LICENSE
|
@ -1,4 +1,7 @@
|
|||
Copyright (c) 2017-2022 The Iris Authors. All rights reserved.
|
||||
Copyright (c) 2017-2022, The Iris Authors. All rights reserved.
|
||||
|
||||
The Iris Authors:
|
||||
* Gerasimos (Makis) Maropoulos
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
33
README.md
33
README.md
|
@ -19,7 +19,8 @@
|
|||
|
||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||
|
||||
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/)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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 |
|
||||
+---------------------------+ +-------------------------+ +--------------------------+
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
1
cache/browser.go
vendored
|
@ -49,6 +49,7 @@ var NoCache = func(ctx *context.Context) {
|
|||
// Usage: `app.Use(cache.StaticCache(24 * time.Hour))` or `app.Use(cache.Staticcache(-1))`.
|
||||
// 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)
|
||||
// [...]
|
||||
|
|
6
cache/client/client.go
vendored
6
cache/client/client.go
vendored
|
@ -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
|
||||
|
|
1
cache/client/rule/validator.go
vendored
1
cache/client/rule/validator.go
vendored
|
@ -22,6 +22,7 @@ type PreValidator func(*context.Context) bool
|
|||
//
|
||||
// Q: What's the difference between this and a PreValidator?
|
||||
// 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
//
|
||||
|
|
|
@ -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{....}
|
||||
|
|
|
@ -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".
|
||||
//
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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")
|
||||
// })
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
// })
|
||||
|
|
|
@ -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
7
doc.go
|
@ -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
1
go.mod
|
@ -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
2
go.sum
generated
|
@ -62,8 +62,6 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
|||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/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=
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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),
|
||||
|
|
2
iris.go
2
iris.go
|
@ -299,6 +299,7 @@ func (app *Application) ConfigurationReadOnly() context.ConfigurationReadOnly {
|
|||
// Adding one or more outputs : app.Logger().AddOutput(io.Writer...)
|
||||
//
|
||||
// Adding 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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
//
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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...)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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...]
|
||||
// }
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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, ",", " ")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -50,6 +50,7 @@ type (
|
|||
// through a Context or within filter functions.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// AsValue("my string")
|
||||
//
|
||||
// Shortcut for `pongo2.AsValue`.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user