github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/context_test.go (about) 1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 // Use of this source code is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package gin 6 7 import ( 8 "bytes" 9 "context" 10 "errors" 11 "fmt" 12 "github.com/hellobchain/newcryptosm/http" 13 "github.com/hellobchain/newcryptosm/http/httptest" 14 "html/template" 15 "io" 16 "mime/multipart" 17 "os" 18 "reflect" 19 "strings" 20 "sync" 21 "testing" 22 "time" 23 24 "github.com/golang/protobuf/proto" 25 "github.com/hellobchain/third_party/gin/binding" 26 "github.com/hellobchain/third_party/sse" 27 "github.com/stretchr/testify/assert" 28 29 testdata "github.com/hellobchain/third_party/gin/testdata/protoexample" 30 ) 31 32 var _ context.Context = &Context{} 33 34 // Unit tests TODO 35 // func (c *Context) File(filepath string) { 36 // func (c *Context) Negotiate(code int, config Negotiate) { 37 // BAD case: func (c *Context) Render(code int, render render.Render, obj ...interface{}) { 38 // test that information is not leaked when reusing Contexts (using the Pool) 39 40 func createMultipartRequest() *http.Request { 41 boundary := "--testboundary" 42 body := new(bytes.Buffer) 43 mw := multipart.NewWriter(body) 44 defer mw.Close() 45 46 must(mw.SetBoundary(boundary)) 47 must(mw.WriteField("foo", "bar")) 48 must(mw.WriteField("bar", "10")) 49 must(mw.WriteField("bar", "foo2")) 50 must(mw.WriteField("array", "first")) 51 must(mw.WriteField("array", "second")) 52 must(mw.WriteField("id", "")) 53 must(mw.WriteField("time_local", "31/12/2016 14:55")) 54 must(mw.WriteField("time_utc", "31/12/2016 14:55")) 55 must(mw.WriteField("time_location", "31/12/2016 14:55")) 56 must(mw.WriteField("names[a]", "thinkerou")) 57 must(mw.WriteField("names[b]", "tianou")) 58 req, err := http.NewRequest("POST", "/", body) 59 must(err) 60 req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary) 61 return req 62 } 63 64 func must(err error) { 65 if err != nil { 66 panic(err.Error()) 67 } 68 } 69 70 func TestContextFormFile(t *testing.T) { 71 buf := new(bytes.Buffer) 72 mw := multipart.NewWriter(buf) 73 w, err := mw.CreateFormFile("file", "test") 74 if assert.NoError(t, err) { 75 _, err = w.Write([]byte("test")) 76 assert.NoError(t, err) 77 } 78 mw.Close() 79 c, _ := CreateTestContext(httptest.NewRecorder()) 80 c.Request, _ = http.NewRequest("POST", "/", buf) 81 c.Request.Header.Set("Content-Type", mw.FormDataContentType()) 82 f, err := c.FormFile("file") 83 if assert.NoError(t, err) { 84 assert.Equal(t, "test", f.Filename) 85 } 86 87 assert.NoError(t, c.SaveUploadedFile(f, "test")) 88 } 89 90 func TestContextFormFileFailed(t *testing.T) { 91 buf := new(bytes.Buffer) 92 mw := multipart.NewWriter(buf) 93 mw.Close() 94 c, _ := CreateTestContext(httptest.NewRecorder()) 95 c.Request, _ = http.NewRequest("POST", "/", nil) 96 c.Request.Header.Set("Content-Type", mw.FormDataContentType()) 97 c.engine.MaxMultipartMemory = 8 << 20 98 f, err := c.FormFile("file") 99 assert.Error(t, err) 100 assert.Nil(t, f) 101 } 102 103 func TestContextMultipartForm(t *testing.T) { 104 buf := new(bytes.Buffer) 105 mw := multipart.NewWriter(buf) 106 assert.NoError(t, mw.WriteField("foo", "bar")) 107 w, err := mw.CreateFormFile("file", "test") 108 if assert.NoError(t, err) { 109 _, err = w.Write([]byte("test")) 110 assert.NoError(t, err) 111 } 112 mw.Close() 113 c, _ := CreateTestContext(httptest.NewRecorder()) 114 c.Request, _ = http.NewRequest("POST", "/", buf) 115 c.Request.Header.Set("Content-Type", mw.FormDataContentType()) 116 f, err := c.MultipartForm() 117 if assert.NoError(t, err) { 118 assert.NotNil(t, f) 119 } 120 121 assert.NoError(t, c.SaveUploadedFile(f.File["file"][0], "test")) 122 } 123 124 func TestSaveUploadedOpenFailed(t *testing.T) { 125 buf := new(bytes.Buffer) 126 mw := multipart.NewWriter(buf) 127 mw.Close() 128 129 c, _ := CreateTestContext(httptest.NewRecorder()) 130 c.Request, _ = http.NewRequest("POST", "/", buf) 131 c.Request.Header.Set("Content-Type", mw.FormDataContentType()) 132 133 f := &multipart.FileHeader{ 134 Filename: "file", 135 } 136 assert.Error(t, c.SaveUploadedFile(f, "test")) 137 } 138 139 func TestSaveUploadedCreateFailed(t *testing.T) { 140 buf := new(bytes.Buffer) 141 mw := multipart.NewWriter(buf) 142 w, err := mw.CreateFormFile("file", "test") 143 if assert.NoError(t, err) { 144 _, err = w.Write([]byte("test")) 145 assert.NoError(t, err) 146 } 147 mw.Close() 148 c, _ := CreateTestContext(httptest.NewRecorder()) 149 c.Request, _ = http.NewRequest("POST", "/", buf) 150 c.Request.Header.Set("Content-Type", mw.FormDataContentType()) 151 f, err := c.FormFile("file") 152 if assert.NoError(t, err) { 153 assert.Equal(t, "test", f.Filename) 154 } 155 156 assert.Error(t, c.SaveUploadedFile(f, "/")) 157 } 158 159 func TestContextReset(t *testing.T) { 160 router := New() 161 c := router.allocateContext() 162 assert.Equal(t, c.engine, router) 163 164 c.index = 2 165 c.Writer = &responseWriter{ResponseWriter: httptest.NewRecorder()} 166 c.Params = Params{Param{}} 167 c.Error(errors.New("test")) // nolint: errcheck 168 c.Set("foo", "bar") 169 c.reset() 170 171 assert.False(t, c.IsAborted()) 172 assert.Nil(t, c.Keys) 173 assert.Nil(t, c.Accepted) 174 assert.Len(t, c.Errors, 0) 175 assert.Empty(t, c.Errors.Errors()) 176 assert.Empty(t, c.Errors.ByType(ErrorTypeAny)) 177 assert.Len(t, c.Params, 0) 178 assert.EqualValues(t, c.index, -1) 179 assert.Equal(t, c.Writer.(*responseWriter), &c.writermem) 180 } 181 182 func TestContextHandlers(t *testing.T) { 183 c, _ := CreateTestContext(httptest.NewRecorder()) 184 assert.Nil(t, c.handlers) 185 assert.Nil(t, c.handlers.Last()) 186 187 c.handlers = HandlersChain{} 188 assert.NotNil(t, c.handlers) 189 assert.Nil(t, c.handlers.Last()) 190 191 f := func(c *Context) {} 192 g := func(c *Context) {} 193 194 c.handlers = HandlersChain{f} 195 compareFunc(t, f, c.handlers.Last()) 196 197 c.handlers = HandlersChain{f, g} 198 compareFunc(t, g, c.handlers.Last()) 199 } 200 201 // TestContextSetGet tests that a parameter is set correctly on the 202 // current context and can be retrieved using Get. 203 func TestContextSetGet(t *testing.T) { 204 c, _ := CreateTestContext(httptest.NewRecorder()) 205 c.Set("foo", "bar") 206 207 value, err := c.Get("foo") 208 assert.Equal(t, "bar", value) 209 assert.True(t, err) 210 211 value, err = c.Get("foo2") 212 assert.Nil(t, value) 213 assert.False(t, err) 214 215 assert.Equal(t, "bar", c.MustGet("foo")) 216 assert.Panics(t, func() { c.MustGet("no_exist") }) 217 } 218 219 func TestContextSetGetValues(t *testing.T) { 220 c, _ := CreateTestContext(httptest.NewRecorder()) 221 c.Set("string", "this is a string") 222 c.Set("int32", int32(-42)) 223 c.Set("int64", int64(42424242424242)) 224 c.Set("uint64", uint64(42)) 225 c.Set("float32", float32(4.2)) 226 c.Set("float64", 4.2) 227 var a interface{} = 1 228 c.Set("intInterface", a) 229 230 assert.Exactly(t, c.MustGet("string").(string), "this is a string") 231 assert.Exactly(t, c.MustGet("int32").(int32), int32(-42)) 232 assert.Exactly(t, c.MustGet("int64").(int64), int64(42424242424242)) 233 assert.Exactly(t, c.MustGet("uint64").(uint64), uint64(42)) 234 assert.Exactly(t, c.MustGet("float32").(float32), float32(4.2)) 235 assert.Exactly(t, c.MustGet("float64").(float64), 4.2) 236 assert.Exactly(t, c.MustGet("intInterface").(int), 1) 237 238 } 239 240 func TestContextGetString(t *testing.T) { 241 c, _ := CreateTestContext(httptest.NewRecorder()) 242 c.Set("string", "this is a string") 243 assert.Equal(t, "this is a string", c.GetString("string")) 244 } 245 246 func TestContextSetGetBool(t *testing.T) { 247 c, _ := CreateTestContext(httptest.NewRecorder()) 248 c.Set("bool", true) 249 assert.True(t, c.GetBool("bool")) 250 } 251 252 func TestContextGetInt(t *testing.T) { 253 c, _ := CreateTestContext(httptest.NewRecorder()) 254 c.Set("int", 1) 255 assert.Equal(t, 1, c.GetInt("int")) 256 } 257 258 func TestContextGetInt64(t *testing.T) { 259 c, _ := CreateTestContext(httptest.NewRecorder()) 260 c.Set("int64", int64(42424242424242)) 261 assert.Equal(t, int64(42424242424242), c.GetInt64("int64")) 262 } 263 264 func TestContextGetUint(t *testing.T) { 265 c, _ := CreateTestContext(httptest.NewRecorder()) 266 c.Set("uint", uint(1)) 267 assert.Equal(t, uint(1), c.GetUint("uint")) 268 } 269 270 func TestContextGetUint64(t *testing.T) { 271 c, _ := CreateTestContext(httptest.NewRecorder()) 272 c.Set("uint64", uint64(18446744073709551615)) 273 assert.Equal(t, uint64(18446744073709551615), c.GetUint64("uint64")) 274 } 275 276 func TestContextGetFloat64(t *testing.T) { 277 c, _ := CreateTestContext(httptest.NewRecorder()) 278 c.Set("float64", 4.2) 279 assert.Equal(t, 4.2, c.GetFloat64("float64")) 280 } 281 282 func TestContextGetTime(t *testing.T) { 283 c, _ := CreateTestContext(httptest.NewRecorder()) 284 t1, _ := time.Parse("1/2/2006 15:04:05", "01/01/2017 12:00:00") 285 c.Set("time", t1) 286 assert.Equal(t, t1, c.GetTime("time")) 287 } 288 289 func TestContextGetDuration(t *testing.T) { 290 c, _ := CreateTestContext(httptest.NewRecorder()) 291 c.Set("duration", time.Second) 292 assert.Equal(t, time.Second, c.GetDuration("duration")) 293 } 294 295 func TestContextGetStringSlice(t *testing.T) { 296 c, _ := CreateTestContext(httptest.NewRecorder()) 297 c.Set("slice", []string{"foo"}) 298 assert.Equal(t, []string{"foo"}, c.GetStringSlice("slice")) 299 } 300 301 func TestContextGetStringMap(t *testing.T) { 302 c, _ := CreateTestContext(httptest.NewRecorder()) 303 var m = make(map[string]interface{}) 304 m["foo"] = 1 305 c.Set("map", m) 306 307 assert.Equal(t, m, c.GetStringMap("map")) 308 assert.Equal(t, 1, c.GetStringMap("map")["foo"]) 309 } 310 311 func TestContextGetStringMapString(t *testing.T) { 312 c, _ := CreateTestContext(httptest.NewRecorder()) 313 var m = make(map[string]string) 314 m["foo"] = "bar" 315 c.Set("map", m) 316 317 assert.Equal(t, m, c.GetStringMapString("map")) 318 assert.Equal(t, "bar", c.GetStringMapString("map")["foo"]) 319 } 320 321 func TestContextGetStringMapStringSlice(t *testing.T) { 322 c, _ := CreateTestContext(httptest.NewRecorder()) 323 var m = make(map[string][]string) 324 m["foo"] = []string{"foo"} 325 c.Set("map", m) 326 327 assert.Equal(t, m, c.GetStringMapStringSlice("map")) 328 assert.Equal(t, []string{"foo"}, c.GetStringMapStringSlice("map")["foo"]) 329 } 330 331 func TestContextCopy(t *testing.T) { 332 c, _ := CreateTestContext(httptest.NewRecorder()) 333 c.index = 2 334 c.Request, _ = http.NewRequest("POST", "/hola", nil) 335 c.handlers = HandlersChain{func(c *Context) {}} 336 c.Params = Params{Param{Key: "foo", Value: "bar"}} 337 c.Set("foo", "bar") 338 339 cp := c.Copy() 340 assert.Nil(t, cp.handlers) 341 assert.Nil(t, cp.writermem.ResponseWriter) 342 assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter)) 343 assert.Equal(t, cp.Request, c.Request) 344 assert.Equal(t, cp.index, abortIndex) 345 assert.Equal(t, cp.Keys, c.Keys) 346 assert.Equal(t, cp.engine, c.engine) 347 assert.Equal(t, cp.Params, c.Params) 348 cp.Set("foo", "notBar") 349 assert.False(t, cp.Keys["foo"] == c.Keys["foo"]) 350 } 351 352 func TestContextHandlerName(t *testing.T) { 353 c, _ := CreateTestContext(httptest.NewRecorder()) 354 c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest} 355 356 assert.Regexp(t, "^(.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest$", c.HandlerName()) 357 } 358 359 func TestContextHandlerNames(t *testing.T) { 360 c, _ := CreateTestContext(httptest.NewRecorder()) 361 c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest, func(c *Context) {}, handlerNameTest2} 362 363 names := c.HandlerNames() 364 365 assert.True(t, len(names) == 4) 366 for _, name := range names { 367 assert.Regexp(t, `^(.*/vendor/)?(github\.com/gin-gonic/gin\.){1}(TestContextHandlerNames\.func.*){0,1}(handlerNameTest.*){0,1}`, name) 368 } 369 } 370 371 func handlerNameTest(c *Context) { 372 373 } 374 375 func handlerNameTest2(c *Context) { 376 377 } 378 379 var handlerTest HandlerFunc = func(c *Context) { 380 381 } 382 383 func TestContextHandler(t *testing.T) { 384 c, _ := CreateTestContext(httptest.NewRecorder()) 385 c.handlers = HandlersChain{func(c *Context) {}, handlerTest} 386 387 assert.Equal(t, reflect.ValueOf(handlerTest).Pointer(), reflect.ValueOf(c.Handler()).Pointer()) 388 } 389 390 func TestContextQuery(t *testing.T) { 391 c, _ := CreateTestContext(httptest.NewRecorder()) 392 c.Request, _ = http.NewRequest("GET", "http://example.com/?foo=bar&page=10&id=", nil) 393 394 value, ok := c.GetQuery("foo") 395 assert.True(t, ok) 396 assert.Equal(t, "bar", value) 397 assert.Equal(t, "bar", c.DefaultQuery("foo", "none")) 398 assert.Equal(t, "bar", c.Query("foo")) 399 400 value, ok = c.GetQuery("page") 401 assert.True(t, ok) 402 assert.Equal(t, "10", value) 403 assert.Equal(t, "10", c.DefaultQuery("page", "0")) 404 assert.Equal(t, "10", c.Query("page")) 405 406 value, ok = c.GetQuery("id") 407 assert.True(t, ok) 408 assert.Empty(t, value) 409 assert.Empty(t, c.DefaultQuery("id", "nada")) 410 assert.Empty(t, c.Query("id")) 411 412 value, ok = c.GetQuery("NoKey") 413 assert.False(t, ok) 414 assert.Empty(t, value) 415 assert.Equal(t, "nada", c.DefaultQuery("NoKey", "nada")) 416 assert.Empty(t, c.Query("NoKey")) 417 418 // postform should not mess 419 value, ok = c.GetPostForm("page") 420 assert.False(t, ok) 421 assert.Empty(t, value) 422 assert.Empty(t, c.PostForm("foo")) 423 } 424 425 func TestContextDefaultQueryOnEmptyRequest(t *testing.T) { 426 c, _ := CreateTestContext(httptest.NewRecorder()) // here c.Request == nil 427 assert.NotPanics(t, func() { 428 value, ok := c.GetQuery("NoKey") 429 assert.False(t, ok) 430 assert.Empty(t, value) 431 }) 432 assert.NotPanics(t, func() { 433 assert.Equal(t, "nada", c.DefaultQuery("NoKey", "nada")) 434 }) 435 assert.NotPanics(t, func() { 436 assert.Empty(t, c.Query("NoKey")) 437 }) 438 } 439 440 func TestContextQueryAndPostForm(t *testing.T) { 441 c, _ := CreateTestContext(httptest.NewRecorder()) 442 body := bytes.NewBufferString("foo=bar&page=11&both=&foo=second") 443 c.Request, _ = http.NewRequest("POST", 444 "/?both=GET&id=main&id=omit&array[]=first&array[]=second&ids[a]=hi&ids[b]=3.14", body) 445 c.Request.Header.Add("Content-Type", MIMEPOSTForm) 446 447 assert.Equal(t, "bar", c.DefaultPostForm("foo", "none")) 448 assert.Equal(t, "bar", c.PostForm("foo")) 449 assert.Empty(t, c.Query("foo")) 450 451 value, ok := c.GetPostForm("page") 452 assert.True(t, ok) 453 assert.Equal(t, "11", value) 454 assert.Equal(t, "11", c.DefaultPostForm("page", "0")) 455 assert.Equal(t, "11", c.PostForm("page")) 456 assert.Empty(t, c.Query("page")) 457 458 value, ok = c.GetPostForm("both") 459 assert.True(t, ok) 460 assert.Empty(t, value) 461 assert.Empty(t, c.PostForm("both")) 462 assert.Empty(t, c.DefaultPostForm("both", "nothing")) 463 assert.Equal(t, "GET", c.Query("both"), "GET") 464 465 value, ok = c.GetQuery("id") 466 assert.True(t, ok) 467 assert.Equal(t, "main", value) 468 assert.Equal(t, "000", c.DefaultPostForm("id", "000")) 469 assert.Equal(t, "main", c.Query("id")) 470 assert.Empty(t, c.PostForm("id")) 471 472 value, ok = c.GetQuery("NoKey") 473 assert.False(t, ok) 474 assert.Empty(t, value) 475 value, ok = c.GetPostForm("NoKey") 476 assert.False(t, ok) 477 assert.Empty(t, value) 478 assert.Equal(t, "nada", c.DefaultPostForm("NoKey", "nada")) 479 assert.Equal(t, "nothing", c.DefaultQuery("NoKey", "nothing")) 480 assert.Empty(t, c.PostForm("NoKey")) 481 assert.Empty(t, c.Query("NoKey")) 482 483 var obj struct { 484 Foo string `form:"foo"` 485 ID string `form:"id"` 486 Page int `form:"page"` 487 Both string `form:"both"` 488 Array []string `form:"array[]"` 489 } 490 assert.NoError(t, c.Bind(&obj)) 491 assert.Equal(t, "bar", obj.Foo, "bar") 492 assert.Equal(t, "main", obj.ID, "main") 493 assert.Equal(t, 11, obj.Page, 11) 494 assert.Empty(t, obj.Both) 495 assert.Equal(t, []string{"first", "second"}, obj.Array) 496 497 values, ok := c.GetQueryArray("array[]") 498 assert.True(t, ok) 499 assert.Equal(t, "first", values[0]) 500 assert.Equal(t, "second", values[1]) 501 502 values = c.QueryArray("array[]") 503 assert.Equal(t, "first", values[0]) 504 assert.Equal(t, "second", values[1]) 505 506 values = c.QueryArray("nokey") 507 assert.Equal(t, 0, len(values)) 508 509 values = c.QueryArray("both") 510 assert.Equal(t, 1, len(values)) 511 assert.Equal(t, "GET", values[0]) 512 513 dicts, ok := c.GetQueryMap("ids") 514 assert.True(t, ok) 515 assert.Equal(t, "hi", dicts["a"]) 516 assert.Equal(t, "3.14", dicts["b"]) 517 518 dicts, ok = c.GetQueryMap("nokey") 519 assert.False(t, ok) 520 assert.Equal(t, 0, len(dicts)) 521 522 dicts, ok = c.GetQueryMap("both") 523 assert.False(t, ok) 524 assert.Equal(t, 0, len(dicts)) 525 526 dicts, ok = c.GetQueryMap("array") 527 assert.False(t, ok) 528 assert.Equal(t, 0, len(dicts)) 529 530 dicts = c.QueryMap("ids") 531 assert.Equal(t, "hi", dicts["a"]) 532 assert.Equal(t, "3.14", dicts["b"]) 533 534 dicts = c.QueryMap("nokey") 535 assert.Equal(t, 0, len(dicts)) 536 } 537 538 func TestContextPostFormMultipart(t *testing.T) { 539 c, _ := CreateTestContext(httptest.NewRecorder()) 540 c.Request = createMultipartRequest() 541 542 var obj struct { 543 Foo string `form:"foo"` 544 Bar string `form:"bar"` 545 BarAsInt int `form:"bar"` 546 Array []string `form:"array"` 547 ID string `form:"id"` 548 TimeLocal time.Time `form:"time_local" time_format:"02/01/2006 15:04"` 549 TimeUTC time.Time `form:"time_utc" time_format:"02/01/2006 15:04" time_utc:"1"` 550 TimeLocation time.Time `form:"time_location" time_format:"02/01/2006 15:04" time_location:"Asia/Tokyo"` 551 BlankTime time.Time `form:"blank_time" time_format:"02/01/2006 15:04"` 552 } 553 assert.NoError(t, c.Bind(&obj)) 554 assert.Equal(t, "bar", obj.Foo) 555 assert.Equal(t, "10", obj.Bar) 556 assert.Equal(t, 10, obj.BarAsInt) 557 assert.Equal(t, []string{"first", "second"}, obj.Array) 558 assert.Empty(t, obj.ID) 559 assert.Equal(t, "31/12/2016 14:55", obj.TimeLocal.Format("02/01/2006 15:04")) 560 assert.Equal(t, time.Local, obj.TimeLocal.Location()) 561 assert.Equal(t, "31/12/2016 14:55", obj.TimeUTC.Format("02/01/2006 15:04")) 562 assert.Equal(t, time.UTC, obj.TimeUTC.Location()) 563 loc, _ := time.LoadLocation("Asia/Tokyo") 564 assert.Equal(t, "31/12/2016 14:55", obj.TimeLocation.Format("02/01/2006 15:04")) 565 assert.Equal(t, loc, obj.TimeLocation.Location()) 566 assert.True(t, obj.BlankTime.IsZero()) 567 568 value, ok := c.GetQuery("foo") 569 assert.False(t, ok) 570 assert.Empty(t, value) 571 assert.Empty(t, c.Query("bar")) 572 assert.Equal(t, "nothing", c.DefaultQuery("id", "nothing")) 573 574 value, ok = c.GetPostForm("foo") 575 assert.True(t, ok) 576 assert.Equal(t, "bar", value) 577 assert.Equal(t, "bar", c.PostForm("foo")) 578 579 value, ok = c.GetPostForm("array") 580 assert.True(t, ok) 581 assert.Equal(t, "first", value) 582 assert.Equal(t, "first", c.PostForm("array")) 583 584 assert.Equal(t, "10", c.DefaultPostForm("bar", "nothing")) 585 586 value, ok = c.GetPostForm("id") 587 assert.True(t, ok) 588 assert.Empty(t, value) 589 assert.Empty(t, c.PostForm("id")) 590 assert.Empty(t, c.DefaultPostForm("id", "nothing")) 591 592 value, ok = c.GetPostForm("nokey") 593 assert.False(t, ok) 594 assert.Empty(t, value) 595 assert.Equal(t, "nothing", c.DefaultPostForm("nokey", "nothing")) 596 597 values, ok := c.GetPostFormArray("array") 598 assert.True(t, ok) 599 assert.Equal(t, "first", values[0]) 600 assert.Equal(t, "second", values[1]) 601 602 values = c.PostFormArray("array") 603 assert.Equal(t, "first", values[0]) 604 assert.Equal(t, "second", values[1]) 605 606 values = c.PostFormArray("nokey") 607 assert.Equal(t, 0, len(values)) 608 609 values = c.PostFormArray("foo") 610 assert.Equal(t, 1, len(values)) 611 assert.Equal(t, "bar", values[0]) 612 613 dicts, ok := c.GetPostFormMap("names") 614 assert.True(t, ok) 615 assert.Equal(t, "thinkerou", dicts["a"]) 616 assert.Equal(t, "tianou", dicts["b"]) 617 618 dicts, ok = c.GetPostFormMap("nokey") 619 assert.False(t, ok) 620 assert.Equal(t, 0, len(dicts)) 621 622 dicts = c.PostFormMap("names") 623 assert.Equal(t, "thinkerou", dicts["a"]) 624 assert.Equal(t, "tianou", dicts["b"]) 625 626 dicts = c.PostFormMap("nokey") 627 assert.Equal(t, 0, len(dicts)) 628 } 629 630 func TestContextSetCookie(t *testing.T) { 631 c, _ := CreateTestContext(httptest.NewRecorder()) 632 c.SetSameSite(http.SameSiteLaxMode) 633 c.SetCookie("user", "gin", 1, "/", "localhost", true, true) 634 assert.Equal(t, "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", c.Writer.Header().Get("Set-Cookie")) 635 } 636 637 func TestContextSetCookiePathEmpty(t *testing.T) { 638 c, _ := CreateTestContext(httptest.NewRecorder()) 639 c.SetSameSite(http.SameSiteLaxMode) 640 c.SetCookie("user", "gin", 1, "", "localhost", true, true) 641 assert.Equal(t, "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", c.Writer.Header().Get("Set-Cookie")) 642 } 643 644 func TestContextGetCookie(t *testing.T) { 645 c, _ := CreateTestContext(httptest.NewRecorder()) 646 c.Request, _ = http.NewRequest("GET", "/get", nil) 647 c.Request.Header.Set("Cookie", "user=gin") 648 cookie, _ := c.Cookie("user") 649 assert.Equal(t, "gin", cookie) 650 651 _, err := c.Cookie("nokey") 652 assert.Error(t, err) 653 } 654 655 func TestContextBodyAllowedForStatus(t *testing.T) { 656 assert.False(t, false, bodyAllowedForStatus(http.StatusProcessing)) 657 assert.False(t, false, bodyAllowedForStatus(http.StatusNoContent)) 658 assert.False(t, false, bodyAllowedForStatus(http.StatusNotModified)) 659 assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError)) 660 } 661 662 type TestPanicRender struct { 663 } 664 665 func (*TestPanicRender) Render(http.ResponseWriter) error { 666 return errors.New("TestPanicRender") 667 } 668 669 func (*TestPanicRender) WriteContentType(http.ResponseWriter) {} 670 671 func TestContextRenderPanicIfErr(t *testing.T) { 672 defer func() { 673 r := recover() 674 assert.Equal(t, "TestPanicRender", fmt.Sprint(r)) 675 }() 676 w := httptest.NewRecorder() 677 c, _ := CreateTestContext(w) 678 679 c.Render(http.StatusOK, &TestPanicRender{}) 680 681 assert.Fail(t, "Panic not detected") 682 } 683 684 // Tests that the response is serialized as JSON 685 // and Content-Type is set to application/json 686 // and special HTML characters are escaped 687 func TestContextRenderJSON(t *testing.T) { 688 w := httptest.NewRecorder() 689 c, _ := CreateTestContext(w) 690 691 c.JSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"}) 692 693 assert.Equal(t, http.StatusCreated, w.Code) 694 assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) 695 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 696 } 697 698 // Tests that the response is serialized as JSONP 699 // and Content-Type is set to application/javascript 700 func TestContextRenderJSONP(t *testing.T) { 701 w := httptest.NewRecorder() 702 c, _ := CreateTestContext(w) 703 c.Request, _ = http.NewRequest("GET", "http://example.com/?callback=x", nil) 704 705 c.JSONP(http.StatusCreated, H{"foo": "bar"}) 706 707 assert.Equal(t, http.StatusCreated, w.Code) 708 assert.Equal(t, "x({\"foo\":\"bar\"});", w.Body.String()) 709 assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) 710 } 711 712 // Tests that the response is serialized as JSONP 713 // and Content-Type is set to application/json 714 func TestContextRenderJSONPWithoutCallback(t *testing.T) { 715 w := httptest.NewRecorder() 716 c, _ := CreateTestContext(w) 717 c.Request, _ = http.NewRequest("GET", "http://example.com", nil) 718 719 c.JSONP(http.StatusCreated, H{"foo": "bar"}) 720 721 assert.Equal(t, http.StatusCreated, w.Code) 722 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) 723 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 724 } 725 726 // Tests that no JSON is rendered if code is 204 727 func TestContextRenderNoContentJSON(t *testing.T) { 728 w := httptest.NewRecorder() 729 c, _ := CreateTestContext(w) 730 731 c.JSON(http.StatusNoContent, H{"foo": "bar"}) 732 733 assert.Equal(t, http.StatusNoContent, w.Code) 734 assert.Empty(t, w.Body.String()) 735 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 736 } 737 738 // Tests that the response is serialized as JSON 739 // we change the content-type before 740 func TestContextRenderAPIJSON(t *testing.T) { 741 w := httptest.NewRecorder() 742 c, _ := CreateTestContext(w) 743 744 c.Header("Content-Type", "application/vnd.api+json") 745 c.JSON(http.StatusCreated, H{"foo": "bar"}) 746 747 assert.Equal(t, http.StatusCreated, w.Code) 748 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) 749 assert.Equal(t, "application/vnd.api+json", w.Header().Get("Content-Type")) 750 } 751 752 // Tests that no Custom JSON is rendered if code is 204 753 func TestContextRenderNoContentAPIJSON(t *testing.T) { 754 w := httptest.NewRecorder() 755 c, _ := CreateTestContext(w) 756 757 c.Header("Content-Type", "application/vnd.api+json") 758 c.JSON(http.StatusNoContent, H{"foo": "bar"}) 759 760 assert.Equal(t, http.StatusNoContent, w.Code) 761 assert.Empty(t, w.Body.String()) 762 assert.Equal(t, w.Header().Get("Content-Type"), "application/vnd.api+json") 763 } 764 765 // Tests that the response is serialized as JSON 766 // and Content-Type is set to application/json 767 func TestContextRenderIndentedJSON(t *testing.T) { 768 w := httptest.NewRecorder() 769 c, _ := CreateTestContext(w) 770 771 c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) 772 773 assert.Equal(t, http.StatusCreated, w.Code) 774 assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String()) 775 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 776 } 777 778 // Tests that no Custom JSON is rendered if code is 204 779 func TestContextRenderNoContentIndentedJSON(t *testing.T) { 780 w := httptest.NewRecorder() 781 c, _ := CreateTestContext(w) 782 783 c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) 784 785 assert.Equal(t, http.StatusNoContent, w.Code) 786 assert.Empty(t, w.Body.String()) 787 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 788 } 789 790 // Tests that the response is serialized as Secure JSON 791 // and Content-Type is set to application/json 792 func TestContextRenderSecureJSON(t *testing.T) { 793 w := httptest.NewRecorder() 794 c, router := CreateTestContext(w) 795 796 router.SecureJsonPrefix("&&&START&&&") 797 c.SecureJSON(http.StatusCreated, []string{"foo", "bar"}) 798 799 assert.Equal(t, http.StatusCreated, w.Code) 800 assert.Equal(t, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String()) 801 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 802 } 803 804 // Tests that no Custom JSON is rendered if code is 204 805 func TestContextRenderNoContentSecureJSON(t *testing.T) { 806 w := httptest.NewRecorder() 807 c, _ := CreateTestContext(w) 808 809 c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"}) 810 811 assert.Equal(t, http.StatusNoContent, w.Code) 812 assert.Empty(t, w.Body.String()) 813 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 814 } 815 816 func TestContextRenderNoContentAsciiJSON(t *testing.T) { 817 w := httptest.NewRecorder() 818 c, _ := CreateTestContext(w) 819 820 c.AsciiJSON(http.StatusNoContent, []string{"lang", "Go语言"}) 821 822 assert.Equal(t, http.StatusNoContent, w.Code) 823 assert.Empty(t, w.Body.String()) 824 assert.Equal(t, "application/json", w.Header().Get("Content-Type")) 825 } 826 827 // Tests that the response is serialized as JSON 828 // and Content-Type is set to application/json 829 // and special HTML characters are preserved 830 func TestContextRenderPureJSON(t *testing.T) { 831 w := httptest.NewRecorder() 832 c, _ := CreateTestContext(w) 833 c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"}) 834 assert.Equal(t, http.StatusCreated, w.Code) 835 assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String()) 836 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 837 } 838 839 // Tests that the response executes the templates 840 // and responds with Content-Type set to text/html 841 func TestContextRenderHTML(t *testing.T) { 842 w := httptest.NewRecorder() 843 c, router := CreateTestContext(w) 844 845 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) 846 router.SetHTMLTemplate(templ) 847 848 c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) 849 850 assert.Equal(t, http.StatusCreated, w.Code) 851 assert.Equal(t, "Hello alexandernyquist", w.Body.String()) 852 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 853 } 854 855 func TestContextRenderHTML2(t *testing.T) { 856 w := httptest.NewRecorder() 857 c, router := CreateTestContext(w) 858 859 // print debug warning log when Engine.trees > 0 860 router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}}) 861 assert.Len(t, router.trees, 1) 862 863 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) 864 re := captureOutput(t, func() { 865 SetMode(DebugMode) 866 router.SetHTMLTemplate(templ) 867 SetMode(TestMode) 868 }) 869 870 assert.Equal(t, "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n", re) 871 872 c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) 873 874 assert.Equal(t, http.StatusCreated, w.Code) 875 assert.Equal(t, "Hello alexandernyquist", w.Body.String()) 876 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 877 } 878 879 // Tests that no HTML is rendered if code is 204 880 func TestContextRenderNoContentHTML(t *testing.T) { 881 w := httptest.NewRecorder() 882 c, router := CreateTestContext(w) 883 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) 884 router.SetHTMLTemplate(templ) 885 886 c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"}) 887 888 assert.Equal(t, http.StatusNoContent, w.Code) 889 assert.Empty(t, w.Body.String()) 890 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 891 } 892 893 // TestContextXML tests that the response is serialized as XML 894 // and Content-Type is set to application/xml 895 func TestContextRenderXML(t *testing.T) { 896 w := httptest.NewRecorder() 897 c, _ := CreateTestContext(w) 898 899 c.XML(http.StatusCreated, H{"foo": "bar"}) 900 901 assert.Equal(t, http.StatusCreated, w.Code) 902 assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String()) 903 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) 904 } 905 906 // Tests that no XML is rendered if code is 204 907 func TestContextRenderNoContentXML(t *testing.T) { 908 w := httptest.NewRecorder() 909 c, _ := CreateTestContext(w) 910 911 c.XML(http.StatusNoContent, H{"foo": "bar"}) 912 913 assert.Equal(t, http.StatusNoContent, w.Code) 914 assert.Empty(t, w.Body.String()) 915 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) 916 } 917 918 // TestContextString tests that the response is returned 919 // with Content-Type set to text/plain 920 func TestContextRenderString(t *testing.T) { 921 w := httptest.NewRecorder() 922 c, _ := CreateTestContext(w) 923 924 c.String(http.StatusCreated, "test %s %d", "string", 2) 925 926 assert.Equal(t, http.StatusCreated, w.Code) 927 assert.Equal(t, "test string 2", w.Body.String()) 928 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 929 } 930 931 // Tests that no String is rendered if code is 204 932 func TestContextRenderNoContentString(t *testing.T) { 933 w := httptest.NewRecorder() 934 c, _ := CreateTestContext(w) 935 936 c.String(http.StatusNoContent, "test %s %d", "string", 2) 937 938 assert.Equal(t, http.StatusNoContent, w.Code) 939 assert.Empty(t, w.Body.String()) 940 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 941 } 942 943 // TestContextString tests that the response is returned 944 // with Content-Type set to text/html 945 func TestContextRenderHTMLString(t *testing.T) { 946 w := httptest.NewRecorder() 947 c, _ := CreateTestContext(w) 948 949 c.Header("Content-Type", "text/html; charset=utf-8") 950 c.String(http.StatusCreated, "<html>%s %d</html>", "string", 3) 951 952 assert.Equal(t, http.StatusCreated, w.Code) 953 assert.Equal(t, "<html>string 3</html>", w.Body.String()) 954 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 955 } 956 957 // Tests that no HTML String is rendered if code is 204 958 func TestContextRenderNoContentHTMLString(t *testing.T) { 959 w := httptest.NewRecorder() 960 c, _ := CreateTestContext(w) 961 962 c.Header("Content-Type", "text/html; charset=utf-8") 963 c.String(http.StatusNoContent, "<html>%s %d</html>", "string", 3) 964 965 assert.Equal(t, http.StatusNoContent, w.Code) 966 assert.Empty(t, w.Body.String()) 967 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 968 } 969 970 // TestContextData tests that the response can be written from `bytestring` 971 // with specified MIME type 972 func TestContextRenderData(t *testing.T) { 973 w := httptest.NewRecorder() 974 c, _ := CreateTestContext(w) 975 976 c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`)) 977 978 assert.Equal(t, http.StatusCreated, w.Code) 979 assert.Equal(t, "foo,bar", w.Body.String()) 980 assert.Equal(t, "text/csv", w.Header().Get("Content-Type")) 981 } 982 983 // Tests that no Custom Data is rendered if code is 204 984 func TestContextRenderNoContentData(t *testing.T) { 985 w := httptest.NewRecorder() 986 c, _ := CreateTestContext(w) 987 988 c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`)) 989 990 assert.Equal(t, http.StatusNoContent, w.Code) 991 assert.Empty(t, w.Body.String()) 992 assert.Equal(t, "text/csv", w.Header().Get("Content-Type")) 993 } 994 995 func TestContextRenderSSE(t *testing.T) { 996 w := httptest.NewRecorder() 997 c, _ := CreateTestContext(w) 998 999 c.SSEvent("float", 1.5) 1000 c.Render(-1, sse.Event{ 1001 Id: "123", 1002 Data: "text", 1003 }) 1004 c.SSEvent("chat", H{ 1005 "foo": "bar", 1006 "bar": "foo", 1007 }) 1008 1009 assert.Equal(t, strings.Replace(w.Body.String(), " ", "", -1), strings.Replace("event:float\ndata:1.5\n\nid:123\ndata:text\n\nevent:chat\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n", " ", "", -1)) 1010 } 1011 1012 func TestContextRenderFile(t *testing.T) { 1013 w := httptest.NewRecorder() 1014 c, _ := CreateTestContext(w) 1015 1016 c.Request, _ = http.NewRequest("GET", "/", nil) 1017 c.File("./gin.go") 1018 1019 assert.Equal(t, http.StatusOK, w.Code) 1020 assert.Contains(t, w.Body.String(), "func New() *Engine {") 1021 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 1022 } 1023 1024 func TestContextRenderFileFromFS(t *testing.T) { 1025 w := httptest.NewRecorder() 1026 c, _ := CreateTestContext(w) 1027 1028 c.Request, _ = http.NewRequest("GET", "/some/path", nil) 1029 c.FileFromFS("./gin.go", Dir(".", false)) 1030 1031 assert.Equal(t, http.StatusOK, w.Code) 1032 assert.Contains(t, w.Body.String(), "func New() *Engine {") 1033 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) 1034 assert.Equal(t, "/some/path", c.Request.URL.Path) 1035 } 1036 1037 func TestContextRenderAttachment(t *testing.T) { 1038 w := httptest.NewRecorder() 1039 c, _ := CreateTestContext(w) 1040 newFilename := "new_filename.go" 1041 1042 c.Request, _ = http.NewRequest("GET", "/", nil) 1043 c.FileAttachment("./gin.go", newFilename) 1044 1045 assert.Equal(t, 200, w.Code) 1046 assert.Contains(t, w.Body.String(), "func New() *Engine {") 1047 assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.HeaderMap.Get("Content-Disposition")) 1048 } 1049 1050 // TestContextRenderYAML tests that the response is serialized as YAML 1051 // and Content-Type is set to application/x-yaml 1052 func TestContextRenderYAML(t *testing.T) { 1053 w := httptest.NewRecorder() 1054 c, _ := CreateTestContext(w) 1055 1056 c.YAML(http.StatusCreated, H{"foo": "bar"}) 1057 1058 assert.Equal(t, http.StatusCreated, w.Code) 1059 assert.Equal(t, "foo: bar\n", w.Body.String()) 1060 assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type")) 1061 } 1062 1063 // TestContextRenderProtoBuf tests that the response is serialized as ProtoBuf 1064 // and Content-Type is set to application/x-protobuf 1065 // and we just use the example protobuf to check if the response is correct 1066 func TestContextRenderProtoBuf(t *testing.T) { 1067 w := httptest.NewRecorder() 1068 c, _ := CreateTestContext(w) 1069 1070 reps := []int64{int64(1), int64(2)} 1071 label := "test" 1072 data := &testdata.Test{ 1073 Label: &label, 1074 Reps: reps, 1075 } 1076 1077 c.ProtoBuf(http.StatusCreated, data) 1078 1079 protoData, err := proto.Marshal(data) 1080 assert.NoError(t, err) 1081 1082 assert.Equal(t, http.StatusCreated, w.Code) 1083 assert.Equal(t, string(protoData), w.Body.String()) 1084 assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type")) 1085 } 1086 1087 func TestContextHeaders(t *testing.T) { 1088 c, _ := CreateTestContext(httptest.NewRecorder()) 1089 c.Header("Content-Type", "text/plain") 1090 c.Header("X-Custom", "value") 1091 1092 assert.Equal(t, "text/plain", c.Writer.Header().Get("Content-Type")) 1093 assert.Equal(t, "value", c.Writer.Header().Get("X-Custom")) 1094 1095 c.Header("Content-Type", "text/html") 1096 c.Header("X-Custom", "") 1097 1098 assert.Equal(t, "text/html", c.Writer.Header().Get("Content-Type")) 1099 _, exist := c.Writer.Header()["X-Custom"] 1100 assert.False(t, exist) 1101 } 1102 1103 // TODO 1104 func TestContextRenderRedirectWithRelativePath(t *testing.T) { 1105 w := httptest.NewRecorder() 1106 c, _ := CreateTestContext(w) 1107 1108 c.Request, _ = http.NewRequest("POST", "http://example.com", nil) 1109 assert.Panics(t, func() { c.Redirect(299, "/new_path") }) 1110 assert.Panics(t, func() { c.Redirect(309, "/new_path") }) 1111 1112 c.Redirect(http.StatusMovedPermanently, "/path") 1113 c.Writer.WriteHeaderNow() 1114 assert.Equal(t, http.StatusMovedPermanently, w.Code) 1115 assert.Equal(t, "/path", w.Header().Get("Location")) 1116 } 1117 1118 func TestContextRenderRedirectWithAbsolutePath(t *testing.T) { 1119 w := httptest.NewRecorder() 1120 c, _ := CreateTestContext(w) 1121 1122 c.Request, _ = http.NewRequest("POST", "http://example.com", nil) 1123 c.Redirect(http.StatusFound, "http://google.com") 1124 c.Writer.WriteHeaderNow() 1125 1126 assert.Equal(t, http.StatusFound, w.Code) 1127 assert.Equal(t, "http://google.com", w.Header().Get("Location")) 1128 } 1129 1130 func TestContextRenderRedirectWith201(t *testing.T) { 1131 w := httptest.NewRecorder() 1132 c, _ := CreateTestContext(w) 1133 1134 c.Request, _ = http.NewRequest("POST", "http://example.com", nil) 1135 c.Redirect(http.StatusCreated, "/resource") 1136 c.Writer.WriteHeaderNow() 1137 1138 assert.Equal(t, http.StatusCreated, w.Code) 1139 assert.Equal(t, "/resource", w.Header().Get("Location")) 1140 } 1141 1142 func TestContextRenderRedirectAll(t *testing.T) { 1143 c, _ := CreateTestContext(httptest.NewRecorder()) 1144 c.Request, _ = http.NewRequest("POST", "http://example.com", nil) 1145 assert.Panics(t, func() { c.Redirect(http.StatusOK, "/resource") }) 1146 assert.Panics(t, func() { c.Redirect(http.StatusAccepted, "/resource") }) 1147 assert.Panics(t, func() { c.Redirect(299, "/resource") }) 1148 assert.Panics(t, func() { c.Redirect(309, "/resource") }) 1149 assert.NotPanics(t, func() { c.Redirect(http.StatusMultipleChoices, "/resource") }) 1150 assert.NotPanics(t, func() { c.Redirect(http.StatusPermanentRedirect, "/resource") }) 1151 } 1152 1153 func TestContextNegotiationWithJSON(t *testing.T) { 1154 w := httptest.NewRecorder() 1155 c, _ := CreateTestContext(w) 1156 c.Request, _ = http.NewRequest("POST", "", nil) 1157 1158 c.Negotiate(http.StatusOK, Negotiate{ 1159 Offered: []string{MIMEJSON, MIMEXML, MIMEYAML}, 1160 Data: H{"foo": "bar"}, 1161 }) 1162 1163 assert.Equal(t, http.StatusOK, w.Code) 1164 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) 1165 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) 1166 } 1167 1168 func TestContextNegotiationWithXML(t *testing.T) { 1169 w := httptest.NewRecorder() 1170 c, _ := CreateTestContext(w) 1171 c.Request, _ = http.NewRequest("POST", "", nil) 1172 1173 c.Negotiate(http.StatusOK, Negotiate{ 1174 Offered: []string{MIMEXML, MIMEJSON, MIMEYAML}, 1175 Data: H{"foo": "bar"}, 1176 }) 1177 1178 assert.Equal(t, http.StatusOK, w.Code) 1179 assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String()) 1180 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) 1181 } 1182 1183 func TestContextNegotiationWithHTML(t *testing.T) { 1184 w := httptest.NewRecorder() 1185 c, router := CreateTestContext(w) 1186 c.Request, _ = http.NewRequest("POST", "", nil) 1187 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) 1188 router.SetHTMLTemplate(templ) 1189 1190 c.Negotiate(http.StatusOK, Negotiate{ 1191 Offered: []string{MIMEHTML}, 1192 Data: H{"name": "gin"}, 1193 HTMLName: "t", 1194 }) 1195 1196 assert.Equal(t, http.StatusOK, w.Code) 1197 assert.Equal(t, "Hello gin", w.Body.String()) 1198 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) 1199 } 1200 1201 func TestContextNegotiationNotSupport(t *testing.T) { 1202 w := httptest.NewRecorder() 1203 c, _ := CreateTestContext(w) 1204 c.Request, _ = http.NewRequest("POST", "", nil) 1205 1206 c.Negotiate(http.StatusOK, Negotiate{ 1207 Offered: []string{MIMEPOSTForm}, 1208 }) 1209 1210 assert.Equal(t, http.StatusNotAcceptable, w.Code) 1211 assert.Equal(t, c.index, abortIndex) 1212 assert.True(t, c.IsAborted()) 1213 } 1214 1215 func TestContextNegotiationFormat(t *testing.T) { 1216 c, _ := CreateTestContext(httptest.NewRecorder()) 1217 c.Request, _ = http.NewRequest("POST", "", nil) 1218 1219 assert.Panics(t, func() { c.NegotiateFormat() }) 1220 assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) 1221 assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML, MIMEJSON)) 1222 } 1223 1224 func TestContextNegotiationFormatWithAccept(t *testing.T) { 1225 c, _ := CreateTestContext(httptest.NewRecorder()) 1226 c.Request, _ = http.NewRequest("POST", "/", nil) 1227 c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8") 1228 1229 assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEJSON, MIMEXML)) 1230 assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEXML, MIMEHTML)) 1231 assert.Empty(t, c.NegotiateFormat(MIMEJSON)) 1232 } 1233 1234 func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) { 1235 c, _ := CreateTestContext(httptest.NewRecorder()) 1236 c.Request, _ = http.NewRequest("POST", "/", nil) 1237 c.Request.Header.Add("Accept", "*/*") 1238 1239 assert.Equal(t, c.NegotiateFormat("*/*"), "*/*") 1240 assert.Equal(t, c.NegotiateFormat("text/*"), "text/*") 1241 assert.Equal(t, c.NegotiateFormat("application/*"), "application/*") 1242 assert.Equal(t, c.NegotiateFormat(MIMEJSON), MIMEJSON) 1243 assert.Equal(t, c.NegotiateFormat(MIMEXML), MIMEXML) 1244 assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML) 1245 1246 c, _ = CreateTestContext(httptest.NewRecorder()) 1247 c.Request, _ = http.NewRequest("POST", "/", nil) 1248 c.Request.Header.Add("Accept", "text/*") 1249 1250 assert.Equal(t, c.NegotiateFormat("*/*"), "*/*") 1251 assert.Equal(t, c.NegotiateFormat("text/*"), "text/*") 1252 assert.Equal(t, c.NegotiateFormat("application/*"), "") 1253 assert.Equal(t, c.NegotiateFormat(MIMEJSON), "") 1254 assert.Equal(t, c.NegotiateFormat(MIMEXML), "") 1255 assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML) 1256 } 1257 1258 func TestContextNegotiationFormatCustom(t *testing.T) { 1259 c, _ := CreateTestContext(httptest.NewRecorder()) 1260 c.Request, _ = http.NewRequest("POST", "/", nil) 1261 c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8") 1262 1263 c.Accepted = nil 1264 c.SetAccepted(MIMEJSON, MIMEXML) 1265 1266 assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML)) 1267 assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML, MIMEHTML)) 1268 assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON)) 1269 } 1270 1271 func TestContextIsAborted(t *testing.T) { 1272 c, _ := CreateTestContext(httptest.NewRecorder()) 1273 assert.False(t, c.IsAborted()) 1274 1275 c.Abort() 1276 assert.True(t, c.IsAborted()) 1277 1278 c.Next() 1279 assert.True(t, c.IsAborted()) 1280 1281 c.index++ 1282 assert.True(t, c.IsAborted()) 1283 } 1284 1285 // TestContextData tests that the response can be written from `bytestring` 1286 // with specified MIME type 1287 func TestContextAbortWithStatus(t *testing.T) { 1288 w := httptest.NewRecorder() 1289 c, _ := CreateTestContext(w) 1290 1291 c.index = 4 1292 c.AbortWithStatus(http.StatusUnauthorized) 1293 1294 assert.Equal(t, abortIndex, c.index) 1295 assert.Equal(t, http.StatusUnauthorized, c.Writer.Status()) 1296 assert.Equal(t, http.StatusUnauthorized, w.Code) 1297 assert.True(t, c.IsAborted()) 1298 } 1299 1300 type testJSONAbortMsg struct { 1301 Foo string `json:"foo"` 1302 Bar string `json:"bar"` 1303 } 1304 1305 func TestContextAbortWithStatusJSON(t *testing.T) { 1306 w := httptest.NewRecorder() 1307 c, _ := CreateTestContext(w) 1308 c.index = 4 1309 1310 in := new(testJSONAbortMsg) 1311 in.Bar = "barValue" 1312 in.Foo = "fooValue" 1313 1314 c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in) 1315 1316 assert.Equal(t, abortIndex, c.index) 1317 assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status()) 1318 assert.Equal(t, http.StatusUnsupportedMediaType, w.Code) 1319 assert.True(t, c.IsAborted()) 1320 1321 contentType := w.Header().Get("Content-Type") 1322 assert.Equal(t, "application/json; charset=utf-8", contentType) 1323 1324 buf := new(bytes.Buffer) 1325 _, err := buf.ReadFrom(w.Body) 1326 assert.NoError(t, err) 1327 jsonStringBody := buf.String() 1328 assert.Equal(t, fmt.Sprint("{\"foo\":\"fooValue\",\"bar\":\"barValue\"}"), jsonStringBody) 1329 } 1330 1331 func TestContextError(t *testing.T) { 1332 c, _ := CreateTestContext(httptest.NewRecorder()) 1333 assert.Empty(t, c.Errors) 1334 1335 firstErr := errors.New("first error") 1336 c.Error(firstErr) // nolint: errcheck 1337 assert.Len(t, c.Errors, 1) 1338 assert.Equal(t, "Error #01: first error\n", c.Errors.String()) 1339 1340 secondErr := errors.New("second error") 1341 c.Error(&Error{ // nolint: errcheck 1342 Err: secondErr, 1343 Meta: "some data 2", 1344 Type: ErrorTypePublic, 1345 }) 1346 assert.Len(t, c.Errors, 2) 1347 1348 assert.Equal(t, firstErr, c.Errors[0].Err) 1349 assert.Nil(t, c.Errors[0].Meta) 1350 assert.Equal(t, ErrorTypePrivate, c.Errors[0].Type) 1351 1352 assert.Equal(t, secondErr, c.Errors[1].Err) 1353 assert.Equal(t, "some data 2", c.Errors[1].Meta) 1354 assert.Equal(t, ErrorTypePublic, c.Errors[1].Type) 1355 1356 assert.Equal(t, c.Errors.Last(), c.Errors[1]) 1357 1358 defer func() { 1359 if recover() == nil { 1360 t.Error("didn't panic") 1361 } 1362 }() 1363 c.Error(nil) // nolint: errcheck 1364 } 1365 1366 func TestContextTypedError(t *testing.T) { 1367 c, _ := CreateTestContext(httptest.NewRecorder()) 1368 c.Error(errors.New("externo 0")).SetType(ErrorTypePublic) // nolint: errcheck 1369 c.Error(errors.New("interno 0")).SetType(ErrorTypePrivate) // nolint: errcheck 1370 1371 for _, err := range c.Errors.ByType(ErrorTypePublic) { 1372 assert.Equal(t, ErrorTypePublic, err.Type) 1373 } 1374 for _, err := range c.Errors.ByType(ErrorTypePrivate) { 1375 assert.Equal(t, ErrorTypePrivate, err.Type) 1376 } 1377 assert.Equal(t, []string{"externo 0", "interno 0"}, c.Errors.Errors()) 1378 } 1379 1380 func TestContextAbortWithError(t *testing.T) { 1381 w := httptest.NewRecorder() 1382 c, _ := CreateTestContext(w) 1383 1384 c.AbortWithError(http.StatusUnauthorized, errors.New("bad input")).SetMeta("some input") // nolint: errcheck 1385 1386 assert.Equal(t, http.StatusUnauthorized, w.Code) 1387 assert.Equal(t, abortIndex, c.index) 1388 assert.True(t, c.IsAborted()) 1389 } 1390 1391 func resetTrustedCIDRs(c *Context) { 1392 c.engine.trustedCIDRs, _ = c.engine.prepareTrustedCIDRs() 1393 } 1394 1395 func TestContextClientIP(t *testing.T) { 1396 c, _ := CreateTestContext(httptest.NewRecorder()) 1397 c.Request, _ = http.NewRequest("POST", "/", nil) 1398 resetTrustedCIDRs(c) 1399 resetContextForClientIPTests(c) 1400 1401 // Legacy tests (validating that the defaults don't break the 1402 // (insecure!) old behaviour) 1403 assert.Equal(t, "20.20.20.20", c.ClientIP()) 1404 1405 c.Request.Header.Del("X-Forwarded-For") 1406 assert.Equal(t, "10.10.10.10", c.ClientIP()) 1407 1408 c.Request.Header.Set("X-Forwarded-For", "30.30.30.30 ") 1409 assert.Equal(t, "30.30.30.30", c.ClientIP()) 1410 1411 c.Request.Header.Del("X-Forwarded-For") 1412 c.Request.Header.Del("X-Real-IP") 1413 c.engine.AppEngine = true 1414 assert.Equal(t, "50.50.50.50", c.ClientIP()) 1415 1416 c.Request.Header.Del("X-Appengine-Remote-Addr") 1417 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1418 1419 // no port 1420 c.Request.RemoteAddr = "50.50.50.50" 1421 assert.Empty(t, c.ClientIP()) 1422 1423 // Tests exercising the TrustedProxies functionality 1424 resetContextForClientIPTests(c) 1425 1426 // No trusted proxies 1427 c.engine.TrustedProxies = []string{} 1428 resetTrustedCIDRs(c) 1429 c.engine.RemoteIPHeaders = []string{"X-Forwarded-For"} 1430 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1431 1432 // Last proxy is trusted, but the RemoteAddr is not 1433 c.engine.TrustedProxies = []string{"30.30.30.30"} 1434 resetTrustedCIDRs(c) 1435 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1436 1437 // Only trust RemoteAddr 1438 c.engine.TrustedProxies = []string{"40.40.40.40"} 1439 resetTrustedCIDRs(c) 1440 assert.Equal(t, "20.20.20.20", c.ClientIP()) 1441 1442 // All steps are trusted 1443 c.engine.TrustedProxies = []string{"40.40.40.40", "30.30.30.30", "20.20.20.20"} 1444 resetTrustedCIDRs(c) 1445 assert.Equal(t, "20.20.20.20", c.ClientIP()) 1446 1447 // Use CIDR 1448 c.engine.TrustedProxies = []string{"40.40.25.25/16", "30.30.30.30"} 1449 resetTrustedCIDRs(c) 1450 assert.Equal(t, "20.20.20.20", c.ClientIP()) 1451 1452 // Use hostname that resolves to all the proxies 1453 c.engine.TrustedProxies = []string{"foo"} 1454 resetTrustedCIDRs(c) 1455 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1456 1457 // Use hostname that returns an error 1458 c.engine.TrustedProxies = []string{"bar"} 1459 resetTrustedCIDRs(c) 1460 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1461 1462 // X-Forwarded-For has a non-IP element 1463 c.engine.TrustedProxies = []string{"40.40.40.40"} 1464 resetTrustedCIDRs(c) 1465 c.Request.Header.Set("X-Forwarded-For", " blah ") 1466 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1467 1468 // Result from LookupHost has non-IP element. This should never 1469 // happen, but we should test it to make sure we handle it 1470 // gracefully. 1471 c.engine.TrustedProxies = []string{"baz"} 1472 resetTrustedCIDRs(c) 1473 c.Request.Header.Set("X-Forwarded-For", " 30.30.30.30 ") 1474 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1475 1476 c.engine.TrustedProxies = []string{"40.40.40.40"} 1477 resetTrustedCIDRs(c) 1478 c.Request.Header.Del("X-Forwarded-For") 1479 c.engine.RemoteIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"} 1480 assert.Equal(t, "10.10.10.10", c.ClientIP()) 1481 1482 c.engine.RemoteIPHeaders = []string{} 1483 c.engine.AppEngine = true 1484 assert.Equal(t, "50.50.50.50", c.ClientIP()) 1485 1486 c.Request.Header.Del("X-Appengine-Remote-Addr") 1487 assert.Equal(t, "40.40.40.40", c.ClientIP()) 1488 1489 // no port 1490 c.Request.RemoteAddr = "50.50.50.50" 1491 assert.Empty(t, c.ClientIP()) 1492 } 1493 1494 func resetContextForClientIPTests(c *Context) { 1495 c.Request.Header.Set("X-Real-IP", " 10.10.10.10 ") 1496 c.Request.Header.Set("X-Forwarded-For", " 20.20.20.20, 30.30.30.30") 1497 c.Request.Header.Set("X-Appengine-Remote-Addr", "50.50.50.50") 1498 c.Request.RemoteAddr = " 40.40.40.40:42123 " 1499 c.engine.AppEngine = false 1500 } 1501 1502 func TestContextContentType(t *testing.T) { 1503 c, _ := CreateTestContext(httptest.NewRecorder()) 1504 c.Request, _ = http.NewRequest("POST", "/", nil) 1505 c.Request.Header.Set("Content-Type", "application/json; charset=utf-8") 1506 1507 assert.Equal(t, "application/json", c.ContentType()) 1508 } 1509 1510 func TestContextAutoBindJSON(t *testing.T) { 1511 c, _ := CreateTestContext(httptest.NewRecorder()) 1512 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}")) 1513 c.Request.Header.Add("Content-Type", MIMEJSON) 1514 1515 var obj struct { 1516 Foo string `json:"foo"` 1517 Bar string `json:"bar"` 1518 } 1519 assert.NoError(t, c.Bind(&obj)) 1520 assert.Equal(t, "foo", obj.Bar) 1521 assert.Equal(t, "bar", obj.Foo) 1522 assert.Empty(t, c.Errors) 1523 } 1524 1525 func TestContextBindWithJSON(t *testing.T) { 1526 w := httptest.NewRecorder() 1527 c, _ := CreateTestContext(w) 1528 1529 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}")) 1530 c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type 1531 1532 var obj struct { 1533 Foo string `json:"foo"` 1534 Bar string `json:"bar"` 1535 } 1536 assert.NoError(t, c.BindJSON(&obj)) 1537 assert.Equal(t, "foo", obj.Bar) 1538 assert.Equal(t, "bar", obj.Foo) 1539 assert.Equal(t, 0, w.Body.Len()) 1540 } 1541 func TestContextBindWithXML(t *testing.T) { 1542 w := httptest.NewRecorder() 1543 c, _ := CreateTestContext(w) 1544 1545 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?> 1546 <root> 1547 <foo>FOO</foo> 1548 <bar>BAR</bar> 1549 </root>`)) 1550 c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type 1551 1552 var obj struct { 1553 Foo string `xml:"foo"` 1554 Bar string `xml:"bar"` 1555 } 1556 assert.NoError(t, c.BindXML(&obj)) 1557 assert.Equal(t, "FOO", obj.Foo) 1558 assert.Equal(t, "BAR", obj.Bar) 1559 assert.Equal(t, 0, w.Body.Len()) 1560 } 1561 1562 func TestContextBindHeader(t *testing.T) { 1563 w := httptest.NewRecorder() 1564 c, _ := CreateTestContext(w) 1565 1566 c.Request, _ = http.NewRequest("POST", "/", nil) 1567 c.Request.Header.Add("rate", "8000") 1568 c.Request.Header.Add("domain", "music") 1569 c.Request.Header.Add("limit", "1000") 1570 1571 var testHeader struct { 1572 Rate int `header:"Rate"` 1573 Domain string `header:"Domain"` 1574 Limit int `header:"limit"` 1575 } 1576 1577 assert.NoError(t, c.BindHeader(&testHeader)) 1578 assert.Equal(t, 8000, testHeader.Rate) 1579 assert.Equal(t, "music", testHeader.Domain) 1580 assert.Equal(t, 1000, testHeader.Limit) 1581 assert.Equal(t, 0, w.Body.Len()) 1582 } 1583 1584 func TestContextBindWithQuery(t *testing.T) { 1585 w := httptest.NewRecorder() 1586 c, _ := CreateTestContext(w) 1587 1588 c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo", bytes.NewBufferString("foo=unused")) 1589 1590 var obj struct { 1591 Foo string `form:"foo"` 1592 Bar string `form:"bar"` 1593 } 1594 assert.NoError(t, c.BindQuery(&obj)) 1595 assert.Equal(t, "foo", obj.Bar) 1596 assert.Equal(t, "bar", obj.Foo) 1597 assert.Equal(t, 0, w.Body.Len()) 1598 } 1599 1600 func TestContextBindWithYAML(t *testing.T) { 1601 w := httptest.NewRecorder() 1602 c, _ := CreateTestContext(w) 1603 1604 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo")) 1605 c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type 1606 1607 var obj struct { 1608 Foo string `yaml:"foo"` 1609 Bar string `yaml:"bar"` 1610 } 1611 assert.NoError(t, c.BindYAML(&obj)) 1612 assert.Equal(t, "foo", obj.Bar) 1613 assert.Equal(t, "bar", obj.Foo) 1614 assert.Equal(t, 0, w.Body.Len()) 1615 } 1616 1617 func TestContextBadAutoBind(t *testing.T) { 1618 w := httptest.NewRecorder() 1619 c, _ := CreateTestContext(w) 1620 1621 c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}")) 1622 c.Request.Header.Add("Content-Type", MIMEJSON) 1623 var obj struct { 1624 Foo string `json:"foo"` 1625 Bar string `json:"bar"` 1626 } 1627 1628 assert.False(t, c.IsAborted()) 1629 assert.Error(t, c.Bind(&obj)) 1630 c.Writer.WriteHeaderNow() 1631 1632 assert.Empty(t, obj.Bar) 1633 assert.Empty(t, obj.Foo) 1634 assert.Equal(t, http.StatusBadRequest, w.Code) 1635 assert.True(t, c.IsAborted()) 1636 } 1637 1638 func TestContextAutoShouldBindJSON(t *testing.T) { 1639 c, _ := CreateTestContext(httptest.NewRecorder()) 1640 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}")) 1641 c.Request.Header.Add("Content-Type", MIMEJSON) 1642 1643 var obj struct { 1644 Foo string `json:"foo"` 1645 Bar string `json:"bar"` 1646 } 1647 assert.NoError(t, c.ShouldBind(&obj)) 1648 assert.Equal(t, "foo", obj.Bar) 1649 assert.Equal(t, "bar", obj.Foo) 1650 assert.Empty(t, c.Errors) 1651 } 1652 1653 func TestContextShouldBindWithJSON(t *testing.T) { 1654 w := httptest.NewRecorder() 1655 c, _ := CreateTestContext(w) 1656 1657 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}")) 1658 c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type 1659 1660 var obj struct { 1661 Foo string `json:"foo"` 1662 Bar string `json:"bar"` 1663 } 1664 assert.NoError(t, c.ShouldBindJSON(&obj)) 1665 assert.Equal(t, "foo", obj.Bar) 1666 assert.Equal(t, "bar", obj.Foo) 1667 assert.Equal(t, 0, w.Body.Len()) 1668 } 1669 1670 func TestContextShouldBindWithXML(t *testing.T) { 1671 w := httptest.NewRecorder() 1672 c, _ := CreateTestContext(w) 1673 1674 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?> 1675 <root> 1676 <foo>FOO</foo> 1677 <bar>BAR</bar> 1678 </root>`)) 1679 c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type 1680 1681 var obj struct { 1682 Foo string `xml:"foo"` 1683 Bar string `xml:"bar"` 1684 } 1685 assert.NoError(t, c.ShouldBindXML(&obj)) 1686 assert.Equal(t, "FOO", obj.Foo) 1687 assert.Equal(t, "BAR", obj.Bar) 1688 assert.Equal(t, 0, w.Body.Len()) 1689 } 1690 1691 func TestContextShouldBindHeader(t *testing.T) { 1692 w := httptest.NewRecorder() 1693 c, _ := CreateTestContext(w) 1694 1695 c.Request, _ = http.NewRequest("POST", "/", nil) 1696 c.Request.Header.Add("rate", "8000") 1697 c.Request.Header.Add("domain", "music") 1698 c.Request.Header.Add("limit", "1000") 1699 1700 var testHeader struct { 1701 Rate int `header:"Rate"` 1702 Domain string `header:"Domain"` 1703 Limit int `header:"limit"` 1704 } 1705 1706 assert.NoError(t, c.ShouldBindHeader(&testHeader)) 1707 assert.Equal(t, 8000, testHeader.Rate) 1708 assert.Equal(t, "music", testHeader.Domain) 1709 assert.Equal(t, 1000, testHeader.Limit) 1710 assert.Equal(t, 0, w.Body.Len()) 1711 } 1712 1713 func TestContextShouldBindWithQuery(t *testing.T) { 1714 w := httptest.NewRecorder() 1715 c, _ := CreateTestContext(w) 1716 1717 c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo&Foo=bar1&Bar=foo1", bytes.NewBufferString("foo=unused")) 1718 1719 var obj struct { 1720 Foo string `form:"foo"` 1721 Bar string `form:"bar"` 1722 Foo1 string `form:"Foo"` 1723 Bar1 string `form:"Bar"` 1724 } 1725 assert.NoError(t, c.ShouldBindQuery(&obj)) 1726 assert.Equal(t, "foo", obj.Bar) 1727 assert.Equal(t, "bar", obj.Foo) 1728 assert.Equal(t, "foo1", obj.Bar1) 1729 assert.Equal(t, "bar1", obj.Foo1) 1730 assert.Equal(t, 0, w.Body.Len()) 1731 } 1732 1733 func TestContextShouldBindWithYAML(t *testing.T) { 1734 w := httptest.NewRecorder() 1735 c, _ := CreateTestContext(w) 1736 1737 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo")) 1738 c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type 1739 1740 var obj struct { 1741 Foo string `yaml:"foo"` 1742 Bar string `yaml:"bar"` 1743 } 1744 assert.NoError(t, c.ShouldBindYAML(&obj)) 1745 assert.Equal(t, "foo", obj.Bar) 1746 assert.Equal(t, "bar", obj.Foo) 1747 assert.Equal(t, 0, w.Body.Len()) 1748 } 1749 1750 func TestContextBadAutoShouldBind(t *testing.T) { 1751 w := httptest.NewRecorder() 1752 c, _ := CreateTestContext(w) 1753 1754 c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}")) 1755 c.Request.Header.Add("Content-Type", MIMEJSON) 1756 var obj struct { 1757 Foo string `json:"foo"` 1758 Bar string `json:"bar"` 1759 } 1760 1761 assert.False(t, c.IsAborted()) 1762 assert.Error(t, c.ShouldBind(&obj)) 1763 1764 assert.Empty(t, obj.Bar) 1765 assert.Empty(t, obj.Foo) 1766 assert.False(t, c.IsAborted()) 1767 } 1768 1769 func TestContextShouldBindBodyWith(t *testing.T) { 1770 type typeA struct { 1771 Foo string `json:"foo" xml:"foo" binding:"required"` 1772 } 1773 type typeB struct { 1774 Bar string `json:"bar" xml:"bar" binding:"required"` 1775 } 1776 for _, tt := range []struct { 1777 name string 1778 bindingA, bindingB binding.BindingBody 1779 bodyA, bodyB string 1780 }{ 1781 { 1782 name: "JSON & JSON", 1783 bindingA: binding.JSON, 1784 bindingB: binding.JSON, 1785 bodyA: `{"foo":"FOO"}`, 1786 bodyB: `{"bar":"BAR"}`, 1787 }, 1788 { 1789 name: "JSON & XML", 1790 bindingA: binding.JSON, 1791 bindingB: binding.XML, 1792 bodyA: `{"foo":"FOO"}`, 1793 bodyB: `<?xml version="1.0" encoding="UTF-8"?> 1794 <root> 1795 <bar>BAR</bar> 1796 </root>`, 1797 }, 1798 { 1799 name: "XML & XML", 1800 bindingA: binding.XML, 1801 bindingB: binding.XML, 1802 bodyA: `<?xml version="1.0" encoding="UTF-8"?> 1803 <root> 1804 <foo>FOO</foo> 1805 </root>`, 1806 bodyB: `<?xml version="1.0" encoding="UTF-8"?> 1807 <root> 1808 <bar>BAR</bar> 1809 </root>`, 1810 }, 1811 } { 1812 t.Logf("testing: %s", tt.name) 1813 // bodyA to typeA and typeB 1814 { 1815 w := httptest.NewRecorder() 1816 c, _ := CreateTestContext(w) 1817 c.Request, _ = http.NewRequest( 1818 "POST", "http://example.com", bytes.NewBufferString(tt.bodyA), 1819 ) 1820 // When it binds to typeA and typeB, it finds the body is 1821 // not typeB but typeA. 1822 objA := typeA{} 1823 assert.NoError(t, c.ShouldBindBodyWith(&objA, tt.bindingA)) 1824 assert.Equal(t, typeA{"FOO"}, objA) 1825 objB := typeB{} 1826 assert.Error(t, c.ShouldBindBodyWith(&objB, tt.bindingB)) 1827 assert.NotEqual(t, typeB{"BAR"}, objB) 1828 } 1829 // bodyB to typeA and typeB 1830 { 1831 // When it binds to typeA and typeB, it finds the body is 1832 // not typeA but typeB. 1833 w := httptest.NewRecorder() 1834 c, _ := CreateTestContext(w) 1835 c.Request, _ = http.NewRequest( 1836 "POST", "http://example.com", bytes.NewBufferString(tt.bodyB), 1837 ) 1838 objA := typeA{} 1839 assert.Error(t, c.ShouldBindBodyWith(&objA, tt.bindingA)) 1840 assert.NotEqual(t, typeA{"FOO"}, objA) 1841 objB := typeB{} 1842 assert.NoError(t, c.ShouldBindBodyWith(&objB, tt.bindingB)) 1843 assert.Equal(t, typeB{"BAR"}, objB) 1844 } 1845 } 1846 } 1847 1848 func TestContextGolangContext(t *testing.T) { 1849 c, _ := CreateTestContext(httptest.NewRecorder()) 1850 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}")) 1851 assert.NoError(t, c.Err()) 1852 assert.Nil(t, c.Done()) 1853 ti, ok := c.Deadline() 1854 assert.Equal(t, ti, time.Time{}) 1855 assert.False(t, ok) 1856 assert.Equal(t, c.Value(0), c.Request) 1857 assert.Nil(t, c.Value("foo")) 1858 1859 c.Set("foo", "bar") 1860 assert.Equal(t, "bar", c.Value("foo")) 1861 assert.Nil(t, c.Value(1)) 1862 } 1863 1864 func TestWebsocketsRequired(t *testing.T) { 1865 // Example request from spec: https://tools.ietf.org/html/rfc6455#section-1.2 1866 c, _ := CreateTestContext(httptest.NewRecorder()) 1867 c.Request, _ = http.NewRequest("GET", "/chat", nil) 1868 c.Request.Header.Set("Host", "server.example.com") 1869 c.Request.Header.Set("Upgrade", "websocket") 1870 c.Request.Header.Set("Connection", "Upgrade") 1871 c.Request.Header.Set("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==") 1872 c.Request.Header.Set("Origin", "http://example.com") 1873 c.Request.Header.Set("Sec-WebSocket-Protocol", "chat, superchat") 1874 c.Request.Header.Set("Sec-WebSocket-Version", "13") 1875 1876 assert.True(t, c.IsWebsocket()) 1877 1878 // Normal request, no websocket required. 1879 c, _ = CreateTestContext(httptest.NewRecorder()) 1880 c.Request, _ = http.NewRequest("GET", "/chat", nil) 1881 c.Request.Header.Set("Host", "server.example.com") 1882 1883 assert.False(t, c.IsWebsocket()) 1884 } 1885 1886 func TestGetRequestHeaderValue(t *testing.T) { 1887 c, _ := CreateTestContext(httptest.NewRecorder()) 1888 c.Request, _ = http.NewRequest("GET", "/chat", nil) 1889 c.Request.Header.Set("Gin-Version", "1.0.0") 1890 1891 assert.Equal(t, "1.0.0", c.GetHeader("Gin-Version")) 1892 assert.Empty(t, c.GetHeader("Connection")) 1893 } 1894 1895 func TestContextGetRawData(t *testing.T) { 1896 c, _ := CreateTestContext(httptest.NewRecorder()) 1897 body := bytes.NewBufferString("Fetch binary post data") 1898 c.Request, _ = http.NewRequest("POST", "/", body) 1899 c.Request.Header.Add("Content-Type", MIMEPOSTForm) 1900 1901 data, err := c.GetRawData() 1902 assert.Nil(t, err) 1903 assert.Equal(t, "Fetch binary post data", string(data)) 1904 } 1905 1906 func TestContextRenderDataFromReader(t *testing.T) { 1907 w := httptest.NewRecorder() 1908 c, _ := CreateTestContext(w) 1909 1910 body := "#!PNG some raw data" 1911 reader := strings.NewReader(body) 1912 contentLength := int64(len(body)) 1913 contentType := "image/png" 1914 extraHeaders := map[string]string{"Content-Disposition": `attachment; filename="gopher.png"`} 1915 1916 c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders) 1917 1918 assert.Equal(t, http.StatusOK, w.Code) 1919 assert.Equal(t, body, w.Body.String()) 1920 assert.Equal(t, contentType, w.Header().Get("Content-Type")) 1921 assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length")) 1922 assert.Equal(t, extraHeaders["Content-Disposition"], w.Header().Get("Content-Disposition")) 1923 } 1924 1925 func TestContextRenderDataFromReaderNoHeaders(t *testing.T) { 1926 w := httptest.NewRecorder() 1927 c, _ := CreateTestContext(w) 1928 1929 body := "#!PNG some raw data" 1930 reader := strings.NewReader(body) 1931 contentLength := int64(len(body)) 1932 contentType := "image/png" 1933 1934 c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil) 1935 1936 assert.Equal(t, http.StatusOK, w.Code) 1937 assert.Equal(t, body, w.Body.String()) 1938 assert.Equal(t, contentType, w.Header().Get("Content-Type")) 1939 assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length")) 1940 } 1941 1942 type TestResponseRecorder struct { 1943 *httptest.ResponseRecorder 1944 closeChannel chan bool 1945 } 1946 1947 func (r *TestResponseRecorder) CloseNotify() <-chan bool { 1948 return r.closeChannel 1949 } 1950 1951 func (r *TestResponseRecorder) closeClient() { 1952 r.closeChannel <- true 1953 } 1954 1955 func CreateTestResponseRecorder() *TestResponseRecorder { 1956 return &TestResponseRecorder{ 1957 httptest.NewRecorder(), 1958 make(chan bool, 1), 1959 } 1960 } 1961 1962 func TestContextStream(t *testing.T) { 1963 w := CreateTestResponseRecorder() 1964 c, _ := CreateTestContext(w) 1965 1966 stopStream := true 1967 c.Stream(func(w io.Writer) bool { 1968 defer func() { 1969 stopStream = false 1970 }() 1971 1972 _, err := w.Write([]byte("test")) 1973 assert.NoError(t, err) 1974 1975 return stopStream 1976 }) 1977 1978 assert.Equal(t, "testtest", w.Body.String()) 1979 } 1980 1981 func TestContextStreamWithClientGone(t *testing.T) { 1982 w := CreateTestResponseRecorder() 1983 c, _ := CreateTestContext(w) 1984 1985 c.Stream(func(writer io.Writer) bool { 1986 defer func() { 1987 w.closeClient() 1988 }() 1989 1990 _, err := writer.Write([]byte("test")) 1991 assert.NoError(t, err) 1992 1993 return true 1994 }) 1995 1996 assert.Equal(t, "test", w.Body.String()) 1997 } 1998 1999 func TestContextResetInHandler(t *testing.T) { 2000 w := CreateTestResponseRecorder() 2001 c, _ := CreateTestContext(w) 2002 2003 c.handlers = []HandlerFunc{ 2004 func(c *Context) { c.reset() }, 2005 } 2006 assert.NotPanics(t, func() { 2007 c.Next() 2008 }) 2009 } 2010 2011 func TestRaceParamsContextCopy(t *testing.T) { 2012 DefaultWriter = os.Stdout 2013 router := Default() 2014 nameGroup := router.Group("/:name") 2015 var wg sync.WaitGroup 2016 wg.Add(2) 2017 { 2018 nameGroup.GET("/api", func(c *Context) { 2019 go func(c *Context, param string) { 2020 defer wg.Done() 2021 // First assert must be executed after the second request 2022 time.Sleep(50 * time.Millisecond) 2023 assert.Equal(t, c.Param("name"), param) 2024 }(c.Copy(), c.Param("name")) 2025 }) 2026 } 2027 performRequest(router, "GET", "/name1/api") 2028 performRequest(router, "GET", "/name2/api") 2029 wg.Wait() 2030 } 2031 2032 func TestContextWithKeysMutex(t *testing.T) { 2033 c := &Context{} 2034 c.Set("foo", "bar") 2035 2036 value, err := c.Get("foo") 2037 assert.Equal(t, "bar", value) 2038 assert.True(t, err) 2039 2040 value, err = c.Get("foo2") 2041 assert.Nil(t, value) 2042 assert.False(t, err) 2043 } 2044 2045 func TestRemoteIPFail(t *testing.T) { 2046 c, _ := CreateTestContext(httptest.NewRecorder()) 2047 c.Request, _ = http.NewRequest("POST", "/", nil) 2048 c.Request.RemoteAddr = "[:::]:80" 2049 ip, trust := c.RemoteIP() 2050 assert.Nil(t, ip) 2051 assert.False(t, trust) 2052 }