Merge "Change seba installation for cord 7.0.0"
[iec.git] / src / foundation / api / revel / http.go
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.
4
5 package revel
6
7 import (
8         "bytes"
9         "errors"
10         "fmt"
11         "io"
12         "net/http"
13         "net/url"
14         "sort"
15         "strconv"
16         "strings"
17
18         "context"
19         "mime/multipart"
20         "path/filepath"
21 )
22
23 // Request is Revel's HTTP request object structure
24 type Request struct {
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
42 }
43
44 var FORM_NOT_FOUND = errors.New("Form Not Found")
45 var httpLog = RevelLog.New("section", "http")
46
47 // Response is Revel's HTTP response object structure
48 type Response struct {
49         Status      int
50         ContentType string
51         Out         OutResponse
52         writer      io.Writer
53 }
54
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
61 }
62
63 // The header defined in Revel
64 type RevelHeader struct {
65         Server ServerHeader // The server
66 }
67
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{}}}
71         r.Out.response = r
72         return r
73 }
74
75 // NewRequest returns a Revel's HTTP request instance with given HTTP instance
76 func NewRequest(r ServerRequest) *Request {
77         req := &Request{Header: &RevelHeader{}}
78         if r != nil {
79                 req.SetRequest(r)
80         }
81         return req
82 }
83 func (req *Request) SetRequest(r ServerRequest) {
84         req.In = r
85         if h, e := req.In.Get(HTTP_SERVER_HEADER); e == nil {
86                 req.Header.Server = h.(ServerHeader)
87         }
88
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)
96
97 }
98
99 // Returns a cookie
100 func (req *Request) Cookie(key string) (ServerCookie, error) {
101         if req.Header.Server != nil {
102                 return req.Header.Server.GetCookie(key)
103         }
104         return nil, http.ErrNoCookie
105 }
106
107 // Fetch the requested URI
108 func (req *Request) GetRequestURI() string {
109         uri, _ := req.GetValue(HTTP_REQUEST_URI).(string)
110         return uri
111 }
112
113 // Fetch the query
114 func (req *Request) GetQuery() (v url.Values) {
115         v, _ = req.GetValue(ENGINE_PARAMETERS).(url.Values)
116         return
117 }
118
119 // Fetch the path
120 func (req *Request) GetPath() (path string) {
121         path, _ = req.GetValue(ENGINE_PATH).(string)
122         return
123 }
124
125 // Fetch the body
126 func (req *Request) GetBody() (body io.Reader) {
127         body, _ = req.GetValue(HTTP_BODY).(io.Reader)
128         return
129 }
130
131 // Fetch the context
132 func (req *Request) Context() (c context.Context) {
133         c, _ = req.GetValue(HTTP_REQUEST_CONTEXT).(context.Context)
134         return
135 }
136
137 // Deprecated use controller.Params.Get()
138 func (req *Request) FormValue(key string) (value string) {
139         return req.controller.Params.Get(key)
140 }
141
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 {
146                 value = valueList[0]
147         }
148         return
149 }
150
151 // Deprecated use GetForm() instead
152 func (req *Request) ParseForm() (e error) {
153         if req.Form == nil {
154                 req.Form, e = req.GetForm()
155         }
156         return
157 }
158
159 func (req *Request) GetForm() (url.Values, error) {
160         if form, err := req.In.Get(HTTP_FORM); err != nil {
161                 return nil, err
162         } else if values, found := form.(url.Values); found {
163                 req.Form = values
164                 return values, nil
165         }
166         return nil, FORM_NOT_FOUND
167 }
168
169 // Deprecated for backwards compatibility only
170 type MultipartForm struct {
171         File   map[string][]*multipart.FileHeader
172         Value  url.Values
173         origin ServerMultipartForm
174 }
175
176 func (req *Request) MultipartReader() (*multipart.Reader, error) {
177
178         return nil, errors.New("MultipartReader not supported, use controller.Param")
179 }
180
181 // Deprecated for backwards compatibility only
182 func newMultipareForm(s ServerMultipartForm) (f *MultipartForm) {
183         return &MultipartForm{File: s.GetFiles(), Value: s.GetValues(), origin: s}
184 }
185
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)
191         }
192         return
193 }
194
195 // Return the args for the controller
196 func (req *Request) Args() map[string]interface{} {
197         return req.controller.Args
198 }
199
200 // Return a multipart form
201 func (req *Request) GetMultipartForm() (ServerMultipartForm, error) {
202         if form, err := req.In.Get(HTTP_MULTIPART_FORM); err != nil {
203                 return nil, err
204         } else if values, found := form.(ServerMultipartForm); found {
205                 return values, nil
206         }
207         return nil, FORM_NOT_FOUND
208 }
209
210 // Destroy the request
211 func (req *Request) Destroy() {
212         req.In = nil
213         req.ContentType = ""
214         req.Format = ""
215         req.AcceptLanguages = nil
216         req.Method = ""
217         req.RemoteAddr = ""
218         req.Host = ""
219         req.Header.Destroy()
220         req.URL = nil
221         req.Form = nil
222         req.MultipartForm = nil
223 }
224
225 // Set the server response
226 func (resp *Response) SetResponse(r ServerResponse) {
227         resp.Out.Server = r
228         if h, e := r.Get(HTTP_SERVER_HEADER); e == nil {
229                 resp.Out.internalHeader.Server, _ = h.(ServerHeader)
230         }
231 }
232
233 // Destroy the output response
234 func (o *OutResponse) Destroy() {
235         o.response = nil
236         o.internalHeader.Destroy()
237 }
238
239 // Destroy the RevelHeader
240 func (h *RevelHeader) Destroy() {
241         h.Server = nil
242 }
243
244 // Destroy the Response
245 func (resp *Response) Destroy() {
246         resp.Out.Destroy()
247         resp.Status = 0
248         resp.ContentType = ""
249         resp.writer = nil
250 }
251
252 // UserAgent returns the client's User-Agent header string.
253 func (r *Request) UserAgent() string {
254         return r.Header.Get("User-Agent")
255 }
256
257 // Referer returns the client's Referer header string.
258 func (req *Request) Referer() string {
259         return req.Header.Get("Referer")
260 }
261
262 // Return the httpheader for the key
263 func (req *Request) GetHttpHeader(key string) string {
264         return req.Header.Get(key)
265 }
266
267 // Return the value from the server
268 func (r *Request) GetValue(key int) (value interface{}) {
269         value, _ = r.In.Get(key)
270         return
271 }
272
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
279         }
280         resp.Out.internalHeader.Set("Content-Type", resp.ContentType)
281         if resp.Status == 0 {
282                 resp.Status = defaultStatusCode
283         }
284         resp.SetStatus(resp.Status)
285 }
286 func (resp *Response) SetStatus(statusCode int) {
287         if resp.Out.internalHeader.Server != nil {
288                 resp.Out.internalHeader.Server.SetStatus(statusCode)
289         } else {
290                 resp.Out.Server.Set(ENGINE_RESPONSE_STATUS, statusCode)
291         }
292
293 }
294
295 // Return the writer
296 func (resp *Response) GetWriter() (writer io.Writer) {
297         writer = resp.writer
298         if writer == nil {
299                 if w, e := resp.Out.Server.Get(ENGINE_WRITER); e == nil {
300                         writer, resp.writer = w.(io.Writer), w.(io.Writer)
301                 }
302         }
303
304         return
305 }
306
307 // Replace the writer
308 func (resp *Response) SetWriter(writer io.Writer) bool {
309         resp.writer = writer
310         // Leave it up to the engine to flush and close the writer
311         return resp.Out.Server.Set(ENGINE_WRITER, writer)
312 }
313
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)
318         }
319         return
320 }
321
322 // Return the header
323 func (o *OutResponse) Header() *RevelHeader {
324         return o.internalHeader
325 }
326
327 // Write the header out
328 func (o *OutResponse) Write(data []byte) (int, error) {
329         return o.response.GetWriter().Write(data)
330 }
331
332 // Set a value in the header
333 func (h *RevelHeader) Set(key, value string) {
334         if h.Server != nil {
335                 h.Server.Set(key, value)
336         }
337 }
338
339 // Add a key to the header
340 func (h *RevelHeader) Add(key, value string) {
341         if h.Server != nil {
342                 h.Server.Add(key, value)
343         }
344 }
345
346 // Set a cookie in the header
347 func (h *RevelHeader) SetCookie(cookie string) {
348         if h.Server != nil {
349                 h.Server.SetCookie(cookie)
350         }
351 }
352
353 // Set the status for the header
354 func (h *RevelHeader) SetStatus(status int) {
355         if h.Server != nil {
356                 h.Server.SetStatus(status)
357         }
358 }
359
360 // Get a key from the header
361 func (h *RevelHeader) Get(key string) (value string) {
362         values := h.GetAll(key)
363         if len(values) > 0 {
364                 value = values[0]
365         }
366         return
367 }
368
369 // GetAll returns []string of items (the header split by a comma)
370 func (h *RevelHeader) GetAll(key string) (values []string) {
371         if h.Server != nil {
372                 values = h.Server.Get(key)
373         }
374         return
375 }
376
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 {
381
382         contentType := req.Header.Get("Content-Type")
383         if contentType == "" {
384                 return "text/html"
385         }
386         return strings.ToLower(strings.TrimSpace(strings.Split(contentType, ";")[0]))
387 }
388
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
392 // value above.
393 func ResolveFormat(req *Request) string {
394         ext := strings.ToLower(filepath.Ext(req.GetPath()))
395         switch ext {
396         case ".html":
397                 return "html"
398         case ".json":
399                 return "json"
400         case ".xml":
401                 return "xml"
402         case ".txt":
403                 return "txt"
404         }
405
406         accept := req.GetHttpHeader("accept")
407
408         switch {
409         case accept == "",
410                 strings.HasPrefix(accept, "*/*"), // */
411                 strings.Contains(accept, "application/xhtml"),
412                 strings.Contains(accept, "text/html"):
413                 return "html"
414         case strings.Contains(accept, "application/json"),
415                 strings.Contains(accept, "text/javascript"),
416                 strings.Contains(accept, "application/javascript"):
417                 return "json"
418         case strings.Contains(accept, "application/xml"),
419                 strings.Contains(accept, "text/xml"):
420                 return "xml"
421         case strings.Contains(accept, "text/plain"):
422                 return "txt"
423         }
424
425         return "html"
426 }
427
428 // AcceptLanguage is a single language from the Accept-Language HTTP header.
429 type AcceptLanguage struct {
430         Language string
431         Quality  float32
432 }
433
434 // AcceptLanguages is collection of sortable AcceptLanguage instances.
435 type AcceptLanguages []AcceptLanguage
436
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)
445                 }
446                 if i != len(al)-1 {
447                         if _, err := output.WriteString(", "); err != nil {
448                                 httpLog.Error("String: WriteString failed:", "error", err)
449                         }
450                 }
451         }
452         return output.String()
453 }
454
455 // ResolveAcceptLanguage returns a sorted list of Accept-Language
456 // header values.
457 //
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.
461 //
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")
466         if header == "" {
467                 return req.AcceptLanguages
468         }
469
470         acceptLanguageHeaderValues := strings.Split(header, ",")
471         acceptLanguages := make(AcceptLanguages, len(acceptLanguageHeaderValues))
472
473         for i, languageRange := range acceptLanguageHeaderValues {
474                 if qualifiedRange := strings.Split(languageRange, ";q="); len(qualifiedRange) == 2 {
475                         quality, err := strconv.ParseFloat(qualifiedRange[1], 32)
476                         if err != nil {
477                                 httpLog.Warn("Detected malformed Accept-Language header quality in  assuming quality is 1", "languageRange", languageRange)
478                                 acceptLanguages[i] = AcceptLanguage{qualifiedRange[0], 1}
479                         } else {
480                                 acceptLanguages[i] = AcceptLanguage{qualifiedRange[0], float32(quality)}
481                         }
482                 } else {
483                         acceptLanguages[i] = AcceptLanguage{languageRange, 1}
484                 }
485         }
486
487         sort.Sort(acceptLanguages)
488         return acceptLanguages
489 }