mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 05:16:35 +08:00
Merge branch 'master' into support_go1.18
This commit is contained in:
commit
47c6e1539e
49
.github/workflows/codeql.yml
vendored
Normal file
49
.github/workflows/codeql.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '0 17 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
# TODO: Enable for javascript later
|
||||
language: [ 'go']
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
8
.github/workflows/gin.yml
vendored
8
.github/workflows/gin.yml
vendored
@ -17,11 +17,11 @@ jobs:
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3.1.0
|
||||
with:
|
||||
version: v1.43.0
|
||||
version: v1.44.0
|
||||
args: --verbose
|
||||
test:
|
||||
needs: lint
|
||||
@ -48,7 +48,7 @@ jobs:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
|
12
README.md
12
README.md
@ -384,8 +384,8 @@ func main() {
|
||||
// Set a lower memory limit for multipart forms (default is 32 MiB)
|
||||
router.MaxMultipartMemory = 8 << 20 // 8 MiB
|
||||
router.POST("/upload", func(c *gin.Context) {
|
||||
// single file
|
||||
file, _ := c.FormFile("Filename")
|
||||
// Single file
|
||||
file, _ := c.FormFile("file")
|
||||
log.Println(file.Filename)
|
||||
|
||||
// Upload the file to specific dst.
|
||||
@ -513,6 +513,7 @@ func main() {
|
||||
|
||||
// nested group
|
||||
testing := authorized.Group("testing")
|
||||
// visit 0.0.0.0:8080/testing/analytics
|
||||
testing.GET("/analytics", analyticsEndpoint)
|
||||
}
|
||||
|
||||
@ -906,7 +907,7 @@ func startPage(c *gin.Context) {
|
||||
var person Person
|
||||
// If `GET`, only `Form` binding engine (`query`) used.
|
||||
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
|
||||
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48
|
||||
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L88
|
||||
if c.ShouldBind(&person) == nil {
|
||||
log.Println(person.Name)
|
||||
log.Println(person.Address)
|
||||
@ -1243,7 +1244,8 @@ func main() {
|
||||
router.Static("/assets", "./assets")
|
||||
router.StaticFS("/more_static", http.Dir("my_file_system"))
|
||||
router.StaticFile("/favicon.ico", "./resources/favicon.ico")
|
||||
|
||||
router.StaticFileFS("/more_favicon.ico", "more_favicon.ico", http.Dir("my_file_system"))
|
||||
|
||||
// Listen and serve on 0.0.0.0:8080
|
||||
router.Run(":8080")
|
||||
}
|
||||
@ -1409,7 +1411,7 @@ import (
|
||||
|
||||
func formatAsDate(t time.Time) string {
|
||||
year, month, day := t.Date()
|
||||
return fmt.Sprintf("%d%02d/%02d", year, month, day)
|
||||
return fmt.Sprintf("%d/%02d/%02d", year, month, day)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -40,7 +40,7 @@ type BindingBody interface {
|
||||
}
|
||||
|
||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||
// but it read the Params.
|
||||
// but it reads the Params.
|
||||
type BindingUri interface {
|
||||
Name() string
|
||||
BindUri(map[string][]string, any) error
|
||||
|
@ -38,7 +38,7 @@ type BindingBody interface {
|
||||
}
|
||||
|
||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||
// but it read the Params.
|
||||
// but it reads the Params.
|
||||
type BindingUri interface {
|
||||
Name() string
|
||||
BindUri(map[string][]string, any) error
|
||||
|
27
context.go
27
context.go
@ -6,7 +6,6 @@ package gin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@ -59,7 +58,7 @@ type Context struct {
|
||||
params *Params
|
||||
skippedNodes *[]skippedNode
|
||||
|
||||
// This mutex protect Keys map
|
||||
// This mutex protects Keys map.
|
||||
mu sync.RWMutex
|
||||
|
||||
// Keys is a key/value pair exclusively for the context of each request.
|
||||
@ -71,10 +70,10 @@ type Context struct {
|
||||
// Accepted defines a list of manually accepted formats for content negotiation.
|
||||
Accepted []string
|
||||
|
||||
// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
|
||||
// queryCache caches the query result from c.Request.URL.Query().
|
||||
queryCache url.Values
|
||||
|
||||
// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
|
||||
// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
|
||||
// or PUT body parameters.
|
||||
formCache url.Values
|
||||
|
||||
@ -601,11 +600,10 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
|
||||
return err
|
||||
}
|
||||
|
||||
// Bind checks the Content-Type to select a binding engine automatically,
|
||||
// Depending on the "Content-Type" header different bindings are used:
|
||||
// Bind checks the Method and Content-Type to select a binding engine automatically,
|
||||
// Depending on the "Content-Type" header different bindings are used, for example:
|
||||
// "application/json" --> JSON binding
|
||||
// "application/xml" --> XML binding
|
||||
// otherwise --> returns an error.
|
||||
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
|
||||
// It decodes the json payload into the struct specified as a pointer.
|
||||
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
|
||||
@ -660,14 +658,13 @@ func (c *Context) MustBindWith(obj any, b binding.Binding) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShouldBind checks the Content-Type to select a binding engine automatically,
|
||||
// Depending on the "Content-Type" header different bindings are used:
|
||||
// ShouldBind checks the Method and Content-Type to select a binding engine automatically,
|
||||
// Depending on the "Content-Type" header different bindings are used, for example:
|
||||
// "application/json" --> JSON binding
|
||||
// "application/xml" --> XML binding
|
||||
// otherwise --> returns an error
|
||||
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
|
||||
// It decodes the json payload into the struct specified as a pointer.
|
||||
// Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid.
|
||||
// Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid.
|
||||
func (c *Context) ShouldBind(obj any) error {
|
||||
b := binding.Default(c.Request.Method, c.ContentType())
|
||||
return c.ShouldBindWith(obj, b)
|
||||
@ -843,7 +840,7 @@ func (c *Context) GetHeader(key string) string {
|
||||
return c.requestHeader(key)
|
||||
}
|
||||
|
||||
// GetRawData return stream data.
|
||||
// GetRawData returns stream data.
|
||||
func (c *Context) GetRawData() ([]byte, error) {
|
||||
return ioutil.ReadAll(c.Request.Body)
|
||||
}
|
||||
@ -1020,7 +1017,11 @@ func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
|
||||
// FileAttachment writes the specified file into the body stream in an efficient way
|
||||
// On the client side, the file will typically be downloaded with the given filename
|
||||
func (c *Context) FileAttachment(filepath, filename string) {
|
||||
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
|
||||
if isASCII(filename) {
|
||||
c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
|
||||
} else {
|
||||
c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
|
||||
}
|
||||
http.ServeFile(c.Writer, c.Request, filepath)
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -1033,6 +1034,19 @@ func TestContextRenderAttachment(t *testing.T) {
|
||||
assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.Header().Get("Content-Disposition"))
|
||||
}
|
||||
|
||||
func TestContextRenderUTF8Attachment(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
newFilename := "new🧡_filename.go"
|
||||
|
||||
c.Request, _ = http.NewRequest("GET", "/", nil)
|
||||
c.FileAttachment("./gin.go", newFilename)
|
||||
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "func New() *Engine {")
|
||||
assert.Equal(t, `attachment; filename*=UTF-8''`+url.QueryEscape(newFilename), w.Header().Get("Content-Disposition"))
|
||||
}
|
||||
|
||||
// TestContextRenderYAML tests that the response is serialized as YAML
|
||||
// and Content-Type is set to application/x-yaml
|
||||
func TestContextRenderYAML(t *testing.T) {
|
||||
@ -2036,8 +2050,8 @@ func TestRaceParamsContextCopy(t *testing.T) {
|
||||
}(c.Copy(), c.Param("name"))
|
||||
})
|
||||
}
|
||||
performRequest(router, "GET", "/name1/api")
|
||||
performRequest(router, "GET", "/name2/api")
|
||||
PerformRequest(router, "GET", "/name1/api")
|
||||
PerformRequest(router, "GET", "/name2/api")
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
|
22
gin.go
22
gin.go
@ -16,6 +16,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin/internal/bytesconv"
|
||||
"github.com/gin-gonic/gin/render"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||
@ -141,6 +143,9 @@ type Engine struct {
|
||||
// method call.
|
||||
MaxMultipartMemory int64
|
||||
|
||||
// Enable h2c support.
|
||||
UseH2C bool
|
||||
|
||||
delims render.Delims
|
||||
secureJSONPrefix string
|
||||
HTMLRender render.HTMLRender
|
||||
@ -207,6 +212,15 @@ func Default() *Engine {
|
||||
return engine
|
||||
}
|
||||
|
||||
func (engine *Engine) Handler() http.Handler {
|
||||
if !engine.UseH2C {
|
||||
return engine
|
||||
}
|
||||
|
||||
h2s := &http2.Server{}
|
||||
return h2c.NewHandler(engine, h2s)
|
||||
}
|
||||
|
||||
func (engine *Engine) allocateContext() *Context {
|
||||
v := make(Params, 0, engine.maxParams)
|
||||
skippedNodes := make([]skippedNode, 0, engine.maxSections)
|
||||
@ -361,7 +375,7 @@ func (engine *Engine) Run(addr ...string) (err error) {
|
||||
|
||||
address := resolveAddress(addr)
|
||||
debugPrint("Listening and serving HTTP on %s\n", address)
|
||||
err = http.ListenAndServe(address, engine)
|
||||
err = http.ListenAndServe(address, engine.Handler())
|
||||
return
|
||||
}
|
||||
|
||||
@ -480,7 +494,7 @@ func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
|
||||
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
|
||||
}
|
||||
|
||||
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
|
||||
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler())
|
||||
return
|
||||
}
|
||||
|
||||
@ -503,7 +517,7 @@ func (engine *Engine) RunUnix(file string) (err error) {
|
||||
defer listener.Close()
|
||||
defer os.Remove(file)
|
||||
|
||||
err = http.Serve(listener, engine)
|
||||
err = http.Serve(listener, engine.Handler())
|
||||
return
|
||||
}
|
||||
|
||||
@ -540,7 +554,7 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) {
|
||||
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
|
||||
}
|
||||
|
||||
err = http.Serve(listener, engine)
|
||||
err = http.Serve(listener, engine.Handler())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes {
|
||||
return engine().StaticFS(relativePath, fs)
|
||||
}
|
||||
|
||||
// Use attaches a global middleware to the router. i.e. the middlewares attached though Use() will be
|
||||
// Use attaches a global middleware to the router. i.e. the middlewares attached through Use() will be
|
||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||
// For example, this is the right place for a logger or error management middleware.
|
||||
func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
|
||||
|
45
gin_test.go
45
gin_test.go
@ -19,6 +19,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
func formatAsDate(t time.Time) string {
|
||||
@ -79,6 +80,44 @@ func TestLoadHTMLGlobDebugMode(t *testing.T) {
|
||||
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
|
||||
}
|
||||
|
||||
func TestH2c(t *testing.T) {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
r := Default()
|
||||
r.UseH2C = true
|
||||
r.GET("/", func(c *Context) {
|
||||
c.String(200, "<h1>Hello world</h1>")
|
||||
})
|
||||
go func() {
|
||||
err := http.Serve(ln, r.Handler())
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}()
|
||||
defer ln.Close()
|
||||
|
||||
url := "http://" + ln.Addr().String() + "/"
|
||||
|
||||
http := http.Client{
|
||||
Transport: &http2.Transport{
|
||||
AllowHTTP: true,
|
||||
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
return net.Dial(netw, addr)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
resp, _ := ioutil.ReadAll(res.Body)
|
||||
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
|
||||
}
|
||||
|
||||
func TestLoadHTMLGlobTestMode(t *testing.T) {
|
||||
ts := setupHTMLFiles(
|
||||
t,
|
||||
@ -395,7 +434,6 @@ func TestNoMethodWithoutGlobalHandlers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRebuild404Handlers(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestNoMethodWithGlobalHandlers(t *testing.T) {
|
||||
@ -491,7 +529,7 @@ func TestEngineHandleContext(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
w := performRequest(r, "GET", "/")
|
||||
w := PerformRequest(r, "GET", "/")
|
||||
assert.Equal(t, 301, w.Code)
|
||||
})
|
||||
}
|
||||
@ -524,7 +562,7 @@ func TestEngineHandleContextManyReEntries(t *testing.T) {
|
||||
})
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
w := performRequest(r, "GET", "/"+strconv.Itoa(expectValue-1)) // include 0 value
|
||||
w := PerformRequest(r, "GET", "/"+strconv.Itoa(expectValue-1)) // include 0 value
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Equal(t, expectValue, w.Body.Len())
|
||||
})
|
||||
@ -636,7 +674,6 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
|
||||
assert.Nil(t, r.trustedCIDRs)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func parseCIDR(cidr string) *net.IPNet {
|
||||
|
@ -302,7 +302,7 @@ func TestShouldBindUri(t *testing.T) {
|
||||
})
|
||||
|
||||
path, _ := exampleFromPath("/rest/:name/:id")
|
||||
w := performRequest(router, http.MethodGet, path)
|
||||
w := PerformRequest(router, http.MethodGet, path)
|
||||
assert.Equal(t, "ShouldBindUri test OK", w.Body.String())
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
@ -324,7 +324,7 @@ func TestBindUri(t *testing.T) {
|
||||
})
|
||||
|
||||
path, _ := exampleFromPath("/rest/:name/:id")
|
||||
w := performRequest(router, http.MethodGet, path)
|
||||
w := PerformRequest(router, http.MethodGet, path)
|
||||
assert.Equal(t, "BindUri test OK", w.Body.String())
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
@ -342,7 +342,7 @@ func TestBindUriError(t *testing.T) {
|
||||
})
|
||||
|
||||
path1, _ := exampleFromPath("/new/rest/:num")
|
||||
w1 := performRequest(router, http.MethodGet, path1)
|
||||
w1 := PerformRequest(router, http.MethodGet, path1)
|
||||
assert.Equal(t, http.StatusBadRequest, w1.Code)
|
||||
}
|
||||
|
||||
@ -358,7 +358,7 @@ func TestRaceContextCopy(t *testing.T) {
|
||||
go readWriteKeys(c.Copy())
|
||||
c.String(http.StatusOK, "run OK, no panics")
|
||||
})
|
||||
w := performRequest(router, http.MethodGet, "/test/copy/race")
|
||||
w := PerformRequest(router, http.MethodGet, "/test/copy/race")
|
||||
assert.Equal(t, "run OK, no panics", w.Body.String())
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ func TestGithubAPI(t *testing.T) {
|
||||
|
||||
for _, route := range githubAPI {
|
||||
path, values := exampleFromPath(route.path)
|
||||
w := performRequest(router, route.method, path)
|
||||
w := PerformRequest(router, route.method, path)
|
||||
|
||||
// TEST
|
||||
assert.Contains(t, w.Body.String(), "\"status\":\"good\"")
|
||||
|
9
go.mod
9
go.mod
@ -4,14 +4,13 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/sse v0.1.0
|
||||
github.com/go-playground/validator/v10 v10.9.0
|
||||
github.com/goccy/go-json v0.8.1
|
||||
github.com/go-playground/validator/v10 v10.10.0
|
||||
github.com/goccy/go-json v0.9.5
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ugorji/go/codec v1.2.6
|
||||
github.com/ugorji/go/codec v1.2.7
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
retract v1.7.5
|
||||
|
17
go.sum
17
go.sum
@ -10,10 +10,10 @@ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
|
||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/goccy/go-json v0.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI=
|
||||
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/goccy/go-json v0.9.5 h1:ooSMW526ZjK+EaL5elrSyN2EzIfi/3V0m4+HJEDYLik=
|
||||
github.com/goccy/go-json v0.9.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@ -47,12 +47,13 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -31,7 +31,7 @@ func TestLogger(t *testing.T) {
|
||||
router.HEAD("/example", func(c *Context) {})
|
||||
router.OPTIONS("/example", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/example?a=100")
|
||||
PerformRequest(router, "GET", "/example?a=100")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
@ -41,43 +41,43 @@ func TestLogger(t *testing.T) {
|
||||
// like integration tests because they test the whole logging process rather
|
||||
// than individual functions. Im not sure where these should go.
|
||||
buffer.Reset()
|
||||
performRequest(router, "POST", "/example")
|
||||
PerformRequest(router, "POST", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "POST")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "PUT", "/example")
|
||||
PerformRequest(router, "PUT", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "PUT")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "DELETE", "/example")
|
||||
PerformRequest(router, "DELETE", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "DELETE")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "PATCH", "/example")
|
||||
PerformRequest(router, "PATCH", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "PATCH")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "HEAD", "/example")
|
||||
PerformRequest(router, "HEAD", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "HEAD")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "OPTIONS", "/example")
|
||||
PerformRequest(router, "OPTIONS", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "OPTIONS")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "GET", "/notfound")
|
||||
PerformRequest(router, "GET", "/notfound")
|
||||
assert.Contains(t, buffer.String(), "404")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/notfound")
|
||||
@ -95,7 +95,7 @@ func TestLoggerWithConfig(t *testing.T) {
|
||||
router.HEAD("/example", func(c *Context) {})
|
||||
router.OPTIONS("/example", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/example?a=100")
|
||||
PerformRequest(router, "GET", "/example?a=100")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
@ -105,43 +105,43 @@ func TestLoggerWithConfig(t *testing.T) {
|
||||
// like integration tests because they test the whole logging process rather
|
||||
// than individual functions. Im not sure where these should go.
|
||||
buffer.Reset()
|
||||
performRequest(router, "POST", "/example")
|
||||
PerformRequest(router, "POST", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "POST")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "PUT", "/example")
|
||||
PerformRequest(router, "PUT", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "PUT")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "DELETE", "/example")
|
||||
PerformRequest(router, "DELETE", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "DELETE")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "PATCH", "/example")
|
||||
PerformRequest(router, "PATCH", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "PATCH")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "HEAD", "/example")
|
||||
PerformRequest(router, "HEAD", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "HEAD")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "OPTIONS", "/example")
|
||||
PerformRequest(router, "OPTIONS", "/example")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
assert.Contains(t, buffer.String(), "OPTIONS")
|
||||
assert.Contains(t, buffer.String(), "/example")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "GET", "/notfound")
|
||||
PerformRequest(router, "GET", "/notfound")
|
||||
assert.Contains(t, buffer.String(), "404")
|
||||
assert.Contains(t, buffer.String(), "GET")
|
||||
assert.Contains(t, buffer.String(), "/notfound")
|
||||
@ -169,7 +169,7 @@ func TestLoggerWithFormatter(t *testing.T) {
|
||||
)
|
||||
}))
|
||||
router.GET("/example", func(c *Context) {})
|
||||
performRequest(router, "GET", "/example?a=100")
|
||||
PerformRequest(router, "GET", "/example?a=100")
|
||||
|
||||
// output test
|
||||
assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
|
||||
@ -209,7 +209,7 @@ func TestLoggerWithConfigFormatting(t *testing.T) {
|
||||
c.Request.Header.Set("X-Forwarded-For", "20.20.20.20")
|
||||
gotKeys = c.Keys
|
||||
})
|
||||
performRequest(router, "GET", "/example?a=100")
|
||||
PerformRequest(router, "GET", "/example?a=100")
|
||||
|
||||
// output test
|
||||
assert.Contains(t, buffer.String(), "[FORMATTER TEST]")
|
||||
@ -228,7 +228,6 @@ func TestLoggerWithConfigFormatting(t *testing.T) {
|
||||
assert.Equal(t, "/example?a=100", gotParam.Path)
|
||||
assert.Empty(t, gotParam.ErrorMessage)
|
||||
assert.Equal(t, gotKeys, gotParam.Keys)
|
||||
|
||||
}
|
||||
|
||||
func TestDefaultLogFormatter(t *testing.T) {
|
||||
@ -282,7 +281,6 @@ func TestDefaultLogFormatter(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 5s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueParam))
|
||||
assert.Equal(t, "[GIN] 2018/12/07 - 09:11:42 |\x1b[97;42m 200 \x1b[0m| 2743h29m3s | 20.20.20.20 |\x1b[97;44m GET \x1b[0m \"/\"\n", defaultLogFormatter(termTrueLongDurationParam))
|
||||
|
||||
}
|
||||
|
||||
func TestColorForMethod(t *testing.T) {
|
||||
@ -369,15 +367,15 @@ func TestErrorLogger(t *testing.T) {
|
||||
c.String(http.StatusInternalServerError, "hola!")
|
||||
})
|
||||
|
||||
w := performRequest(router, "GET", "/error")
|
||||
w := PerformRequest(router, "GET", "/error")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "{\"error\":\"this is an error\"}", w.Body.String())
|
||||
|
||||
w = performRequest(router, "GET", "/abort")
|
||||
w = PerformRequest(router, "GET", "/abort")
|
||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
assert.Equal(t, "{\"error\":\"no authorized\"}", w.Body.String())
|
||||
|
||||
w = performRequest(router, "GET", "/print")
|
||||
w = PerformRequest(router, "GET", "/print")
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
assert.Equal(t, "hola!{\"error\":\"this is an error\"}", w.Body.String())
|
||||
}
|
||||
@ -389,11 +387,11 @@ func TestLoggerWithWriterSkippingPaths(t *testing.T) {
|
||||
router.GET("/logged", func(c *Context) {})
|
||||
router.GET("/skipped", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/logged")
|
||||
PerformRequest(router, "GET", "/logged")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "GET", "/skipped")
|
||||
PerformRequest(router, "GET", "/skipped")
|
||||
assert.Contains(t, buffer.String(), "")
|
||||
}
|
||||
|
||||
@ -407,11 +405,11 @@ func TestLoggerWithConfigSkippingPaths(t *testing.T) {
|
||||
router.GET("/logged", func(c *Context) {})
|
||||
router.GET("/skipped", func(c *Context) {})
|
||||
|
||||
performRequest(router, "GET", "/logged")
|
||||
PerformRequest(router, "GET", "/logged")
|
||||
assert.Contains(t, buffer.String(), "200")
|
||||
|
||||
buffer.Reset()
|
||||
performRequest(router, "GET", "/skipped")
|
||||
PerformRequest(router, "GET", "/skipped")
|
||||
assert.Contains(t, buffer.String(), "")
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ func TestMiddlewareGeneralCase(t *testing.T) {
|
||||
signature += " XX "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
@ -71,7 +71,7 @@ func TestMiddlewareNoRoute(t *testing.T) {
|
||||
signature += " X "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
@ -108,7 +108,7 @@ func TestMiddlewareNoMethodEnabled(t *testing.T) {
|
||||
signature += " XX "
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||
@ -149,7 +149,7 @@ func TestMiddlewareNoMethodDisabled(t *testing.T) {
|
||||
})
|
||||
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
@ -175,7 +175,7 @@ func TestMiddlewareAbort(t *testing.T) {
|
||||
})
|
||||
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
@ -190,14 +190,13 @@ func TestMiddlewareAbortHandlersChainAndNext(t *testing.T) {
|
||||
c.Next()
|
||||
c.AbortWithStatus(http.StatusGone)
|
||||
signature += "B"
|
||||
|
||||
})
|
||||
router.GET("/", func(c *Context) {
|
||||
signature += "C"
|
||||
c.Next()
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusGone, w.Code)
|
||||
@ -220,7 +219,7 @@ func TestMiddlewareFailHandlersChain(t *testing.T) {
|
||||
signature += "C"
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
@ -247,7 +246,7 @@ func TestMiddlewareWrite(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
w := performRequest(router, "GET", "/")
|
||||
w := PerformRequest(router, "GET", "/")
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Equal(t, strings.Replace("hola\n<map><foo>bar</foo></map>{\"foo\":\"bar\"}{\"foo\":\"bar\"}event:test\ndata:message\n\n", " ", "", -1), strings.Replace(w.Body.String(), " ", "", -1))
|
||||
|
@ -27,7 +27,7 @@ func TestPanicClean(t *testing.T) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery",
|
||||
w := PerformRequest(router, "GET", "/recovery",
|
||||
header{
|
||||
Key: "Host",
|
||||
Value: "www.google.com",
|
||||
@ -57,7 +57,7 @@ func TestPanicInHandler(t *testing.T) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
w := PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
assert.Contains(t, buffer.String(), "panic recovered")
|
||||
@ -68,7 +68,7 @@ func TestPanicInHandler(t *testing.T) {
|
||||
// Debug mode prints the request
|
||||
SetMode(DebugMode)
|
||||
// RUN
|
||||
w = performRequest(router, "GET", "/recovery")
|
||||
w = PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||
@ -85,7 +85,7 @@ func TestPanicWithAbort(t *testing.T) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
w := PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
}
|
||||
@ -122,7 +122,6 @@ func TestPanicWithBrokenPipe(t *testing.T) {
|
||||
|
||||
for errno, expectMsg := range expectMsgs {
|
||||
t.Run(expectMsg, func(t *testing.T) {
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
router := New()
|
||||
@ -137,7 +136,7 @@ func TestPanicWithBrokenPipe(t *testing.T) {
|
||||
panic(e)
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
w := PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, expectCode, w.Code)
|
||||
assert.Contains(t, strings.ToLower(buf.String()), expectMsg)
|
||||
@ -158,7 +157,7 @@ func TestCustomRecoveryWithWriter(t *testing.T) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
w := PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Contains(t, buffer.String(), "panic recovered")
|
||||
@ -169,7 +168,7 @@ func TestCustomRecoveryWithWriter(t *testing.T) {
|
||||
// Debug mode prints the request
|
||||
SetMode(DebugMode)
|
||||
// RUN
|
||||
w = performRequest(router, "GET", "/recovery")
|
||||
w = PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||
@ -193,7 +192,7 @@ func TestCustomRecovery(t *testing.T) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
w := PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Contains(t, buffer.String(), "panic recovered")
|
||||
@ -204,7 +203,7 @@ func TestCustomRecovery(t *testing.T) {
|
||||
// Debug mode prints the request
|
||||
SetMode(DebugMode)
|
||||
// RUN
|
||||
w = performRequest(router, "GET", "/recovery")
|
||||
w = PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||
@ -228,7 +227,7 @@ func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
|
||||
panic("Oupps, Houston, we have a problem")
|
||||
})
|
||||
// RUN
|
||||
w := performRequest(router, "GET", "/recovery")
|
||||
w := PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Contains(t, buffer.String(), "panic recovered")
|
||||
@ -239,7 +238,7 @@ func TestRecoveryWithWriterWithCustomRecovery(t *testing.T) {
|
||||
// Debug mode prints the request
|
||||
SetMode(DebugMode)
|
||||
// RUN
|
||||
w = performRequest(router, "GET", "/recovery")
|
||||
w = PerformRequest(router, "GET", "/recovery")
|
||||
// TEST
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Contains(t, buffer.String(), "GET /recovery")
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// reg match english letters for http method name
|
||||
// regEnLetter matches english letters for http method name
|
||||
regEnLetter = regexp.MustCompile("^[A-Z]+$")
|
||||
|
||||
// anyMethods for RouterGroup Any method
|
||||
@ -44,6 +44,7 @@ type IRoutes interface {
|
||||
HEAD(string, ...HandlerFunc) IRoutes
|
||||
|
||||
StaticFile(string, string) IRoutes
|
||||
StaticFileFS(string, string, http.FileSystem) IRoutes
|
||||
Static(string, string) IRoutes
|
||||
StaticFS(string, http.FileSystem) IRoutes
|
||||
}
|
||||
@ -153,12 +154,24 @@ func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRou
|
||||
// StaticFile registers a single route in order to serve a single file of the local filesystem.
|
||||
// router.StaticFile("favicon.ico", "./resources/favicon.ico")
|
||||
func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
|
||||
return group.staticFileHandler(relativePath, func(c *Context) {
|
||||
c.File(filepath)
|
||||
})
|
||||
}
|
||||
|
||||
// StaticFileFS works just like `StaticFile` but a custom `http.FileSystem` can be used instead..
|
||||
// router.StaticFileFS("favicon.ico", "./resources/favicon.ico", Dir{".", false})
|
||||
// Gin by default user: gin.Dir()
|
||||
func (group *RouterGroup) StaticFileFS(relativePath, filepath string, fs http.FileSystem) IRoutes {
|
||||
return group.staticFileHandler(relativePath, func(c *Context) {
|
||||
c.FileFromFS(filepath, fs)
|
||||
})
|
||||
}
|
||||
|
||||
func (group *RouterGroup) staticFileHandler(relativePath string, handler HandlerFunc) IRoutes {
|
||||
if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
|
||||
panic("URL parameters can not be used when serving a static file")
|
||||
}
|
||||
handler := func(c *Context) {
|
||||
c.File(filepath)
|
||||
}
|
||||
group.GET(relativePath, handler)
|
||||
group.HEAD(relativePath, handler)
|
||||
return group.returnObj()
|
||||
|
@ -80,11 +80,11 @@ func performRequestInGroup(t *testing.T, method string) {
|
||||
panic("unknown method")
|
||||
}
|
||||
|
||||
w := performRequest(router, method, "/v1/login/test")
|
||||
w := PerformRequest(router, method, "/v1/login/test")
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Equal(t, "the method was "+method+" and index 3", w.Body.String())
|
||||
|
||||
w = performRequest(router, method, "/v1/test")
|
||||
w = PerformRequest(router, method, "/v1/test")
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Equal(t, "the method was "+method+" and index 1", w.Body.String())
|
||||
}
|
||||
@ -111,6 +111,17 @@ func TestRouterGroupInvalidStaticFile(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouterGroupInvalidStaticFileFS(t *testing.T) {
|
||||
router := New()
|
||||
assert.Panics(t, func() {
|
||||
router.StaticFileFS("/path/:param", "favicon.ico", Dir(".", false))
|
||||
})
|
||||
|
||||
assert.Panics(t, func() {
|
||||
router.StaticFileFS("/path/*param", "favicon.ico", Dir(".", false))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouterGroupTooManyHandlers(t *testing.T) {
|
||||
const (
|
||||
panicValue = "too many handlers"
|
||||
@ -177,6 +188,7 @@ func testRoutesInterface(t *testing.T, r IRoutes) {
|
||||
assert.Equal(t, r, r.HEAD("/", handler))
|
||||
|
||||
assert.Equal(t, r, r.StaticFile("/file", "."))
|
||||
assert.Equal(t, r, r.StaticFileFS("/static2", ".", Dir(".", false)))
|
||||
assert.Equal(t, r, r.Static("/static", "."))
|
||||
assert.Equal(t, r, r.StaticFS("/static2", Dir(".", false)))
|
||||
}
|
||||
|
145
routes_test.go
145
routes_test.go
@ -21,7 +21,8 @@ type header struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func performRequest(r http.Handler, method, path string, headers ...header) *httptest.ResponseRecorder {
|
||||
// PerformRequest for testing gin router.
|
||||
func PerformRequest(r http.Handler, method, path string, headers ...header) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest(method, path, nil)
|
||||
for _, h := range headers {
|
||||
req.Header.Add(h.Key, h.Value)
|
||||
@ -42,11 +43,11 @@ func testRouteOK(method string, t *testing.T) {
|
||||
passed = true
|
||||
})
|
||||
|
||||
w := performRequest(r, method, "/test")
|
||||
w := PerformRequest(r, method, "/test")
|
||||
assert.True(t, passed)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
performRequest(r, method, "/test2")
|
||||
PerformRequest(r, method, "/test2")
|
||||
assert.True(t, passedAny)
|
||||
}
|
||||
|
||||
@ -58,7 +59,7 @@ func testRouteNotOK(method string, t *testing.T) {
|
||||
passed = true
|
||||
})
|
||||
|
||||
w := performRequest(router, method, "/test")
|
||||
w := PerformRequest(router, method, "/test")
|
||||
|
||||
assert.False(t, passed)
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
@ -79,7 +80,7 @@ func testRouteNotOK2(method string, t *testing.T) {
|
||||
passed = true
|
||||
})
|
||||
|
||||
w := performRequest(router, method, "/test")
|
||||
w := PerformRequest(router, method, "/test")
|
||||
|
||||
assert.False(t, passed)
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||
@ -99,7 +100,7 @@ func TestRouterMethod(t *testing.T) {
|
||||
c.String(http.StatusOK, "sup3")
|
||||
})
|
||||
|
||||
w := performRequest(router, http.MethodPut, "/hey")
|
||||
w := PerformRequest(router, http.MethodPut, "/hey")
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "called", w.Body.String())
|
||||
@ -150,50 +151,50 @@ func TestRouteRedirectTrailingSlash(t *testing.T) {
|
||||
router.POST("/path3", func(c *Context) {})
|
||||
router.PUT("/path4/", func(c *Context) {})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/path/")
|
||||
w := PerformRequest(router, http.MethodGet, "/path/")
|
||||
assert.Equal(t, "/path", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path2")
|
||||
w = PerformRequest(router, http.MethodGet, "/path2")
|
||||
assert.Equal(t, "/path2/", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodPost, "/path3/")
|
||||
w = PerformRequest(router, http.MethodPost, "/path3/")
|
||||
assert.Equal(t, "/path3", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodPut, "/path4")
|
||||
w = PerformRequest(router, http.MethodPut, "/path4")
|
||||
assert.Equal(t, "/path4/", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path")
|
||||
w = PerformRequest(router, http.MethodGet, "/path")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path2/")
|
||||
w = PerformRequest(router, http.MethodGet, "/path2/")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodPost, "/path3")
|
||||
w = PerformRequest(router, http.MethodPost, "/path3")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodPut, "/path4/")
|
||||
w = PerformRequest(router, http.MethodPut, "/path4/")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/api"})
|
||||
w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/api"})
|
||||
assert.Equal(t, "/api/path2/", w.Header().Get("Location"))
|
||||
assert.Equal(t, 301, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path2/", header{Key: "X-Forwarded-Prefix", Value: "/api/"})
|
||||
w = PerformRequest(router, http.MethodGet, "/path2/", header{Key: "X-Forwarded-Prefix", Value: "/api/"})
|
||||
assert.Equal(t, 200, w.Code)
|
||||
|
||||
router.RedirectTrailingSlash = false
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path/")
|
||||
w = PerformRequest(router, http.MethodGet, "/path/")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
w = performRequest(router, http.MethodGet, "/path2")
|
||||
w = PerformRequest(router, http.MethodGet, "/path2")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
w = performRequest(router, http.MethodPost, "/path3/")
|
||||
w = PerformRequest(router, http.MethodPost, "/path3/")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
w = performRequest(router, http.MethodPut, "/path4")
|
||||
w = PerformRequest(router, http.MethodPut, "/path4")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
}
|
||||
|
||||
@ -207,19 +208,19 @@ func TestRouteRedirectFixedPath(t *testing.T) {
|
||||
router.POST("/PATH3", func(c *Context) {})
|
||||
router.POST("/Path4/", func(c *Context) {})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/PATH")
|
||||
w := PerformRequest(router, http.MethodGet, "/PATH")
|
||||
assert.Equal(t, "/path", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodGet, "/path2")
|
||||
w = PerformRequest(router, http.MethodGet, "/path2")
|
||||
assert.Equal(t, "/Path2", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodPost, "/path3")
|
||||
w = PerformRequest(router, http.MethodPost, "/path3")
|
||||
assert.Equal(t, "/PATH3", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||
|
||||
w = performRequest(router, http.MethodPost, "/path4")
|
||||
w = PerformRequest(router, http.MethodPost, "/path4")
|
||||
assert.Equal(t, "/Path4/", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||
}
|
||||
@ -248,7 +249,7 @@ func TestRouteParamsByName(t *testing.T) {
|
||||
assert.False(t, ok)
|
||||
})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/test/john/smith/is/super/great")
|
||||
w := PerformRequest(router, http.MethodGet, "/test/john/smith/is/super/great")
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "john", name)
|
||||
@ -281,7 +282,7 @@ func TestRouteParamsByNameWithExtraSlash(t *testing.T) {
|
||||
assert.False(t, ok)
|
||||
})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "//test//john//smith//is//super//great")
|
||||
w := PerformRequest(router, http.MethodGet, "//test//john//smith//is//super//great")
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "john", name)
|
||||
@ -309,16 +310,50 @@ func TestRouteStaticFile(t *testing.T) {
|
||||
router.Static("/using_static", dir)
|
||||
router.StaticFile("/result", f.Name())
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/using_static/"+filename)
|
||||
w2 := performRequest(router, http.MethodGet, "/result")
|
||||
w := PerformRequest(router, http.MethodGet, "/using_static/"+filename)
|
||||
w2 := PerformRequest(router, http.MethodGet, "/result")
|
||||
|
||||
assert.Equal(t, w, w2)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "Gin Web Framework", w.Body.String())
|
||||
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
|
||||
w3 := performRequest(router, http.MethodHead, "/using_static/"+filename)
|
||||
w4 := performRequest(router, http.MethodHead, "/result")
|
||||
w3 := PerformRequest(router, http.MethodHead, "/using_static/"+filename)
|
||||
w4 := PerformRequest(router, http.MethodHead, "/result")
|
||||
|
||||
assert.Equal(t, w3, w4)
|
||||
assert.Equal(t, http.StatusOK, w3.Code)
|
||||
}
|
||||
|
||||
// TestHandleStaticFile - ensure the static file handles properly
|
||||
func TestRouteStaticFileFS(t *testing.T) {
|
||||
// SETUP file
|
||||
testRoot, _ := os.Getwd()
|
||||
f, err := ioutil.TempFile(testRoot, "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
_, err = f.WriteString("Gin Web Framework")
|
||||
assert.NoError(t, err)
|
||||
f.Close()
|
||||
|
||||
dir, filename := filepath.Split(f.Name())
|
||||
// SETUP gin
|
||||
router := New()
|
||||
router.Static("/using_static", dir)
|
||||
router.StaticFileFS("/result_fs", filename, Dir(dir, false))
|
||||
|
||||
w := PerformRequest(router, http.MethodGet, "/using_static/"+filename)
|
||||
w2 := PerformRequest(router, http.MethodGet, "/result_fs")
|
||||
|
||||
assert.Equal(t, w, w2)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "Gin Web Framework", w.Body.String())
|
||||
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
|
||||
w3 := PerformRequest(router, http.MethodHead, "/using_static/"+filename)
|
||||
w4 := PerformRequest(router, http.MethodHead, "/result_fs")
|
||||
|
||||
assert.Equal(t, w3, w4)
|
||||
assert.Equal(t, http.StatusOK, w3.Code)
|
||||
@ -329,7 +364,7 @@ func TestRouteStaticListingDir(t *testing.T) {
|
||||
router := New()
|
||||
router.StaticFS("/", Dir("./", true))
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/")
|
||||
w := PerformRequest(router, http.MethodGet, "/")
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "gin.go")
|
||||
@ -341,7 +376,7 @@ func TestRouteStaticNoListing(t *testing.T) {
|
||||
router := New()
|
||||
router.Static("/", "./")
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/")
|
||||
w := PerformRequest(router, http.MethodGet, "/")
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
assert.NotContains(t, w.Body.String(), "gin.go")
|
||||
@ -356,7 +391,7 @@ func TestRouterMiddlewareAndStatic(t *testing.T) {
|
||||
})
|
||||
static.Static("/", "./")
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/gin.go")
|
||||
w := PerformRequest(router, http.MethodGet, "/gin.go")
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "package gin")
|
||||
@ -372,13 +407,13 @@ func TestRouteNotAllowedEnabled(t *testing.T) {
|
||||
router := New()
|
||||
router.HandleMethodNotAllowed = true
|
||||
router.POST("/path", func(c *Context) {})
|
||||
w := performRequest(router, http.MethodGet, "/path")
|
||||
w := PerformRequest(router, http.MethodGet, "/path")
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||
|
||||
router.NoMethod(func(c *Context) {
|
||||
c.String(http.StatusTeapot, "responseText")
|
||||
})
|
||||
w = performRequest(router, http.MethodGet, "/path")
|
||||
w = PerformRequest(router, http.MethodGet, "/path")
|
||||
assert.Equal(t, "responseText", w.Body.String())
|
||||
assert.Equal(t, http.StatusTeapot, w.Code)
|
||||
}
|
||||
@ -389,7 +424,7 @@ func TestRouteNotAllowedEnabled2(t *testing.T) {
|
||||
// add one methodTree to trees
|
||||
router.addRoute(http.MethodPost, "/", HandlersChain{func(_ *Context) {}})
|
||||
router.GET("/path2", func(c *Context) {})
|
||||
w := performRequest(router, http.MethodPost, "/path2")
|
||||
w := PerformRequest(router, http.MethodPost, "/path2")
|
||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||
}
|
||||
|
||||
@ -397,13 +432,13 @@ func TestRouteNotAllowedDisabled(t *testing.T) {
|
||||
router := New()
|
||||
router.HandleMethodNotAllowed = false
|
||||
router.POST("/path", func(c *Context) {})
|
||||
w := performRequest(router, http.MethodGet, "/path")
|
||||
w := PerformRequest(router, http.MethodGet, "/path")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
|
||||
router.NoMethod(func(c *Context) {
|
||||
c.String(http.StatusTeapot, "responseText")
|
||||
})
|
||||
w = performRequest(router, http.MethodGet, "/path")
|
||||
w = PerformRequest(router, http.MethodGet, "/path")
|
||||
assert.Equal(t, "404 page not found", w.Body.String())
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
}
|
||||
@ -423,7 +458,7 @@ func TestRouterNotFoundWithRemoveExtraSlash(t *testing.T) {
|
||||
{"/nope", http.StatusNotFound, ""}, // NotFound
|
||||
}
|
||||
for _, tr := range testRoutes {
|
||||
w := performRequest(router, "GET", tr.route)
|
||||
w := PerformRequest(router, "GET", tr.route)
|
||||
assert.Equal(t, tr.code, w.Code)
|
||||
if w.Code != http.StatusNotFound {
|
||||
assert.Equal(t, tr.location, fmt.Sprint(w.Header().Get("Location")))
|
||||
@ -453,7 +488,7 @@ func TestRouterNotFound(t *testing.T) {
|
||||
{"/nope", http.StatusNotFound, ""}, // NotFound
|
||||
}
|
||||
for _, tr := range testRoutes {
|
||||
w := performRequest(router, http.MethodGet, tr.route)
|
||||
w := PerformRequest(router, http.MethodGet, tr.route)
|
||||
assert.Equal(t, tr.code, w.Code)
|
||||
if w.Code != http.StatusNotFound {
|
||||
assert.Equal(t, tr.location, fmt.Sprint(w.Header().Get("Location")))
|
||||
@ -466,20 +501,20 @@ func TestRouterNotFound(t *testing.T) {
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
notFound = true
|
||||
})
|
||||
w := performRequest(router, http.MethodGet, "/nope")
|
||||
w := PerformRequest(router, http.MethodGet, "/nope")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
assert.True(t, notFound)
|
||||
|
||||
// Test other method than GET (want 307 instead of 301)
|
||||
router.PATCH("/path", func(c *Context) {})
|
||||
w = performRequest(router, http.MethodPatch, "/path/")
|
||||
w = PerformRequest(router, http.MethodPatch, "/path/")
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||
assert.Equal(t, "map[Location:[/path]]", fmt.Sprint(w.Header()))
|
||||
|
||||
// Test special case where no node for the prefix "/" exists
|
||||
router = New()
|
||||
router.GET("/a", func(c *Context) {})
|
||||
w = performRequest(router, http.MethodGet, "/")
|
||||
w = PerformRequest(router, http.MethodGet, "/")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
|
||||
// Reproduction test for the bug of issue #2843
|
||||
@ -492,9 +527,9 @@ func TestRouterNotFound(t *testing.T) {
|
||||
router.GET("/logout", func(c *Context) {
|
||||
c.String(200, "logout")
|
||||
})
|
||||
w = performRequest(router, http.MethodGet, "/login")
|
||||
w = PerformRequest(router, http.MethodGet, "/login")
|
||||
assert.Equal(t, "login", w.Body.String())
|
||||
w = performRequest(router, http.MethodGet, "/logout")
|
||||
w = PerformRequest(router, http.MethodGet, "/logout")
|
||||
assert.Equal(t, "logout", w.Body.String())
|
||||
}
|
||||
|
||||
@ -505,10 +540,10 @@ func TestRouterStaticFSNotFound(t *testing.T) {
|
||||
c.String(404, "non existent")
|
||||
})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/nonexistent")
|
||||
w := PerformRequest(router, http.MethodGet, "/nonexistent")
|
||||
assert.Equal(t, "non existent", w.Body.String())
|
||||
|
||||
w = performRequest(router, http.MethodHead, "/nonexistent")
|
||||
w = PerformRequest(router, http.MethodHead, "/nonexistent")
|
||||
assert.Equal(t, "non existent", w.Body.String())
|
||||
}
|
||||
|
||||
@ -518,7 +553,7 @@ func TestRouterStaticFSFileNotFound(t *testing.T) {
|
||||
router.StaticFS("/", http.FileSystem(http.Dir(".")))
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
performRequest(router, http.MethodGet, "/nonexistent")
|
||||
PerformRequest(router, http.MethodGet, "/nonexistent")
|
||||
})
|
||||
}
|
||||
|
||||
@ -535,11 +570,11 @@ func TestMiddlewareCalledOnceByRouterStaticFSNotFound(t *testing.T) {
|
||||
router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
|
||||
|
||||
// First access
|
||||
performRequest(router, http.MethodGet, "/nonexistent")
|
||||
PerformRequest(router, http.MethodGet, "/nonexistent")
|
||||
assert.Equal(t, 1, middlewareCalledNum)
|
||||
|
||||
// Second access
|
||||
performRequest(router, http.MethodHead, "/nonexistent")
|
||||
PerformRequest(router, http.MethodHead, "/nonexistent")
|
||||
assert.Equal(t, 2, middlewareCalledNum)
|
||||
}
|
||||
|
||||
@ -558,7 +593,7 @@ func TestRouteRawPath(t *testing.T) {
|
||||
assert.Equal(t, "222", num)
|
||||
})
|
||||
|
||||
w := performRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/222")
|
||||
w := PerformRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/222")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
@ -578,7 +613,7 @@ func TestRouteRawPathNoUnescape(t *testing.T) {
|
||||
assert.Equal(t, "333", num)
|
||||
})
|
||||
|
||||
w := performRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/333")
|
||||
w := PerformRequest(route, http.MethodPost, "/project/Some%2FOther%2FProject/build/333")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
@ -589,7 +624,7 @@ func TestRouteServeErrorWithWriteHeader(t *testing.T) {
|
||||
c.Next()
|
||||
})
|
||||
|
||||
w := performRequest(route, http.MethodGet, "/NotFound")
|
||||
w := PerformRequest(route, http.MethodGet, "/NotFound")
|
||||
assert.Equal(t, 421, w.Code)
|
||||
assert.Equal(t, 0, w.Body.Len())
|
||||
}
|
||||
@ -623,7 +658,7 @@ func TestRouteContextHoldsFullPath(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
w := performRequest(router, http.MethodGet, route)
|
||||
w := PerformRequest(router, http.MethodGet, route)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
@ -633,6 +668,6 @@ func TestRouteContextHoldsFullPath(t *testing.T) {
|
||||
assert.Equal(t, "", c.FullPath())
|
||||
})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/not-found")
|
||||
w := PerformRequest(router, http.MethodGet, "/not-found")
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
}
|
||||
|
6
tree.go
6
tree.go
@ -81,7 +81,7 @@ func longestCommonPrefix(a, b string) int {
|
||||
return i
|
||||
}
|
||||
|
||||
// addChild will add a child node, keeping wildcards at the end
|
||||
// addChild will add a child node, keeping wildcardChild at the end
|
||||
func (n *node) addChild(child *node) {
|
||||
if n.wildChild && len(n.children) > 0 {
|
||||
wildcardChild := n.children[len(n.children)-1]
|
||||
@ -296,7 +296,7 @@ func (n *node) insertChild(path string, fullPath string, handlers HandlersChain)
|
||||
break
|
||||
}
|
||||
|
||||
// The wildcard name must not contain ':' and '*'
|
||||
// The wildcard name must only contain one ':' or '*' character
|
||||
if !valid {
|
||||
panic("only one wildcard per path segment is allowed, has: '" +
|
||||
wildcard + "' in path '" + fullPath + "'")
|
||||
@ -325,7 +325,7 @@ func (n *node) insertChild(path string, fullPath string, handlers HandlersChain)
|
||||
n.priority++
|
||||
|
||||
// if the path doesn't end with the wildcard, then there
|
||||
// will be another non-wildcard subpath starting with '/'
|
||||
// will be another subpath starting with '/'
|
||||
if len(wildcard) < len(path) {
|
||||
path = path[len(wildcard):]
|
||||
|
||||
|
11
utils.go
11
utils.go
@ -12,6 +12,7 @@ import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// BindKey indicates a default bind key.
|
||||
@ -151,3 +152,13 @@ func resolveAddress(addr []string) string {
|
||||
panic("too many parameters")
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters
|
||||
func isASCII(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] > unicode.MaxASCII {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -45,11 +45,11 @@ func TestWrap(t *testing.T) {
|
||||
fmt.Fprint(w, "hola!")
|
||||
}))
|
||||
|
||||
w := performRequest(router, "POST", "/path")
|
||||
w := PerformRequest(router, "POST", "/path")
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
assert.Equal(t, "hello", w.Body.String())
|
||||
|
||||
w = performRequest(router, "GET", "/path2")
|
||||
w = PerformRequest(router, "GET", "/path2")
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
assert.Equal(t, "hola!", w.Body.String())
|
||||
}
|
||||
@ -119,13 +119,13 @@ func TestBindMiddleware(t *testing.T) {
|
||||
called = true
|
||||
value = c.MustGet(BindKey).(*bindTestStruct)
|
||||
})
|
||||
performRequest(router, "GET", "/?foo=hola&bar=10")
|
||||
PerformRequest(router, "GET", "/?foo=hola&bar=10")
|
||||
assert.True(t, called)
|
||||
assert.Equal(t, "hola", value.Foo)
|
||||
assert.Equal(t, 10, value.Bar)
|
||||
|
||||
called = false
|
||||
performRequest(router, "GET", "/?foo=hola&bar=1")
|
||||
PerformRequest(router, "GET", "/?foo=hola&bar=1")
|
||||
assert.False(t, called)
|
||||
|
||||
assert.Panics(t, func() {
|
||||
@ -143,3 +143,8 @@ func TestMarshalXMLforH(t *testing.T) {
|
||||
e := h.MarshalXML(enc, x)
|
||||
assert.Error(t, e)
|
||||
}
|
||||
|
||||
func TestIsASCII(t *testing.T) {
|
||||
assert.Equal(t, isASCII("test"), true)
|
||||
assert.Equal(t, isASCII("🧡💛💚💙💜"), false)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user