1 // Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
2 // Revel Framework source code and usage is governed by a MIT style
3 // license that can be found in the LICENSE file.
23 // Request is Revel's HTTP request object structure
25 In ServerRequest // The server request
26 Header *RevelHeader // The revel header
27 ContentType string // The content type
28 Format string // The output format "html", "xml", "json", or "txt"
29 AcceptLanguages AcceptLanguages // The languages to accept
30 Locale string // THe locale
31 WebSocket ServerWebSocket // The websocket
32 Method string // The method
33 RemoteAddr string // The remote address
34 Host string // The host
35 // URL request path from the server (built)
36 URL *url.URL // The url
37 // DEPRECATED use GetForm()
38 Form url.Values // The Form
39 // DEPRECATED use GetMultipartForm()
40 MultipartForm *MultipartForm // The multipart form
41 controller *Controller // The controller, so some of this data can be fetched
44 var FORM_NOT_FOUND = errors.New("Form Not Found")
45 var httpLog = RevelLog.New("section", "http")
47 // Response is Revel's HTTP response object structure
48 type Response struct {
55 // The output response
56 type OutResponse struct {
57 // internalHeader.Server Set by ServerResponse.Get(HTTP_SERVER_HEADER), saves calling the get every time the header needs to be written to
58 internalHeader *RevelHeader // The internal header
59 Server ServerResponse // The server response
60 response *Response // The response
63 // The header defined in Revel
64 type RevelHeader struct {
65 Server ServerHeader // The server
68 // NewResponse wraps ServerResponse inside a Revel's Response and returns it
69 func NewResponse(w ServerResponse) (r *Response) {
70 r = &Response{Out: OutResponse{Server: w, internalHeader: &RevelHeader{}}}
75 // NewRequest returns a Revel's HTTP request instance with given HTTP instance
76 func NewRequest(r ServerRequest) *Request {
77 req := &Request{Header: &RevelHeader{}}
83 func (req *Request) SetRequest(r ServerRequest) {
85 if h, e := req.In.Get(HTTP_SERVER_HEADER); e == nil {
86 req.Header.Server = h.(ServerHeader)
89 req.URL, _ = req.GetValue(HTTP_URL).(*url.URL)
90 req.ContentType = ResolveContentType(req)
91 req.Format = ResolveFormat(req)
92 req.AcceptLanguages = ResolveAcceptLanguage(req)
93 req.Method, _ = req.GetValue(HTTP_METHOD).(string)
94 req.RemoteAddr, _ = req.GetValue(HTTP_REMOTE_ADDR).(string)
95 req.Host, _ = req.GetValue(HTTP_HOST).(string)
100 func (req *Request) Cookie(key string) (ServerCookie, error) {
101 if req.Header.Server != nil {
102 return req.Header.Server.GetCookie(key)
104 return nil, http.ErrNoCookie
107 // Fetch the requested URI
108 func (req *Request) GetRequestURI() string {
109 uri, _ := req.GetValue(HTTP_REQUEST_URI).(string)
114 func (req *Request) GetQuery() (v url.Values) {
115 v, _ = req.GetValue(ENGINE_PARAMETERS).(url.Values)
120 func (req *Request) GetPath() (path string) {
121 path, _ = req.GetValue(ENGINE_PATH).(string)
126 func (req *Request) GetBody() (body io.Reader) {
127 body, _ = req.GetValue(HTTP_BODY).(io.Reader)
132 func (req *Request) Context() (c context.Context) {
133 c, _ = req.GetValue(HTTP_REQUEST_CONTEXT).(context.Context)
137 // Deprecated use controller.Params.Get()
138 func (req *Request) FormValue(key string) (value string) {
139 return req.controller.Params.Get(key)
142 // Deprecated use controller.Params.Form[Key]
143 func (req *Request) PostFormValue(key string) (value string) {
144 valueList := req.controller.Params.Form[key]
145 if len(valueList) > 0 {
151 // Deprecated use GetForm() instead
152 func (req *Request) ParseForm() (e error) {
154 req.Form, e = req.GetForm()
159 func (req *Request) GetForm() (url.Values, error) {
160 if form, err := req.In.Get(HTTP_FORM); err != nil {
162 } else if values, found := form.(url.Values); found {
166 return nil, FORM_NOT_FOUND
169 // Deprecated for backwards compatibility only
170 type MultipartForm struct {
171 File map[string][]*multipart.FileHeader
173 origin ServerMultipartForm
176 func (req *Request) MultipartReader() (*multipart.Reader, error) {
178 return nil, errors.New("MultipartReader not supported, use controller.Param")
181 // Deprecated for backwards compatibility only
182 func newMultipareForm(s ServerMultipartForm) (f *MultipartForm) {
183 return &MultipartForm{File: s.GetFiles(), Value: s.GetValues(), origin: s}
186 // Deprecated use GetMultipartForm() instead
187 func (req *Request) ParseMultipartForm(_ int64) (e error) {
188 var s ServerMultipartForm
189 if s, e = req.GetMultipartForm(); e == nil {
190 req.MultipartForm = newMultipareForm(s)
195 // Return the args for the controller
196 func (req *Request) Args() map[string]interface{} {
197 return req.controller.Args
200 // Return a multipart form
201 func (req *Request) GetMultipartForm() (ServerMultipartForm, error) {
202 if form, err := req.In.Get(HTTP_MULTIPART_FORM); err != nil {
204 } else if values, found := form.(ServerMultipartForm); found {
207 return nil, FORM_NOT_FOUND
210 // Destroy the request
211 func (req *Request) Destroy() {
215 req.AcceptLanguages = nil
222 req.MultipartForm = nil
225 // Set the server response
226 func (resp *Response) SetResponse(r ServerResponse) {
228 if h, e := r.Get(HTTP_SERVER_HEADER); e == nil {
229 resp.Out.internalHeader.Server, _ = h.(ServerHeader)
233 // Destroy the output response
234 func (o *OutResponse) Destroy() {
236 o.internalHeader.Destroy()
239 // Destroy the RevelHeader
240 func (h *RevelHeader) Destroy() {
244 // Destroy the Response
245 func (resp *Response) Destroy() {
248 resp.ContentType = ""
252 // UserAgent returns the client's User-Agent header string.
253 func (r *Request) UserAgent() string {
254 return r.Header.Get("User-Agent")
257 // Referer returns the client's Referer header string.
258 func (req *Request) Referer() string {
259 return req.Header.Get("Referer")
262 // Return the httpheader for the key
263 func (req *Request) GetHttpHeader(key string) string {
264 return req.Header.Get(key)
267 // Return the value from the server
268 func (r *Request) GetValue(key int) (value interface{}) {
269 value, _ = r.In.Get(key)
273 // WriteHeader writes the header (for now, just the status code).
274 // The status may be set directly by the application (c.Response.Status = 501).
275 // If it isn't, then fall back to the provided status code.
276 func (resp *Response) WriteHeader(defaultStatusCode int, defaultContentType string) {
277 if resp.ContentType == "" {
278 resp.ContentType = defaultContentType
280 resp.Out.internalHeader.Set("Content-Type", resp.ContentType)
281 if resp.Status == 0 {
282 resp.Status = defaultStatusCode
284 resp.SetStatus(resp.Status)
286 func (resp *Response) SetStatus(statusCode int) {
287 if resp.Out.internalHeader.Server != nil {
288 resp.Out.internalHeader.Server.SetStatus(statusCode)
290 resp.Out.Server.Set(ENGINE_RESPONSE_STATUS, statusCode)
296 func (resp *Response) GetWriter() (writer io.Writer) {
299 if w, e := resp.Out.Server.Get(ENGINE_WRITER); e == nil {
300 writer, resp.writer = w.(io.Writer), w.(io.Writer)
307 // Replace the writer
308 func (resp *Response) SetWriter(writer io.Writer) bool {
310 // Leave it up to the engine to flush and close the writer
311 return resp.Out.Server.Set(ENGINE_WRITER, writer)
314 // Passes full control to the response to the caller - terminates any initial writes
315 func (resp *Response) GetStreamWriter() (writer StreamWriter) {
316 if w, e := resp.Out.Server.Get(HTTP_STREAM_WRITER); e == nil {
317 writer = w.(StreamWriter)
323 func (o *OutResponse) Header() *RevelHeader {
324 return o.internalHeader
327 // Write the header out
328 func (o *OutResponse) Write(data []byte) (int, error) {
329 return o.response.GetWriter().Write(data)
332 // Set a value in the header
333 func (h *RevelHeader) Set(key, value string) {
335 h.Server.Set(key, value)
339 // Add a key to the header
340 func (h *RevelHeader) Add(key, value string) {
342 h.Server.Add(key, value)
346 // Set a cookie in the header
347 func (h *RevelHeader) SetCookie(cookie string) {
349 h.Server.SetCookie(cookie)
353 // Set the status for the header
354 func (h *RevelHeader) SetStatus(status int) {
356 h.Server.SetStatus(status)
360 // Get a key from the header
361 func (h *RevelHeader) Get(key string) (value string) {
362 values := h.GetAll(key)
369 // GetAll returns []string of items (the header split by a comma)
370 func (h *RevelHeader) GetAll(key string) (values []string) {
372 values = h.Server.Get(key)
377 // ResolveContentType gets the content type.
378 // e.g. From "multipart/form-data; boundary=--" to "multipart/form-data"
379 // If none is specified, returns "text/html" by default.
380 func ResolveContentType(req *Request) string {
382 contentType := req.Header.Get("Content-Type")
383 if contentType == "" {
386 return strings.ToLower(strings.TrimSpace(strings.Split(contentType, ";")[0]))
389 // ResolveFormat maps the request's Accept MIME type declaration to
390 // a Request.Format attribute, specifically "html", "xml", "json", or "txt",
391 // returning a default of "html" when Accept header cannot be mapped to a
393 func ResolveFormat(req *Request) string {
394 ext := strings.ToLower(filepath.Ext(req.GetPath()))
406 accept := req.GetHttpHeader("accept")
410 strings.HasPrefix(accept, "*/*"), // */
411 strings.Contains(accept, "application/xhtml"),
412 strings.Contains(accept, "text/html"):
414 case strings.Contains(accept, "application/json"),
415 strings.Contains(accept, "text/javascript"),
416 strings.Contains(accept, "application/javascript"):
418 case strings.Contains(accept, "application/xml"),
419 strings.Contains(accept, "text/xml"):
421 case strings.Contains(accept, "text/plain"):
428 // AcceptLanguage is a single language from the Accept-Language HTTP header.
429 type AcceptLanguage struct {
434 // AcceptLanguages is collection of sortable AcceptLanguage instances.
435 type AcceptLanguages []AcceptLanguage
437 func (al AcceptLanguages) Len() int { return len(al) }
438 func (al AcceptLanguages) Swap(i, j int) { al[i], al[j] = al[j], al[i] }
439 func (al AcceptLanguages) Less(i, j int) bool { return al[i].Quality > al[j].Quality }
440 func (al AcceptLanguages) String() string {
441 output := bytes.NewBufferString("")
442 for i, language := range al {
443 if _, err := output.WriteString(fmt.Sprintf("%s (%1.1f)", language.Language, language.Quality)); err != nil {
444 httpLog.Error("String: WriteString failed:", "error", err)
447 if _, err := output.WriteString(", "); err != nil {
448 httpLog.Error("String: WriteString failed:", "error", err)
452 return output.String()
455 // ResolveAcceptLanguage returns a sorted list of Accept-Language
458 // The results are sorted using the quality defined in the header for each
459 // language range with the most qualified language range as the first
460 // element in the slice.
462 // See the HTTP header fields specification
463 // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4) for more details.
464 func ResolveAcceptLanguage(req *Request) AcceptLanguages {
465 header := req.Header.Get("Accept-Language")
467 return req.AcceptLanguages
470 acceptLanguageHeaderValues := strings.Split(header, ",")
471 acceptLanguages := make(AcceptLanguages, len(acceptLanguageHeaderValues))
473 for i, languageRange := range acceptLanguageHeaderValues {
474 if qualifiedRange := strings.Split(languageRange, ";q="); len(qualifiedRange) == 2 {
475 quality, err := strconv.ParseFloat(qualifiedRange[1], 32)
477 httpLog.Warn("Detected malformed Accept-Language header quality in assuming quality is 1", "languageRange", languageRange)
478 acceptLanguages[i] = AcceptLanguage{qualifiedRange[0], 1}
480 acceptLanguages[i] = AcceptLanguage{qualifiedRange[0], float32(quality)}
483 acceptLanguages[i] = AcceptLanguage{languageRange, 1}
487 sort.Sort(acceptLanguages)
488 return acceptLanguages