github.com/cloudwego/hertz@v0.9.3/pkg/app/context.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * The MIT License (MIT) 17 * 18 * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors 19 * 20 * Permission is hereby granted, free of charge, to any person obtaining a copy 21 * of this software and associated documentation files (the "Software"), to deal 22 * in the Software without restriction, including without limitation the rights 23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 * copies of the Software, and to permit persons to whom the Software is 25 * furnished to do so, subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be included in 28 * all copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 * THE SOFTWARE. 37 * 38 * This file may have been modified by CloudWeGo authors. All CloudWeGo 39 * Modifications are Copyright 2022 CloudWeGo Authors. 40 */ 41 42 package app 43 44 import ( 45 "context" 46 "fmt" 47 "io" 48 "mime/multipart" 49 "net" 50 "net/url" 51 "os" 52 "reflect" 53 "strings" 54 "sync" 55 "time" 56 57 "github.com/cloudwego/hertz/internal/bytesconv" 58 "github.com/cloudwego/hertz/internal/bytestr" 59 "github.com/cloudwego/hertz/pkg/app/server/binding" 60 "github.com/cloudwego/hertz/pkg/app/server/render" 61 "github.com/cloudwego/hertz/pkg/common/errors" 62 "github.com/cloudwego/hertz/pkg/common/tracer/traceinfo" 63 "github.com/cloudwego/hertz/pkg/common/utils" 64 "github.com/cloudwego/hertz/pkg/network" 65 "github.com/cloudwego/hertz/pkg/protocol" 66 "github.com/cloudwego/hertz/pkg/protocol/consts" 67 rConsts "github.com/cloudwego/hertz/pkg/route/consts" 68 "github.com/cloudwego/hertz/pkg/route/param" 69 ) 70 71 var zeroTCPAddr = &net.TCPAddr{ 72 IP: net.IPv4zero, 73 } 74 75 type Handler interface { 76 ServeHTTP(c context.Context, ctx *RequestContext) 77 } 78 79 type ClientIP func(ctx *RequestContext) string 80 81 type ClientIPOptions struct { 82 RemoteIPHeaders []string 83 TrustedCIDRs []*net.IPNet 84 } 85 86 var defaultTrustedCIDRs = []*net.IPNet{ 87 { // 0.0.0.0/0 (IPv4) 88 IP: net.IP{0x0, 0x0, 0x0, 0x0}, 89 Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}, 90 }, 91 { // ::/0 (IPv6) 92 IP: net.IP{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 93 Mask: net.IPMask{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 94 }, 95 } 96 97 var defaultClientIPOptions = ClientIPOptions{ 98 RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, 99 TrustedCIDRs: defaultTrustedCIDRs, 100 } 101 102 // ClientIPWithOption used to generate custom ClientIP function and set by engine.SetClientIPFunc 103 func ClientIPWithOption(opts ClientIPOptions) ClientIP { 104 return func(ctx *RequestContext) string { 105 RemoteIPHeaders := opts.RemoteIPHeaders 106 TrustedCIDRs := opts.TrustedCIDRs 107 108 remoteIPStr, _, err := net.SplitHostPort(strings.TrimSpace(ctx.RemoteAddr().String())) 109 if err != nil { 110 return "" 111 } 112 113 remoteIP := net.ParseIP(remoteIPStr) 114 if remoteIP == nil { 115 return "" 116 } 117 118 trusted := isTrustedProxy(TrustedCIDRs, remoteIP) 119 120 if trusted { 121 for _, headerName := range RemoteIPHeaders { 122 ip, valid := validateHeader(TrustedCIDRs, ctx.Request.Header.Get(headerName)) 123 if valid { 124 return ip 125 } 126 } 127 } 128 129 return remoteIPStr 130 } 131 } 132 133 // isTrustedProxy will check whether the IP address is included in the trusted list according to trustedCIDRs 134 func isTrustedProxy(trustedCIDRs []*net.IPNet, remoteIP net.IP) bool { 135 if trustedCIDRs == nil { 136 return false 137 } 138 139 for _, cidr := range trustedCIDRs { 140 if cidr.Contains(remoteIP) { 141 return true 142 } 143 } 144 return false 145 } 146 147 // validateHeader will parse X-Real-IP and X-Forwarded-For header and return the Initial client IP address or an untrusted IP address 148 func validateHeader(trustedCIDRs []*net.IPNet, header string) (clientIP string, valid bool) { 149 if header == "" { 150 return "", false 151 } 152 items := strings.Split(header, ",") 153 for i := len(items) - 1; i >= 0; i-- { 154 ipStr := strings.TrimSpace(items[i]) 155 ip := net.ParseIP(ipStr) 156 if ip == nil { 157 break 158 } 159 160 // X-Forwarded-For is appended by proxy 161 // Check IPs in reverse order and stop when find untrusted proxy 162 if (i == 0) || (!isTrustedProxy(trustedCIDRs, ip)) { 163 return ipStr, true 164 } 165 } 166 return "", false 167 } 168 169 var defaultClientIP = ClientIPWithOption(defaultClientIPOptions) 170 171 // SetClientIPFunc sets ClientIP function implementation to get ClientIP. 172 // Deprecated: Use engine.SetClientIPFunc instead of SetClientIPFunc 173 func SetClientIPFunc(fn ClientIP) { 174 defaultClientIP = fn 175 } 176 177 type FormValueFunc func(*RequestContext, string) []byte 178 179 var defaultFormValue = func(ctx *RequestContext, key string) []byte { 180 v := ctx.QueryArgs().Peek(key) 181 if len(v) > 0 { 182 return v 183 } 184 v = ctx.PostArgs().Peek(key) 185 if len(v) > 0 { 186 return v 187 } 188 mf, err := ctx.MultipartForm() 189 if err == nil && mf.Value != nil { 190 vv := mf.Value[key] 191 if len(vv) > 0 { 192 return []byte(vv[0]) 193 } 194 } 195 return nil 196 } 197 198 type RequestContext struct { 199 conn network.Conn 200 Request protocol.Request 201 Response protocol.Response 202 203 // Errors is a list of errors attached to all the handlers/middlewares who used this context. 204 Errors errors.ErrorChain 205 206 Params param.Params 207 handlers HandlersChain 208 fullPath string 209 index int8 210 HTMLRender render.HTMLRender 211 212 // This mutex protect Keys map. 213 mu sync.RWMutex 214 215 // Keys is a key/value pair exclusively for the context of each request. 216 Keys map[string]interface{} 217 218 hijackHandler HijackHandler 219 220 finishedMu sync.Mutex 221 222 // finished means the request end. 223 finished chan struct{} 224 225 // traceInfo defines the trace information. 226 traceInfo traceinfo.TraceInfo 227 228 // enableTrace defines whether enable trace. 229 enableTrace bool 230 231 // clientIPFunc get client ip by use custom function. 232 clientIPFunc ClientIP 233 234 // clientIPFunc get form value by use custom function. 235 formValueFunc FormValueFunc 236 237 binder binding.Binder 238 validator binding.StructValidator 239 exiled bool 240 } 241 242 // Exile marks this RequestContext as not to be recycled. 243 // Experimental features: Use with caution, it may have a slight impact on performance. 244 func (ctx *RequestContext) Exile() { 245 ctx.exiled = true 246 } 247 248 func (ctx *RequestContext) IsExiled() bool { 249 return ctx.exiled 250 } 251 252 // Flush is the shortcut for ctx.Response.GetHijackWriter().Flush(). 253 // Will return nil if the response writer is not hijacked. 254 func (ctx *RequestContext) Flush() error { 255 if ctx.Response.GetHijackWriter() == nil { 256 return nil 257 } 258 return ctx.Response.GetHijackWriter().Flush() 259 } 260 261 func (ctx *RequestContext) SetClientIPFunc(f ClientIP) { 262 ctx.clientIPFunc = f 263 } 264 265 func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) { 266 ctx.formValueFunc = f 267 } 268 269 func (ctx *RequestContext) SetBinder(binder binding.Binder) { 270 ctx.binder = binder 271 } 272 273 func (ctx *RequestContext) SetValidator(validator binding.StructValidator) { 274 ctx.validator = validator 275 } 276 277 func (ctx *RequestContext) GetTraceInfo() traceinfo.TraceInfo { 278 return ctx.traceInfo 279 } 280 281 func (ctx *RequestContext) SetTraceInfo(t traceinfo.TraceInfo) { 282 ctx.traceInfo = t 283 } 284 285 func (ctx *RequestContext) IsEnableTrace() bool { 286 return ctx.enableTrace 287 } 288 289 // SetEnableTrace sets whether enable trace. 290 // 291 // NOTE: biz handler must not modify this value, otherwise, it may panic. 292 func (ctx *RequestContext) SetEnableTrace(enable bool) { 293 ctx.enableTrace = enable 294 } 295 296 // NewContext make a pure RequestContext without any http request/response information 297 // 298 // Set the Request filed before use it for handlers 299 func NewContext(maxParams uint16) *RequestContext { 300 v := make(param.Params, 0, maxParams) 301 ctx := &RequestContext{Params: v, index: -1} 302 return ctx 303 } 304 305 // Loop fn for every k/v in Keys 306 func (ctx *RequestContext) ForEachKey(fn func(k string, v interface{})) { 307 ctx.mu.RLock() 308 for key, val := range ctx.Keys { 309 fn(key, val) 310 } 311 ctx.mu.RUnlock() 312 } 313 314 func (ctx *RequestContext) SetConn(c network.Conn) { 315 ctx.conn = c 316 } 317 318 func (ctx *RequestContext) GetConn() network.Conn { 319 return ctx.conn 320 } 321 322 func (ctx *RequestContext) SetHijackHandler(h HijackHandler) { 323 ctx.hijackHandler = h 324 } 325 326 func (ctx *RequestContext) GetHijackHandler() HijackHandler { 327 return ctx.hijackHandler 328 } 329 330 func (ctx *RequestContext) GetReader() network.Reader { 331 return ctx.conn 332 } 333 334 func (ctx *RequestContext) GetWriter() network.Writer { 335 return ctx.conn 336 } 337 338 func (ctx *RequestContext) GetIndex() int8 { 339 return ctx.index 340 } 341 342 // SetIndex reset the handler's execution index 343 // Disclaimer: You can loop yourself to deal with this, use wisely. 344 func (ctx *RequestContext) SetIndex(index int8) { 345 ctx.index = index 346 } 347 348 type HandlerFunc func(c context.Context, ctx *RequestContext) 349 350 // HandlersChain defines a HandlerFunc array. 351 type HandlersChain []HandlerFunc 352 353 type HandlerNameOperator interface { 354 SetHandlerName(handler HandlerFunc, name string) 355 GetHandlerName(handler HandlerFunc) string 356 } 357 358 func SetHandlerNameOperator(o HandlerNameOperator) { 359 inbuiltHandlerNameOperator = o 360 } 361 362 type inbuiltHandlerNameOperatorStruct struct { 363 handlerNames map[uintptr]string 364 } 365 366 func (o *inbuiltHandlerNameOperatorStruct) SetHandlerName(handler HandlerFunc, name string) { 367 o.handlerNames[getFuncAddr(handler)] = name 368 } 369 370 func (o *inbuiltHandlerNameOperatorStruct) GetHandlerName(handler HandlerFunc) string { 371 return o.handlerNames[getFuncAddr(handler)] 372 } 373 374 type concurrentHandlerNameOperatorStruct struct { 375 handlerNames map[uintptr]string 376 lock sync.RWMutex 377 } 378 379 func (o *concurrentHandlerNameOperatorStruct) SetHandlerName(handler HandlerFunc, name string) { 380 o.lock.Lock() 381 defer o.lock.Unlock() 382 o.handlerNames[getFuncAddr(handler)] = name 383 } 384 385 func (o *concurrentHandlerNameOperatorStruct) GetHandlerName(handler HandlerFunc) string { 386 o.lock.RLock() 387 defer o.lock.RUnlock() 388 return o.handlerNames[getFuncAddr(handler)] 389 } 390 391 func SetConcurrentHandlerNameOperator() { 392 SetHandlerNameOperator(&concurrentHandlerNameOperatorStruct{handlerNames: map[uintptr]string{}}) 393 } 394 395 func init() { 396 inbuiltHandlerNameOperator = &inbuiltHandlerNameOperatorStruct{handlerNames: map[uintptr]string{}} 397 } 398 399 var inbuiltHandlerNameOperator HandlerNameOperator 400 401 func SetHandlerName(handler HandlerFunc, name string) { 402 inbuiltHandlerNameOperator.SetHandlerName(handler, name) 403 } 404 405 func GetHandlerName(handler HandlerFunc) string { 406 return inbuiltHandlerNameOperator.GetHandlerName(handler) 407 } 408 409 func getFuncAddr(v interface{}) uintptr { 410 return reflect.ValueOf(reflect.ValueOf(v)).Field(1).Pointer() 411 } 412 413 // HijackHandler must process the hijacked connection c. 414 // 415 // If KeepHijackedConns is disabled, which is by default, 416 // the connection c is automatically closed after returning from HijackHandler. 417 // 418 // The connection c must not be used after returning from the handler, if KeepHijackedConns is disabled. 419 // 420 // When KeepHijackedConns enabled, hertz will not Close() the connection, 421 // you must do it when you need it. You must not use c in any way after calling Close(). 422 // 423 // network.Connection provide two options of io: net.Conn and zero-copy read/write 424 type HijackHandler func(c network.Conn) 425 426 // Hijack registers the given handler for connection hijacking. 427 // 428 // The handler is called after returning from RequestHandler 429 // and sending http response. The current connection is passed 430 // to the handler. The connection is automatically closed after 431 // returning from the handler. 432 // 433 // The server skips calling the handler in the following cases: 434 // 435 // - 'Connection: close' header exists in either request or response. 436 // - Unexpected error during response writing to the connection. 437 // 438 // The server stops processing requests from hijacked connections. 439 // 440 // Server limits such as Concurrency, ReadTimeout, WriteTimeout, etc. 441 // aren't applied to hijacked connections. 442 // 443 // The handler must not retain references to ctx members. 444 // 445 // Arbitrary 'Connection: Upgrade' protocols may be implemented 446 // with HijackHandler. For instance, 447 // 448 // - WebSocket ( https://en.wikipedia.org/wiki/WebSocket ) 449 // - HTTP/2.0 ( https://en.wikipedia.org/wiki/HTTP/2 ) 450 func (ctx *RequestContext) Hijack(handler HijackHandler) { 451 ctx.hijackHandler = handler 452 } 453 454 // Last returns the last handler of the handler chain. 455 // 456 // Generally speaking, the last handler is the main handler. 457 func (c HandlersChain) Last() HandlerFunc { 458 if length := len(c); length > 0 { 459 return c[length-1] 460 } 461 return nil 462 } 463 464 func (ctx *RequestContext) Finished() <-chan struct{} { 465 ctx.finishedMu.Lock() 466 if ctx.finished == nil { 467 ctx.finished = make(chan struct{}) 468 } 469 ch := ctx.finished 470 ctx.finishedMu.Unlock() 471 return ch 472 } 473 474 // GetRequest returns a copy of Request. 475 func (ctx *RequestContext) GetRequest() (dst *protocol.Request) { 476 dst = &protocol.Request{} 477 ctx.Request.CopyTo(dst) 478 return 479 } 480 481 // GetResponse returns a copy of Response. 482 func (ctx *RequestContext) GetResponse() (dst *protocol.Response) { 483 dst = &protocol.Response{} 484 ctx.Response.CopyTo(dst) 485 return 486 } 487 488 // Value returns the value associated with this context for key, or nil 489 // if no value is associated with key. Successive calls to Value with 490 // the same key returns the same result. 491 // 492 // In case the Key is reset after response, Value() return nil if ctx.Key is nil. 493 func (ctx *RequestContext) Value(key interface{}) interface{} { 494 // this ctx has been reset, return nil. 495 if ctx.Keys == nil { 496 return nil 497 } 498 if keyString, ok := key.(string); ok { 499 val, _ := ctx.Get(keyString) 500 return val 501 } 502 return nil 503 } 504 505 // Hijacked returns true after Hijack is called. 506 func (ctx *RequestContext) Hijacked() bool { 507 return ctx.hijackHandler != nil 508 } 509 510 // SetBodyStream sets response body stream and, optionally body size. 511 // 512 // bodyStream.Close() is called after finishing reading all body data 513 // if it implements io.Closer. 514 // 515 // If bodySize is >= 0, then bodySize bytes must be provided by bodyStream 516 // before returning io.EOF. 517 // 518 // If bodySize < 0, then bodyStream is read until io.EOF. 519 // 520 // See also SetBodyStreamWriter. 521 func (ctx *RequestContext) SetBodyStream(bodyStream io.Reader, bodySize int) { 522 ctx.Response.SetBodyStream(bodyStream, bodySize) 523 } 524 525 // Host returns requested host. 526 // 527 // The host is valid until returning from RequestHandler. 528 func (ctx *RequestContext) Host() []byte { 529 return ctx.URI().Host() 530 } 531 532 // RemoteAddr returns client address for the given request. 533 // 534 // If address is nil, it will return zeroTCPAddr. 535 func (ctx *RequestContext) RemoteAddr() net.Addr { 536 if ctx.conn == nil { 537 return zeroTCPAddr 538 } 539 addr := ctx.conn.RemoteAddr() 540 if addr == nil { 541 return zeroTCPAddr 542 } 543 return addr 544 } 545 546 // WriteString appends s to response body. 547 func (ctx *RequestContext) WriteString(s string) (int, error) { 548 ctx.Response.AppendBodyString(s) 549 return len(s), nil 550 } 551 552 // SetContentType sets response Content-Type. 553 func (ctx *RequestContext) SetContentType(contentType string) { 554 ctx.Response.Header.SetContentType(contentType) 555 } 556 557 // Path returns requested path. 558 // 559 // The path is valid until returning from RequestHandler. 560 func (ctx *RequestContext) Path() []byte { 561 return ctx.URI().Path() 562 } 563 564 // NotModified resets response and sets '304 Not Modified' response status code. 565 func (ctx *RequestContext) NotModified() { 566 ctx.Response.Reset() 567 ctx.SetStatusCode(consts.StatusNotModified) 568 } 569 570 // IfModifiedSince returns true if lastModified exceeds 'If-Modified-Since' 571 // value from the request header. 572 // 573 // The function returns true also 'If-Modified-Since' request header is missing. 574 func (ctx *RequestContext) IfModifiedSince(lastModified time.Time) bool { 575 ifModStr := ctx.Request.Header.PeekIfModifiedSinceBytes() 576 if len(ifModStr) == 0 { 577 return true 578 } 579 ifMod, err := bytesconv.ParseHTTPDate(ifModStr) 580 if err != nil { 581 return true 582 } 583 lastModified = lastModified.Truncate(time.Second) 584 return ifMod.Before(lastModified) 585 } 586 587 // URI returns requested uri. 588 // 589 // The uri is valid until returning from RequestHandler. 590 func (ctx *RequestContext) URI() *protocol.URI { 591 return ctx.Request.URI() 592 } 593 594 func (ctx *RequestContext) String(code int, format string, values ...interface{}) { 595 ctx.Render(code, render.String{Format: format, Data: values}) 596 } 597 598 // FullPath returns a matched route full path. For not found routes 599 // returns an empty string. 600 // 601 // router.GET("/user/:id", func(c context.Context, ctx *app.RequestContext) { 602 // ctx.FullPath() == "/user/:id" // true 603 // }) 604 func (ctx *RequestContext) FullPath() string { 605 return ctx.fullPath 606 } 607 608 func (ctx *RequestContext) SetFullPath(p string) { 609 ctx.fullPath = p 610 } 611 612 // SetStatusCode sets response status code. 613 func (ctx *RequestContext) SetStatusCode(statusCode int) { 614 ctx.Response.SetStatusCode(statusCode) 615 } 616 617 // Write writes p into response body. 618 func (ctx *RequestContext) Write(p []byte) (int, error) { 619 ctx.Response.AppendBody(p) 620 return len(p), nil 621 } 622 623 // File writes the specified file into the body stream in an efficient way. 624 func (ctx *RequestContext) File(filepath string) { 625 ServeFile(ctx, filepath) 626 } 627 628 func (ctx *RequestContext) FileFromFS(filepath string, fs *FS) { 629 defer func(old string) { 630 ctx.Request.URI().SetPath(old) 631 }(string(ctx.Request.URI().Path())) 632 633 ctx.Request.URI().SetPath(filepath) 634 635 fs.NewRequestHandler()(context.Background(), ctx) 636 } 637 638 // FileAttachment use an efficient way to write the file to body stream. 639 // 640 // When client download the file, it will rename the file as filename 641 func (ctx *RequestContext) FileAttachment(filepath, filename string) { 642 ctx.Response.Header.Set("content-disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) 643 ServeFile(ctx, filepath) 644 } 645 646 // SetBodyString sets response body to the given value. 647 func (ctx *RequestContext) SetBodyString(body string) { 648 ctx.Response.SetBodyString(body) 649 } 650 651 // SetContentTypeBytes sets response Content-Type. 652 // 653 // It is safe modifying contentType buffer after function return. 654 func (ctx *RequestContext) SetContentTypeBytes(contentType []byte) { 655 ctx.Response.Header.SetContentTypeBytes(contentType) 656 } 657 658 // FormFile returns the first file for the provided form key. 659 func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) { 660 return ctx.Request.FormFile(name) 661 } 662 663 // FormValue returns form value associated with the given key. 664 // 665 // The value is searched in the following places: 666 // 667 // - Query string. 668 // - POST or PUT body. 669 // 670 // There are more fine-grained methods for obtaining form values: 671 // 672 // - QueryArgs for obtaining values from query string. 673 // - PostArgs for obtaining values from POST or PUT body. 674 // - MultipartForm for obtaining values from multipart form. 675 // - FormFile for obtaining uploaded files. 676 // 677 // The returned value is valid until returning from RequestHandler. 678 // Use engine.SetCustomFormValueFunc to change action of FormValue. 679 func (ctx *RequestContext) FormValue(key string) []byte { 680 if ctx.formValueFunc != nil { 681 return ctx.formValueFunc(ctx, key) 682 } 683 return defaultFormValue(ctx, key) 684 } 685 686 func (ctx *RequestContext) multipartFormValue(key string) (string, bool) { 687 mf, err := ctx.MultipartForm() 688 if err == nil && mf.Value != nil { 689 vv := mf.Value[key] 690 if len(vv) > 0 { 691 return vv[0], true 692 } 693 } 694 return "", false 695 } 696 697 func (ctx *RequestContext) multipartFormValueArray(key string) ([]string, bool) { 698 mf, err := ctx.MultipartForm() 699 if err == nil && mf.Value != nil { 700 vv := mf.Value[key] 701 if len(vv) > 0 { 702 return vv, true 703 } 704 } 705 return nil, false 706 } 707 708 func (ctx *RequestContext) RequestBodyStream() io.Reader { 709 return ctx.Request.BodyStream() 710 } 711 712 // MultipartForm returns request's multipart form. 713 // 714 // Returns errNoMultipartForm if request's content-type 715 // isn't 'multipart/form-data'. 716 // 717 // All uploaded temporary files are automatically deleted after 718 // returning from RequestHandler. Either move or copy uploaded files 719 // into new place if you want retaining them. 720 // 721 // Use SaveMultipartFile function for permanently saving uploaded file. 722 // 723 // The returned form is valid until returning from RequestHandler. 724 // 725 // See also FormFile and FormValue. 726 func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) { 727 return ctx.Request.MultipartForm() 728 } 729 730 // SaveUploadedFile uploads the form file to specific dst. 731 func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error { 732 src, err := file.Open() 733 if err != nil { 734 return err 735 } 736 defer src.Close() 737 738 out, err := os.Create(dst) 739 if err != nil { 740 return err 741 } 742 defer out.Close() 743 744 _, err = io.Copy(out, src) 745 return err 746 } 747 748 // SetConnectionClose sets 'Connection: close' response header. 749 func (ctx *RequestContext) SetConnectionClose() { 750 ctx.Response.SetConnectionClose() 751 } 752 753 // IsGet returns true if request method is GET. 754 func (ctx *RequestContext) IsGet() bool { 755 return ctx.Request.Header.IsGet() 756 } 757 758 // IsHead returns true if request method is HEAD. 759 func (ctx *RequestContext) IsHead() bool { 760 return ctx.Request.Header.IsHead() 761 } 762 763 // IsPost returns true if request method is POST. 764 func (ctx *RequestContext) IsPost() bool { 765 return ctx.Request.Header.IsPost() 766 } 767 768 // Method return request method. 769 // 770 // Returned value is valid until returning from RequestHandler. 771 func (ctx *RequestContext) Method() []byte { 772 return ctx.Request.Header.Method() 773 } 774 775 // NotFound resets response and sets '404 Not Found' response status code. 776 func (ctx *RequestContext) NotFound() { 777 ctx.Response.Reset() 778 ctx.SetStatusCode(consts.StatusNotFound) 779 ctx.SetBodyString(consts.StatusMessage(consts.StatusNotFound)) 780 } 781 782 func (ctx *RequestContext) redirect(uri []byte, statusCode int) { 783 ctx.Response.Header.SetCanonical(bytestr.StrLocation, uri) 784 statusCode = getRedirectStatusCode(statusCode) 785 ctx.Response.SetStatusCode(statusCode) 786 } 787 788 func getRedirectStatusCode(statusCode int) int { 789 if statusCode == consts.StatusMovedPermanently || statusCode == consts.StatusFound || 790 statusCode == consts.StatusSeeOther || statusCode == consts.StatusTemporaryRedirect || 791 statusCode == consts.StatusPermanentRedirect { 792 return statusCode 793 } 794 return consts.StatusFound 795 } 796 797 // Copy returns a copy of the current context that can be safely used outside 798 // the request's scope. 799 // 800 // NOTE: If you want to pass requestContext to a goroutine, call this method 801 // to get a copy of requestContext. 802 func (ctx *RequestContext) Copy() *RequestContext { 803 cp := &RequestContext{ 804 conn: ctx.conn, 805 Params: ctx.Params, 806 } 807 ctx.Request.CopyTo(&cp.Request) 808 ctx.Response.CopyTo(&cp.Response) 809 cp.index = rConsts.AbortIndex 810 cp.handlers = nil 811 cp.Keys = map[string]interface{}{} 812 ctx.mu.RLock() 813 for k, v := range ctx.Keys { 814 cp.Keys[k] = v 815 } 816 ctx.mu.RUnlock() 817 paramCopy := make([]param.Param, len(cp.Params)) 818 copy(paramCopy, cp.Params) 819 cp.Params = paramCopy 820 cp.fullPath = ctx.fullPath 821 cp.clientIPFunc = ctx.clientIPFunc 822 cp.formValueFunc = ctx.formValueFunc 823 cp.binder = ctx.binder 824 cp.validator = ctx.validator 825 return cp 826 } 827 828 // Next should be used only inside middleware. 829 // It executes the pending handlers in the chain inside the calling handler. 830 func (ctx *RequestContext) Next(c context.Context) { 831 ctx.index++ 832 for ctx.index < int8(len(ctx.handlers)) { 833 ctx.handlers[ctx.index](c, ctx) 834 ctx.index++ 835 } 836 } 837 838 // Handler returns the main handler. 839 func (ctx *RequestContext) Handler() HandlerFunc { 840 return ctx.handlers.Last() 841 } 842 843 // Handlers returns the handler chain. 844 func (ctx *RequestContext) Handlers() HandlersChain { 845 return ctx.handlers 846 } 847 848 func (ctx *RequestContext) SetHandlers(hc HandlersChain) { 849 ctx.handlers = hc 850 } 851 852 // HandlerName returns the main handler's name. 853 // 854 // For example if the handler is "handleGetUsers()", this function will return "main.handleGetUsers". 855 func (ctx *RequestContext) HandlerName() string { 856 return utils.NameOfFunction(ctx.handlers.Last()) 857 } 858 859 func (ctx *RequestContext) ResetWithoutConn() { 860 ctx.Params = ctx.Params[0:0] 861 ctx.Errors = ctx.Errors[0:0] 862 ctx.handlers = nil 863 ctx.index = -1 864 ctx.fullPath = "" 865 ctx.Keys = nil 866 867 if ctx.finished != nil { 868 close(ctx.finished) 869 ctx.finished = nil 870 } 871 872 ctx.Request.ResetWithoutConn() 873 ctx.Response.Reset() 874 if ctx.IsEnableTrace() { 875 ctx.traceInfo.Reset() 876 } 877 } 878 879 // Reset resets requestContext. 880 // 881 // NOTE: It is an internal function. You should not use it. 882 func (ctx *RequestContext) Reset() { 883 ctx.ResetWithoutConn() 884 ctx.conn = nil 885 } 886 887 // Redirect returns an HTTP redirect to the specific location. 888 // Note that this will not stop the current handler. 889 // In other words, even if Redirect() is called, the remaining handlers will still be executed and cause unexpected result. 890 // So it should call Abort to ensure the remaining handlers of this request will not be called. 891 // 892 // ctx.Abort() 893 // return 894 func (ctx *RequestContext) Redirect(statusCode int, uri []byte) { 895 ctx.redirect(uri, statusCode) 896 } 897 898 // Header is an intelligent shortcut for ctx.Response.Header.Set(key, value). 899 // It writes a header in the response. 900 // If value == "", this method removes the header `ctx.Response.Header.Del(key)`. 901 func (ctx *RequestContext) Header(key, value string) { 902 if value == "" { 903 ctx.Response.Header.Del(key) 904 return 905 } 906 ctx.Response.Header.Set(key, value) 907 } 908 909 // Set is used to store a new key/value pair exclusively for this context. 910 // It also lazy initializes c.Keys if it was not used previously. 911 func (ctx *RequestContext) Set(key string, value interface{}) { 912 ctx.mu.Lock() 913 if ctx.Keys == nil { 914 ctx.Keys = make(map[string]interface{}) 915 } 916 917 ctx.Keys[key] = value 918 ctx.mu.Unlock() 919 } 920 921 // Get returns the value for the given key, ie: (value, true). 922 // If the value does not exist it returns (nil, false) 923 func (ctx *RequestContext) Get(key string) (value interface{}, exists bool) { 924 ctx.mu.RLock() 925 value, exists = ctx.Keys[key] 926 ctx.mu.RUnlock() 927 return 928 } 929 930 // MustGet returns the value for the given key if it exists, otherwise it panics. 931 func (ctx *RequestContext) MustGet(key string) interface{} { 932 if value, exists := ctx.Get(key); exists { 933 return value 934 } 935 panic("Key \"" + key + "\" does not exist") 936 } 937 938 // GetString returns the value associated with the key as a string. Return "" when type is error. 939 func (ctx *RequestContext) GetString(key string) (s string) { 940 if val, ok := ctx.Get(key); ok && val != nil { 941 s, _ = val.(string) 942 } 943 return 944 } 945 946 // GetBool returns the value associated with the key as a boolean. Return false when type is error. 947 func (ctx *RequestContext) GetBool(key string) (b bool) { 948 if val, ok := ctx.Get(key); ok && val != nil { 949 b, _ = val.(bool) 950 } 951 return 952 } 953 954 // GetInt returns the value associated with the key as an integer. Return 0 when type is error. 955 func (ctx *RequestContext) GetInt(key string) (i int) { 956 if val, ok := ctx.Get(key); ok && val != nil { 957 i, _ = val.(int) 958 } 959 return 960 } 961 962 // GetInt32 returns the value associated with the key as an integer. Return int32(0) when type is error. 963 func (ctx *RequestContext) GetInt32(key string) (i32 int32) { 964 if val, ok := ctx.Get(key); ok && val != nil { 965 i32, _ = val.(int32) 966 } 967 return 968 } 969 970 // GetInt64 returns the value associated with the key as an integer. Return int64(0) when type is error. 971 func (ctx *RequestContext) GetInt64(key string) (i64 int64) { 972 if val, ok := ctx.Get(key); ok && val != nil { 973 i64, _ = val.(int64) 974 } 975 return 976 } 977 978 // GetUint returns the value associated with the key as an unsigned integer. Return uint(0) when type is error. 979 func (ctx *RequestContext) GetUint(key string) (ui uint) { 980 if val, ok := ctx.Get(key); ok && val != nil { 981 ui, _ = val.(uint) 982 } 983 return 984 } 985 986 // GetUint32 returns the value associated with the key as an unsigned integer. Return uint32(0) when type is error. 987 func (ctx *RequestContext) GetUint32(key string) (ui32 uint32) { 988 if val, ok := ctx.Get(key); ok && val != nil { 989 ui32, _ = val.(uint32) 990 } 991 return 992 } 993 994 // GetUint64 returns the value associated with the key as an unsigned integer. Return uint64(0) when type is error. 995 func (ctx *RequestContext) GetUint64(key string) (ui64 uint64) { 996 if val, ok := ctx.Get(key); ok && val != nil { 997 ui64, _ = val.(uint64) 998 } 999 return 1000 } 1001 1002 // GetFloat32 returns the value associated with the key as a float32. Return float32(0.0) when type is error. 1003 func (ctx *RequestContext) GetFloat32(key string) (f32 float32) { 1004 if val, ok := ctx.Get(key); ok && val != nil { 1005 f32, _ = val.(float32) 1006 } 1007 return 1008 } 1009 1010 // GetFloat64 returns the value associated with the key as a float64. Return 0.0 when type is error. 1011 func (ctx *RequestContext) GetFloat64(key string) (f64 float64) { 1012 if val, ok := ctx.Get(key); ok && val != nil { 1013 f64, _ = val.(float64) 1014 } 1015 return 1016 } 1017 1018 // GetTime returns the value associated with the key as time. Return time.Time{} when type is error. 1019 func (ctx *RequestContext) GetTime(key string) (t time.Time) { 1020 if val, ok := ctx.Get(key); ok && val != nil { 1021 t, _ = val.(time.Time) 1022 } 1023 return 1024 } 1025 1026 // GetDuration returns the value associated with the key as a duration. Return time.Duration(0) when type is error. 1027 func (ctx *RequestContext) GetDuration(key string) (d time.Duration) { 1028 if val, ok := ctx.Get(key); ok && val != nil { 1029 d, _ = val.(time.Duration) 1030 } 1031 return 1032 } 1033 1034 // GetStringSlice returns the value associated with the key as a slice of strings. 1035 // 1036 // Return []string(nil) when type is error. 1037 func (ctx *RequestContext) GetStringSlice(key string) (ss []string) { 1038 if val, ok := ctx.Get(key); ok && val != nil { 1039 ss, _ = val.([]string) 1040 } 1041 return 1042 } 1043 1044 // GetStringMap returns the value associated with the key as a map of interfaces. 1045 // 1046 // Return map[string]interface{}(nil) when type is error. 1047 func (ctx *RequestContext) GetStringMap(key string) (sm map[string]interface{}) { 1048 if val, ok := ctx.Get(key); ok && val != nil { 1049 sm, _ = val.(map[string]interface{}) 1050 } 1051 return 1052 } 1053 1054 // GetStringMapString returns the value associated with the key as a map of strings. 1055 // 1056 // Return map[string]string(nil) when type is error. 1057 func (ctx *RequestContext) GetStringMapString(key string) (sms map[string]string) { 1058 if val, ok := ctx.Get(key); ok && val != nil { 1059 sms, _ = val.(map[string]string) 1060 } 1061 return 1062 } 1063 1064 // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. 1065 // 1066 // Return map[string][]string(nil) when type is error. 1067 func (ctx *RequestContext) GetStringMapStringSlice(key string) (smss map[string][]string) { 1068 if val, ok := ctx.Get(key); ok && val != nil { 1069 smss, _ = val.(map[string][]string) 1070 } 1071 return 1072 } 1073 1074 // Param returns the value of the URL param. 1075 // It is a shortcut for c.Params.ByName(key) 1076 // 1077 // router.GET("/user/:id", func(c context.Context, ctx *app.RequestContext) { 1078 // // a GET request to /user/john 1079 // id := ctx.Param("id") // id == "john" 1080 // }) 1081 func (ctx *RequestContext) Param(key string) string { 1082 return ctx.Params.ByName(key) 1083 } 1084 1085 // Abort prevents pending handlers from being called. 1086 // 1087 // Note that this will not stop the current handler. 1088 // Let's say you have an authorization middleware that validates that the current request is authorized. 1089 // If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers 1090 // for this request are not called. 1091 func (ctx *RequestContext) Abort() { 1092 ctx.index = rConsts.AbortIndex 1093 } 1094 1095 // AbortWithStatus calls `Abort()` and writes the headers with the specified status code. 1096 // 1097 // For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401). 1098 func (ctx *RequestContext) AbortWithStatus(code int) { 1099 ctx.SetStatusCode(code) 1100 ctx.Abort() 1101 } 1102 1103 // AbortWithMsg sets response status code to the given value and sets response body 1104 // to the given message. 1105 // 1106 // Warning: this will reset the response headers and body already set! 1107 func (ctx *RequestContext) AbortWithMsg(msg string, statusCode int) { 1108 ctx.Response.Reset() 1109 ctx.SetStatusCode(statusCode) 1110 ctx.SetContentTypeBytes(bytestr.DefaultContentType) 1111 ctx.SetBodyString(msg) 1112 ctx.Abort() 1113 } 1114 1115 // AbortWithStatusJSON calls `Abort()` and then `JSON` internally. 1116 // 1117 // This method stops the chain, writes the status code and return a JSON body. 1118 // It also sets the Content-Type as "application/json". 1119 func (ctx *RequestContext) AbortWithStatusJSON(code int, jsonObj interface{}) { 1120 ctx.Abort() 1121 ctx.JSON(code, jsonObj) 1122 } 1123 1124 // Render writes the response headers and calls render.Render to render data. 1125 func (ctx *RequestContext) Render(code int, r render.Render) { 1126 ctx.SetStatusCode(code) 1127 1128 if !bodyAllowedForStatus(code) { 1129 r.WriteContentType(&ctx.Response) 1130 return 1131 } 1132 1133 if err := r.Render(&ctx.Response); err != nil { 1134 panic(err) 1135 } 1136 } 1137 1138 // ProtoBuf serializes the given struct as ProtoBuf into the response body. 1139 func (ctx *RequestContext) ProtoBuf(code int, obj interface{}) { 1140 ctx.Render(code, render.ProtoBuf{Data: obj}) 1141 } 1142 1143 // JSON serializes the given struct as JSON into the response body. 1144 // 1145 // It also sets the Content-Type as "application/json". 1146 func (ctx *RequestContext) JSON(code int, obj interface{}) { 1147 ctx.Render(code, render.JSONRender{Data: obj}) 1148 } 1149 1150 // PureJSON serializes the given struct as JSON into the response body. 1151 // PureJSON, unlike JSON, does not replace special html characters with their unicode entities. 1152 func (ctx *RequestContext) PureJSON(code int, obj interface{}) { 1153 ctx.Render(code, render.PureJSON{Data: obj}) 1154 } 1155 1156 // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. 1157 // It also sets the Content-Type as "application/json". 1158 func (ctx *RequestContext) IndentedJSON(code int, obj interface{}) { 1159 ctx.Render(code, render.IndentedJSON{Data: obj}) 1160 } 1161 1162 // HTML renders the HTTP template specified by its file name. 1163 // 1164 // It also updates the HTTP code and sets the Content-Type as "text/html". 1165 // See http://golang.org/doc/articles/wiki/ 1166 func (ctx *RequestContext) HTML(code int, name string, obj interface{}) { 1167 instance := ctx.HTMLRender.Instance(name, obj) 1168 ctx.Render(code, instance) 1169 } 1170 1171 // Data writes some data into the body stream and updates the HTTP code. 1172 func (ctx *RequestContext) Data(code int, contentType string, data []byte) { 1173 ctx.Render(code, render.Data{ 1174 ContentType: contentType, 1175 Data: data, 1176 }) 1177 } 1178 1179 // XML serializes the given struct as XML into the response body. 1180 // 1181 // It also sets the Content-Type as "application/xml". 1182 func (ctx *RequestContext) XML(code int, obj interface{}) { 1183 ctx.Render(code, render.XML{Data: obj}) 1184 } 1185 1186 // AbortWithError calls `AbortWithStatus()` and `Error()` internally. 1187 // 1188 // This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. 1189 // See RequestContext.Error() for more details. 1190 func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error { 1191 ctx.AbortWithStatus(code) 1192 return ctx.Error(err) 1193 } 1194 1195 // IsAborted returns true if the current context has aborted. 1196 func (ctx *RequestContext) IsAborted() bool { 1197 return ctx.index >= rConsts.AbortIndex 1198 } 1199 1200 // Error attaches an error to the current context. The error is pushed to a list of errors. 1201 // 1202 // It's a good idea to call Error for each error that occurred during the resolution of a request. 1203 // A middleware can be used to collect all the errors and push them to a database together, 1204 // print a log, or append it in the HTTP response. 1205 // Error will panic if err is nil. 1206 func (ctx *RequestContext) Error(err error) *errors.Error { 1207 if err == nil { 1208 panic("err is nil") 1209 } 1210 1211 parsedError, ok := err.(*errors.Error) 1212 if !ok { 1213 parsedError = &errors.Error{ 1214 Err: err, 1215 Type: errors.ErrorTypePrivate, 1216 } 1217 } 1218 1219 ctx.Errors = append(ctx.Errors, parsedError) 1220 return parsedError 1221 } 1222 1223 // ContentType returns the Content-Type header of the request. 1224 func (ctx *RequestContext) ContentType() []byte { 1225 return ctx.Request.Header.ContentType() 1226 } 1227 1228 // Cookie returns the value of the request cookie key. 1229 func (ctx *RequestContext) Cookie(key string) []byte { 1230 return ctx.Request.Header.Cookie(key) 1231 } 1232 1233 // SetCookie adds a Set-Cookie header to the Response's headers. 1234 // 1235 // Parameter introduce: 1236 // name and value is used to set cookie's name and value, eg. Set-Cookie: name=value 1237 // maxAge is use to set cookie's expiry date, eg. Set-Cookie: name=value; max-age=1 1238 // path and domain is used to set the scope of a cookie, eg. Set-Cookie: name=value;domain=localhost; path=/; 1239 // secure and httpOnly is used to sent cookies securely; eg. Set-Cookie: name=value;HttpOnly; secure; 1240 // sameSite let servers specify whether/when cookies are sent with cross-site requests; eg. Set-Cookie: name=value;HttpOnly; secure; SameSite=Lax; 1241 // 1242 // For example: 1243 // 1. ctx.SetCookie("user", "hertz", 1, "/", "localhost",protocol.CookieSameSiteLaxMode, true, true) 1244 // add response header ---> Set-Cookie: user=hertz; max-age=1; domain=localhost; path=/; HttpOnly; secure; SameSite=Lax; 1245 // 2. ctx.SetCookie("user", "hertz", 10, "/", "localhost",protocol.CookieSameSiteLaxMode, false, false) 1246 // add response header ---> Set-Cookie: user=hertz; max-age=10; domain=localhost; path=/; SameSite=Lax; 1247 // 3. ctx.SetCookie("", "hertz", 10, "/", "localhost",protocol.CookieSameSiteLaxMode, false, false) 1248 // add response header ---> Set-Cookie: hertz; max-age=10; domain=localhost; path=/; SameSite=Lax; 1249 // 4. ctx.SetCookie("user", "", 10, "/", "localhost",protocol.CookieSameSiteLaxMode, false, false) 1250 // add response header ---> Set-Cookie: user=; max-age=10; domain=localhost; path=/; SameSite=Lax; 1251 func (ctx *RequestContext) SetCookie(name, value string, maxAge int, path, domain string, sameSite protocol.CookieSameSite, secure, httpOnly bool) { 1252 ctx.setCookie(name, value, maxAge, path, domain, sameSite, secure, httpOnly, false) 1253 } 1254 1255 func (ctx *RequestContext) setCookie(name, value string, maxAge int, path, domain string, sameSite protocol.CookieSameSite, secure, httpOnly, partitioned bool) { 1256 if path == "" { 1257 path = "/" 1258 } 1259 cookie := protocol.AcquireCookie() 1260 defer protocol.ReleaseCookie(cookie) 1261 cookie.SetKey(name) 1262 cookie.SetValue(url.QueryEscape(value)) 1263 cookie.SetMaxAge(maxAge) 1264 cookie.SetPath(path) 1265 cookie.SetDomain(domain) 1266 cookie.SetSecure(secure) 1267 cookie.SetHTTPOnly(httpOnly) 1268 cookie.SetSameSite(sameSite) 1269 cookie.SetPartitioned(partitioned) 1270 ctx.Response.Header.SetCookie(cookie) 1271 } 1272 1273 // SetPartitionedCookie adds a partitioned cookie to the Response's headers. 1274 // Use protocol.CookieSameSiteNoneMode for cross-site cookies to work. 1275 // 1276 // Usage: ctx.SetPartitionedCookie("user", "name", 10, "/", "localhost", protocol.CookieSameSiteNoneMode, true, true) 1277 // 1278 // This adds the response header: Set-Cookie: user=name; Max-Age=10; Domain=localhost; Path=/; HttpOnly; Secure; SameSite=None; Partitioned 1279 func (ctx *RequestContext) SetPartitionedCookie(name, value string, maxAge int, path, domain string, sameSite protocol.CookieSameSite, secure, httpOnly bool) { 1280 ctx.setCookie(name, value, maxAge, path, domain, sameSite, secure, httpOnly, true) 1281 } 1282 1283 // UserAgent returns the value of the request user_agent. 1284 func (ctx *RequestContext) UserAgent() []byte { 1285 return ctx.Request.Header.UserAgent() 1286 } 1287 1288 // Status sets the HTTP response code. 1289 func (ctx *RequestContext) Status(code int) { 1290 ctx.SetStatusCode(code) 1291 } 1292 1293 // GetHeader returns value from request headers. 1294 func (ctx *RequestContext) GetHeader(key string) []byte { 1295 return ctx.Request.Header.Peek(key) 1296 } 1297 1298 // GetRawData returns body data. 1299 func (ctx *RequestContext) GetRawData() []byte { 1300 return ctx.Request.Body() 1301 } 1302 1303 // Body returns body data 1304 func (ctx *RequestContext) Body() ([]byte, error) { 1305 return ctx.Request.BodyE() 1306 } 1307 1308 // ClientIP tries to parse the headers in [X-Real-Ip, X-Forwarded-For]. 1309 // It calls RemoteIP() under the hood. If it cannot satisfy the requirements, 1310 // use engine.SetClientIPFunc to inject your own implementation. 1311 func (ctx *RequestContext) ClientIP() string { 1312 if ctx.clientIPFunc != nil { 1313 return ctx.clientIPFunc(ctx) 1314 } 1315 return defaultClientIP(ctx) 1316 } 1317 1318 // QueryArgs returns query arguments from RequestURI. 1319 // 1320 // It doesn't return POST'ed arguments - use PostArgs() for this. 1321 // Returned arguments are valid until returning from RequestHandler. 1322 // See also PostArgs, FormValue and FormFile. 1323 func (ctx *RequestContext) QueryArgs() *protocol.Args { 1324 return ctx.URI().QueryArgs() 1325 } 1326 1327 // PostArgs returns POST arguments. 1328 // 1329 // It doesn't return query arguments from RequestURI - use QueryArgs for this. 1330 // Returned arguments are valid until returning from RequestHandler. 1331 // See also QueryArgs, FormValue and FormFile. 1332 func (ctx *RequestContext) PostArgs() *protocol.Args { 1333 return ctx.Request.PostArgs() 1334 } 1335 1336 // Query returns the keyed url query value if it exists, otherwise it returns an empty string `("")`. 1337 // 1338 // For example: 1339 // 1340 // GET /path?id=1234&name=Manu&value= 1341 // c.Query("id") == "1234" 1342 // c.Query("name") == "Manu" 1343 // c.Query("value") == "" 1344 // c.Query("wtf") == "" 1345 func (ctx *RequestContext) Query(key string) string { 1346 value, _ := ctx.GetQuery(key) 1347 return value 1348 } 1349 1350 // DefaultQuery returns the keyed url query value if it exists, 1351 // otherwise it returns the specified defaultValue string. 1352 func (ctx *RequestContext) DefaultQuery(key, defaultValue string) string { 1353 if value, ok := ctx.GetQuery(key); ok { 1354 return value 1355 } 1356 return defaultValue 1357 } 1358 1359 // GetQuery returns the keyed url query value 1360 // 1361 // if it exists `(value, true)` (even when the value is an empty string) will be returned, 1362 // otherwise it returns `("", false)`. 1363 // For example: 1364 // 1365 // GET /?name=Manu&lastname= 1366 // ("Manu", true) == c.GetQuery("name") 1367 // ("", false) == c.GetQuery("id") 1368 // ("", true) == c.GetQuery("lastname") 1369 func (ctx *RequestContext) GetQuery(key string) (string, bool) { 1370 return ctx.QueryArgs().PeekExists(key) 1371 } 1372 1373 // PostForm returns the specified key from a POST urlencoded form or multipart form 1374 // when it exists, otherwise it returns an empty string `("")`. 1375 func (ctx *RequestContext) PostForm(key string) string { 1376 value, _ := ctx.GetPostForm(key) 1377 return value 1378 } 1379 1380 // PostFormArray returns the specified key from a POST urlencoded form or multipart form 1381 // when it exists, otherwise it returns an empty array `([])`. 1382 func (ctx *RequestContext) PostFormArray(key string) []string { 1383 values, _ := ctx.GetPostFormArray(key) 1384 return values 1385 } 1386 1387 // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form 1388 // when it exists, otherwise it returns the specified defaultValue string. 1389 // 1390 // See: PostForm() and GetPostForm() for further information. 1391 func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string { 1392 if value, ok := ctx.GetPostForm(key); ok { 1393 return value 1394 } 1395 return defaultValue 1396 } 1397 1398 // GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded 1399 // form or multipart form when it exists `(value, true)` (even when the value is an empty string), 1400 // otherwise it returns ("", false). 1401 // 1402 // For example, during a PATCH request to update the user's email: 1403 // 1404 // email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com" 1405 // email= --> ("", true) := GetPostForm("email") // set email to "" 1406 // --> ("", false) := GetPostForm("email") // do nothing with email 1407 func (ctx *RequestContext) GetPostForm(key string) (string, bool) { 1408 if v, exists := ctx.PostArgs().PeekExists(key); exists { 1409 return v, exists 1410 } 1411 return ctx.multipartFormValue(key) 1412 } 1413 1414 // GetPostFormArray is like PostFormArray(key). It returns the specified key from a POST urlencoded 1415 // form or multipart form when it exists `([]string, true)` (even when the value is an empty string), 1416 // otherwise it returns ([]string(nil), false). 1417 // 1418 // For example, during a PATCH request to update the item's tags: 1419 // 1420 // tag=tag1 tag=tag2 tag=tag3 --> (["tag1", "tag2", "tag3"], true) := GetPostFormArray("tags") // set tags to ["tag1", "tag2", "tag3"] 1421 // tags= --> (nil, true) := GetPostFormArray("tags") // set tags to nil 1422 // --> (nil, false) := GetPostFormArray("tags") // do nothing with tags 1423 func (ctx *RequestContext) GetPostFormArray(key string) ([]string, bool) { 1424 vs := ctx.PostArgs().PeekAll(key) 1425 values := make([]string, len(vs)) 1426 for i, v := range vs { 1427 values[i] = string(v) 1428 } 1429 if len(values) == 0 { 1430 return ctx.multipartFormValueArray(key) 1431 } else { 1432 return values, true 1433 } 1434 } 1435 1436 // bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function. 1437 func bodyAllowedForStatus(status int) bool { 1438 switch { 1439 case status >= 100 && status <= 199: 1440 return false 1441 case status == consts.StatusNoContent: 1442 return false 1443 case status == consts.StatusNotModified: 1444 return false 1445 } 1446 return true 1447 } 1448 1449 func (ctx *RequestContext) getBinder() binding.Binder { 1450 if ctx.binder != nil { 1451 return ctx.binder 1452 } 1453 return binding.DefaultBinder() 1454 } 1455 1456 func (ctx *RequestContext) getValidator() binding.StructValidator { 1457 if ctx.validator != nil { 1458 return ctx.validator 1459 } 1460 return binding.DefaultValidator() 1461 } 1462 1463 // BindAndValidate binds data from *RequestContext to obj and validates them if needed. 1464 // NOTE: obj should be a pointer. 1465 func (ctx *RequestContext) BindAndValidate(obj interface{}) error { 1466 return ctx.getBinder().BindAndValidate(&ctx.Request, obj, ctx.Params) 1467 } 1468 1469 // Bind binds data from *RequestContext to obj. 1470 // NOTE: obj should be a pointer. 1471 func (ctx *RequestContext) Bind(obj interface{}) error { 1472 return ctx.getBinder().Bind(&ctx.Request, obj, ctx.Params) 1473 } 1474 1475 // Validate validates obj with "vd" tag 1476 // NOTE: obj should be a pointer. 1477 func (ctx *RequestContext) Validate(obj interface{}) error { 1478 return ctx.getValidator().ValidateStruct(obj) 1479 } 1480 1481 // BindQuery binds query parameters from *RequestContext to obj with 'query' tag. It will only use 'query' tag for binding. 1482 // NOTE: obj should be a pointer. 1483 func (ctx *RequestContext) BindQuery(obj interface{}) error { 1484 return ctx.getBinder().BindQuery(&ctx.Request, obj) 1485 } 1486 1487 // BindHeader binds header parameters from *RequestContext to obj with 'header' tag. It will only use 'header' tag for binding. 1488 // NOTE: obj should be a pointer. 1489 func (ctx *RequestContext) BindHeader(obj interface{}) error { 1490 return ctx.getBinder().BindHeader(&ctx.Request, obj) 1491 } 1492 1493 // BindPath binds router parameters from *RequestContext to obj with 'path' tag. It will only use 'path' tag for binding. 1494 // NOTE: obj should be a pointer. 1495 func (ctx *RequestContext) BindPath(obj interface{}) error { 1496 return ctx.getBinder().BindPath(&ctx.Request, obj, ctx.Params) 1497 } 1498 1499 // BindForm binds form parameters from *RequestContext to obj with 'form' tag. It will only use 'form' tag for binding. 1500 // NOTE: obj should be a pointer. 1501 func (ctx *RequestContext) BindForm(obj interface{}) error { 1502 if len(ctx.Request.Body()) == 0 { 1503 return fmt.Errorf("missing form body") 1504 } 1505 return ctx.getBinder().BindForm(&ctx.Request, obj) 1506 } 1507 1508 // BindJSON binds JSON body from *RequestContext. 1509 // NOTE: obj should be a pointer. 1510 func (ctx *RequestContext) BindJSON(obj interface{}) error { 1511 return ctx.getBinder().BindJSON(&ctx.Request, obj) 1512 } 1513 1514 // BindProtobuf binds protobuf body from *RequestContext. 1515 // NOTE: obj should be a pointer. 1516 func (ctx *RequestContext) BindProtobuf(obj interface{}) error { 1517 return ctx.getBinder().BindProtobuf(&ctx.Request, obj) 1518 } 1519 1520 // BindByContentType will select the binding type on the ContentType automatically. 1521 // NOTE: obj should be a pointer. 1522 func (ctx *RequestContext) BindByContentType(obj interface{}) error { 1523 if ctx.Request.Header.IsGet() { 1524 return ctx.BindQuery(obj) 1525 } 1526 ct := utils.FilterContentType(bytesconv.B2s(ctx.Request.Header.ContentType())) 1527 switch strings.ToLower(ct) { 1528 case consts.MIMEApplicationJSON: 1529 return ctx.BindJSON(obj) 1530 case consts.MIMEPROTOBUF: 1531 return ctx.BindProtobuf(obj) 1532 case consts.MIMEApplicationHTMLForm, consts.MIMEMultipartPOSTForm: 1533 return ctx.BindForm(obj) 1534 default: 1535 return fmt.Errorf("unsupported bind content-type for '%s'", ct) 1536 } 1537 } 1538 1539 // VisitAllQueryArgs calls f for each existing query arg. 1540 // 1541 // f must not retain references to key and value after returning. 1542 // Make key and/or value copies if you need storing them after returning. 1543 func (ctx *RequestContext) VisitAllQueryArgs(f func(key, value []byte)) { 1544 ctx.QueryArgs().VisitAll(f) 1545 } 1546 1547 // VisitAllPostArgs calls f for each existing post arg. 1548 // 1549 // f must not retain references to key and value after returning. 1550 // Make key and/or value copies if you need storing them after returning. 1551 func (ctx *RequestContext) VisitAllPostArgs(f func(key, value []byte)) { 1552 ctx.Request.PostArgs().VisitAll(f) 1553 } 1554 1555 // VisitAllHeaders calls f for each request header. 1556 // 1557 // f must not retain references to key and/or value after returning. 1558 // Copy key and/or value contents before returning if you need retaining them. 1559 // 1560 // To get the headers in order they were received use VisitAllInOrder. 1561 func (ctx *RequestContext) VisitAllHeaders(f func(key, value []byte)) { 1562 ctx.Request.Header.VisitAll(f) 1563 } 1564 1565 // VisitAllCookie calls f for each request cookie. 1566 // 1567 // f must not retain references to key and/or value after returning. 1568 func (ctx *RequestContext) VisitAllCookie(f func(key, value []byte)) { 1569 ctx.Request.Header.VisitAllCookie(f) 1570 }