1
2
3
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"
16 "net/http"
17 "net/http/httptest"
18 "net/url"
19 "os"
20 "reflect"
21 "strings"
22 "sync"
23 "testing"
24 "time"
25
26 "github.com/gin-contrib/sse"
27 "github.com/gin-gonic/gin/binding"
28 testdata "github.com/gin-gonic/gin/testdata/protoexample"
29 "github.com/stretchr/testify/assert"
30 "google.golang.org/protobuf/proto"
31 )
32
33 var _ context.Context = (*Context)(nil)
34
35 var errTestRender = errors.New("TestRender")
36
37
38
39
40
41
42
43 func createMultipartRequest() *http.Request {
44 boundary := "--testboundary"
45 body := new(bytes.Buffer)
46 mw := multipart.NewWriter(body)
47 defer mw.Close()
48
49 must(mw.SetBoundary(boundary))
50 must(mw.WriteField("foo", "bar"))
51 must(mw.WriteField("bar", "10"))
52 must(mw.WriteField("bar", "foo2"))
53 must(mw.WriteField("array", "first"))
54 must(mw.WriteField("array", "second"))
55 must(mw.WriteField("id", ""))
56 must(mw.WriteField("time_local", "31/12/2016 14:55"))
57 must(mw.WriteField("time_utc", "31/12/2016 14:55"))
58 must(mw.WriteField("time_location", "31/12/2016 14:55"))
59 must(mw.WriteField("names[a]", "thinkerou"))
60 must(mw.WriteField("names[b]", "tianou"))
61 req, err := http.NewRequest("POST", "/", body)
62 must(err)
63 req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
64 return req
65 }
66
67 func must(err error) {
68 if err != nil {
69 panic(err.Error())
70 }
71 }
72
73 func TestContextFormFile(t *testing.T) {
74 buf := new(bytes.Buffer)
75 mw := multipart.NewWriter(buf)
76 w, err := mw.CreateFormFile("file", "test")
77 if assert.NoError(t, err) {
78 _, err = w.Write([]byte("test"))
79 assert.NoError(t, err)
80 }
81 mw.Close()
82 c, _ := CreateTestContext(httptest.NewRecorder())
83 c.Request, _ = http.NewRequest("POST", "/", buf)
84 c.Request.Header.Set("Content-Type", mw.FormDataContentType())
85 f, err := c.FormFile("file")
86 if assert.NoError(t, err) {
87 assert.Equal(t, "test", f.Filename)
88 }
89
90 assert.NoError(t, c.SaveUploadedFile(f, "test"))
91 }
92
93 func TestContextMultipartForm(t *testing.T) {
94 buf := new(bytes.Buffer)
95 mw := multipart.NewWriter(buf)
96 assert.NoError(t, mw.WriteField("foo", "bar"))
97 w, err := mw.CreateFormFile("file", "test")
98 if assert.NoError(t, err) {
99 _, err = w.Write([]byte("test"))
100 assert.NoError(t, err)
101 }
102 mw.Close()
103 c, _ := CreateTestContext(httptest.NewRecorder())
104 c.Request, _ = http.NewRequest("POST", "/", buf)
105 c.Request.Header.Set("Content-Type", mw.FormDataContentType())
106 f, err := c.MultipartForm()
107 if assert.NoError(t, err) {
108 assert.NotNil(t, f)
109 }
110
111 assert.NoError(t, c.SaveUploadedFile(f.File["file"][0], "test"))
112 }
113
114 func TestSaveUploadedOpenFailed(t *testing.T) {
115 buf := new(bytes.Buffer)
116 mw := multipart.NewWriter(buf)
117 mw.Close()
118
119 c, _ := CreateTestContext(httptest.NewRecorder())
120 c.Request, _ = http.NewRequest("POST", "/", buf)
121 c.Request.Header.Set("Content-Type", mw.FormDataContentType())
122
123 f := &multipart.FileHeader{
124 Filename: "file",
125 }
126 assert.Error(t, c.SaveUploadedFile(f, "test"))
127 }
128
129 func TestSaveUploadedCreateFailed(t *testing.T) {
130 buf := new(bytes.Buffer)
131 mw := multipart.NewWriter(buf)
132 w, err := mw.CreateFormFile("file", "test")
133 if assert.NoError(t, err) {
134 _, err = w.Write([]byte("test"))
135 assert.NoError(t, err)
136 }
137 mw.Close()
138 c, _ := CreateTestContext(httptest.NewRecorder())
139 c.Request, _ = http.NewRequest("POST", "/", buf)
140 c.Request.Header.Set("Content-Type", mw.FormDataContentType())
141 f, err := c.FormFile("file")
142 if assert.NoError(t, err) {
143 assert.Equal(t, "test", f.Filename)
144 }
145
146 assert.Error(t, c.SaveUploadedFile(f, "/"))
147 }
148
149 func TestContextReset(t *testing.T) {
150 router := New()
151 c := router.allocateContext(0)
152 assert.Equal(t, c.engine, router)
153
154 c.index = 2
155 c.Writer = &responseWriter{ResponseWriter: httptest.NewRecorder()}
156 c.Params = Params{Param{}}
157 c.Error(errors.New("test"))
158 c.Set("foo", "bar")
159 c.reset()
160
161 assert.False(t, c.IsAborted())
162 assert.Nil(t, c.Keys)
163 assert.Nil(t, c.Accepted)
164 assert.Len(t, c.Errors, 0)
165 assert.Empty(t, c.Errors.Errors())
166 assert.Empty(t, c.Errors.ByType(ErrorTypeAny))
167 assert.Len(t, c.Params, 0)
168 assert.EqualValues(t, c.index, -1)
169 assert.Equal(t, c.Writer.(*responseWriter), &c.writermem)
170 }
171
172 func TestContextHandlers(t *testing.T) {
173 c, _ := CreateTestContext(httptest.NewRecorder())
174 assert.Nil(t, c.handlers)
175 assert.Nil(t, c.handlers.Last())
176
177 c.handlers = HandlersChain{}
178 assert.NotNil(t, c.handlers)
179 assert.Nil(t, c.handlers.Last())
180
181 f := func(c *Context) {}
182 g := func(c *Context) {}
183
184 c.handlers = HandlersChain{f}
185 compareFunc(t, f, c.handlers.Last())
186
187 c.handlers = HandlersChain{f, g}
188 compareFunc(t, g, c.handlers.Last())
189 }
190
191
192
193 func TestContextSetGet(t *testing.T) {
194 c, _ := CreateTestContext(httptest.NewRecorder())
195 c.Set("foo", "bar")
196
197 value, err := c.Get("foo")
198 assert.Equal(t, "bar", value)
199 assert.True(t, err)
200
201 value, err = c.Get("foo2")
202 assert.Nil(t, value)
203 assert.False(t, err)
204
205 assert.Equal(t, "bar", c.MustGet("foo"))
206 assert.Panics(t, func() { c.MustGet("no_exist") })
207 }
208
209 func TestContextSetGetValues(t *testing.T) {
210 c, _ := CreateTestContext(httptest.NewRecorder())
211 c.Set("string", "this is a string")
212 c.Set("int32", int32(-42))
213 c.Set("int64", int64(42424242424242))
214 c.Set("uint64", uint64(42))
215 c.Set("float32", float32(4.2))
216 c.Set("float64", 4.2)
217 var a any = 1
218 c.Set("intInterface", a)
219
220 assert.Exactly(t, c.MustGet("string").(string), "this is a string")
221 assert.Exactly(t, c.MustGet("int32").(int32), int32(-42))
222 assert.Exactly(t, c.MustGet("int64").(int64), int64(42424242424242))
223 assert.Exactly(t, c.MustGet("uint64").(uint64), uint64(42))
224 assert.Exactly(t, c.MustGet("float32").(float32), float32(4.2))
225 assert.Exactly(t, c.MustGet("float64").(float64), 4.2)
226 assert.Exactly(t, c.MustGet("intInterface").(int), 1)
227 }
228
229 func TestContextGetString(t *testing.T) {
230 c, _ := CreateTestContext(httptest.NewRecorder())
231 c.Set("string", "this is a string")
232 assert.Equal(t, "this is a string", c.GetString("string"))
233 }
234
235 func TestContextSetGetBool(t *testing.T) {
236 c, _ := CreateTestContext(httptest.NewRecorder())
237 c.Set("bool", true)
238 assert.True(t, c.GetBool("bool"))
239 }
240
241 func TestContextGetInt(t *testing.T) {
242 c, _ := CreateTestContext(httptest.NewRecorder())
243 c.Set("int", 1)
244 assert.Equal(t, 1, c.GetInt("int"))
245 }
246
247 func TestContextGetInt64(t *testing.T) {
248 c, _ := CreateTestContext(httptest.NewRecorder())
249 c.Set("int64", int64(42424242424242))
250 assert.Equal(t, int64(42424242424242), c.GetInt64("int64"))
251 }
252
253 func TestContextGetUint(t *testing.T) {
254 c, _ := CreateTestContext(httptest.NewRecorder())
255 c.Set("uint", uint(1))
256 assert.Equal(t, uint(1), c.GetUint("uint"))
257 }
258
259 func TestContextGetUint64(t *testing.T) {
260 c, _ := CreateTestContext(httptest.NewRecorder())
261 c.Set("uint64", uint64(18446744073709551615))
262 assert.Equal(t, uint64(18446744073709551615), c.GetUint64("uint64"))
263 }
264
265 func TestContextGetFloat64(t *testing.T) {
266 c, _ := CreateTestContext(httptest.NewRecorder())
267 c.Set("float64", 4.2)
268 assert.Equal(t, 4.2, c.GetFloat64("float64"))
269 }
270
271 func TestContextGetTime(t *testing.T) {
272 c, _ := CreateTestContext(httptest.NewRecorder())
273 t1, _ := time.Parse("1/2/2006 15:04:05", "01/01/2017 12:00:00")
274 c.Set("time", t1)
275 assert.Equal(t, t1, c.GetTime("time"))
276 }
277
278 func TestContextGetDuration(t *testing.T) {
279 c, _ := CreateTestContext(httptest.NewRecorder())
280 c.Set("duration", time.Second)
281 assert.Equal(t, time.Second, c.GetDuration("duration"))
282 }
283
284 func TestContextGetStringSlice(t *testing.T) {
285 c, _ := CreateTestContext(httptest.NewRecorder())
286 c.Set("slice", []string{"foo"})
287 assert.Equal(t, []string{"foo"}, c.GetStringSlice("slice"))
288 }
289
290 func TestContextGetStringMap(t *testing.T) {
291 c, _ := CreateTestContext(httptest.NewRecorder())
292 m := make(map[string]any)
293 m["foo"] = 1
294 c.Set("map", m)
295
296 assert.Equal(t, m, c.GetStringMap("map"))
297 assert.Equal(t, 1, c.GetStringMap("map")["foo"])
298 }
299
300 func TestContextGetStringMapString(t *testing.T) {
301 c, _ := CreateTestContext(httptest.NewRecorder())
302 m := make(map[string]string)
303 m["foo"] = "bar"
304 c.Set("map", m)
305
306 assert.Equal(t, m, c.GetStringMapString("map"))
307 assert.Equal(t, "bar", c.GetStringMapString("map")["foo"])
308 }
309
310 func TestContextGetStringMapStringSlice(t *testing.T) {
311 c, _ := CreateTestContext(httptest.NewRecorder())
312 m := make(map[string][]string)
313 m["foo"] = []string{"foo"}
314 c.Set("map", m)
315
316 assert.Equal(t, m, c.GetStringMapStringSlice("map"))
317 assert.Equal(t, []string{"foo"}, c.GetStringMapStringSlice("map")["foo"])
318 }
319
320 func TestContextCopy(t *testing.T) {
321 c, _ := CreateTestContext(httptest.NewRecorder())
322 c.index = 2
323 c.Request, _ = http.NewRequest("POST", "/hola", nil)
324 c.handlers = HandlersChain{func(c *Context) {}}
325 c.Params = Params{Param{Key: "foo", Value: "bar"}}
326 c.Set("foo", "bar")
327
328 cp := c.Copy()
329 assert.Nil(t, cp.handlers)
330 assert.Nil(t, cp.writermem.ResponseWriter)
331 assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
332 assert.Equal(t, cp.Request, c.Request)
333 assert.Equal(t, cp.index, abortIndex)
334 assert.Equal(t, cp.Keys, c.Keys)
335 assert.Equal(t, cp.engine, c.engine)
336 assert.Equal(t, cp.Params, c.Params)
337 cp.Set("foo", "notBar")
338 assert.False(t, cp.Keys["foo"] == c.Keys["foo"])
339 }
340
341 func TestContextHandlerName(t *testing.T) {
342 c, _ := CreateTestContext(httptest.NewRecorder())
343 c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest}
344
345 assert.Regexp(t, "^(.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest$", c.HandlerName())
346 }
347
348 func TestContextHandlerNames(t *testing.T) {
349 c, _ := CreateTestContext(httptest.NewRecorder())
350 c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest, func(c *Context) {}, handlerNameTest2}
351
352 names := c.HandlerNames()
353
354 assert.True(t, len(names) == 4)
355 for _, name := range names {
356 assert.Regexp(t, `^(.*/vendor/)?(github\.com/gin-gonic/gin\.){1}(TestContextHandlerNames\.func.*){0,1}(handlerNameTest.*){0,1}`, name)
357 }
358 }
359
360 func handlerNameTest(c *Context) {
361 }
362
363 func handlerNameTest2(c *Context) {
364 }
365
366 var handlerTest HandlerFunc = func(c *Context) {
367 }
368
369 func TestContextHandler(t *testing.T) {
370 c, _ := CreateTestContext(httptest.NewRecorder())
371 c.handlers = HandlersChain{func(c *Context) {}, handlerTest}
372
373 assert.Equal(t, reflect.ValueOf(handlerTest).Pointer(), reflect.ValueOf(c.Handler()).Pointer())
374 }
375
376 func TestContextQuery(t *testing.T) {
377 c, _ := CreateTestContext(httptest.NewRecorder())
378 c.Request, _ = http.NewRequest("GET", "http://example.com/?foo=bar&page=10&id=", nil)
379
380 value, ok := c.GetQuery("foo")
381 assert.True(t, ok)
382 assert.Equal(t, "bar", value)
383 assert.Equal(t, "bar", c.DefaultQuery("foo", "none"))
384 assert.Equal(t, "bar", c.Query("foo"))
385
386 value, ok = c.GetQuery("page")
387 assert.True(t, ok)
388 assert.Equal(t, "10", value)
389 assert.Equal(t, "10", c.DefaultQuery("page", "0"))
390 assert.Equal(t, "10", c.Query("page"))
391
392 value, ok = c.GetQuery("id")
393 assert.True(t, ok)
394 assert.Empty(t, value)
395 assert.Empty(t, c.DefaultQuery("id", "nada"))
396 assert.Empty(t, c.Query("id"))
397
398 value, ok = c.GetQuery("NoKey")
399 assert.False(t, ok)
400 assert.Empty(t, value)
401 assert.Equal(t, "nada", c.DefaultQuery("NoKey", "nada"))
402 assert.Empty(t, c.Query("NoKey"))
403
404
405 value, ok = c.GetPostForm("page")
406 assert.False(t, ok)
407 assert.Empty(t, value)
408 assert.Empty(t, c.PostForm("foo"))
409 }
410
411 func TestContextDefaultQueryOnEmptyRequest(t *testing.T) {
412 c, _ := CreateTestContext(httptest.NewRecorder())
413 assert.NotPanics(t, func() {
414 value, ok := c.GetQuery("NoKey")
415 assert.False(t, ok)
416 assert.Empty(t, value)
417 })
418 assert.NotPanics(t, func() {
419 assert.Equal(t, "nada", c.DefaultQuery("NoKey", "nada"))
420 })
421 assert.NotPanics(t, func() {
422 assert.Empty(t, c.Query("NoKey"))
423 })
424 }
425
426 func TestContextQueryAndPostForm(t *testing.T) {
427 c, _ := CreateTestContext(httptest.NewRecorder())
428 body := bytes.NewBufferString("foo=bar&page=11&both=&foo=second")
429 c.Request, _ = http.NewRequest("POST",
430 "/?both=GET&id=main&id=omit&array[]=first&array[]=second&ids[a]=hi&ids[b]=3.14", body)
431 c.Request.Header.Add("Content-Type", MIMEPOSTForm)
432
433 assert.Equal(t, "bar", c.DefaultPostForm("foo", "none"))
434 assert.Equal(t, "bar", c.PostForm("foo"))
435 assert.Empty(t, c.Query("foo"))
436
437 value, ok := c.GetPostForm("page")
438 assert.True(t, ok)
439 assert.Equal(t, "11", value)
440 assert.Equal(t, "11", c.DefaultPostForm("page", "0"))
441 assert.Equal(t, "11", c.PostForm("page"))
442 assert.Empty(t, c.Query("page"))
443
444 value, ok = c.GetPostForm("both")
445 assert.True(t, ok)
446 assert.Empty(t, value)
447 assert.Empty(t, c.PostForm("both"))
448 assert.Empty(t, c.DefaultPostForm("both", "nothing"))
449 assert.Equal(t, "GET", c.Query("both"), "GET")
450
451 value, ok = c.GetQuery("id")
452 assert.True(t, ok)
453 assert.Equal(t, "main", value)
454 assert.Equal(t, "000", c.DefaultPostForm("id", "000"))
455 assert.Equal(t, "main", c.Query("id"))
456 assert.Empty(t, c.PostForm("id"))
457
458 value, ok = c.GetQuery("NoKey")
459 assert.False(t, ok)
460 assert.Empty(t, value)
461 value, ok = c.GetPostForm("NoKey")
462 assert.False(t, ok)
463 assert.Empty(t, value)
464 assert.Equal(t, "nada", c.DefaultPostForm("NoKey", "nada"))
465 assert.Equal(t, "nothing", c.DefaultQuery("NoKey", "nothing"))
466 assert.Empty(t, c.PostForm("NoKey"))
467 assert.Empty(t, c.Query("NoKey"))
468
469 var obj struct {
470 Foo string `form:"foo"`
471 ID string `form:"id"`
472 Page int `form:"page"`
473 Both string `form:"both"`
474 Array []string `form:"array[]"`
475 }
476 assert.NoError(t, c.Bind(&obj))
477 assert.Equal(t, "bar", obj.Foo, "bar")
478 assert.Equal(t, "main", obj.ID, "main")
479 assert.Equal(t, 11, obj.Page, 11)
480 assert.Empty(t, obj.Both)
481 assert.Equal(t, []string{"first", "second"}, obj.Array)
482
483 values, ok := c.GetQueryArray("array[]")
484 assert.True(t, ok)
485 assert.Equal(t, "first", values[0])
486 assert.Equal(t, "second", values[1])
487
488 values = c.QueryArray("array[]")
489 assert.Equal(t, "first", values[0])
490 assert.Equal(t, "second", values[1])
491
492 values = c.QueryArray("nokey")
493 assert.Equal(t, 0, len(values))
494
495 values = c.QueryArray("both")
496 assert.Equal(t, 1, len(values))
497 assert.Equal(t, "GET", values[0])
498
499 dicts, ok := c.GetQueryMap("ids")
500 assert.True(t, ok)
501 assert.Equal(t, "hi", dicts["a"])
502 assert.Equal(t, "3.14", dicts["b"])
503
504 dicts, ok = c.GetQueryMap("nokey")
505 assert.False(t, ok)
506 assert.Equal(t, 0, len(dicts))
507
508 dicts, ok = c.GetQueryMap("both")
509 assert.False(t, ok)
510 assert.Equal(t, 0, len(dicts))
511
512 dicts, ok = c.GetQueryMap("array")
513 assert.False(t, ok)
514 assert.Equal(t, 0, len(dicts))
515
516 dicts = c.QueryMap("ids")
517 assert.Equal(t, "hi", dicts["a"])
518 assert.Equal(t, "3.14", dicts["b"])
519
520 dicts = c.QueryMap("nokey")
521 assert.Equal(t, 0, len(dicts))
522 }
523
524 func TestContextPostFormMultipart(t *testing.T) {
525 c, _ := CreateTestContext(httptest.NewRecorder())
526 c.Request = createMultipartRequest()
527
528 var obj struct {
529 Foo string `form:"foo"`
530 Bar string `form:"bar"`
531 BarAsInt int `form:"bar"`
532 Array []string `form:"array"`
533 ID string `form:"id"`
534 TimeLocal time.Time `form:"time_local" time_format:"02/01/2006 15:04"`
535 TimeUTC time.Time `form:"time_utc" time_format:"02/01/2006 15:04" time_utc:"1"`
536 TimeLocation time.Time `form:"time_location" time_format:"02/01/2006 15:04" time_location:"Asia/Tokyo"`
537 BlankTime time.Time `form:"blank_time" time_format:"02/01/2006 15:04"`
538 }
539 assert.NoError(t, c.Bind(&obj))
540 assert.Equal(t, "bar", obj.Foo)
541 assert.Equal(t, "10", obj.Bar)
542 assert.Equal(t, 10, obj.BarAsInt)
543 assert.Equal(t, []string{"first", "second"}, obj.Array)
544 assert.Empty(t, obj.ID)
545 assert.Equal(t, "31/12/2016 14:55", obj.TimeLocal.Format("02/01/2006 15:04"))
546 assert.Equal(t, time.Local, obj.TimeLocal.Location())
547 assert.Equal(t, "31/12/2016 14:55", obj.TimeUTC.Format("02/01/2006 15:04"))
548 assert.Equal(t, time.UTC, obj.TimeUTC.Location())
549 loc, _ := time.LoadLocation("Asia/Tokyo")
550 assert.Equal(t, "31/12/2016 14:55", obj.TimeLocation.Format("02/01/2006 15:04"))
551 assert.Equal(t, loc, obj.TimeLocation.Location())
552 assert.True(t, obj.BlankTime.IsZero())
553
554 value, ok := c.GetQuery("foo")
555 assert.False(t, ok)
556 assert.Empty(t, value)
557 assert.Empty(t, c.Query("bar"))
558 assert.Equal(t, "nothing", c.DefaultQuery("id", "nothing"))
559
560 value, ok = c.GetPostForm("foo")
561 assert.True(t, ok)
562 assert.Equal(t, "bar", value)
563 assert.Equal(t, "bar", c.PostForm("foo"))
564
565 value, ok = c.GetPostForm("array")
566 assert.True(t, ok)
567 assert.Equal(t, "first", value)
568 assert.Equal(t, "first", c.PostForm("array"))
569
570 assert.Equal(t, "10", c.DefaultPostForm("bar", "nothing"))
571
572 value, ok = c.GetPostForm("id")
573 assert.True(t, ok)
574 assert.Empty(t, value)
575 assert.Empty(t, c.PostForm("id"))
576 assert.Empty(t, c.DefaultPostForm("id", "nothing"))
577
578 value, ok = c.GetPostForm("nokey")
579 assert.False(t, ok)
580 assert.Empty(t, value)
581 assert.Equal(t, "nothing", c.DefaultPostForm("nokey", "nothing"))
582
583 values, ok := c.GetPostFormArray("array")
584 assert.True(t, ok)
585 assert.Equal(t, "first", values[0])
586 assert.Equal(t, "second", values[1])
587
588 values = c.PostFormArray("array")
589 assert.Equal(t, "first", values[0])
590 assert.Equal(t, "second", values[1])
591
592 values = c.PostFormArray("nokey")
593 assert.Equal(t, 0, len(values))
594
595 values = c.PostFormArray("foo")
596 assert.Equal(t, 1, len(values))
597 assert.Equal(t, "bar", values[0])
598
599 dicts, ok := c.GetPostFormMap("names")
600 assert.True(t, ok)
601 assert.Equal(t, "thinkerou", dicts["a"])
602 assert.Equal(t, "tianou", dicts["b"])
603
604 dicts, ok = c.GetPostFormMap("nokey")
605 assert.False(t, ok)
606 assert.Equal(t, 0, len(dicts))
607
608 dicts = c.PostFormMap("names")
609 assert.Equal(t, "thinkerou", dicts["a"])
610 assert.Equal(t, "tianou", dicts["b"])
611
612 dicts = c.PostFormMap("nokey")
613 assert.Equal(t, 0, len(dicts))
614 }
615
616 func TestContextSetCookie(t *testing.T) {
617 c, _ := CreateTestContext(httptest.NewRecorder())
618 c.SetSameSite(http.SameSiteLaxMode)
619 c.SetCookie("user", "gin", 1, "/", "localhost", true, true)
620 assert.Equal(t, "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", c.Writer.Header().Get("Set-Cookie"))
621 }
622
623 func TestContextSetCookiePathEmpty(t *testing.T) {
624 c, _ := CreateTestContext(httptest.NewRecorder())
625 c.SetSameSite(http.SameSiteLaxMode)
626 c.SetCookie("user", "gin", 1, "", "localhost", true, true)
627 assert.Equal(t, "user=gin; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure; SameSite=Lax", c.Writer.Header().Get("Set-Cookie"))
628 }
629
630 func TestContextGetCookie(t *testing.T) {
631 c, _ := CreateTestContext(httptest.NewRecorder())
632 c.Request, _ = http.NewRequest("GET", "/get", nil)
633 c.Request.Header.Set("Cookie", "user=gin")
634 cookie, _ := c.Cookie("user")
635 assert.Equal(t, "gin", cookie)
636
637 _, err := c.Cookie("nokey")
638 assert.Error(t, err)
639 }
640
641 func TestContextBodyAllowedForStatus(t *testing.T) {
642 assert.False(t, false, bodyAllowedForStatus(http.StatusProcessing))
643 assert.False(t, false, bodyAllowedForStatus(http.StatusNoContent))
644 assert.False(t, false, bodyAllowedForStatus(http.StatusNotModified))
645 assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError))
646 }
647
648 type TestRender struct{}
649
650 func (*TestRender) Render(http.ResponseWriter) error {
651 return errTestRender
652 }
653
654 func (*TestRender) WriteContentType(http.ResponseWriter) {}
655
656 func TestContextRenderIfErr(t *testing.T) {
657 w := httptest.NewRecorder()
658 c, _ := CreateTestContext(w)
659
660 c.Render(http.StatusOK, &TestRender{})
661
662 assert.Equal(t, errorMsgs{&Error{Err: errTestRender, Type: 1}}, c.Errors)
663 }
664
665
666
667
668 func TestContextRenderJSON(t *testing.T) {
669 w := httptest.NewRecorder()
670 c, _ := CreateTestContext(w)
671
672 c.JSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"})
673
674 assert.Equal(t, http.StatusCreated, w.Code)
675 assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
676 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
677 }
678
679
680
681 func TestContextRenderJSONP(t *testing.T) {
682 w := httptest.NewRecorder()
683 c, _ := CreateTestContext(w)
684 c.Request, _ = http.NewRequest("GET", "http://example.com/?callback=x", nil)
685
686 c.JSONP(http.StatusCreated, H{"foo": "bar"})
687
688 assert.Equal(t, http.StatusCreated, w.Code)
689 assert.Equal(t, "x({\"foo\":\"bar\"});", w.Body.String())
690 assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
691 }
692
693
694
695 func TestContextRenderJSONPWithoutCallback(t *testing.T) {
696 w := httptest.NewRecorder()
697 c, _ := CreateTestContext(w)
698 c.Request, _ = http.NewRequest("GET", "http://example.com", nil)
699
700 c.JSONP(http.StatusCreated, H{"foo": "bar"})
701
702 assert.Equal(t, http.StatusCreated, w.Code)
703 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
704 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
705 }
706
707
708 func TestContextRenderNoContentJSON(t *testing.T) {
709 w := httptest.NewRecorder()
710 c, _ := CreateTestContext(w)
711
712 c.JSON(http.StatusNoContent, H{"foo": "bar"})
713
714 assert.Equal(t, http.StatusNoContent, w.Code)
715 assert.Empty(t, w.Body.String())
716 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
717 }
718
719
720
721 func TestContextRenderAPIJSON(t *testing.T) {
722 w := httptest.NewRecorder()
723 c, _ := CreateTestContext(w)
724
725 c.Header("Content-Type", "application/vnd.api+json")
726 c.JSON(http.StatusCreated, H{"foo": "bar"})
727
728 assert.Equal(t, http.StatusCreated, w.Code)
729 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
730 assert.Equal(t, "application/vnd.api+json", w.Header().Get("Content-Type"))
731 }
732
733
734 func TestContextRenderNoContentAPIJSON(t *testing.T) {
735 w := httptest.NewRecorder()
736 c, _ := CreateTestContext(w)
737
738 c.Header("Content-Type", "application/vnd.api+json")
739 c.JSON(http.StatusNoContent, H{"foo": "bar"})
740
741 assert.Equal(t, http.StatusNoContent, w.Code)
742 assert.Empty(t, w.Body.String())
743 assert.Equal(t, w.Header().Get("Content-Type"), "application/vnd.api+json")
744 }
745
746
747
748 func TestContextRenderIndentedJSON(t *testing.T) {
749 w := httptest.NewRecorder()
750 c, _ := CreateTestContext(w)
751
752 c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
753
754 assert.Equal(t, http.StatusCreated, w.Code)
755 assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String())
756 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
757 }
758
759
760 func TestContextRenderNoContentIndentedJSON(t *testing.T) {
761 w := httptest.NewRecorder()
762 c, _ := CreateTestContext(w)
763
764 c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
765
766 assert.Equal(t, http.StatusNoContent, w.Code)
767 assert.Empty(t, w.Body.String())
768 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
769 }
770
771
772
773 func TestContextRenderSecureJSON(t *testing.T) {
774 w := httptest.NewRecorder()
775 c, router := CreateTestContext(w)
776
777 router.SecureJsonPrefix("&&&START&&&")
778 c.SecureJSON(http.StatusCreated, []string{"foo", "bar"})
779
780 assert.Equal(t, http.StatusCreated, w.Code)
781 assert.Equal(t, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String())
782 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
783 }
784
785
786 func TestContextRenderNoContentSecureJSON(t *testing.T) {
787 w := httptest.NewRecorder()
788 c, _ := CreateTestContext(w)
789
790 c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"})
791
792 assert.Equal(t, http.StatusNoContent, w.Code)
793 assert.Empty(t, w.Body.String())
794 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
795 }
796
797 func TestContextRenderNoContentAsciiJSON(t *testing.T) {
798 w := httptest.NewRecorder()
799 c, _ := CreateTestContext(w)
800
801 c.AsciiJSON(http.StatusNoContent, []string{"lang", "Goè¯è¨€"})
802
803 assert.Equal(t, http.StatusNoContent, w.Code)
804 assert.Empty(t, w.Body.String())
805 assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
806 }
807
808
809
810
811 func TestContextRenderPureJSON(t *testing.T) {
812 w := httptest.NewRecorder()
813 c, _ := CreateTestContext(w)
814 c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"})
815 assert.Equal(t, http.StatusCreated, w.Code)
816 assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String())
817 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
818 }
819
820
821
822 func TestContextRenderHTML(t *testing.T) {
823 w := httptest.NewRecorder()
824 c, router := CreateTestContext(w)
825
826 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
827 router.SetHTMLTemplate(templ)
828
829 c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"})
830
831 assert.Equal(t, http.StatusCreated, w.Code)
832 assert.Equal(t, "Hello alexandernyquist", w.Body.String())
833 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
834 }
835
836 func TestContextRenderHTML2(t *testing.T) {
837 w := httptest.NewRecorder()
838 c, router := CreateTestContext(w)
839
840
841 router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}})
842 assert.Len(t, router.trees, 1)
843
844 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
845 re := captureOutput(t, func() {
846 SetMode(DebugMode)
847 router.SetHTMLTemplate(templ)
848 SetMode(TestMode)
849 })
850
851 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)
852
853 c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"})
854
855 assert.Equal(t, http.StatusCreated, w.Code)
856 assert.Equal(t, "Hello alexandernyquist", w.Body.String())
857 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
858 }
859
860
861 func TestContextRenderNoContentHTML(t *testing.T) {
862 w := httptest.NewRecorder()
863 c, router := CreateTestContext(w)
864 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
865 router.SetHTMLTemplate(templ)
866
867 c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"})
868
869 assert.Equal(t, http.StatusNoContent, w.Code)
870 assert.Empty(t, w.Body.String())
871 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
872 }
873
874
875
876 func TestContextRenderXML(t *testing.T) {
877 w := httptest.NewRecorder()
878 c, _ := CreateTestContext(w)
879
880 c.XML(http.StatusCreated, H{"foo": "bar"})
881
882 assert.Equal(t, http.StatusCreated, w.Code)
883 assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
884 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
885 }
886
887
888 func TestContextRenderNoContentXML(t *testing.T) {
889 w := httptest.NewRecorder()
890 c, _ := CreateTestContext(w)
891
892 c.XML(http.StatusNoContent, H{"foo": "bar"})
893
894 assert.Equal(t, http.StatusNoContent, w.Code)
895 assert.Empty(t, w.Body.String())
896 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
897 }
898
899
900
901 func TestContextRenderString(t *testing.T) {
902 w := httptest.NewRecorder()
903 c, _ := CreateTestContext(w)
904
905 c.String(http.StatusCreated, "test %s %d", "string", 2)
906
907 assert.Equal(t, http.StatusCreated, w.Code)
908 assert.Equal(t, "test string 2", w.Body.String())
909 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
910 }
911
912
913 func TestContextRenderNoContentString(t *testing.T) {
914 w := httptest.NewRecorder()
915 c, _ := CreateTestContext(w)
916
917 c.String(http.StatusNoContent, "test %s %d", "string", 2)
918
919 assert.Equal(t, http.StatusNoContent, w.Code)
920 assert.Empty(t, w.Body.String())
921 assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
922 }
923
924
925
926 func TestContextRenderHTMLString(t *testing.T) {
927 w := httptest.NewRecorder()
928 c, _ := CreateTestContext(w)
929
930 c.Header("Content-Type", "text/html; charset=utf-8")
931 c.String(http.StatusCreated, "<html>%s %d</html>", "string", 3)
932
933 assert.Equal(t, http.StatusCreated, w.Code)
934 assert.Equal(t, "<html>string 3</html>", w.Body.String())
935 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
936 }
937
938
939 func TestContextRenderNoContentHTMLString(t *testing.T) {
940 w := httptest.NewRecorder()
941 c, _ := CreateTestContext(w)
942
943 c.Header("Content-Type", "text/html; charset=utf-8")
944 c.String(http.StatusNoContent, "<html>%s %d</html>", "string", 3)
945
946 assert.Equal(t, http.StatusNoContent, w.Code)
947 assert.Empty(t, w.Body.String())
948 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
949 }
950
951
952
953 func TestContextRenderData(t *testing.T) {
954 w := httptest.NewRecorder()
955 c, _ := CreateTestContext(w)
956
957 c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`))
958
959 assert.Equal(t, http.StatusCreated, w.Code)
960 assert.Equal(t, "foo,bar", w.Body.String())
961 assert.Equal(t, "text/csv", w.Header().Get("Content-Type"))
962 }
963
964
965 func TestContextRenderNoContentData(t *testing.T) {
966 w := httptest.NewRecorder()
967 c, _ := CreateTestContext(w)
968
969 c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`))
970
971 assert.Equal(t, http.StatusNoContent, w.Code)
972 assert.Empty(t, w.Body.String())
973 assert.Equal(t, "text/csv", w.Header().Get("Content-Type"))
974 }
975
976 func TestContextRenderSSE(t *testing.T) {
977 w := httptest.NewRecorder()
978 c, _ := CreateTestContext(w)
979
980 c.SSEvent("float", 1.5)
981 c.Render(-1, sse.Event{
982 Id: "123",
983 Data: "text",
984 })
985 c.SSEvent("chat", H{
986 "foo": "bar",
987 "bar": "foo",
988 })
989
990 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))
991 }
992
993 func TestContextRenderFile(t *testing.T) {
994 w := httptest.NewRecorder()
995 c, _ := CreateTestContext(w)
996
997 c.Request, _ = http.NewRequest("GET", "/", nil)
998 c.File("./gin.go")
999
1000 assert.Equal(t, http.StatusOK, w.Code)
1001 assert.Contains(t, w.Body.String(), "func New() *Engine {")
1002
1003
1004 assert.NotEqual(t, "", w.Header().Get("Content-Type"))
1005 }
1006
1007 func TestContextRenderFileFromFS(t *testing.T) {
1008 w := httptest.NewRecorder()
1009 c, _ := CreateTestContext(w)
1010
1011 c.Request, _ = http.NewRequest("GET", "/some/path", nil)
1012 c.FileFromFS("./gin.go", Dir(".", false))
1013
1014 assert.Equal(t, http.StatusOK, w.Code)
1015 assert.Contains(t, w.Body.String(), "func New() *Engine {")
1016
1017
1018 assert.NotEqual(t, "", w.Header().Get("Content-Type"))
1019 assert.Equal(t, "/some/path", c.Request.URL.Path)
1020 }
1021
1022 func TestContextRenderAttachment(t *testing.T) {
1023 w := httptest.NewRecorder()
1024 c, _ := CreateTestContext(w)
1025 newFilename := "new_filename.go"
1026
1027 c.Request, _ = http.NewRequest("GET", "/", nil)
1028 c.FileAttachment("./gin.go", newFilename)
1029
1030 assert.Equal(t, 200, w.Code)
1031 assert.Contains(t, w.Body.String(), "func New() *Engine {")
1032 assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.Header().Get("Content-Disposition"))
1033 }
1034
1035 func TestContextRenderAndEscapeAttachment(t *testing.T) {
1036 w := httptest.NewRecorder()
1037 c, _ := CreateTestContext(w)
1038 maliciousFilename := "tampering_field.sh\"; \\\"; dummy=.go"
1039 actualEscapedResponseFilename := "tampering_field.sh\\\"; \\\\\\\"; dummy=.go"
1040
1041 c.Request, _ = http.NewRequest("GET", "/", nil)
1042 c.FileAttachment("./gin.go", maliciousFilename)
1043
1044 assert.Equal(t, 200, w.Code)
1045 assert.Contains(t, w.Body.String(), "func New() *Engine {")
1046 assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", actualEscapedResponseFilename), w.Header().Get("Content-Disposition"))
1047 }
1048
1049 func TestContextRenderUTF8Attachment(t *testing.T) {
1050 w := httptest.NewRecorder()
1051 c, _ := CreateTestContext(w)
1052 newFilename := "new🧡_filename.go"
1053
1054 c.Request, _ = http.NewRequest("GET", "/", nil)
1055 c.FileAttachment("./gin.go", newFilename)
1056
1057 assert.Equal(t, 200, w.Code)
1058 assert.Contains(t, w.Body.String(), "func New() *Engine {")
1059 assert.Equal(t, `attachment; filename*=UTF-8''`+url.QueryEscape(newFilename), w.Header().Get("Content-Disposition"))
1060 }
1061
1062
1063
1064 func TestContextRenderYAML(t *testing.T) {
1065 w := httptest.NewRecorder()
1066 c, _ := CreateTestContext(w)
1067
1068 c.YAML(http.StatusCreated, H{"foo": "bar"})
1069
1070 assert.Equal(t, http.StatusCreated, w.Code)
1071 assert.Equal(t, "foo: bar\n", w.Body.String())
1072 assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
1073 }
1074
1075
1076
1077 func TestContextRenderTOML(t *testing.T) {
1078 w := httptest.NewRecorder()
1079 c, _ := CreateTestContext(w)
1080
1081 c.TOML(http.StatusCreated, H{"foo": "bar"})
1082
1083 assert.Equal(t, http.StatusCreated, w.Code)
1084 assert.Equal(t, "foo = 'bar'\n", w.Body.String())
1085 assert.Equal(t, "application/toml; charset=utf-8", w.Header().Get("Content-Type"))
1086 }
1087
1088
1089
1090
1091 func TestContextRenderProtoBuf(t *testing.T) {
1092 w := httptest.NewRecorder()
1093 c, _ := CreateTestContext(w)
1094
1095 reps := []int64{int64(1), int64(2)}
1096 label := "test"
1097 data := &testdata.Test{
1098 Label: &label,
1099 Reps: reps,
1100 }
1101
1102 c.ProtoBuf(http.StatusCreated, data)
1103
1104 protoData, err := proto.Marshal(data)
1105 assert.NoError(t, err)
1106
1107 assert.Equal(t, http.StatusCreated, w.Code)
1108 assert.Equal(t, string(protoData), w.Body.String())
1109 assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
1110 }
1111
1112 func TestContextHeaders(t *testing.T) {
1113 c, _ := CreateTestContext(httptest.NewRecorder())
1114 c.Header("Content-Type", "text/plain")
1115 c.Header("X-Custom", "value")
1116
1117 assert.Equal(t, "text/plain", c.Writer.Header().Get("Content-Type"))
1118 assert.Equal(t, "value", c.Writer.Header().Get("X-Custom"))
1119
1120 c.Header("Content-Type", "text/html")
1121 c.Header("X-Custom", "")
1122
1123 assert.Equal(t, "text/html", c.Writer.Header().Get("Content-Type"))
1124 _, exist := c.Writer.Header()["X-Custom"]
1125 assert.False(t, exist)
1126 }
1127
1128
1129 func TestContextRenderRedirectWithRelativePath(t *testing.T) {
1130 w := httptest.NewRecorder()
1131 c, _ := CreateTestContext(w)
1132
1133 c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
1134 assert.Panics(t, func() { c.Redirect(299, "/new_path") })
1135 assert.Panics(t, func() { c.Redirect(309, "/new_path") })
1136
1137 c.Redirect(http.StatusMovedPermanently, "/path")
1138 c.Writer.WriteHeaderNow()
1139 assert.Equal(t, http.StatusMovedPermanently, w.Code)
1140 assert.Equal(t, "/path", w.Header().Get("Location"))
1141 }
1142
1143 func TestContextRenderRedirectWithAbsolutePath(t *testing.T) {
1144 w := httptest.NewRecorder()
1145 c, _ := CreateTestContext(w)
1146
1147 c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
1148 c.Redirect(http.StatusFound, "http://google.com")
1149 c.Writer.WriteHeaderNow()
1150
1151 assert.Equal(t, http.StatusFound, w.Code)
1152 assert.Equal(t, "http://google.com", w.Header().Get("Location"))
1153 }
1154
1155 func TestContextRenderRedirectWith201(t *testing.T) {
1156 w := httptest.NewRecorder()
1157 c, _ := CreateTestContext(w)
1158
1159 c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
1160 c.Redirect(http.StatusCreated, "/resource")
1161 c.Writer.WriteHeaderNow()
1162
1163 assert.Equal(t, http.StatusCreated, w.Code)
1164 assert.Equal(t, "/resource", w.Header().Get("Location"))
1165 }
1166
1167 func TestContextRenderRedirectAll(t *testing.T) {
1168 c, _ := CreateTestContext(httptest.NewRecorder())
1169 c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
1170 assert.Panics(t, func() { c.Redirect(http.StatusOK, "/resource") })
1171 assert.Panics(t, func() { c.Redirect(http.StatusAccepted, "/resource") })
1172 assert.Panics(t, func() { c.Redirect(299, "/resource") })
1173 assert.Panics(t, func() { c.Redirect(309, "/resource") })
1174 assert.NotPanics(t, func() { c.Redirect(http.StatusMultipleChoices, "/resource") })
1175 assert.NotPanics(t, func() { c.Redirect(http.StatusPermanentRedirect, "/resource") })
1176 }
1177
1178 func TestContextNegotiationWithJSON(t *testing.T) {
1179 w := httptest.NewRecorder()
1180 c, _ := CreateTestContext(w)
1181 c.Request, _ = http.NewRequest("POST", "", nil)
1182
1183 c.Negotiate(http.StatusOK, Negotiate{
1184 Offered: []string{MIMEJSON, MIMEXML, MIMEYAML},
1185 Data: H{"foo": "bar"},
1186 })
1187
1188 assert.Equal(t, http.StatusOK, w.Code)
1189 assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
1190 assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
1191 }
1192
1193 func TestContextNegotiationWithXML(t *testing.T) {
1194 w := httptest.NewRecorder()
1195 c, _ := CreateTestContext(w)
1196 c.Request, _ = http.NewRequest("POST", "", nil)
1197
1198 c.Negotiate(http.StatusOK, Negotiate{
1199 Offered: []string{MIMEXML, MIMEJSON, MIMEYAML},
1200 Data: H{"foo": "bar"},
1201 })
1202
1203 assert.Equal(t, http.StatusOK, w.Code)
1204 assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
1205 assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
1206 }
1207
1208 func TestContextNegotiationWithYAML(t *testing.T) {
1209 w := httptest.NewRecorder()
1210 c, _ := CreateTestContext(w)
1211 c.Request, _ = http.NewRequest("POST", "", nil)
1212
1213 c.Negotiate(http.StatusOK, Negotiate{
1214 Offered: []string{MIMEYAML, MIMEXML, MIMEJSON, MIMETOML},
1215 Data: H{"foo": "bar"},
1216 })
1217
1218 assert.Equal(t, http.StatusOK, w.Code)
1219 assert.Equal(t, "foo: bar\n", w.Body.String())
1220 assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
1221 }
1222
1223 func TestContextNegotiationWithTOML(t *testing.T) {
1224 w := httptest.NewRecorder()
1225 c, _ := CreateTestContext(w)
1226 c.Request, _ = http.NewRequest("POST", "", nil)
1227
1228 c.Negotiate(http.StatusOK, Negotiate{
1229 Offered: []string{MIMETOML, MIMEXML, MIMEJSON, MIMEYAML},
1230 Data: H{"foo": "bar"},
1231 })
1232
1233 assert.Equal(t, http.StatusOK, w.Code)
1234 assert.Equal(t, "foo = 'bar'\n", w.Body.String())
1235 assert.Equal(t, "application/toml; charset=utf-8", w.Header().Get("Content-Type"))
1236 }
1237
1238 func TestContextNegotiationWithHTML(t *testing.T) {
1239 w := httptest.NewRecorder()
1240 c, router := CreateTestContext(w)
1241 c.Request, _ = http.NewRequest("POST", "", nil)
1242 templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
1243 router.SetHTMLTemplate(templ)
1244
1245 c.Negotiate(http.StatusOK, Negotiate{
1246 Offered: []string{MIMEHTML},
1247 Data: H{"name": "gin"},
1248 HTMLName: "t",
1249 })
1250
1251 assert.Equal(t, http.StatusOK, w.Code)
1252 assert.Equal(t, "Hello gin", w.Body.String())
1253 assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
1254 }
1255
1256 func TestContextNegotiationNotSupport(t *testing.T) {
1257 w := httptest.NewRecorder()
1258 c, _ := CreateTestContext(w)
1259 c.Request, _ = http.NewRequest("POST", "", nil)
1260
1261 c.Negotiate(http.StatusOK, Negotiate{
1262 Offered: []string{MIMEPOSTForm},
1263 })
1264
1265 assert.Equal(t, http.StatusNotAcceptable, w.Code)
1266 assert.Equal(t, c.index, abortIndex)
1267 assert.True(t, c.IsAborted())
1268 }
1269
1270 func TestContextNegotiationFormat(t *testing.T) {
1271 c, _ := CreateTestContext(httptest.NewRecorder())
1272 c.Request, _ = http.NewRequest("POST", "", nil)
1273
1274 assert.Panics(t, func() { c.NegotiateFormat() })
1275 assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML))
1276 assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML, MIMEJSON))
1277 }
1278
1279 func TestContextNegotiationFormatWithAccept(t *testing.T) {
1280 c, _ := CreateTestContext(httptest.NewRecorder())
1281 c.Request, _ = http.NewRequest("POST", "/", nil)
1282 c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8")
1283
1284 assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEJSON, MIMEXML))
1285 assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEXML, MIMEHTML))
1286 assert.Empty(t, c.NegotiateFormat(MIMEJSON))
1287 }
1288
1289 func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
1290 c, _ := CreateTestContext(httptest.NewRecorder())
1291 c.Request, _ = http.NewRequest("POST", "/", nil)
1292 c.Request.Header.Add("Accept", "*/*")
1293
1294 assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
1295 assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
1296 assert.Equal(t, c.NegotiateFormat("application/*"), "application/*")
1297 assert.Equal(t, c.NegotiateFormat(MIMEJSON), MIMEJSON)
1298 assert.Equal(t, c.NegotiateFormat(MIMEXML), MIMEXML)
1299 assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML)
1300
1301 c, _ = CreateTestContext(httptest.NewRecorder())
1302 c.Request, _ = http.NewRequest("POST", "/", nil)
1303 c.Request.Header.Add("Accept", "text/*")
1304
1305 assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
1306 assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
1307 assert.Equal(t, c.NegotiateFormat("application/*"), "")
1308 assert.Equal(t, c.NegotiateFormat(MIMEJSON), "")
1309 assert.Equal(t, c.NegotiateFormat(MIMEXML), "")
1310 assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML)
1311 }
1312
1313 func TestContextNegotiationFormatCustom(t *testing.T) {
1314 c, _ := CreateTestContext(httptest.NewRecorder())
1315 c.Request, _ = http.NewRequest("POST", "/", nil)
1316 c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8")
1317
1318 c.Accepted = nil
1319 c.SetAccepted(MIMEJSON, MIMEXML)
1320
1321 assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML))
1322 assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML, MIMEHTML))
1323 assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON))
1324 }
1325
1326 func TestContextNegotiationFormat2(t *testing.T) {
1327 c, _ := CreateTestContext(httptest.NewRecorder())
1328 c.Request, _ = http.NewRequest("POST", "/", nil)
1329 c.Request.Header.Add("Accept", "image/tiff-fx")
1330
1331 assert.Equal(t, "", c.NegotiateFormat("image/tiff"))
1332 }
1333
1334 func TestContextIsAborted(t *testing.T) {
1335 c, _ := CreateTestContext(httptest.NewRecorder())
1336 assert.False(t, c.IsAborted())
1337
1338 c.Abort()
1339 assert.True(t, c.IsAborted())
1340
1341 c.Next()
1342 assert.True(t, c.IsAborted())
1343
1344 c.index++
1345 assert.True(t, c.IsAborted())
1346 }
1347
1348
1349
1350 func TestContextAbortWithStatus(t *testing.T) {
1351 w := httptest.NewRecorder()
1352 c, _ := CreateTestContext(w)
1353
1354 c.index = 4
1355 c.AbortWithStatus(http.StatusUnauthorized)
1356
1357 assert.Equal(t, abortIndex, c.index)
1358 assert.Equal(t, http.StatusUnauthorized, c.Writer.Status())
1359 assert.Equal(t, http.StatusUnauthorized, w.Code)
1360 assert.True(t, c.IsAborted())
1361 }
1362
1363 type testJSONAbortMsg struct {
1364 Foo string `json:"foo"`
1365 Bar string `json:"bar"`
1366 }
1367
1368 func TestContextAbortWithStatusJSON(t *testing.T) {
1369 w := httptest.NewRecorder()
1370 c, _ := CreateTestContext(w)
1371 c.index = 4
1372
1373 in := new(testJSONAbortMsg)
1374 in.Bar = "barValue"
1375 in.Foo = "fooValue"
1376
1377 c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in)
1378
1379 assert.Equal(t, abortIndex, c.index)
1380 assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status())
1381 assert.Equal(t, http.StatusUnsupportedMediaType, w.Code)
1382 assert.True(t, c.IsAborted())
1383
1384 contentType := w.Header().Get("Content-Type")
1385 assert.Equal(t, "application/json; charset=utf-8", contentType)
1386
1387 buf := new(bytes.Buffer)
1388 _, err := buf.ReadFrom(w.Body)
1389 assert.NoError(t, err)
1390 jsonStringBody := buf.String()
1391 assert.Equal(t, "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}", jsonStringBody)
1392 }
1393
1394 func TestContextError(t *testing.T) {
1395 c, _ := CreateTestContext(httptest.NewRecorder())
1396 assert.Empty(t, c.Errors)
1397
1398 firstErr := errors.New("first error")
1399 c.Error(firstErr)
1400 assert.Len(t, c.Errors, 1)
1401 assert.Equal(t, "Error #01: first error\n", c.Errors.String())
1402
1403 secondErr := errors.New("second error")
1404 c.Error(&Error{
1405 Err: secondErr,
1406 Meta: "some data 2",
1407 Type: ErrorTypePublic,
1408 })
1409 assert.Len(t, c.Errors, 2)
1410
1411 assert.Equal(t, firstErr, c.Errors[0].Err)
1412 assert.Nil(t, c.Errors[0].Meta)
1413 assert.Equal(t, ErrorTypePrivate, c.Errors[0].Type)
1414
1415 assert.Equal(t, secondErr, c.Errors[1].Err)
1416 assert.Equal(t, "some data 2", c.Errors[1].Meta)
1417 assert.Equal(t, ErrorTypePublic, c.Errors[1].Type)
1418
1419 assert.Equal(t, c.Errors.Last(), c.Errors[1])
1420
1421 defer func() {
1422 if recover() == nil {
1423 t.Error("didn't panic")
1424 }
1425 }()
1426 c.Error(nil)
1427 }
1428
1429 func TestContextTypedError(t *testing.T) {
1430 c, _ := CreateTestContext(httptest.NewRecorder())
1431 c.Error(errors.New("externo 0")).SetType(ErrorTypePublic)
1432 c.Error(errors.New("interno 0")).SetType(ErrorTypePrivate)
1433
1434 for _, err := range c.Errors.ByType(ErrorTypePublic) {
1435 assert.Equal(t, ErrorTypePublic, err.Type)
1436 }
1437 for _, err := range c.Errors.ByType(ErrorTypePrivate) {
1438 assert.Equal(t, ErrorTypePrivate, err.Type)
1439 }
1440 assert.Equal(t, []string{"externo 0", "interno 0"}, c.Errors.Errors())
1441 }
1442
1443 func TestContextAbortWithError(t *testing.T) {
1444 w := httptest.NewRecorder()
1445 c, _ := CreateTestContext(w)
1446
1447 c.AbortWithError(http.StatusUnauthorized, errors.New("bad input")).SetMeta("some input")
1448
1449 assert.Equal(t, http.StatusUnauthorized, w.Code)
1450 assert.Equal(t, abortIndex, c.index)
1451 assert.True(t, c.IsAborted())
1452 }
1453
1454 func TestContextClientIP(t *testing.T) {
1455 c, _ := CreateTestContext(httptest.NewRecorder())
1456 c.Request, _ = http.NewRequest("POST", "/", nil)
1457 c.engine.trustedCIDRs, _ = c.engine.prepareTrustedCIDRs()
1458 resetContextForClientIPTests(c)
1459
1460
1461
1462 assert.Equal(t, "20.20.20.20", c.ClientIP())
1463
1464 c.Request.Header.Del("X-Forwarded-For")
1465 assert.Equal(t, "10.10.10.10", c.ClientIP())
1466
1467 c.Request.Header.Set("X-Forwarded-For", "30.30.30.30 ")
1468 assert.Equal(t, "30.30.30.30", c.ClientIP())
1469
1470 c.Request.Header.Del("X-Forwarded-For")
1471 c.Request.Header.Del("X-Real-IP")
1472 c.engine.TrustedPlatform = PlatformGoogleAppEngine
1473 assert.Equal(t, "50.50.50.50", c.ClientIP())
1474
1475 c.Request.Header.Del("X-Appengine-Remote-Addr")
1476 assert.Equal(t, "40.40.40.40", c.ClientIP())
1477
1478
1479 c.Request.RemoteAddr = "50.50.50.50"
1480 assert.Empty(t, c.ClientIP())
1481
1482
1483 resetContextForClientIPTests(c)
1484
1485
1486 c.Request.RemoteAddr = "[::1]:12345"
1487 assert.Equal(t, "20.20.20.20", c.ClientIP())
1488
1489 resetContextForClientIPTests(c)
1490
1491 _ = c.engine.SetTrustedProxies([]string{})
1492 c.engine.RemoteIPHeaders = []string{"X-Forwarded-For"}
1493 assert.Equal(t, "40.40.40.40", c.ClientIP())
1494
1495
1496 _ = c.engine.SetTrustedProxies(nil)
1497 assert.Equal(t, "40.40.40.40", c.ClientIP())
1498
1499
1500 _ = c.engine.SetTrustedProxies([]string{"30.30.30.30"})
1501 assert.Equal(t, "40.40.40.40", c.ClientIP())
1502
1503
1504 _ = c.engine.SetTrustedProxies([]string{"40.40.40.40"})
1505 assert.Equal(t, "30.30.30.30", c.ClientIP())
1506
1507
1508 _ = c.engine.SetTrustedProxies([]string{"40.40.40.40", "30.30.30.30", "20.20.20.20"})
1509 assert.Equal(t, "20.20.20.20", c.ClientIP())
1510
1511
1512 _ = c.engine.SetTrustedProxies([]string{"40.40.25.25/16", "30.30.30.30"})
1513 assert.Equal(t, "20.20.20.20", c.ClientIP())
1514
1515
1516 _ = c.engine.SetTrustedProxies([]string{"foo"})
1517 assert.Equal(t, "40.40.40.40", c.ClientIP())
1518
1519
1520 _ = c.engine.SetTrustedProxies([]string{"bar"})
1521 assert.Equal(t, "40.40.40.40", c.ClientIP())
1522
1523
1524 _ = c.engine.SetTrustedProxies([]string{"40.40.40.40"})
1525 c.Request.Header.Set("X-Forwarded-For", " blah ")
1526 assert.Equal(t, "40.40.40.40", c.ClientIP())
1527
1528
1529
1530
1531 _ = c.engine.SetTrustedProxies([]string{"baz"})
1532 c.Request.Header.Set("X-Forwarded-For", " 30.30.30.30 ")
1533 assert.Equal(t, "40.40.40.40", c.ClientIP())
1534
1535 _ = c.engine.SetTrustedProxies([]string{"40.40.40.40"})
1536 c.Request.Header.Del("X-Forwarded-For")
1537 c.engine.RemoteIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"}
1538 assert.Equal(t, "10.10.10.10", c.ClientIP())
1539
1540 c.engine.RemoteIPHeaders = []string{}
1541 c.engine.TrustedPlatform = PlatformGoogleAppEngine
1542 assert.Equal(t, "50.50.50.50", c.ClientIP())
1543
1544
1545 c.engine.TrustedPlatform = "X-CDN-IP"
1546 c.Request.Header.Set("X-CDN-IP", "80.80.80.80")
1547 assert.Equal(t, "80.80.80.80", c.ClientIP())
1548
1549 c.engine.TrustedPlatform = "X-Wrong-Header"
1550 assert.Equal(t, "40.40.40.40", c.ClientIP())
1551
1552 c.Request.Header.Del("X-CDN-IP")
1553
1554 c.engine.TrustedPlatform = ""
1555 assert.Equal(t, "40.40.40.40", c.ClientIP())
1556
1557
1558 c.engine.AppEngine = true
1559 assert.Equal(t, "50.50.50.50", c.ClientIP())
1560 c.engine.AppEngine = false
1561 c.engine.TrustedPlatform = PlatformGoogleAppEngine
1562
1563 c.Request.Header.Del("X-Appengine-Remote-Addr")
1564 assert.Equal(t, "40.40.40.40", c.ClientIP())
1565
1566 c.engine.TrustedPlatform = PlatformCloudflare
1567 assert.Equal(t, "60.60.60.60", c.ClientIP())
1568
1569 c.Request.Header.Del("CF-Connecting-IP")
1570 assert.Equal(t, "40.40.40.40", c.ClientIP())
1571
1572 c.engine.TrustedPlatform = ""
1573
1574
1575 c.Request.RemoteAddr = "50.50.50.50"
1576 assert.Empty(t, c.ClientIP())
1577 }
1578
1579 func resetContextForClientIPTests(c *Context) {
1580 c.Request.Header.Set("X-Real-IP", " 10.10.10.10 ")
1581 c.Request.Header.Set("X-Forwarded-For", " 20.20.20.20, 30.30.30.30")
1582 c.Request.Header.Set("X-Appengine-Remote-Addr", "50.50.50.50")
1583 c.Request.Header.Set("CF-Connecting-IP", "60.60.60.60")
1584 c.Request.RemoteAddr = " 40.40.40.40:42123 "
1585 c.engine.TrustedPlatform = ""
1586 c.engine.trustedCIDRs = defaultTrustedCIDRs
1587 c.engine.AppEngine = false
1588 }
1589
1590 func TestContextContentType(t *testing.T) {
1591 c, _ := CreateTestContext(httptest.NewRecorder())
1592 c.Request, _ = http.NewRequest("POST", "/", nil)
1593 c.Request.Header.Set("Content-Type", "application/json; charset=utf-8")
1594
1595 assert.Equal(t, "application/json", c.ContentType())
1596 }
1597
1598 func TestContextAutoBindJSON(t *testing.T) {
1599 c, _ := CreateTestContext(httptest.NewRecorder())
1600 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
1601 c.Request.Header.Add("Content-Type", MIMEJSON)
1602
1603 var obj struct {
1604 Foo string `json:"foo"`
1605 Bar string `json:"bar"`
1606 }
1607 assert.NoError(t, c.Bind(&obj))
1608 assert.Equal(t, "foo", obj.Bar)
1609 assert.Equal(t, "bar", obj.Foo)
1610 assert.Empty(t, c.Errors)
1611 }
1612
1613 func TestContextBindWithJSON(t *testing.T) {
1614 w := httptest.NewRecorder()
1615 c, _ := CreateTestContext(w)
1616
1617 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
1618 c.Request.Header.Add("Content-Type", MIMEXML)
1619
1620 var obj struct {
1621 Foo string `json:"foo"`
1622 Bar string `json:"bar"`
1623 }
1624 assert.NoError(t, c.BindJSON(&obj))
1625 assert.Equal(t, "foo", obj.Bar)
1626 assert.Equal(t, "bar", obj.Foo)
1627 assert.Equal(t, 0, w.Body.Len())
1628 }
1629
1630 func TestContextBindWithXML(t *testing.T) {
1631 w := httptest.NewRecorder()
1632 c, _ := CreateTestContext(w)
1633
1634 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
1635 <root>
1636 <foo>FOO</foo>
1637 <bar>BAR</bar>
1638 </root>`))
1639 c.Request.Header.Add("Content-Type", MIMEXML)
1640
1641 var obj struct {
1642 Foo string `xml:"foo"`
1643 Bar string `xml:"bar"`
1644 }
1645 assert.NoError(t, c.BindXML(&obj))
1646 assert.Equal(t, "FOO", obj.Foo)
1647 assert.Equal(t, "BAR", obj.Bar)
1648 assert.Equal(t, 0, w.Body.Len())
1649 }
1650
1651 func TestContextBindHeader(t *testing.T) {
1652 w := httptest.NewRecorder()
1653 c, _ := CreateTestContext(w)
1654
1655 c.Request, _ = http.NewRequest("POST", "/", nil)
1656 c.Request.Header.Add("rate", "8000")
1657 c.Request.Header.Add("domain", "music")
1658 c.Request.Header.Add("limit", "1000")
1659
1660 var testHeader struct {
1661 Rate int `header:"Rate"`
1662 Domain string `header:"Domain"`
1663 Limit int `header:"limit"`
1664 }
1665
1666 assert.NoError(t, c.BindHeader(&testHeader))
1667 assert.Equal(t, 8000, testHeader.Rate)
1668 assert.Equal(t, "music", testHeader.Domain)
1669 assert.Equal(t, 1000, testHeader.Limit)
1670 assert.Equal(t, 0, w.Body.Len())
1671 }
1672
1673 func TestContextBindWithQuery(t *testing.T) {
1674 w := httptest.NewRecorder()
1675 c, _ := CreateTestContext(w)
1676
1677 c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo", bytes.NewBufferString("foo=unused"))
1678
1679 var obj struct {
1680 Foo string `form:"foo"`
1681 Bar string `form:"bar"`
1682 }
1683 assert.NoError(t, c.BindQuery(&obj))
1684 assert.Equal(t, "foo", obj.Bar)
1685 assert.Equal(t, "bar", obj.Foo)
1686 assert.Equal(t, 0, w.Body.Len())
1687 }
1688
1689 func TestContextBindWithYAML(t *testing.T) {
1690 w := httptest.NewRecorder()
1691 c, _ := CreateTestContext(w)
1692
1693 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo"))
1694 c.Request.Header.Add("Content-Type", MIMEXML)
1695
1696 var obj struct {
1697 Foo string `yaml:"foo"`
1698 Bar string `yaml:"bar"`
1699 }
1700 assert.NoError(t, c.BindYAML(&obj))
1701 assert.Equal(t, "foo", obj.Bar)
1702 assert.Equal(t, "bar", obj.Foo)
1703 assert.Equal(t, 0, w.Body.Len())
1704 }
1705
1706 func TestContextBindWithTOML(t *testing.T) {
1707 w := httptest.NewRecorder()
1708 c, _ := CreateTestContext(w)
1709
1710 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo = 'bar'\nbar = 'foo'"))
1711 c.Request.Header.Add("Content-Type", MIMEXML)
1712
1713 var obj struct {
1714 Foo string `toml:"foo"`
1715 Bar string `toml:"bar"`
1716 }
1717 assert.NoError(t, c.BindTOML(&obj))
1718 assert.Equal(t, "foo", obj.Bar)
1719 assert.Equal(t, "bar", obj.Foo)
1720 assert.Equal(t, 0, w.Body.Len())
1721 }
1722
1723 func TestContextBadAutoBind(t *testing.T) {
1724 w := httptest.NewRecorder()
1725 c, _ := CreateTestContext(w)
1726
1727 c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}"))
1728 c.Request.Header.Add("Content-Type", MIMEJSON)
1729 var obj struct {
1730 Foo string `json:"foo"`
1731 Bar string `json:"bar"`
1732 }
1733
1734 assert.False(t, c.IsAborted())
1735 assert.Error(t, c.Bind(&obj))
1736 c.Writer.WriteHeaderNow()
1737
1738 assert.Empty(t, obj.Bar)
1739 assert.Empty(t, obj.Foo)
1740 assert.Equal(t, http.StatusBadRequest, w.Code)
1741 assert.True(t, c.IsAborted())
1742 }
1743
1744 func TestContextAutoShouldBindJSON(t *testing.T) {
1745 c, _ := CreateTestContext(httptest.NewRecorder())
1746 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
1747 c.Request.Header.Add("Content-Type", MIMEJSON)
1748
1749 var obj struct {
1750 Foo string `json:"foo"`
1751 Bar string `json:"bar"`
1752 }
1753 assert.NoError(t, c.ShouldBind(&obj))
1754 assert.Equal(t, "foo", obj.Bar)
1755 assert.Equal(t, "bar", obj.Foo)
1756 assert.Empty(t, c.Errors)
1757 }
1758
1759 func TestContextShouldBindWithJSON(t *testing.T) {
1760 w := httptest.NewRecorder()
1761 c, _ := CreateTestContext(w)
1762
1763 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
1764 c.Request.Header.Add("Content-Type", MIMEXML)
1765
1766 var obj struct {
1767 Foo string `json:"foo"`
1768 Bar string `json:"bar"`
1769 }
1770 assert.NoError(t, c.ShouldBindJSON(&obj))
1771 assert.Equal(t, "foo", obj.Bar)
1772 assert.Equal(t, "bar", obj.Foo)
1773 assert.Equal(t, 0, w.Body.Len())
1774 }
1775
1776 func TestContextShouldBindWithXML(t *testing.T) {
1777 w := httptest.NewRecorder()
1778 c, _ := CreateTestContext(w)
1779
1780 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
1781 <root>
1782 <foo>FOO</foo>
1783 <bar>BAR</bar>
1784 </root>`))
1785 c.Request.Header.Add("Content-Type", MIMEXML)
1786
1787 var obj struct {
1788 Foo string `xml:"foo"`
1789 Bar string `xml:"bar"`
1790 }
1791 assert.NoError(t, c.ShouldBindXML(&obj))
1792 assert.Equal(t, "FOO", obj.Foo)
1793 assert.Equal(t, "BAR", obj.Bar)
1794 assert.Equal(t, 0, w.Body.Len())
1795 }
1796
1797 func TestContextShouldBindHeader(t *testing.T) {
1798 w := httptest.NewRecorder()
1799 c, _ := CreateTestContext(w)
1800
1801 c.Request, _ = http.NewRequest("POST", "/", nil)
1802 c.Request.Header.Add("rate", "8000")
1803 c.Request.Header.Add("domain", "music")
1804 c.Request.Header.Add("limit", "1000")
1805
1806 var testHeader struct {
1807 Rate int `header:"Rate"`
1808 Domain string `header:"Domain"`
1809 Limit int `header:"limit"`
1810 }
1811
1812 assert.NoError(t, c.ShouldBindHeader(&testHeader))
1813 assert.Equal(t, 8000, testHeader.Rate)
1814 assert.Equal(t, "music", testHeader.Domain)
1815 assert.Equal(t, 1000, testHeader.Limit)
1816 assert.Equal(t, 0, w.Body.Len())
1817 }
1818
1819 func TestContextShouldBindWithQuery(t *testing.T) {
1820 w := httptest.NewRecorder()
1821 c, _ := CreateTestContext(w)
1822
1823 c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo&Foo=bar1&Bar=foo1", bytes.NewBufferString("foo=unused"))
1824
1825 var obj struct {
1826 Foo string `form:"foo"`
1827 Bar string `form:"bar"`
1828 Foo1 string `form:"Foo"`
1829 Bar1 string `form:"Bar"`
1830 }
1831 assert.NoError(t, c.ShouldBindQuery(&obj))
1832 assert.Equal(t, "foo", obj.Bar)
1833 assert.Equal(t, "bar", obj.Foo)
1834 assert.Equal(t, "foo1", obj.Bar1)
1835 assert.Equal(t, "bar1", obj.Foo1)
1836 assert.Equal(t, 0, w.Body.Len())
1837 }
1838
1839 func TestContextShouldBindWithYAML(t *testing.T) {
1840 w := httptest.NewRecorder()
1841 c, _ := CreateTestContext(w)
1842
1843 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo"))
1844 c.Request.Header.Add("Content-Type", MIMEXML)
1845
1846 var obj struct {
1847 Foo string `yaml:"foo"`
1848 Bar string `yaml:"bar"`
1849 }
1850 assert.NoError(t, c.ShouldBindYAML(&obj))
1851 assert.Equal(t, "foo", obj.Bar)
1852 assert.Equal(t, "bar", obj.Foo)
1853 assert.Equal(t, 0, w.Body.Len())
1854 }
1855
1856 func TestContextShouldBindWithTOML(t *testing.T) {
1857 w := httptest.NewRecorder()
1858 c, _ := CreateTestContext(w)
1859
1860 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo='bar'\nbar= 'foo'"))
1861 c.Request.Header.Add("Content-Type", MIMETOML)
1862
1863 var obj struct {
1864 Foo string `toml:"foo"`
1865 Bar string `toml:"bar"`
1866 }
1867 assert.NoError(t, c.ShouldBindTOML(&obj))
1868 assert.Equal(t, "foo", obj.Bar)
1869 assert.Equal(t, "bar", obj.Foo)
1870 assert.Equal(t, 0, w.Body.Len())
1871 }
1872
1873 func TestContextBadAutoShouldBind(t *testing.T) {
1874 w := httptest.NewRecorder()
1875 c, _ := CreateTestContext(w)
1876
1877 c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}"))
1878 c.Request.Header.Add("Content-Type", MIMEJSON)
1879 var obj struct {
1880 Foo string `json:"foo"`
1881 Bar string `json:"bar"`
1882 }
1883
1884 assert.False(t, c.IsAborted())
1885 assert.Error(t, c.ShouldBind(&obj))
1886
1887 assert.Empty(t, obj.Bar)
1888 assert.Empty(t, obj.Foo)
1889 assert.False(t, c.IsAborted())
1890 }
1891
1892 func TestContextShouldBindBodyWith(t *testing.T) {
1893 type typeA struct {
1894 Foo string `json:"foo" xml:"foo" binding:"required"`
1895 }
1896 type typeB struct {
1897 Bar string `json:"bar" xml:"bar" binding:"required"`
1898 }
1899 for _, tt := range []struct {
1900 name string
1901 bindingA, bindingB binding.BindingBody
1902 bodyA, bodyB string
1903 }{
1904 {
1905 name: "JSON & JSON",
1906 bindingA: binding.JSON,
1907 bindingB: binding.JSON,
1908 bodyA: `{"foo":"FOO"}`,
1909 bodyB: `{"bar":"BAR"}`,
1910 },
1911 {
1912 name: "JSON & XML",
1913 bindingA: binding.JSON,
1914 bindingB: binding.XML,
1915 bodyA: `{"foo":"FOO"}`,
1916 bodyB: `<?xml version="1.0" encoding="UTF-8"?>
1917 <root>
1918 <bar>BAR</bar>
1919 </root>`,
1920 },
1921 {
1922 name: "XML & XML",
1923 bindingA: binding.XML,
1924 bindingB: binding.XML,
1925 bodyA: `<?xml version="1.0" encoding="UTF-8"?>
1926 <root>
1927 <foo>FOO</foo>
1928 </root>`,
1929 bodyB: `<?xml version="1.0" encoding="UTF-8"?>
1930 <root>
1931 <bar>BAR</bar>
1932 </root>`,
1933 },
1934 } {
1935 t.Logf("testing: %s", tt.name)
1936
1937 {
1938 w := httptest.NewRecorder()
1939 c, _ := CreateTestContext(w)
1940 c.Request, _ = http.NewRequest(
1941 "POST", "http://example.com", bytes.NewBufferString(tt.bodyA),
1942 )
1943
1944
1945 objA := typeA{}
1946 assert.NoError(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
1947 assert.Equal(t, typeA{"FOO"}, objA)
1948 objB := typeB{}
1949 assert.Error(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
1950 assert.NotEqual(t, typeB{"BAR"}, objB)
1951 }
1952
1953 {
1954
1955
1956 w := httptest.NewRecorder()
1957 c, _ := CreateTestContext(w)
1958 c.Request, _ = http.NewRequest(
1959 "POST", "http://example.com", bytes.NewBufferString(tt.bodyB),
1960 )
1961 objA := typeA{}
1962 assert.Error(t, c.ShouldBindBodyWith(&objA, tt.bindingA))
1963 assert.NotEqual(t, typeA{"FOO"}, objA)
1964 objB := typeB{}
1965 assert.NoError(t, c.ShouldBindBodyWith(&objB, tt.bindingB))
1966 assert.Equal(t, typeB{"BAR"}, objB)
1967 }
1968 }
1969 }
1970
1971 func TestContextGolangContext(t *testing.T) {
1972 c, _ := CreateTestContext(httptest.NewRecorder())
1973 c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
1974 assert.NoError(t, c.Err())
1975 assert.Nil(t, c.Done())
1976 ti, ok := c.Deadline()
1977 assert.Equal(t, ti, time.Time{})
1978 assert.False(t, ok)
1979 assert.Equal(t, c.Value(0), c.Request)
1980 assert.Equal(t, c.Value(ContextKey), c)
1981 assert.Nil(t, c.Value("foo"))
1982
1983 c.Set("foo", "bar")
1984 assert.Equal(t, "bar", c.Value("foo"))
1985 assert.Nil(t, c.Value(1))
1986 }
1987
1988 func TestWebsocketsRequired(t *testing.T) {
1989
1990 c, _ := CreateTestContext(httptest.NewRecorder())
1991 c.Request, _ = http.NewRequest("GET", "/chat", nil)
1992 c.Request.Header.Set("Host", "server.example.com")
1993 c.Request.Header.Set("Upgrade", "websocket")
1994 c.Request.Header.Set("Connection", "Upgrade")
1995 c.Request.Header.Set("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==")
1996 c.Request.Header.Set("Origin", "http://example.com")
1997 c.Request.Header.Set("Sec-WebSocket-Protocol", "chat, superchat")
1998 c.Request.Header.Set("Sec-WebSocket-Version", "13")
1999
2000 assert.True(t, c.IsWebsocket())
2001
2002
2003 c, _ = CreateTestContext(httptest.NewRecorder())
2004 c.Request, _ = http.NewRequest("GET", "/chat", nil)
2005 c.Request.Header.Set("Host", "server.example.com")
2006
2007 assert.False(t, c.IsWebsocket())
2008 }
2009
2010 func TestGetRequestHeaderValue(t *testing.T) {
2011 c, _ := CreateTestContext(httptest.NewRecorder())
2012 c.Request, _ = http.NewRequest("GET", "/chat", nil)
2013 c.Request.Header.Set("Gin-Version", "1.0.0")
2014
2015 assert.Equal(t, "1.0.0", c.GetHeader("Gin-Version"))
2016 assert.Empty(t, c.GetHeader("Connection"))
2017 }
2018
2019 func TestContextGetRawData(t *testing.T) {
2020 c, _ := CreateTestContext(httptest.NewRecorder())
2021 body := bytes.NewBufferString("Fetch binary post data")
2022 c.Request, _ = http.NewRequest("POST", "/", body)
2023 c.Request.Header.Add("Content-Type", MIMEPOSTForm)
2024
2025 data, err := c.GetRawData()
2026 assert.Nil(t, err)
2027 assert.Equal(t, "Fetch binary post data", string(data))
2028 }
2029
2030 func TestContextRenderDataFromReader(t *testing.T) {
2031 w := httptest.NewRecorder()
2032 c, _ := CreateTestContext(w)
2033
2034 body := "#!PNG some raw data"
2035 reader := strings.NewReader(body)
2036 contentLength := int64(len(body))
2037 contentType := "image/png"
2038 extraHeaders := map[string]string{"Content-Disposition": `attachment; filename="gopher.png"`}
2039
2040 c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
2041
2042 assert.Equal(t, http.StatusOK, w.Code)
2043 assert.Equal(t, body, w.Body.String())
2044 assert.Equal(t, contentType, w.Header().Get("Content-Type"))
2045 assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length"))
2046 assert.Equal(t, extraHeaders["Content-Disposition"], w.Header().Get("Content-Disposition"))
2047 }
2048
2049 func TestContextRenderDataFromReaderNoHeaders(t *testing.T) {
2050 w := httptest.NewRecorder()
2051 c, _ := CreateTestContext(w)
2052
2053 body := "#!PNG some raw data"
2054 reader := strings.NewReader(body)
2055 contentLength := int64(len(body))
2056 contentType := "image/png"
2057
2058 c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil)
2059
2060 assert.Equal(t, http.StatusOK, w.Code)
2061 assert.Equal(t, body, w.Body.String())
2062 assert.Equal(t, contentType, w.Header().Get("Content-Type"))
2063 assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length"))
2064 }
2065
2066 type TestResponseRecorder struct {
2067 *httptest.ResponseRecorder
2068 closeChannel chan bool
2069 }
2070
2071 func (r *TestResponseRecorder) CloseNotify() <-chan bool {
2072 return r.closeChannel
2073 }
2074
2075 func (r *TestResponseRecorder) closeClient() {
2076 r.closeChannel <- true
2077 }
2078
2079 func CreateTestResponseRecorder() *TestResponseRecorder {
2080 return &TestResponseRecorder{
2081 httptest.NewRecorder(),
2082 make(chan bool, 1),
2083 }
2084 }
2085
2086 func TestContextStream(t *testing.T) {
2087 w := CreateTestResponseRecorder()
2088 c, _ := CreateTestContext(w)
2089
2090 stopStream := true
2091 c.Stream(func(w io.Writer) bool {
2092 defer func() {
2093 stopStream = false
2094 }()
2095
2096 _, err := w.Write([]byte("test"))
2097 assert.NoError(t, err)
2098
2099 return stopStream
2100 })
2101
2102 assert.Equal(t, "testtest", w.Body.String())
2103 }
2104
2105 func TestContextStreamWithClientGone(t *testing.T) {
2106 w := CreateTestResponseRecorder()
2107 c, _ := CreateTestContext(w)
2108
2109 c.Stream(func(writer io.Writer) bool {
2110 defer func() {
2111 w.closeClient()
2112 }()
2113
2114 _, err := writer.Write([]byte("test"))
2115 assert.NoError(t, err)
2116
2117 return true
2118 })
2119
2120 assert.Equal(t, "test", w.Body.String())
2121 }
2122
2123 func TestContextResetInHandler(t *testing.T) {
2124 w := CreateTestResponseRecorder()
2125 c, _ := CreateTestContext(w)
2126
2127 c.handlers = []HandlerFunc{
2128 func(c *Context) { c.reset() },
2129 }
2130 assert.NotPanics(t, func() {
2131 c.Next()
2132 })
2133 }
2134
2135 func TestRaceParamsContextCopy(t *testing.T) {
2136 DefaultWriter = os.Stdout
2137 router := Default()
2138 nameGroup := router.Group("/:name")
2139 var wg sync.WaitGroup
2140 wg.Add(2)
2141 {
2142 nameGroup.GET("/api", func(c *Context) {
2143 go func(c *Context, param string) {
2144 defer wg.Done()
2145
2146 time.Sleep(50 * time.Millisecond)
2147 assert.Equal(t, c.Param("name"), param)
2148 }(c.Copy(), c.Param("name"))
2149 })
2150 }
2151 PerformRequest(router, "GET", "/name1/api")
2152 PerformRequest(router, "GET", "/name2/api")
2153 wg.Wait()
2154 }
2155
2156 func TestContextWithKeysMutex(t *testing.T) {
2157 c := &Context{}
2158 c.Set("foo", "bar")
2159
2160 value, err := c.Get("foo")
2161 assert.Equal(t, "bar", value)
2162 assert.True(t, err)
2163
2164 value, err = c.Get("foo2")
2165 assert.Nil(t, value)
2166 assert.False(t, err)
2167 }
2168
2169 func TestRemoteIPFail(t *testing.T) {
2170 c, _ := CreateTestContext(httptest.NewRecorder())
2171 c.Request, _ = http.NewRequest("POST", "/", nil)
2172 c.Request.RemoteAddr = "[:::]:80"
2173 ip := net.ParseIP(c.RemoteIP())
2174 trust := c.engine.isTrustedProxy(ip)
2175 assert.Nil(t, ip)
2176 assert.False(t, trust)
2177 }
2178
2179 func TestHasRequestContext(t *testing.T) {
2180 c, _ := CreateTestContext(httptest.NewRecorder())
2181 assert.False(t, c.hasRequestContext(), "no request, no fallback")
2182 c.engine.ContextWithFallback = true
2183 assert.False(t, c.hasRequestContext(), "no request, has fallback")
2184 c.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
2185 assert.True(t, c.hasRequestContext(), "has request, has fallback")
2186 c.Request, _ = http.NewRequestWithContext(nil, "", "", nil)
2187 assert.False(t, c.hasRequestContext(), "has request with nil ctx, has fallback")
2188 c.engine.ContextWithFallback = false
2189 assert.False(t, c.hasRequestContext(), "has request, no fallback")
2190
2191 c = &Context{}
2192 assert.False(t, c.hasRequestContext(), "no request, no engine")
2193 c.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
2194 assert.False(t, c.hasRequestContext(), "has request, no engine")
2195 }
2196
2197 func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) {
2198 c, _ := CreateTestContext(httptest.NewRecorder())
2199
2200 c.engine.ContextWithFallback = true
2201
2202 deadline, ok := c.Deadline()
2203 assert.Zero(t, deadline)
2204 assert.False(t, ok)
2205
2206 c2, _ := CreateTestContext(httptest.NewRecorder())
2207
2208 c2.engine.ContextWithFallback = true
2209
2210 c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
2211 d := time.Now().Add(time.Second)
2212 ctx, cancel := context.WithDeadline(context.Background(), d)
2213 defer cancel()
2214 c2.Request = c2.Request.WithContext(ctx)
2215 deadline, ok = c2.Deadline()
2216 assert.Equal(t, d, deadline)
2217 assert.True(t, ok)
2218 }
2219
2220 func TestContextWithFallbackDoneFromRequestContext(t *testing.T) {
2221 c, _ := CreateTestContext(httptest.NewRecorder())
2222
2223 c.engine.ContextWithFallback = true
2224
2225 assert.Nil(t, c.Done())
2226
2227 c2, _ := CreateTestContext(httptest.NewRecorder())
2228
2229 c2.engine.ContextWithFallback = true
2230
2231 c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
2232 ctx, cancel := context.WithCancel(context.Background())
2233 c2.Request = c2.Request.WithContext(ctx)
2234 cancel()
2235 assert.NotNil(t, <-c2.Done())
2236 }
2237
2238 func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
2239 c, _ := CreateTestContext(httptest.NewRecorder())
2240
2241 c.engine.ContextWithFallback = true
2242
2243 assert.Nil(t, c.Err())
2244
2245 c2, _ := CreateTestContext(httptest.NewRecorder())
2246
2247 c2.engine.ContextWithFallback = true
2248
2249 c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
2250 ctx, cancel := context.WithCancel(context.Background())
2251 c2.Request = c2.Request.WithContext(ctx)
2252 cancel()
2253
2254 assert.EqualError(t, c2.Err(), context.Canceled.Error())
2255 }
2256
2257 func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
2258 type contextKey string
2259
2260 tests := []struct {
2261 name string
2262 getContextAndKey func() (*Context, any)
2263 value any
2264 }{
2265 {
2266 name: "c with struct context key",
2267 getContextAndKey: func() (*Context, any) {
2268 var key struct{}
2269 c, _ := CreateTestContext(httptest.NewRecorder())
2270
2271 c.engine.ContextWithFallback = true
2272 c.Request, _ = http.NewRequest("POST", "/", nil)
2273 c.Request = c.Request.WithContext(context.WithValue(context.TODO(), key, "value"))
2274 return c, key
2275 },
2276 value: "value",
2277 },
2278 {
2279 name: "c with string context key",
2280 getContextAndKey: func() (*Context, any) {
2281 c, _ := CreateTestContext(httptest.NewRecorder())
2282
2283 c.engine.ContextWithFallback = true
2284 c.Request, _ = http.NewRequest("POST", "/", nil)
2285 c.Request = c.Request.WithContext(context.WithValue(context.TODO(), contextKey("key"), "value"))
2286 return c, contextKey("key")
2287 },
2288 value: "value",
2289 },
2290 {
2291 name: "c with nil http.Request",
2292 getContextAndKey: func() (*Context, any) {
2293 c, _ := CreateTestContext(httptest.NewRecorder())
2294
2295 c.engine.ContextWithFallback = true
2296 c.Request = nil
2297 return c, "key"
2298 },
2299 value: nil,
2300 },
2301 {
2302 name: "c with nil http.Request.Context()",
2303 getContextAndKey: func() (*Context, any) {
2304 c, _ := CreateTestContext(httptest.NewRecorder())
2305
2306 c.engine.ContextWithFallback = true
2307 c.Request, _ = http.NewRequest("POST", "/", nil)
2308 return c, "key"
2309 },
2310 value: nil,
2311 },
2312 }
2313 for _, tt := range tests {
2314 t.Run(tt.name, func(t *testing.T) {
2315 c, key := tt.getContextAndKey()
2316 assert.Equal(t, tt.value, c.Value(key))
2317 })
2318 }
2319 }
2320
2321 func TestContextCopyShouldNotCancel(t *testing.T) {
2322 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
2323 w.WriteHeader(http.StatusOK)
2324 }))
2325 defer srv.Close()
2326
2327 ensureRequestIsOver := make(chan struct{})
2328
2329 wg := &sync.WaitGroup{}
2330
2331 r := New()
2332 r.GET("/", func(ginctx *Context) {
2333 wg.Add(1)
2334
2335 ginctx = ginctx.Copy()
2336
2337
2338 go func() {
2339 defer wg.Done()
2340
2341 <-ensureRequestIsOver
2342
2343 req, err := http.NewRequestWithContext(ginctx, http.MethodGet, srv.URL, nil)
2344 must(err)
2345
2346 res, err := http.DefaultClient.Do(req)
2347 if err != nil {
2348 t.Error(fmt.Errorf("request error: %w", err))
2349 return
2350 }
2351
2352 if res.StatusCode != http.StatusOK {
2353 t.Error(fmt.Errorf("unexpected status code: %s", res.Status))
2354 }
2355 }()
2356 })
2357
2358 l, err := net.Listen("tcp", ":0")
2359 must(err)
2360 go func() {
2361 s := &http.Server{
2362 Handler: r,
2363 }
2364
2365 must(s.Serve(l))
2366 }()
2367
2368 addr := strings.Split(l.Addr().String(), ":")
2369 res, err := http.Get(fmt.Sprintf("http://127.0.0.1:%s/", addr[len(addr)-1]))
2370 if err != nil {
2371 t.Error(fmt.Errorf("request error: %w", err))
2372 return
2373 }
2374
2375 close(ensureRequestIsOver)
2376
2377 if res.StatusCode != http.StatusOK {
2378 t.Error(fmt.Errorf("unexpected status code: %s", res.Status))
2379 return
2380 }
2381
2382 wg.Wait()
2383 }
2384
2385 func TestContextAddParam(t *testing.T) {
2386 c := &Context{}
2387 id := "id"
2388 value := "1"
2389 c.AddParam(id, value)
2390
2391 v, ok := c.Params.Get(id)
2392 assert.Equal(t, ok, true)
2393 assert.Equal(t, value, v)
2394 }
2395
2396 func TestCreateTestContextWithRouteParams(t *testing.T) {
2397 w := httptest.NewRecorder()
2398 engine := New()
2399 engine.GET("/:action/:name", func(ctx *Context) {
2400 ctx.String(http.StatusOK, "%s %s", ctx.Param("action"), ctx.Param("name"))
2401 })
2402 c := CreateTestContextOnly(w, engine)
2403 c.Request, _ = http.NewRequest(http.MethodGet, "/hello/gin", nil)
2404 engine.HandleContext(c)
2405
2406 assert.Equal(t, http.StatusOK, w.Code)
2407 assert.Equal(t, "hello gin", w.Body.String())
2408 }
2409
2410 type interceptedWriter struct {
2411 ResponseWriter
2412 b *bytes.Buffer
2413 }
2414
2415 func (i interceptedWriter) WriteHeader(code int) {
2416 i.Header().Del("X-Test")
2417 i.ResponseWriter.WriteHeader(code)
2418 }
2419
2420 func TestInterceptedHeader(t *testing.T) {
2421 w := httptest.NewRecorder()
2422 c, r := CreateTestContext(w)
2423
2424 r.Use(func(c *Context) {
2425 i := interceptedWriter{
2426 ResponseWriter: c.Writer,
2427 b: bytes.NewBuffer(nil),
2428 }
2429 c.Writer = i
2430 c.Next()
2431 c.Header("X-Test", "overridden")
2432 c.Writer = i.ResponseWriter
2433 })
2434 r.GET("/", func(c *Context) {
2435 c.Header("X-Test", "original")
2436 c.Header("X-Test-2", "present")
2437 c.String(http.StatusOK, "hello world")
2438 })
2439 c.Request = httptest.NewRequest("GET", "/", nil)
2440 r.HandleContext(c)
2441
2442
2443
2444
2445 assert.Equal(t, "", w.Result().Header.Get("X-Test"))
2446 assert.Equal(t, "present", w.Result().Header.Get("X-Test-2"))
2447 }
2448
View as plain text