Merge e00b80a59113c05796b61b73a4a5fd923b3a52d4 into db9174ae0c2587fe1c755def0f88cb9aba9e9641

This commit is contained in:
unlikezy 2019-11-01 17:34:16 +08:00 committed by GitHub
commit 352bd0ea49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 36 deletions

View File

@ -5,6 +5,7 @@
package gin
import (
"context"
"errors"
"fmt"
"io"
@ -15,6 +16,7 @@ import (
"net/http"
"net/url"
"os"
"reflect"
"strings"
"time"
@ -41,6 +43,7 @@ const abortIndex int8 = math.MaxInt8 / 2
// Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example.
type Context struct {
context.Context //point to parent
writermem responseWriter
Request *http.Request
Writer ResponseWriter
@ -86,6 +89,37 @@ func (c *Context) reset() {
c.formCache = nil
}
type gin_context string
const gin_context_key gin_context = "gin_real_context"
// GinContext try to Get gin.Context from context.Context
func GinContext(ctx context.Context) (*Context, error) {
v := ctx.Value(gin_context_key)
if gc, ok := v.(*Context); ok {
return gc, nil
} else {
return nil, fmt.Errorf("GinContext fail,TypeOf(v):%s", reflect.TypeOf(v))
}
}
// MustGinContext try to gin.Context from context.Context
// Will panic if fail
func MustGinContext(ctx context.Context) *Context {
if gc, err := GinContext(ctx); err == nil {
return gc
} else {
panic(fmt.Sprintf("MustGinContext fail:%s", err))
}
}
// NewContext wrap gin.Context with context.Context
func NewContext(e *Engine) *Context {
c := &Context{engine: e}
c.Context = context.WithValue(context.Background(), gin_context_key, c) //With a value point to gin.Context
return c
}
// Copy returns a copy of the current context that can be safely used outside the request's scope.
// This has to be used when the context has to be passed to a goroutine.
func (c *Context) Copy() *Context {
@ -1028,34 +1062,6 @@ func (c *Context) SetAccepted(formats ...string) {
c.Accepted = formats
}
/************************************/
/***** GOLANG.ORG/X/NET/CONTEXT *****/
/************************************/
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
func (c *Context) Deadline() (deadline time.Time, ok bool) {
return
}
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
func (c *Context) Done() <-chan struct{} {
return nil
}
// Err returns a non-nil error value after Done is closed,
// successive calls to Err return the same error.
// If Done is not yet closed, Err returns nil.
// If Done is closed, Err returns a non-nil error explaining why:
// Canceled if the context was canceled
// or DeadlineExceeded if the context's deadline passed.
func (c *Context) Err() error {
return nil
}
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
@ -1064,8 +1070,10 @@ func (c *Context) Value(key interface{}) interface{} {
return c.Request
}
if keyAsString, ok := key.(string); ok {
val, _ := c.Get(keyAsString)
val, ok := c.Get(keyAsString)
if ok {
return val
}
return nil
}
return c.Context.Value(key)
}

View File

@ -1868,6 +1868,42 @@ func TestContextResetInHandler(t *testing.T) {
})
}
func UserFunc2Mock(ctx context.Context, t *testing.T) {
v, ok := ctx.Value("user_self_defined_value").(string)
assert.Equal(t, true, ok)
assert.Equal(t, "vvvvv", v)
assert.NotPanics(t, func() {
gc := MustGinContext(ctx) //get gin.Context back as need
assert.NotEqual(t, gc, nil)
})
}
func UserFunc3Mock(ctx context.Context, t *testing.T) {
assert.Panics(t, func() {
gc := MustGinContext(ctx) //get gin.Context back as need
assert.Equal(t, gc, nil)
})
}
func UserFunc1Mock(ctx context.Context, t *testing.T) {
//add user defined value
ctx = context.WithValue(ctx, "user_self_defined_value", "vvvvv")
//do user's business
UserFunc2Mock(ctx, t)
}
func TestNewContextMustGin(t *testing.T) {
ctx := NewContext(nil)
UserFunc1Mock(ctx, t) //use gin.Context as standard context
}
func TestStandardContext(t *testing.T) {
ctx := context.Background()
UserFunc3Mock(ctx, t)
}
func TestRaceParamsContextCopy(t *testing.T) {
DefaultWriter = os.Stdout
router := Default()

2
gin.go
View File

@ -156,7 +156,7 @@ func Default() *Engine {
}
func (engine *Engine) allocateContext() *Context {
return &Context{engine: engine}
return NewContext(engine)
}
// Delims sets template left and right delims and returns a Engine instance.

4
go.mod
View File

@ -3,6 +3,7 @@ module github.com/gin-gonic/gin
go 1.12
require (
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3
github.com/gin-contrib/sse v0.1.0
github.com/go-playground/locales v0.12.1 // indirect
github.com/go-playground/universal-translator v0.16.0 // indirect
@ -12,6 +13,9 @@ require (
github.com/mattn/go-isatty v0.0.9
github.com/stretchr/testify v1.4.0
github.com/ugorji/go/codec v1.1.7
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gopkg.in/go-playground/validator.v9 v9.29.1
gopkg.in/yaml.v2 v2.2.2