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