github.com/gogf/gf@v1.16.9/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 "context" 11 "fmt" 12 "net/http" 13 "strings" 14 "time" 15 16 "github.com/gogf/gf/internal/intlog" 17 "github.com/gogf/gf/os/gres" 18 "github.com/gogf/gf/os/gsession" 19 "github.com/gogf/gf/os/gview" 20 "github.com/gogf/gf/util/guid" 21 22 "github.com/gogf/gf/os/gtime" 23 "github.com/gogf/gf/text/gregex" 24 ) 25 26 // Request is the context object for a request. 27 type Request struct { 28 *http.Request 29 Server *Server // Server. 30 Cookie *Cookie // Cookie. 31 Session *gsession.Session // Session. 32 Response *Response // Corresponding Response of this request. 33 Router *Router // Matched Router for this request. Note that it's not available in HOOK handler. 34 EnterTime int64 // Request starting time in microseconds. 35 LeaveTime int64 // Request ending time in microseconds. 36 Middleware *middleware // Middleware manager. 37 StaticFile *staticFile // Static file object for static file serving. 38 context context.Context // Custom context for internal usage purpose. 39 handlers []*handlerParsedItem // All matched handlers containing handler, hook and middleware for this request. 40 handlerResponse handlerResponse // Handler response object and its error value. 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're 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 data from client. 50 bodyMap map[string]interface{} // Body parameters map, which might be nil if there're no body content. 51 error error // Current executing error of the request. 52 exit 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 } 60 61 type handlerResponse struct { 62 Object interface{} 63 Error error 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.TimestampMilli(), 80 } 81 request.Cookie = GetCookie(request) 82 request.Session = s.sessionManager.New( 83 r.Context(), 84 request.GetSessionId(), 85 ) 86 request.Response.Request = request 87 request.Middleware = &middleware{ 88 request: request, 89 } 90 // Custom session id creating function. 91 err := request.Session.SetIdFunc(func(ttl time.Duration) string { 92 var ( 93 address = request.RemoteAddr 94 header = fmt.Sprintf("%v", request.Header) 95 ) 96 intlog.Print(r.Context(), address, header) 97 return guid.S([]byte(address), []byte(header)) 98 }) 99 if err != nil { 100 panic(err) 101 } 102 return request 103 } 104 105 // WebSocket upgrades current request as a websocket request. 106 // It returns a new WebSocket object if success, or the error if failure. 107 // Note that the request should be a websocket request, or it will surely fail upgrading. 108 func (r *Request) WebSocket() (*WebSocket, error) { 109 if conn, err := wsUpGrader.Upgrade(r.Response.Writer, r.Request, nil); err == nil { 110 return &WebSocket{ 111 conn, 112 }, nil 113 } else { 114 return nil, err 115 } 116 } 117 118 // Exit exits executing of current HTTP handler. 119 func (r *Request) Exit() { 120 panic(exceptionExit) 121 } 122 123 // ExitAll exits executing of current and following HTTP handlers. 124 func (r *Request) ExitAll() { 125 r.exit = true 126 panic(exceptionExitAll) 127 } 128 129 // ExitHook exits executing of current and following HTTP HOOK handlers. 130 func (r *Request) ExitHook() { 131 panic(exceptionExitHook) 132 } 133 134 // IsExited checks and returns whether current request is exited. 135 func (r *Request) IsExited() bool { 136 return r.exit 137 } 138 139 // GetHeader retrieves and returns the header value with given <key>. 140 func (r *Request) GetHeader(key string) string { 141 return r.Header.Get(key) 142 } 143 144 // GetHost returns current request host name, which might be a domain or an IP without port. 145 func (r *Request) GetHost() string { 146 if len(r.parsedHost) == 0 { 147 array, _ := gregex.MatchString(`(.+):(\d+)`, r.Host) 148 if len(array) > 1 { 149 r.parsedHost = array[1] 150 } else { 151 r.parsedHost = r.Host 152 } 153 } 154 return r.parsedHost 155 } 156 157 // IsFileRequest checks and returns whether current request is serving file. 158 func (r *Request) IsFileRequest() bool { 159 return r.isFileRequest 160 } 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 167 // GetClientIp returns the client ip of this request without port. 168 // Note that this ip address might be modified by client header. 169 func (r *Request) GetClientIp() string { 170 if len(r.clientIp) == 0 { 171 realIps := r.Header.Get("X-Forwarded-For") 172 if realIps != "" && len(realIps) != 0 && !strings.EqualFold("unknown", realIps) { 173 ipArray := strings.Split(realIps, ",") 174 r.clientIp = ipArray[0] 175 } 176 if r.clientIp == "" || strings.EqualFold("unknown", realIps) { 177 r.clientIp = r.Header.Get("Proxy-Client-IP") 178 } 179 if r.clientIp == "" || strings.EqualFold("unknown", realIps) { 180 r.clientIp = r.Header.Get("WL-Proxy-Client-IP") 181 } 182 if r.clientIp == "" || strings.EqualFold("unknown", realIps) { 183 r.clientIp = r.Header.Get("HTTP_CLIENT_IP") 184 } 185 if r.clientIp == "" || strings.EqualFold("unknown", realIps) { 186 r.clientIp = r.Header.Get("HTTP_X_FORWARDED_FOR") 187 } 188 if r.clientIp == "" || strings.EqualFold("unknown", realIps) { 189 r.clientIp = r.Header.Get("X-Real-IP") 190 } 191 if r.clientIp == "" || strings.EqualFold("unknown", realIps) { 192 r.clientIp = r.GetRemoteIp() 193 } 194 } 195 return r.clientIp 196 } 197 198 // GetRemoteIp returns the ip from RemoteAddr. 199 func (r *Request) GetRemoteIp() string { 200 array, _ := gregex.MatchString(`(.+):(\d+)`, r.RemoteAddr) 201 if len(array) > 1 { 202 return array[1] 203 } 204 return r.RemoteAddr 205 } 206 207 // GetUrl returns current URL of this request. 208 func (r *Request) GetUrl() string { 209 scheme := "http" 210 if r.TLS != nil { 211 scheme = "https" 212 } 213 return fmt.Sprintf(`%s://%s%s`, scheme, r.Host, r.URL.String()) 214 } 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 225 // GetReferer returns referer of this request. 226 func (r *Request) GetReferer() string { 227 return r.Header.Get("Referer") 228 } 229 230 // GetError returns the error occurs in the procedure of the request. 231 // It returns nil if there's no error. 232 func (r *Request) GetError() error { 233 return r.error 234 } 235 236 // ReloadParam is used for modifying request parameter. 237 // Sometimes, we want to modify request parameters through middleware, but directly modifying Request.Body 238 // is invalid, so it clears the parsed* marks to make the parameters re-parsed. 239 func (r *Request) ReloadParam() { 240 r.parsedBody = false 241 r.parsedForm = false 242 r.parsedQuery = false 243 r.bodyContent = nil 244 } 245 246 // GetHandlerResponse retrieves and returns the handler response object and its error. 247 func (r *Request) GetHandlerResponse() (res interface{}, err error) { 248 return r.handlerResponse.Object, r.handlerResponse.Error 249 }