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  }