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