goyave.dev/goyave/v5@v5.0.0-rc9.0.20240517145003-d3f977d0b9f3/request.go (about) 1 package goyave 2 3 import ( 4 "context" 5 "io" 6 "net/http" 7 "net/url" 8 "strings" 9 "time" 10 11 "goyave.dev/goyave/v5/lang" 12 ) 13 14 type ( 15 // ExtraBodyValidationRules the key used in `Context.Extra` to 16 // store the body validation rules. 17 ExtraBodyValidationRules struct{} 18 19 // ExtraQueryValidationRules the key used in `Context.Extra` to 20 // store the query validation rules. 21 ExtraQueryValidationRules struct{} 22 23 // ExtraValidationError the key used in `Context.Extra` to 24 // store the body validation errors. 25 ExtraValidationError struct{} 26 27 // ExtraQueryValidationError the key used in `Context.Extra` to 28 // store the query validation errors. 29 ExtraQueryValidationError struct{} 30 ) 31 32 // Request represents an http request received by the server. 33 type Request struct { 34 httpRequest *http.Request 35 Now time.Time 36 Data any 37 User any 38 Query map[string]any 39 Lang *lang.Language 40 41 // Extra can be used to store any extra information related to the request. 42 // For example, the JWT middleware stores the token claim in the extras. 43 // 44 // The keys must be comparable and should not be of type 45 // string or any other built-in type to avoid collisions. 46 // To avoid allocating when assigning to an `interface{}`, context keys often have 47 // concrete type `struct{}`. Alternatively, exported context key variables' static 48 // type should be a pointer or interface. 49 Extra map[any]any 50 Route *Route 51 RouteParams map[string]string 52 cookies []*http.Cookie 53 } 54 55 // NewRequest create a new Request from the given raw http request. 56 // Initializes Now with the current time and Extra with a non-nil map. 57 func NewRequest(httpRequest *http.Request) *Request { 58 return &Request{ 59 httpRequest: httpRequest, 60 Now: time.Now(), 61 Extra: map[any]any{}, 62 // Route is set by the router 63 // Lang is set inside the language middleware 64 // Query is set inside the parse request middleware 65 } 66 } 67 68 // Request return the raw http request. 69 // Prefer using the "goyave.Request" accessors. 70 func (r *Request) Request() *http.Request { 71 return r.httpRequest 72 } 73 74 // Method specifies the HTTP method (GET, POST, PUT, etc.). 75 func (r *Request) Method() string { 76 return r.httpRequest.Method 77 } 78 79 // Protocol the protocol used by this request, "HTTP/1.1" for example. 80 func (r *Request) Protocol() string { 81 return r.httpRequest.Proto 82 } 83 84 // URL specifies the URL being requested. 85 func (r *Request) URL() *url.URL { 86 return r.httpRequest.URL 87 } 88 89 // Header contains the request header fields either received 90 // by the server or to be sent by the client. 91 // Header names are case-insensitive. 92 // 93 // If the raw request has the following header lines, 94 // 95 // Host: example.com 96 // accept-encoding: gzip, deflate 97 // Accept-Language: en-us 98 // fOO: Bar 99 // foo: two 100 // 101 // then the header map will look like this: 102 // 103 // Header = map[string][]string{ 104 // "Accept-Encoding": {"gzip, deflate"}, 105 // "Accept-Language": {"en-us"}, 106 // "Foo": {"Bar", "two"}, 107 // } 108 func (r *Request) Header() http.Header { 109 return r.httpRequest.Header 110 } 111 112 // ContentLength records the length of the associated content. 113 // The value -1 indicates that the length is unknown. 114 func (r *Request) ContentLength() int64 { 115 return r.httpRequest.ContentLength 116 } 117 118 // RemoteAddress allows to record the network address that 119 // sent the request, usually for logging. 120 func (r *Request) RemoteAddress() string { 121 return r.httpRequest.RemoteAddr 122 } 123 124 // Cookies returns the HTTP cookies sent with the request. 125 func (r *Request) Cookies() []*http.Cookie { 126 if r.cookies == nil { 127 r.cookies = r.httpRequest.Cookies() 128 } 129 return r.cookies 130 } 131 132 // Referrer returns the referring URL, if sent in the request. 133 func (r *Request) Referrer() string { 134 return r.httpRequest.Referer() 135 } 136 137 // UserAgent returns the client's User-Agent, if sent in the request. 138 func (r *Request) UserAgent() string { 139 return r.httpRequest.UserAgent() 140 } 141 142 // BasicAuth returns the username and password provided in the request's 143 // Authorization header, if the request uses HTTP Basic Authentication. 144 func (r *Request) BasicAuth() (username, password string, ok bool) { 145 return r.httpRequest.BasicAuth() 146 } 147 148 // BearerToken extract the auth token from the "Authorization" header. 149 // Only takes tokens of type "Bearer". 150 // Returns empty string if no token found or the header is invalid. 151 func (r *Request) BearerToken() (string, bool) { 152 const schema = "Bearer " 153 header := r.Header().Get("Authorization") 154 if !strings.HasPrefix(header, schema) { 155 return "", false 156 } 157 return strings.TrimSpace(header[len(schema):]), true 158 } 159 160 // Body the request body. 161 // Always non-nil, but will return EOF immediately when no body is present. 162 // The server will close the request body so handlers don't need to. 163 func (r *Request) Body() io.ReadCloser { 164 return r.httpRequest.Body 165 } 166 167 // Context returns the request's context. To change the context, use `WithContext`. 168 // 169 // The returned context is always non-nil; it defaults to the 170 // background context. 171 // 172 // The context is canceled when the client's connection closes, the request is canceled (with HTTP/2), 173 // or when the `ServeHTTP` method returns (after the finalization step of the request lifecycle). 174 func (r *Request) Context() context.Context { 175 return r.httpRequest.Context() 176 } 177 178 // WithContext creates a shallow copy of the underlying `*http.Request` with 179 // its context changed to `ctx` then returns itself. 180 // The provided ctx must be non-nil. 181 func (r *Request) WithContext(ctx context.Context) *Request { 182 r.httpRequest = r.httpRequest.WithContext(ctx) 183 return r 184 }