github.com/System-Glitch/goyave/v2@v2.10.3-0.20200819142921-51011e75d504/request.go (about) 1 package goyave 2 3 import ( 4 "net" 5 "net/http" 6 "net/url" 7 "strings" 8 "time" 9 10 "github.com/System-Glitch/goyave/v2/cors" 11 12 "github.com/System-Glitch/goyave/v2/helper/filesystem" 13 "github.com/System-Glitch/goyave/v2/validation" 14 "github.com/google/uuid" 15 ) 16 17 // Request struct represents an http request. 18 // Contains the validated body in the Data attribute if the route was defined with a request generator function 19 type Request struct { 20 httpRequest *http.Request 21 corsOptions *cors.Options 22 cookies []*http.Cookie 23 route *Route 24 User interface{} 25 Rules *validation.Rules 26 Data map[string]interface{} 27 Params map[string]string 28 Lang string 29 } 30 31 // Request return the raw http request. 32 // Prefer using the "goyave.Request" accessors. 33 func (r *Request) Request() *http.Request { 34 return r.httpRequest 35 } 36 37 // Method specifies the HTTP method (GET, POST, PUT, etc.). 38 func (r *Request) Method() string { 39 return r.httpRequest.Method 40 } 41 42 // Protocol the protocol used by this request, "HTTP/1.1" for example. 43 func (r *Request) Protocol() string { 44 return r.httpRequest.Proto 45 } 46 47 // URI specifies the URI being requested. 48 // Use this if you absolutely need the raw query params, url, etc. 49 // Otherwise use the provided methods and fields of the "goyave.Request". 50 func (r *Request) URI() *url.URL { 51 return r.httpRequest.URL 52 } 53 54 // Route returns the current route. 55 func (r *Request) Route() *Route { 56 return r.route 57 } 58 59 // Header contains the request header fields either received 60 // by the server or to be sent by the client. 61 // Header names are case-insensitive. 62 // 63 // If the raw request has the following header lines, 64 // 65 // Host: example.com 66 // accept-encoding: gzip, deflate 67 // Accept-Language: en-us 68 // fOO: Bar 69 // foo: two 70 // 71 // then the header map will look like this: 72 // 73 // Header = map[string][]string{ 74 // "Accept-Encoding": {"gzip, deflate"}, 75 // "Accept-Language": {"en-us"}, 76 // "Foo": {"Bar", "two"}, 77 // } 78 func (r *Request) Header() http.Header { 79 return r.httpRequest.Header 80 } 81 82 // ContentLength records the length of the associated content. 83 // The value -1 indicates that the length is unknown. 84 func (r *Request) ContentLength() int64 { 85 return r.httpRequest.ContentLength 86 } 87 88 // RemoteAddress allows to record the network address that 89 // sent the request, usually for logging. 90 func (r *Request) RemoteAddress() string { 91 return r.httpRequest.RemoteAddr 92 } 93 94 // Cookies returns the HTTP cookies sent with the request. 95 func (r *Request) Cookies(name string) []*http.Cookie { 96 if r.cookies == nil { 97 r.cookies = r.httpRequest.Cookies() 98 } 99 return r.cookies 100 } 101 102 // Referrer returns the referring URL, if sent in the request. 103 func (r *Request) Referrer() string { 104 return r.httpRequest.Referer() 105 } 106 107 // UserAgent returns the client's User-Agent, if sent in the request. 108 func (r *Request) UserAgent() string { 109 return r.httpRequest.UserAgent() 110 } 111 112 // BasicAuth returns the username and password provided in the request's 113 // Authorization header, if the request uses HTTP Basic Authentication. 114 func (r *Request) BasicAuth() (username, password string, ok bool) { 115 return r.httpRequest.BasicAuth() 116 } 117 118 // BearerToken extract the auth token from the "Authorization" header. 119 // Only takes tokens of type "Bearer". 120 // Returns empty string if no token found or the header is invalid. 121 func (r *Request) BearerToken() (string, bool) { 122 const schema = "Bearer " 123 header := r.Header().Get("Authorization") 124 if !strings.HasPrefix(header, schema) { 125 return "", false 126 } 127 return strings.TrimSpace(header[len(schema):]), true 128 } 129 130 // CORSOptions returns the CORS options applied to this request, or nil. 131 // The returned object is a copy of the options applied to the router. 132 // Therefore, altering the returned object will not alter the router's options. 133 func (r *Request) CORSOptions() *cors.Options { 134 if r.corsOptions == nil { 135 return nil 136 } 137 138 cpy := *r.corsOptions 139 return &cpy 140 } 141 142 // Has check if the given field exists in the request data. 143 func (r *Request) Has(field string) bool { 144 _, exists := r.Data[field] 145 return exists 146 } 147 148 // String get a string field from the request data. 149 // Panics if the field is not a string. 150 func (r *Request) String(field string) string { 151 str, ok := r.Data[field].(string) 152 if !ok { 153 ErrLogger.Panicf("Field \"%s\" is not a string", field) 154 } 155 return str 156 } 157 158 // Numeric get a numeric field from the request data. 159 // Panics if the field is not numeric. 160 func (r *Request) Numeric(field string) float64 { 161 str, ok := r.Data[field].(float64) 162 if !ok { 163 ErrLogger.Panicf("Field \"%s\" is not numeric", field) 164 } 165 return str 166 } 167 168 // Integer get an integer field from the request data. 169 // Panics if the field is not an integer. 170 func (r *Request) Integer(field string) int { 171 str, ok := r.Data[field].(int) 172 if !ok { 173 ErrLogger.Panicf("Field \"%s\" is not an integer", field) 174 } 175 return str 176 } 177 178 // Bool get a bool field from the request data. 179 // Panics if the field is not a bool. 180 func (r *Request) Bool(field string) bool { 181 str, ok := r.Data[field].(bool) 182 if !ok { 183 ErrLogger.Panicf("Field \"%s\" is not a bool", field) 184 } 185 return str 186 } 187 188 // File get a file field from the request data. 189 // Panics if the field is not numeric. 190 func (r *Request) File(field string) []filesystem.File { 191 str, ok := r.Data[field].([]filesystem.File) 192 if !ok { 193 ErrLogger.Panicf("Field \"%s\" is not a file", field) 194 } 195 return str 196 } 197 198 // Timezone get a timezone field from the request data. 199 // Panics if the field is not a timezone. 200 func (r *Request) Timezone(field string) *time.Location { 201 str, ok := r.Data[field].(*time.Location) 202 if !ok { 203 ErrLogger.Panicf("Field \"%s\" is not a timezone", field) 204 } 205 return str 206 } 207 208 // IP get an IP field from the request data. 209 // Panics if the field is not an IP. 210 func (r *Request) IP(field string) net.IP { 211 str, ok := r.Data[field].(net.IP) 212 if !ok { 213 ErrLogger.Panicf("Field \"%s\" is not an IP", field) 214 } 215 return str 216 } 217 218 // URL get a URL field from the request data. 219 // Panics if the field is not a URL. 220 func (r *Request) URL(field string) *url.URL { 221 str, ok := r.Data[field].(*url.URL) 222 if !ok { 223 ErrLogger.Panicf("Field \"%s\" is not a URL", field) 224 } 225 return str 226 } 227 228 // UUID get a UUID field from the request data. 229 // Panics if the field is not a UUID. 230 func (r *Request) UUID(field string) uuid.UUID { 231 str, ok := r.Data[field].(uuid.UUID) 232 if !ok { 233 ErrLogger.Panicf("Field \"%s\" is not an UUID", field) 234 } 235 return str 236 } 237 238 // Date get a date field from the request data. 239 // Panics if the field is not a date. 240 func (r *Request) Date(field string) time.Time { 241 str, ok := r.Data[field].(time.Time) 242 if !ok { 243 ErrLogger.Panicf("Field \"%s\" is not a date", field) 244 } 245 return str 246 } 247 248 func (r *Request) validate() map[string]validation.Errors { 249 if r.Rules == nil { 250 return nil 251 } 252 253 errors := validation.Validate(r.Data, r.Rules, r.httpRequest.Header.Get("Content-Type") == "application/json", r.Lang) 254 if len(errors) > 0 { 255 return map[string]validation.Errors{"validationError": errors} 256 } 257 258 return nil 259 }