Merge branch 'master' into split-examples

This commit is contained in:
田欧 2019-02-22 18:21:41 +08:00 committed by GitHub
commit 94088fde55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 44 deletions

View File

@ -61,6 +61,10 @@ type FooStructForMapType struct {
MapFoo map[string]interface{} `form:"map_foo"`
}
type FooStructForIgnoreFormTag struct {
Foo *string `form:"-"`
}
type InvalidNameType struct {
TestName string `invalid_name:"test_name"`
}
@ -278,6 +282,12 @@ func TestBindingFormForTime2(t *testing.T) {
"", "")
}
func TestFormBindingIgnoreField(t *testing.T) {
testFormBindingIgnoreField(t, "POST",
"/", "/",
"-=bar", "")
}
func TestBindingFormInvalidName(t *testing.T) {
testFormBindingInvalidName(t, "POST",
"/", "/",
@ -860,6 +870,21 @@ func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, bod
assert.Error(t, err)
}
func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBody string) {
b := Form
assert.Equal(t, "form", b.Name())
obj := FooStructForIgnoreFormTag{}
req := requestWithBody(method, path, body)
if method == "POST" {
req.Header.Add("Content-Type", MIMEPOSTForm)
}
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Nil(t, obj.Foo)
}
func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBody string) {
b := Form
assert.Equal(t, "form", b.Name())

View File

@ -41,6 +41,9 @@ func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
defaultValue = defaultList[1]
}
}
if inputFieldName == "-" {
continue
}
if inputFieldName == "" {
inputFieldName = typeField.Name

1
gin.go
View File

@ -318,6 +318,7 @@ func (engine *Engine) RunUnix(file string) (err error) {
return
}
defer listener.Close()
os.Chmod(file, 0777)
err = http.Serve(listener, engine)
return
}

View File

@ -64,15 +64,62 @@ type LogFormatterParams struct {
ErrorMessage string
// IsTerm shows whether does gin's output descriptor refers to a terminal.
IsTerm bool
// BodySize is the size of the Response Body
BodySize int
}
// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal.
func (p *LogFormatterParams) StatusCodeColor() string {
code := p.StatusCode
switch {
case code >= http.StatusOK && code < http.StatusMultipleChoices:
return green
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
return white
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
return yellow
default:
return red
}
}
// MethodColor is the ANSI color for appropriately logging http method to a terminal.
func (p *LogFormatterParams) MethodColor() string {
method := p.Method
switch method {
case "GET":
return blue
case "POST":
return cyan
case "PUT":
return yellow
case "DELETE":
return red
case "PATCH":
return green
case "HEAD":
return magenta
case "OPTIONS":
return white
default:
return reset
}
}
// ResetColor resets all escape attributes.
func (p *LogFormatterParams) ResetColor() string {
return reset
}
// defaultLogFormatter is the default log format function Logger middleware uses.
var defaultLogFormatter = func(param LogFormatterParams) string {
var statusColor, methodColor, resetColor string
if param.IsTerm {
statusColor = colorForStatus(param.StatusCode)
methodColor = colorForMethod(param.Method)
resetColor = reset
statusColor = param.StatusCodeColor()
methodColor = param.MethodColor()
resetColor = param.ResetColor()
}
return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
@ -191,6 +238,8 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
param.StatusCode = c.Writer.Status()
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
param.BodySize = c.Writer.Size()
if raw != "" {
path = path + "?" + raw
}
@ -201,37 +250,3 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
}
}
}
func colorForStatus(code int) string {
switch {
case code >= http.StatusOK && code < http.StatusMultipleChoices:
return green
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
return white
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
return yellow
default:
return red
}
}
func colorForMethod(method string) string {
switch method {
case "GET":
return blue
case "POST":
return cyan
case "PUT":
return yellow
case "DELETE":
return red
case "PATCH":
return green
case "HEAD":
return magenta
case "OPTIONS":
return white
default:
return reset
}
}

View File

@ -257,6 +257,13 @@ func TestDefaultLogFormatter(t *testing.T) {
}
func TestColorForMethod(t *testing.T) {
colorForMethod := func(method string) string {
p := LogFormatterParams{
Method: method,
}
return p.MethodColor()
}
assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 52, 109}), colorForMethod("GET"), "get should be blue")
assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 54, 109}), colorForMethod("POST"), "post should be cyan")
assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForMethod("PUT"), "put should be yellow")
@ -268,12 +275,24 @@ func TestColorForMethod(t *testing.T) {
}
func TestColorForStatus(t *testing.T) {
colorForStatus := func(code int) string {
p := LogFormatterParams{
StatusCode: code,
}
return p.StatusCodeColor()
}
assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForStatus(http.StatusOK), "2xx should be green")
assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForStatus(http.StatusMovedPermanently), "3xx should be white")
assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForStatus(http.StatusNotFound), "4xx should be yellow")
assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForStatus(2), "other things should be red")
}
func TestResetColor(t *testing.T) {
p := LogFormatterParams{}
assert.Equal(t, string([]byte{27, 91, 48, 109}), p.ResetColor())
}
func TestErrorLogger(t *testing.T) {
router := New()
router.Use(ErrorLogger())

View File

@ -11,8 +11,8 @@ import (
"github.com/gin-gonic/gin/binding"
)
// ENV_GIN_MODE indicates environment name for gin mode.
const ENV_GIN_MODE = "GIN_MODE"
// EnvGinMode indicates environment name for gin mode.
const EnvGinMode = "GIN_MODE"
const (
// DebugMode indicates gin mode is debug.
@ -44,7 +44,7 @@ var ginMode = debugCode
var modeName = DebugMode
func init() {
mode := os.Getenv(ENV_GIN_MODE)
mode := os.Getenv(EnvGinMode)
SetMode(mode)
}

View File

@ -13,13 +13,13 @@ import (
)
func init() {
os.Setenv(ENV_GIN_MODE, TestMode)
os.Setenv(EnvGinMode, TestMode)
}
func TestSetMode(t *testing.T) {
assert.Equal(t, testCode, ginMode)
assert.Equal(t, TestMode, Mode())
os.Unsetenv(ENV_GIN_MODE)
os.Unsetenv(EnvGinMode)
SetMode("")
assert.Equal(t, debugCode, ginMode)

View File

@ -36,8 +36,8 @@ func (r Reader) WriteContentType(w http.ResponseWriter) {
func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) {
header := w.Header()
for k, v := range headers {
if val := header[k]; len(val) == 0 {
header[k] = []string{v}
if header.Get(k) == "" {
header.Set(k, v)
}
}
}

View File

@ -470,6 +470,7 @@ func TestRenderReader(t *testing.T) {
body := "#!PNG some raw data"
headers := make(map[string]string)
headers["Content-Disposition"] = `attachment; filename="filename.png"`
headers["x-request-id"] = "requestId"
err := (Reader{
ContentLength: int64(len(body)),
@ -483,4 +484,5 @@ func TestRenderReader(t *testing.T) {
assert.Equal(t, "image/png", w.Header().Get("Content-Type"))
assert.Equal(t, strconv.Itoa(len(body)), w.Header().Get("Content-Length"))
assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition"))
assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id"))
}