ghttp_request.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package ghttp
  7. import (
  8. "context"
  9. "fmt"
  10. "net/http"
  11. "strings"
  12. "time"
  13. "github.com/gogf/gf/internal/intlog"
  14. "github.com/gogf/gf/os/gres"
  15. "github.com/gogf/gf/os/gsession"
  16. "github.com/gogf/gf/os/gview"
  17. "github.com/gogf/gf/util/guid"
  18. "github.com/gogf/gf/os/gtime"
  19. "github.com/gogf/gf/text/gregex"
  20. )
  21. // Request is the context object for a request.
  22. type Request struct {
  23. *http.Request
  24. Server *Server // Server.
  25. Cookie *Cookie // Cookie.
  26. Session *gsession.Session // Session.
  27. Response *Response // Corresponding Response of this request.
  28. Router *Router // Matched Router for this request. Note that it's not available in HOOK handler.
  29. EnterTime int64 // Request starting time in microseconds.
  30. LeaveTime int64 // Request ending time in microseconds.
  31. Middleware *Middleware // Middleware manager.
  32. StaticFile *StaticFile // Static file object for static file serving.
  33. context context.Context // Custom context for internal usage purpose.
  34. handlers []*handlerParsedItem // All matched handlers containing handler, hook and middleware for this request.
  35. hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
  36. hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
  37. parsedQuery bool // A bool marking whether the GET parameters parsed.
  38. parsedBody bool // A bool marking whether the request body parsed.
  39. parsedForm bool // A bool marking whether request Form parsed for HTTP method PUT, POST, PATCH.
  40. paramsMap map[string]interface{} // Custom parameters map.
  41. routerMap map[string]string // Router parameters map, which might be nil if there're no router parameters.
  42. queryMap map[string]interface{} // Query parameters map, which is nil if there's no query string.
  43. formMap map[string]interface{} // Form parameters map, which is nil if there's no form data from client.
  44. bodyMap map[string]interface{} // Body parameters map, which might be nil if there're no body content.
  45. error error // Current executing error of the request.
  46. exit bool // A bool marking whether current request is exited.
  47. parsedHost string // The parsed host name for current host used by GetHost function.
  48. clientIp string // The parsed client ip for current host used by GetClientIp function.
  49. bodyContent []byte // Request body content.
  50. isFileRequest bool // A bool marking whether current request is file serving.
  51. viewObject *gview.View // Custom template view engine object for this response.
  52. viewParams gview.Params // Custom template view variables for this response.
  53. }
  54. // StaticFile is the file struct for static file service.
  55. type StaticFile struct {
  56. File *gres.File // Resource file object.
  57. Path string // File path.
  58. IsDir bool // Is directory.
  59. }
  60. // newRequest creates and returns a new request object.
  61. func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
  62. request := &Request{
  63. Server: s,
  64. Request: r,
  65. Response: newResponse(s, w),
  66. EnterTime: gtime.TimestampMilli(),
  67. }
  68. request.Cookie = GetCookie(request)
  69. request.Session = s.sessionManager.New(request.GetSessionId())
  70. request.Response.Request = request
  71. request.Middleware = &Middleware{
  72. request: request,
  73. }
  74. // Custom session id creating function.
  75. err := request.Session.SetIdFunc(func(ttl time.Duration) string {
  76. var (
  77. address = request.RemoteAddr
  78. header = fmt.Sprintf("%v", request.Header)
  79. )
  80. intlog.Print(address, header)
  81. return guid.S([]byte(address), []byte(header))
  82. })
  83. if err != nil {
  84. panic(err)
  85. }
  86. return request
  87. }
  88. // WebSocket upgrades current request as a websocket request.
  89. // It returns a new WebSocket object if success, or the error if failure.
  90. // Note that the request should be a websocket request, or it will surely fail upgrading.
  91. func (r *Request) WebSocket() (*WebSocket, error) {
  92. if conn, err := wsUpGrader.Upgrade(r.Response.Writer, r.Request, nil); err == nil {
  93. return &WebSocket{
  94. conn,
  95. }, nil
  96. } else {
  97. return nil, err
  98. }
  99. }
  100. // Exit exits executing of current HTTP handler.
  101. func (r *Request) Exit() {
  102. panic(exceptionExit)
  103. }
  104. // ExitAll exits executing of current and following HTTP handlers.
  105. func (r *Request) ExitAll() {
  106. r.exit = true
  107. panic(exceptionExitAll)
  108. }
  109. // ExitHook exits executing of current and following HTTP HOOK handlers.
  110. func (r *Request) ExitHook() {
  111. panic(exceptionExitHook)
  112. }
  113. // IsExited checks and returns whether current request is exited.
  114. func (r *Request) IsExited() bool {
  115. return r.exit
  116. }
  117. // GetHeader retrieves and returns the header value with given <key>.
  118. func (r *Request) GetHeader(key string) string {
  119. return r.Header.Get(key)
  120. }
  121. // GetHost returns current request host name, which might be a domain or an IP without port.
  122. func (r *Request) GetHost() string {
  123. if len(r.parsedHost) == 0 {
  124. array, _ := gregex.MatchString(`(.+):(\d+)`, r.Host)
  125. if len(array) > 1 {
  126. r.parsedHost = array[1]
  127. } else {
  128. r.parsedHost = r.Host
  129. }
  130. }
  131. return r.parsedHost
  132. }
  133. // IsFileRequest checks and returns whether current request is serving file.
  134. func (r *Request) IsFileRequest() bool {
  135. return r.isFileRequest
  136. }
  137. // IsAjaxRequest checks and returns whether current request is an AJAX request.
  138. func (r *Request) IsAjaxRequest() bool {
  139. return strings.EqualFold(r.Header.Get("X-Requested-With"), "XMLHttpRequest")
  140. }
  141. // GetClientIp returns the client ip of this request without port.
  142. // Note that this ip address might be modified by client header.
  143. func (r *Request) GetClientIp() string {
  144. if len(r.clientIp) == 0 {
  145. realIps := r.Header.Get("X-Forwarded-For")
  146. if realIps != "" && len(realIps) != 0 && !strings.EqualFold("unknown", realIps) {
  147. ipArray := strings.Split(realIps, ",")
  148. r.clientIp = ipArray[0]
  149. }
  150. if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
  151. r.clientIp = r.Header.Get("Proxy-Client-IP")
  152. }
  153. if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
  154. r.clientIp = r.Header.Get("WL-Proxy-Client-IP")
  155. }
  156. if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
  157. r.clientIp = r.Header.Get("HTTP_CLIENT_IP")
  158. }
  159. if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
  160. r.clientIp = r.Header.Get("HTTP_X_FORWARDED_FOR")
  161. }
  162. if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
  163. r.clientIp = r.Header.Get("X-Real-IP")
  164. }
  165. if r.clientIp == "" || strings.EqualFold("unknown", realIps) {
  166. r.clientIp = r.GetRemoteIp()
  167. }
  168. }
  169. return r.clientIp
  170. }
  171. // GetRemoteIp returns the ip from RemoteAddr.
  172. func (r *Request) GetRemoteIp() string {
  173. array, _ := gregex.MatchString(`(.+):(\d+)`, r.RemoteAddr)
  174. if len(array) > 1 {
  175. return array[1]
  176. }
  177. return r.RemoteAddr
  178. }
  179. // GetUrl returns current URL of this request.
  180. func (r *Request) GetUrl() string {
  181. scheme := "http"
  182. if r.TLS != nil {
  183. scheme = "https"
  184. }
  185. return fmt.Sprintf(`%s://%s%s`, scheme, r.Host, r.URL.String())
  186. }
  187. // GetSessionId retrieves and returns session id from cookie or header.
  188. func (r *Request) GetSessionId() string {
  189. id := r.Cookie.GetSessionId()
  190. if id == "" {
  191. id = r.Header.Get(r.Server.GetSessionIdName())
  192. }
  193. return id
  194. }
  195. // GetReferer returns referer of this request.
  196. func (r *Request) GetReferer() string {
  197. return r.Header.Get("Referer")
  198. }
  199. // GetError returns the error occurs in the procedure of the request.
  200. // It returns nil if there's no error.
  201. func (r *Request) GetError() error {
  202. return r.error
  203. }
  204. // ReloadParam is used for modifying request parameter.
  205. // Sometimes, we want to modify request parameters through middleware, but directly modifying Request.Body
  206. // is invalid, so it clears the parsed* marks to make the parameters re-parsed.
  207. func (r *Request) ReloadParam() {
  208. r.parsedBody = false
  209. r.parsedForm = false
  210. r.parsedQuery = false
  211. r.bodyContent = nil
  212. }