mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
Merge branch 'gin-gonic:master' into dev/strings_builder
This commit is contained in:
commit
8489cb280c
2
.github/workflows/gin.yml
vendored
2
.github/workflows/gin.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
go: [1.15, 1.16, 1.17, 1.18]
|
go: [1.16, 1.17, 1.18, 1.19]
|
||||||
test-tags: ['', '-tags nomsgpack', '-tags "sonic avx"', '-tags go_json']
|
test-tags: ['', '-tags nomsgpack', '-tags "sonic avx"', '-tags go_json']
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
|
2
.github/workflows/goreleaser.yml
vendored
2
.github/workflows/goreleaser.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
-
|
-
|
||||||
name: Set up Go
|
name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.17
|
go-version: 1.17
|
||||||
-
|
-
|
||||||
|
@ -87,7 +87,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
|||||||
|
|
||||||
To install Gin package, you need to install Go and set your Go workspace first.
|
To install Gin package, you need to install Go and set your Go workspace first.
|
||||||
|
|
||||||
1. You first need [Go](https://golang.org/) installed (**version 1.15+ is required**), then you can use the below Go command to install Gin.
|
1. You first need [Go](https://golang.org/) installed (**version 1.16+ is required**), then you can use the below Go command to install Gin.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go get -u github.com/gin-gonic/gin
|
go get -u github.com/gin-gonic/gin
|
||||||
|
@ -1107,9 +1107,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
|||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
struct {
|
struct {
|
||||||
Idx int "form:\"idx\""
|
Idx int "form:\"idx\""
|
||||||
}(struct {
|
}{Idx: 123},
|
||||||
Idx int "form:\"idx\""
|
|
||||||
}{Idx: 123}),
|
|
||||||
obj.StructFoo)
|
obj.StructFoo)
|
||||||
case "StructPointer":
|
case "StructPointer":
|
||||||
obj := FooStructForStructPointerType{}
|
obj := FooStructForStructPointerType{}
|
||||||
@ -1118,9 +1116,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
|||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
struct {
|
struct {
|
||||||
Name string "form:\"name\""
|
Name string "form:\"name\""
|
||||||
}(struct {
|
}{Name: "thinkerou"},
|
||||||
Name string "form:\"name\""
|
|
||||||
}{Name: "thinkerou"}),
|
|
||||||
*obj.StructPointerFoo)
|
*obj.StructPointerFoo)
|
||||||
case "Map":
|
case "Map":
|
||||||
obj := FooStructForMapType{}
|
obj := FooStructForMapType{}
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
errUnknownType = errors.New("unknown type")
|
errUnknownType = errors.New("unknown type")
|
||||||
|
|
||||||
// ErrConvertMapStringSlice can not covert to map[string][]string
|
// ErrConvertMapStringSlice can not convert to map[string][]string
|
||||||
ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings")
|
ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings")
|
||||||
|
|
||||||
// ErrConvertToMapString can not convert to map[string]string
|
// ErrConvertToMapString can not convert to map[string]string
|
||||||
|
@ -114,7 +114,7 @@ func TestMappingPrivateField(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := mappingByPtr(&s, formSource{"field": {"6"}}, "form")
|
err := mappingByPtr(&s, formSource{"field": {"6"}}, "form")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int(0), s.f)
|
assert.Equal(t, 0, s.f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMappingUnknownFieldType(t *testing.T) {
|
func TestMappingUnknownFieldType(t *testing.T) {
|
||||||
@ -133,7 +133,7 @@ func TestMappingURI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := mapURI(&s, map[string][]string{"field": {"6"}})
|
err := mapURI(&s, map[string][]string{"field": {"6"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int(6), s.F)
|
assert.Equal(t, 6, s.F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMappingForm(t *testing.T) {
|
func TestMappingForm(t *testing.T) {
|
||||||
@ -142,7 +142,7 @@ func TestMappingForm(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := mapForm(&s, map[string][]string{"field": {"6"}})
|
err := mapForm(&s, map[string][]string{"field": {"6"}})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int(6), s.F)
|
assert.Equal(t, 6, s.F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMapFormWithTag(t *testing.T) {
|
func TestMapFormWithTag(t *testing.T) {
|
||||||
@ -151,7 +151,7 @@ func TestMapFormWithTag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := MapFormWithTag(&s, map[string][]string{"field": {"6"}}, "externalTag")
|
err := MapFormWithTag(&s, map[string][]string{"field": {"6"}}, "externalTag")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int(6), s.F)
|
assert.Equal(t, 6, s.F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMappingTime(t *testing.T) {
|
func TestMappingTime(t *testing.T) {
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -601,6 +602,10 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
|
|||||||
}
|
}
|
||||||
defer src.Close()
|
defer src.Close()
|
||||||
|
|
||||||
|
if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
out, err := os.Create(dst)
|
out, err := os.Create(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -12,6 +12,8 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -28,6 +30,9 @@ func (i interceptedWriter) WriteHeader(code int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestContextFormFileFailed17(t *testing.T) {
|
func TestContextFormFileFailed17(t *testing.T) {
|
||||||
|
if !isGo117OrGo118() {
|
||||||
|
return
|
||||||
|
}
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
mw := multipart.NewWriter(buf)
|
mw := multipart.NewWriter(buf)
|
||||||
defer func(mw *multipart.Writer) {
|
defer func(mw *multipart.Writer) {
|
||||||
@ -75,3 +80,15 @@ func TestInterceptedHeader(t *testing.T) {
|
|||||||
assert.Equal(t, "", w.Result().Header.Get("X-Test"))
|
assert.Equal(t, "", w.Result().Header.Get("X-Test"))
|
||||||
assert.Equal(t, "present", w.Result().Header.Get("X-Test-2"))
|
assert.Equal(t, "present", w.Result().Header.Get("X-Test-2"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isGo117OrGo118() bool {
|
||||||
|
version := strings.Split(runtime.Version()[2:], ".")
|
||||||
|
if len(version) >= 2 {
|
||||||
|
x := version[0]
|
||||||
|
y := version[1]
|
||||||
|
if x == "1" && (y == "17" || y == "18") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
31
context_1.19_test.go
Normal file
31
context_1.19_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2022 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go1.19
|
||||||
|
// +build go1.19
|
||||||
|
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContextFormFileFailed19(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
mw := multipart.NewWriter(buf)
|
||||||
|
mw.Close()
|
||||||
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", nil)
|
||||||
|
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
|
||||||
|
c.engine.MaxMultipartMemory = 8 << 20
|
||||||
|
f, err := c.FormFile("file")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, f)
|
||||||
|
}
|
4
debug.go
4
debug.go
@ -12,7 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ginSupportMinGoVer = 15
|
const ginSupportMinGoVer = 16
|
||||||
|
|
||||||
// IsDebugging returns true if the framework is running in debug mode.
|
// IsDebugging returns true if the framework is running in debug mode.
|
||||||
// Use SetMode(gin.ReleaseMode) to disable debug mode.
|
// Use SetMode(gin.ReleaseMode) to disable debug mode.
|
||||||
@ -67,7 +67,7 @@ func getMinVer(v string) (uint64, error) {
|
|||||||
|
|
||||||
func debugPrintWARNINGDefault() {
|
func debugPrintWARNINGDefault() {
|
||||||
if v, e := getMinVer(runtime.Version()); e == nil && v < ginSupportMinGoVer {
|
if v, e := getMinVer(runtime.Version()); e == nil && v < ginSupportMinGoVer {
|
||||||
debugPrint(`[WARNING] Now Gin requires Go 1.15+.
|
debugPrint(`[WARNING] Now Gin requires Go 1.16+.
|
||||||
|
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) {
|
|||||||
})
|
})
|
||||||
m, e := getMinVer(runtime.Version())
|
m, e := getMinVer(runtime.Version())
|
||||||
if e == nil && m < ginSupportMinGoVer {
|
if e == nil && m < ginSupportMinGoVer {
|
||||||
assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.15+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.16+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/pelletier/go-toml/v2 v2.0.2
|
github.com/pelletier/go-toml/v2 v2.0.2
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/ugorji/go/codec v1.2.7
|
github.com/ugorji/go/codec v1.2.7
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
golang.org/x/net v0.0.0-20221004154528-8021a29435af
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
3
go.sum
3
go.sum
@ -81,8 +81,9 @@ golang.org/x/arch v0.0.0-20220412001346-fc48f9fe4c15 h1:GVfVkciLYxn5mY5EncwAe0SX
|
|||||||
golang.org/x/arch v0.0.0-20220412001346-fc48f9fe4c15/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20220412001346-fc48f9fe4c15/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
|
||||||
|
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -173,7 +173,7 @@ func TestRenderAsciiJSON(t *testing.T) {
|
|||||||
assert.Equal(t, "application/json", w1.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json", w1.Header().Get("Content-Type"))
|
||||||
|
|
||||||
w2 := httptest.NewRecorder()
|
w2 := httptest.NewRecorder()
|
||||||
data2 := float64(3.1415926)
|
data2 := 3.1415926
|
||||||
|
|
||||||
err = (AsciiJSON{data2}).Render(w2)
|
err = (AsciiJSON{data2}).Render(w2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user