1
2
3
4
5 package gin
6
7 import (
8 "errors"
9 "io"
10 "log"
11 "math"
12 "mime/multipart"
13 "net"
14 "net/http"
15 "net/url"
16 "os"
17 "path/filepath"
18 "strings"
19 "sync"
20 "time"
21
22 "github.com/gin-contrib/sse"
23 "github.com/gin-gonic/gin/binding"
24 "github.com/gin-gonic/gin/render"
25 )
26
27
28 const (
29 MIMEJSON = binding.MIMEJSON
30 MIMEHTML = binding.MIMEHTML
31 MIMEXML = binding.MIMEXML
32 MIMEXML2 = binding.MIMEXML2
33 MIMEPlain = binding.MIMEPlain
34 MIMEPOSTForm = binding.MIMEPOSTForm
35 MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
36 MIMEYAML = binding.MIMEYAML
37 MIMETOML = binding.MIMETOML
38 )
39
40
41 const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
42
43
44 const ContextKey = "_gin-gonic/gin/contextkey"
45
46
47 const abortIndex int8 = math.MaxInt8 >> 1
48
49
50
51 type Context struct {
52 writermem responseWriter
53 Request *http.Request
54 Writer ResponseWriter
55
56 Params Params
57 handlers HandlersChain
58 index int8
59 fullPath string
60
61 engine *Engine
62 params *Params
63 skippedNodes *[]skippedNode
64
65
66 mu sync.RWMutex
67
68
69 Keys map[string]any
70
71
72 Errors errorMsgs
73
74
75 Accepted []string
76
77
78 queryCache url.Values
79
80
81
82 formCache url.Values
83
84
85
86 sameSite http.SameSite
87 }
88
89
90
91
92
93 func (c *Context) reset() {
94 c.Writer = &c.writermem
95 c.Params = c.Params[:0]
96 c.handlers = nil
97 c.index = -1
98
99 c.fullPath = ""
100 c.Keys = nil
101 c.Errors = c.Errors[:0]
102 c.Accepted = nil
103 c.queryCache = nil
104 c.formCache = nil
105 c.sameSite = 0
106 *c.params = (*c.params)[:0]
107 *c.skippedNodes = (*c.skippedNodes)[:0]
108 }
109
110
111
112 func (c *Context) Copy() *Context {
113 cp := Context{
114 writermem: c.writermem,
115 Request: c.Request,
116 Params: c.Params,
117 engine: c.engine,
118 }
119 cp.writermem.ResponseWriter = nil
120 cp.Writer = &cp.writermem
121 cp.index = abortIndex
122 cp.handlers = nil
123 cp.Keys = map[string]any{}
124 for k, v := range c.Keys {
125 cp.Keys[k] = v
126 }
127 paramCopy := make([]Param, len(cp.Params))
128 copy(paramCopy, cp.Params)
129 cp.Params = paramCopy
130 return &cp
131 }
132
133
134
135 func (c *Context) HandlerName() string {
136 return nameOfFunction(c.handlers.Last())
137 }
138
139
140
141 func (c *Context) HandlerNames() []string {
142 hn := make([]string, 0, len(c.handlers))
143 for _, val := range c.handlers {
144 hn = append(hn, nameOfFunction(val))
145 }
146 return hn
147 }
148
149
150 func (c *Context) Handler() HandlerFunc {
151 return c.handlers.Last()
152 }
153
154
155
156
157
158
159
160 func (c *Context) FullPath() string {
161 return c.fullPath
162 }
163
164
165
166
167
168
169
170
171 func (c *Context) Next() {
172 c.index++
173 for c.index < int8(len(c.handlers)) {
174 c.handlers[c.index](c)
175 c.index++
176 }
177 }
178
179
180 func (c *Context) IsAborted() bool {
181 return c.index >= abortIndex
182 }
183
184
185
186
187
188 func (c *Context) Abort() {
189 c.index = abortIndex
190 }
191
192
193
194 func (c *Context) AbortWithStatus(code int) {
195 c.Status(code)
196 c.Writer.WriteHeaderNow()
197 c.Abort()
198 }
199
200
201
202
203 func (c *Context) AbortWithStatusJSON(code int, jsonObj any) {
204 c.Abort()
205 c.JSON(code, jsonObj)
206 }
207
208
209
210
211 func (c *Context) AbortWithError(code int, err error) *Error {
212 c.AbortWithStatus(code)
213 return c.Error(err)
214 }
215
216
217
218
219
220
221
222
223
224
225 func (c *Context) Error(err error) *Error {
226 if err == nil {
227 panic("err is nil")
228 }
229
230 var parsedError *Error
231 ok := errors.As(err, &parsedError)
232 if !ok {
233 parsedError = &Error{
234 Err: err,
235 Type: ErrorTypePrivate,
236 }
237 }
238
239 c.Errors = append(c.Errors, parsedError)
240 return parsedError
241 }
242
243
244
245
246
247
248
249 func (c *Context) Set(key string, value any) {
250 c.mu.Lock()
251 defer c.mu.Unlock()
252 if c.Keys == nil {
253 c.Keys = make(map[string]any)
254 }
255
256 c.Keys[key] = value
257 }
258
259
260
261 func (c *Context) Get(key string) (value any, exists bool) {
262 c.mu.RLock()
263 defer c.mu.RUnlock()
264 value, exists = c.Keys[key]
265 return
266 }
267
268
269 func (c *Context) MustGet(key string) any {
270 if value, exists := c.Get(key); exists {
271 return value
272 }
273 panic("Key \"" + key + "\" does not exist")
274 }
275
276
277 func (c *Context) GetString(key string) (s string) {
278 if val, ok := c.Get(key); ok && val != nil {
279 s, _ = val.(string)
280 }
281 return
282 }
283
284
285 func (c *Context) GetBool(key string) (b bool) {
286 if val, ok := c.Get(key); ok && val != nil {
287 b, _ = val.(bool)
288 }
289 return
290 }
291
292
293 func (c *Context) GetInt(key string) (i int) {
294 if val, ok := c.Get(key); ok && val != nil {
295 i, _ = val.(int)
296 }
297 return
298 }
299
300
301 func (c *Context) GetInt64(key string) (i64 int64) {
302 if val, ok := c.Get(key); ok && val != nil {
303 i64, _ = val.(int64)
304 }
305 return
306 }
307
308
309 func (c *Context) GetUint(key string) (ui uint) {
310 if val, ok := c.Get(key); ok && val != nil {
311 ui, _ = val.(uint)
312 }
313 return
314 }
315
316
317 func (c *Context) GetUint64(key string) (ui64 uint64) {
318 if val, ok := c.Get(key); ok && val != nil {
319 ui64, _ = val.(uint64)
320 }
321 return
322 }
323
324
325 func (c *Context) GetFloat64(key string) (f64 float64) {
326 if val, ok := c.Get(key); ok && val != nil {
327 f64, _ = val.(float64)
328 }
329 return
330 }
331
332
333 func (c *Context) GetTime(key string) (t time.Time) {
334 if val, ok := c.Get(key); ok && val != nil {
335 t, _ = val.(time.Time)
336 }
337 return
338 }
339
340
341 func (c *Context) GetDuration(key string) (d time.Duration) {
342 if val, ok := c.Get(key); ok && val != nil {
343 d, _ = val.(time.Duration)
344 }
345 return
346 }
347
348
349 func (c *Context) GetStringSlice(key string) (ss []string) {
350 if val, ok := c.Get(key); ok && val != nil {
351 ss, _ = val.([]string)
352 }
353 return
354 }
355
356
357 func (c *Context) GetStringMap(key string) (sm map[string]any) {
358 if val, ok := c.Get(key); ok && val != nil {
359 sm, _ = val.(map[string]any)
360 }
361 return
362 }
363
364
365 func (c *Context) GetStringMapString(key string) (sms map[string]string) {
366 if val, ok := c.Get(key); ok && val != nil {
367 sms, _ = val.(map[string]string)
368 }
369 return
370 }
371
372
373 func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) {
374 if val, ok := c.Get(key); ok && val != nil {
375 smss, _ = val.(map[string][]string)
376 }
377 return
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 func (c *Context) Param(key string) string {
394 return c.Params.ByName(key)
395 }
396
397
398
399
400
401
402 func (c *Context) AddParam(key, value string) {
403 c.Params = append(c.Params, Param{Key: key, Value: value})
404 }
405
406
407
408
409
410
411
412
413
414
415 func (c *Context) Query(key string) (value string) {
416 value, _ = c.GetQuery(key)
417 return
418 }
419
420
421
422
423
424
425
426
427
428 func (c *Context) DefaultQuery(key, defaultValue string) string {
429 if value, ok := c.GetQuery(key); ok {
430 return value
431 }
432 return defaultValue
433 }
434
435
436
437
438
439
440
441
442
443
444 func (c *Context) GetQuery(key string) (string, bool) {
445 if values, ok := c.GetQueryArray(key); ok {
446 return values[0], ok
447 }
448 return "", false
449 }
450
451
452
453 func (c *Context) QueryArray(key string) (values []string) {
454 values, _ = c.GetQueryArray(key)
455 return
456 }
457
458 func (c *Context) initQueryCache() {
459 if c.queryCache == nil {
460 if c.Request != nil {
461 c.queryCache = c.Request.URL.Query()
462 } else {
463 c.queryCache = url.Values{}
464 }
465 }
466 }
467
468
469
470 func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
471 c.initQueryCache()
472 values, ok = c.queryCache[key]
473 return
474 }
475
476
477 func (c *Context) QueryMap(key string) (dicts map[string]string) {
478 dicts, _ = c.GetQueryMap(key)
479 return
480 }
481
482
483
484 func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
485 c.initQueryCache()
486 return c.get(c.queryCache, key)
487 }
488
489
490
491 func (c *Context) PostForm(key string) (value string) {
492 value, _ = c.GetPostForm(key)
493 return
494 }
495
496
497
498
499 func (c *Context) DefaultPostForm(key, defaultValue string) string {
500 if value, ok := c.GetPostForm(key); ok {
501 return value
502 }
503 return defaultValue
504 }
505
506
507
508
509
510
511
512
513
514 func (c *Context) GetPostForm(key string) (string, bool) {
515 if values, ok := c.GetPostFormArray(key); ok {
516 return values[0], ok
517 }
518 return "", false
519 }
520
521
522
523 func (c *Context) PostFormArray(key string) (values []string) {
524 values, _ = c.GetPostFormArray(key)
525 return
526 }
527
528 func (c *Context) initFormCache() {
529 if c.formCache == nil {
530 c.formCache = make(url.Values)
531 req := c.Request
532 if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
533 if !errors.Is(err, http.ErrNotMultipart) {
534 debugPrint("error on parse multipart form array: %v", err)
535 }
536 }
537 c.formCache = req.PostForm
538 }
539 }
540
541
542
543 func (c *Context) GetPostFormArray(key string) (values []string, ok bool) {
544 c.initFormCache()
545 values, ok = c.formCache[key]
546 return
547 }
548
549
550 func (c *Context) PostFormMap(key string) (dicts map[string]string) {
551 dicts, _ = c.GetPostFormMap(key)
552 return
553 }
554
555
556
557 func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
558 c.initFormCache()
559 return c.get(c.formCache, key)
560 }
561
562
563 func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) {
564 dicts := make(map[string]string)
565 exist := false
566 for k, v := range m {
567 if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key {
568 if j := strings.IndexByte(k[i+1:], ']'); j >= 1 {
569 exist = true
570 dicts[k[i+1:][:j]] = v[0]
571 }
572 }
573 }
574 return dicts, exist
575 }
576
577
578 func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
579 if c.Request.MultipartForm == nil {
580 if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
581 return nil, err
582 }
583 }
584 f, fh, err := c.Request.FormFile(name)
585 if err != nil {
586 return nil, err
587 }
588 f.Close()
589 return fh, err
590 }
591
592
593 func (c *Context) MultipartForm() (*multipart.Form, error) {
594 err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory)
595 return c.Request.MultipartForm, err
596 }
597
598
599 func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error {
600 src, err := file.Open()
601 if err != nil {
602 return err
603 }
604 defer src.Close()
605
606 if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
607 return err
608 }
609
610 out, err := os.Create(dst)
611 if err != nil {
612 return err
613 }
614 defer out.Close()
615
616 _, err = io.Copy(out, src)
617 return err
618 }
619
620
621
622
623
624
625
626
627
628
629 func (c *Context) Bind(obj any) error {
630 b := binding.Default(c.Request.Method, c.ContentType())
631 return c.MustBindWith(obj, b)
632 }
633
634
635 func (c *Context) BindJSON(obj any) error {
636 return c.MustBindWith(obj, binding.JSON)
637 }
638
639
640 func (c *Context) BindXML(obj any) error {
641 return c.MustBindWith(obj, binding.XML)
642 }
643
644
645 func (c *Context) BindQuery(obj any) error {
646 return c.MustBindWith(obj, binding.Query)
647 }
648
649
650 func (c *Context) BindYAML(obj any) error {
651 return c.MustBindWith(obj, binding.YAML)
652 }
653
654
655 func (c *Context) BindTOML(obj any) error {
656 return c.MustBindWith(obj, binding.TOML)
657 }
658
659
660 func (c *Context) BindHeader(obj any) error {
661 return c.MustBindWith(obj, binding.Header)
662 }
663
664
665
666 func (c *Context) BindUri(obj any) error {
667 if err := c.ShouldBindUri(obj); err != nil {
668 c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind)
669 return err
670 }
671 return nil
672 }
673
674
675
676
677 func (c *Context) MustBindWith(obj any, b binding.Binding) error {
678 if err := c.ShouldBindWith(obj, b); err != nil {
679 c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind)
680 return err
681 }
682 return nil
683 }
684
685
686
687
688
689
690
691
692
693
694 func (c *Context) ShouldBind(obj any) error {
695 b := binding.Default(c.Request.Method, c.ContentType())
696 return c.ShouldBindWith(obj, b)
697 }
698
699
700 func (c *Context) ShouldBindJSON(obj any) error {
701 return c.ShouldBindWith(obj, binding.JSON)
702 }
703
704
705 func (c *Context) ShouldBindXML(obj any) error {
706 return c.ShouldBindWith(obj, binding.XML)
707 }
708
709
710 func (c *Context) ShouldBindQuery(obj any) error {
711 return c.ShouldBindWith(obj, binding.Query)
712 }
713
714
715 func (c *Context) ShouldBindYAML(obj any) error {
716 return c.ShouldBindWith(obj, binding.YAML)
717 }
718
719
720 func (c *Context) ShouldBindTOML(obj any) error {
721 return c.ShouldBindWith(obj, binding.TOML)
722 }
723
724
725 func (c *Context) ShouldBindHeader(obj any) error {
726 return c.ShouldBindWith(obj, binding.Header)
727 }
728
729
730 func (c *Context) ShouldBindUri(obj any) error {
731 m := make(map[string][]string)
732 for _, v := range c.Params {
733 m[v.Key] = []string{v.Value}
734 }
735 return binding.Uri.BindUri(m, obj)
736 }
737
738
739
740 func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
741 return b.Bind(c.Request, obj)
742 }
743
744
745
746
747
748
749 func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error) {
750 var body []byte
751 if cb, ok := c.Get(BodyBytesKey); ok {
752 if cbb, ok := cb.([]byte); ok {
753 body = cbb
754 }
755 }
756 if body == nil {
757 body, err = io.ReadAll(c.Request.Body)
758 if err != nil {
759 return err
760 }
761 c.Set(BodyBytesKey, body)
762 }
763 return bb.BindBody(body, obj)
764 }
765
766
767
768
769
770
771 func (c *Context) ClientIP() string {
772
773 if c.engine.TrustedPlatform != "" {
774
775 if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" {
776 return addr
777 }
778 }
779
780
781 if c.engine.AppEngine {
782 log.Println(`The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`)
783 if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
784 return addr
785 }
786 }
787
788
789
790
791 remoteIP := net.ParseIP(c.RemoteIP())
792 if remoteIP == nil {
793 return ""
794 }
795 trusted := c.engine.isTrustedProxy(remoteIP)
796
797 if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil {
798 for _, headerName := range c.engine.RemoteIPHeaders {
799 ip, valid := c.engine.validateHeader(c.requestHeader(headerName))
800 if valid {
801 return ip
802 }
803 }
804 }
805 return remoteIP.String()
806 }
807
808
809 func (c *Context) RemoteIP() string {
810 ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr))
811 if err != nil {
812 return ""
813 }
814 return ip
815 }
816
817
818 func (c *Context) ContentType() string {
819 return filterFlags(c.requestHeader("Content-Type"))
820 }
821
822
823
824 func (c *Context) IsWebsocket() bool {
825 if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") &&
826 strings.EqualFold(c.requestHeader("Upgrade"), "websocket") {
827 return true
828 }
829 return false
830 }
831
832 func (c *Context) requestHeader(key string) string {
833 return c.Request.Header.Get(key)
834 }
835
836
837
838
839
840
841 func bodyAllowedForStatus(status int) bool {
842 switch {
843 case status >= 100 && status <= 199:
844 return false
845 case status == http.StatusNoContent:
846 return false
847 case status == http.StatusNotModified:
848 return false
849 }
850 return true
851 }
852
853
854 func (c *Context) Status(code int) {
855 c.Writer.WriteHeader(code)
856 }
857
858
859
860
861 func (c *Context) Header(key, value string) {
862 if value == "" {
863 c.Writer.Header().Del(key)
864 return
865 }
866 c.Writer.Header().Set(key, value)
867 }
868
869
870 func (c *Context) GetHeader(key string) string {
871 return c.requestHeader(key)
872 }
873
874
875 func (c *Context) GetRawData() ([]byte, error) {
876 return io.ReadAll(c.Request.Body)
877 }
878
879
880 func (c *Context) SetSameSite(samesite http.SameSite) {
881 c.sameSite = samesite
882 }
883
884
885
886
887 func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
888 if path == "" {
889 path = "/"
890 }
891 http.SetCookie(c.Writer, &http.Cookie{
892 Name: name,
893 Value: url.QueryEscape(value),
894 MaxAge: maxAge,
895 Path: path,
896 Domain: domain,
897 SameSite: c.sameSite,
898 Secure: secure,
899 HttpOnly: httpOnly,
900 })
901 }
902
903
904
905
906
907 func (c *Context) Cookie(name string) (string, error) {
908 cookie, err := c.Request.Cookie(name)
909 if err != nil {
910 return "", err
911 }
912 val, _ := url.QueryUnescape(cookie.Value)
913 return val, nil
914 }
915
916
917 func (c *Context) Render(code int, r render.Render) {
918 c.Status(code)
919
920 if !bodyAllowedForStatus(code) {
921 r.WriteContentType(c.Writer)
922 c.Writer.WriteHeaderNow()
923 return
924 }
925
926 if err := r.Render(c.Writer); err != nil {
927
928 _ = c.Error(err)
929 c.Abort()
930 }
931 }
932
933
934
935
936 func (c *Context) HTML(code int, name string, obj any) {
937 instance := c.engine.HTMLRender.Instance(name, obj)
938 c.Render(code, instance)
939 }
940
941
942
943
944
945 func (c *Context) IndentedJSON(code int, obj any) {
946 c.Render(code, render.IndentedJSON{Data: obj})
947 }
948
949
950
951
952 func (c *Context) SecureJSON(code int, obj any) {
953 c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj})
954 }
955
956
957
958
959 func (c *Context) JSONP(code int, obj any) {
960 callback := c.DefaultQuery("callback", "")
961 if callback == "" {
962 c.Render(code, render.JSON{Data: obj})
963 return
964 }
965 c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
966 }
967
968
969
970 func (c *Context) JSON(code int, obj any) {
971 c.Render(code, render.JSON{Data: obj})
972 }
973
974
975
976 func (c *Context) AsciiJSON(code int, obj any) {
977 c.Render(code, render.AsciiJSON{Data: obj})
978 }
979
980
981
982 func (c *Context) PureJSON(code int, obj any) {
983 c.Render(code, render.PureJSON{Data: obj})
984 }
985
986
987
988 func (c *Context) XML(code int, obj any) {
989 c.Render(code, render.XML{Data: obj})
990 }
991
992
993 func (c *Context) YAML(code int, obj any) {
994 c.Render(code, render.YAML{Data: obj})
995 }
996
997
998 func (c *Context) TOML(code int, obj any) {
999 c.Render(code, render.TOML{Data: obj})
1000 }
1001
1002
1003 func (c *Context) ProtoBuf(code int, obj any) {
1004 c.Render(code, render.ProtoBuf{Data: obj})
1005 }
1006
1007
1008 func (c *Context) String(code int, format string, values ...any) {
1009 c.Render(code, render.String{Format: format, Data: values})
1010 }
1011
1012
1013 func (c *Context) Redirect(code int, location string) {
1014 c.Render(-1, render.Redirect{
1015 Code: code,
1016 Location: location,
1017 Request: c.Request,
1018 })
1019 }
1020
1021
1022 func (c *Context) Data(code int, contentType string, data []byte) {
1023 c.Render(code, render.Data{
1024 ContentType: contentType,
1025 Data: data,
1026 })
1027 }
1028
1029
1030 func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) {
1031 c.Render(code, render.Reader{
1032 Headers: extraHeaders,
1033 ContentType: contentType,
1034 ContentLength: contentLength,
1035 Reader: reader,
1036 })
1037 }
1038
1039
1040 func (c *Context) File(filepath string) {
1041 http.ServeFile(c.Writer, c.Request, filepath)
1042 }
1043
1044
1045 func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
1046 defer func(old string) {
1047 c.Request.URL.Path = old
1048 }(c.Request.URL.Path)
1049
1050 c.Request.URL.Path = filepath
1051
1052 http.FileServer(fs).ServeHTTP(c.Writer, c.Request)
1053 }
1054
1055 var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
1056
1057 func escapeQuotes(s string) string {
1058 return quoteEscaper.Replace(s)
1059 }
1060
1061
1062
1063 func (c *Context) FileAttachment(filepath, filename string) {
1064 if isASCII(filename) {
1065 c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+escapeQuotes(filename)+`"`)
1066 } else {
1067 c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
1068 }
1069 http.ServeFile(c.Writer, c.Request, filepath)
1070 }
1071
1072
1073 func (c *Context) SSEvent(name string, message any) {
1074 c.Render(-1, sse.Event{
1075 Event: name,
1076 Data: message,
1077 })
1078 }
1079
1080
1081
1082 func (c *Context) Stream(step func(w io.Writer) bool) bool {
1083 w := c.Writer
1084 clientGone := w.CloseNotify()
1085 for {
1086 select {
1087 case <-clientGone:
1088 return true
1089 default:
1090 keepOpen := step(w)
1091 w.Flush()
1092 if !keepOpen {
1093 return false
1094 }
1095 }
1096 }
1097 }
1098
1099
1100
1101
1102
1103
1104 type Negotiate struct {
1105 Offered []string
1106 HTMLName string
1107 HTMLData any
1108 JSONData any
1109 XMLData any
1110 YAMLData any
1111 Data any
1112 TOMLData any
1113 }
1114
1115
1116 func (c *Context) Negotiate(code int, config Negotiate) {
1117 switch c.NegotiateFormat(config.Offered...) {
1118 case binding.MIMEJSON:
1119 data := chooseData(config.JSONData, config.Data)
1120 c.JSON(code, data)
1121
1122 case binding.MIMEHTML:
1123 data := chooseData(config.HTMLData, config.Data)
1124 c.HTML(code, config.HTMLName, data)
1125
1126 case binding.MIMEXML:
1127 data := chooseData(config.XMLData, config.Data)
1128 c.XML(code, data)
1129
1130 case binding.MIMEYAML:
1131 data := chooseData(config.YAMLData, config.Data)
1132 c.YAML(code, data)
1133
1134 case binding.MIMETOML:
1135 data := chooseData(config.TOMLData, config.Data)
1136 c.TOML(code, data)
1137
1138 default:
1139 c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server"))
1140 }
1141 }
1142
1143
1144 func (c *Context) NegotiateFormat(offered ...string) string {
1145 assert1(len(offered) > 0, "you must provide at least one offer")
1146
1147 if c.Accepted == nil {
1148 c.Accepted = parseAccept(c.requestHeader("Accept"))
1149 }
1150 if len(c.Accepted) == 0 {
1151 return offered[0]
1152 }
1153 for _, accepted := range c.Accepted {
1154 for _, offer := range offered {
1155
1156
1157 i := 0
1158 for ; i < len(accepted) && i < len(offer); i++ {
1159 if accepted[i] == '*' || offer[i] == '*' {
1160 return offer
1161 }
1162 if accepted[i] != offer[i] {
1163 break
1164 }
1165 }
1166 if i == len(accepted) {
1167 return offer
1168 }
1169 }
1170 }
1171 return ""
1172 }
1173
1174
1175 func (c *Context) SetAccepted(formats ...string) {
1176 c.Accepted = formats
1177 }
1178
1179
1180
1181
1182
1183
1184 func (c *Context) hasRequestContext() bool {
1185 hasFallback := c.engine != nil && c.engine.ContextWithFallback
1186 hasRequestContext := c.Request != nil && c.Request.Context() != nil
1187 return hasFallback && hasRequestContext
1188 }
1189
1190
1191 func (c *Context) Deadline() (deadline time.Time, ok bool) {
1192 if !c.hasRequestContext() {
1193 return
1194 }
1195 return c.Request.Context().Deadline()
1196 }
1197
1198
1199 func (c *Context) Done() <-chan struct{} {
1200 if !c.hasRequestContext() {
1201 return nil
1202 }
1203 return c.Request.Context().Done()
1204 }
1205
1206
1207 func (c *Context) Err() error {
1208 if !c.hasRequestContext() {
1209 return nil
1210 }
1211 return c.Request.Context().Err()
1212 }
1213
1214
1215
1216
1217 func (c *Context) Value(key any) any {
1218 if key == 0 {
1219 return c.Request
1220 }
1221 if key == ContextKey {
1222 return c
1223 }
1224 if keyAsString, ok := key.(string); ok {
1225 if val, exists := c.Get(keyAsString); exists {
1226 return val
1227 }
1228 }
1229 if !c.hasRequestContext() {
1230 return nil
1231 }
1232 return c.Request.Context().Value(key)
1233 }
1234
View as plain text