ghttp_request.go 9.6 KB

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