Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / server_adapter_go.go
1 package revel
2
3 import (
4         "net"
5         "net/http"
6         "time"
7         "context"
8         "golang.org/x/net/websocket"
9         "io"
10         "mime/multipart"
11         "net/url"
12         "os"
13         "os/signal"
14         "path"
15         "sort"
16         "strconv"
17         "strings"
18         "github.com/revel/revel/utils"
19 )
20
21 // Register the GoHttpServer engine
22 func init() {
23         AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) {
24                 if typeOf == REVEL_BEFORE_MODULES_LOADED {
25                         RegisterServerEngine(GO_NATIVE_SERVER_ENGINE, func() ServerEngine { return &GoHttpServer{} })
26                 }
27                 return
28         })
29 }
30
31 // The Go HTTP server
32 type GoHttpServer struct {
33         Server               *http.Server           // The server instance
34         ServerInit           *EngineInit            // The server engine initialization
35         MaxMultipartSize     int64                  // The largest size of file to accept
36         goContextStack       *utils.SimpleLockStack // The context stack Set via server.context.stack, server.context.maxstack
37         goMultipartFormStack *utils.SimpleLockStack // The multipart form stack set via server.form.stack, server.form.maxstack
38         HttpMuxList          ServerMuxList
39         HasAppMux            bool
40         signalChan           chan os.Signal
41 }
42
43 // Called to initialize the server with this EngineInit
44 func (g *GoHttpServer) Init(init *EngineInit) {
45         g.MaxMultipartSize = int64(Config.IntDefault("server.request.max.multipart.filesize", 32)) << 20 /* 32 MB */
46         g.goContextStack = utils.NewStackLock(Config.IntDefault("server.context.stack", 100),
47                 Config.IntDefault("server.context.maxstack", 200),
48                 func() interface{} {
49                         return NewGoContext(g)
50                 })
51         g.goMultipartFormStack = utils.NewStackLock(Config.IntDefault("server.form.stack", 100),
52                 Config.IntDefault("server.form.maxstack", 200),
53                 func() interface{} { return &GoMultipartForm{} })
54         g.ServerInit = init
55
56         revelHandler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
57                 g.Handle(writer, request)
58         })
59
60         // Adds the mux list
61         g.HttpMuxList = init.HTTPMuxList
62         sort.Sort(g.HttpMuxList)
63         g.HasAppMux = len(g.HttpMuxList) > 0
64         g.signalChan = make(chan os.Signal)
65
66         g.Server = &http.Server{
67                 Addr:         init.Address,
68                 Handler:      revelHandler,
69                 ReadTimeout:  time.Duration(Config.IntDefault("http.timeout.read", 0)) * time.Second,
70                 WriteTimeout: time.Duration(Config.IntDefault("http.timeout.write", 0)) * time.Second,
71         }
72
73 }
74
75 // Handler is assigned in the Init
76 func (g *GoHttpServer) Start() {
77         go func() {
78                 time.Sleep(100 * time.Millisecond)
79                 serverLogger.Debugf("Start: Listening on %s...", g.Server.Addr)
80         }()
81         if HTTPSsl {
82                 if g.ServerInit.Network != "tcp" {
83                         // This limitation is just to reduce complexity, since it is standard
84                         // to terminate SSL upstream when using unix domain sockets.
85                         serverLogger.Fatal("SSL is only supported for TCP sockets. Specify a port to listen on.")
86                 }
87                 serverLogger.Fatal("Failed to listen:", "error",
88                         g.Server.ListenAndServeTLS(HTTPSslCert, HTTPSslKey))
89         } else {
90                 listener, err := net.Listen(g.ServerInit.Network, g.Server.Addr)
91                 if err != nil {
92                         serverLogger.Fatal("Failed to listen:", "error", err)
93                 }
94                 serverLogger.Warn("Server exiting:", "error", g.Server.Serve(listener))
95         }
96 }
97
98 // Handle the request and response for the server
99 func (g *GoHttpServer) Handle(w http.ResponseWriter, r *http.Request) {
100         // This section is called if the developer has added custom mux to the app
101         if g.HasAppMux && g.handleAppMux(w, r) {
102                 return
103         }
104         g.handleMux(w, r)
105 }
106
107 // Handle the request and response for the servers mux
108 func (g *GoHttpServer) handleAppMux(w http.ResponseWriter, r *http.Request) bool {
109         // Check the prefix and split them
110         requestPath := path.Clean(r.URL.Path)
111         if handler, hasHandler := g.HttpMuxList.Find(requestPath); hasHandler {
112                 clientIP := HttpClientIP(r)
113                 localLog := AppLog.New("ip", clientIP,
114                         "path", r.URL.Path, "method", r.Method)
115                 defer func() {
116                         if err := recover(); err != nil {
117                                 localLog.Error("An error was caught using the handler", "path", requestPath, "error", err)
118                                 w.WriteHeader(http.StatusInternalServerError)
119                         }
120                 }()
121                 start := time.Now()
122                 handler.(http.HandlerFunc)(w, r)
123                 localLog.Info("Request Stats",
124                         "start", start,
125                         "duration_seconds", time.Since(start).Seconds(), "section", "requestlog",
126                 )
127                 return true
128         }
129         return false
130 }
131
132 // Passes the server request to Revel
133 func (g *GoHttpServer) handleMux(w http.ResponseWriter, r *http.Request) {
134         if maxRequestSize := int64(Config.IntDefault("http.maxrequestsize", 0)); maxRequestSize > 0 {
135                 r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
136         }
137
138         upgrade := r.Header.Get("Upgrade")
139         context := g.goContextStack.Pop().(*GoContext)
140         defer func() {
141                 g.goContextStack.Push(context)
142         }()
143         context.Request.SetRequest(r)
144         context.Response.SetResponse(w)
145
146         if upgrade == "websocket" || upgrade == "Websocket" {
147                 websocket.Handler(func(ws *websocket.Conn) {
148                         //Override default Read/Write timeout with sane value for a web socket request
149                         if err := ws.SetDeadline(time.Now().Add(time.Hour * 24)); err != nil {
150                                 serverLogger.Error("SetDeadLine failed:", err)
151                         }
152                         r.Method = "WS"
153                         context.Request.WebSocket = ws
154                         context.WebSocket = &GoWebSocket{Conn: ws, GoResponse: *context.Response}
155                         g.ServerInit.Callback(context)
156                 }).ServeHTTP(w, r)
157         } else {
158                 g.ServerInit.Callback(context)
159         }
160 }
161
162 // ClientIP method returns client IP address from HTTP request.
163 //
164 // Note: Set property "app.behind.proxy" to true only if Revel is running
165 // behind proxy like nginx, haproxy, apache, etc. Otherwise
166 // you may get inaccurate Client IP address. Revel parses the
167 // IP address in the order of X-Forwarded-For, X-Real-IP.
168 //
169 // By default revel will get http.Request's RemoteAddr
170 func HttpClientIP(r *http.Request) string {
171         if Config.BoolDefault("app.behind.proxy", false) {
172                 // Header X-Forwarded-For
173                 if fwdFor := strings.TrimSpace(r.Header.Get(HdrForwardedFor)); fwdFor != "" {
174                         index := strings.Index(fwdFor, ",")
175                         if index == -1 {
176                                 return fwdFor
177                         }
178                         return fwdFor[:index]
179                 }
180
181                 // Header X-Real-Ip
182                 if realIP := strings.TrimSpace(r.Header.Get(HdrRealIP)); realIP != "" {
183                         return realIP
184                 }
185         }
186
187         if remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
188                 return remoteAddr
189         }
190
191         return ""
192 }
193
194 // The server key name
195 const GO_NATIVE_SERVER_ENGINE = "go"
196
197 // Returns the name of this engine
198 func (g *GoHttpServer) Name() string {
199         return GO_NATIVE_SERVER_ENGINE
200 }
201
202 // Returns stats for this engine
203 func (g *GoHttpServer) Stats() map[string]interface{} {
204         return map[string]interface{}{
205                 "Go Engine Context": g.goContextStack.String(),
206                 "Go Engine Forms":   g.goMultipartFormStack.String(),
207         }
208 }
209
210 // Return the engine instance
211 func (g *GoHttpServer) Engine() interface{} {
212         return g.Server
213 }
214
215 // Handles an event from Revel
216 func (g *GoHttpServer) Event(event Event, args interface{}) (r EventResponse) {
217         switch event {
218         case ENGINE_STARTED:
219                 signal.Notify(g.signalChan, os.Interrupt, os.Kill)
220                 go func() {
221                         _ = <-g.signalChan
222                         serverLogger.Info("Received quit singal Please wait ... ")
223                         RaiseEvent(ENGINE_SHUTDOWN_REQUEST, nil)
224                 }()
225         case ENGINE_SHUTDOWN_REQUEST:
226                 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(Config.IntDefault("app.cancel.timeout", 60)))
227                 defer cancel()
228                 g.Server.Shutdown(ctx)
229         default:
230
231         }
232
233         return
234 }
235
236 type (
237         // The go context
238         GoContext struct {
239                 Request   *GoRequest   // The request
240                 Response  *GoResponse  // The response
241                 WebSocket *GoWebSocket // The websocket
242         }
243
244         // The go request
245         GoRequest struct {
246                 Original        *http.Request    // The original
247                 FormParsed      bool             // True if form parsed
248                 MultiFormParsed bool             // True if multipart form parsed
249                 WebSocket       *websocket.Conn  // The websocket
250                 ParsedForm      *GoMultipartForm // The parsed form data
251                 Goheader        *GoHeader        // The header
252                 Engine          *GoHttpServer    // THe server
253         }
254
255         // The response
256         GoResponse struct {
257                 Original http.ResponseWriter // The original writer
258                 Goheader *GoHeader           // The header
259                 Writer   io.Writer           // The writer
260                 Request  *GoRequest          // The request
261                 Engine   *GoHttpServer       // The engine
262         }
263
264         // The multipart form
265         GoMultipartForm struct {
266                 Form *multipart.Form // The form
267         }
268
269         // The go header
270         GoHeader struct {
271                 Source     interface{} // The source
272                 isResponse bool        // True if response header
273         }
274
275         // The websocket
276         GoWebSocket struct {
277                 Conn       *websocket.Conn // The connection
278                 GoResponse                 // The response
279         }
280
281         // The cookie
282         GoCookie http.Cookie
283 )
284
285 // Create a new go context
286 func NewGoContext(instance *GoHttpServer) *GoContext {
287         // This bit in here is for the test cases, which pass in a nil value
288         if instance == nil {
289                 instance = &GoHttpServer{MaxMultipartSize: 32 << 20}
290                 instance.goContextStack = utils.NewStackLock(100, 200,
291                         func() interface{} {
292                                 return NewGoContext(instance)
293                         })
294                 instance.goMultipartFormStack = utils.NewStackLock(100, 200,
295                         func() interface{} { return &GoMultipartForm{} })
296         }
297         c := &GoContext{Request: &GoRequest{Goheader: &GoHeader{}, Engine: instance}}
298         c.Response = &GoResponse{Goheader: &GoHeader{}, Request: c.Request, Engine: instance}
299         return c
300 }
301
302 // get the request
303 func (c *GoContext) GetRequest() ServerRequest {
304         return c.Request
305 }
306
307 // Get the response
308 func (c *GoContext) GetResponse() ServerResponse {
309         if c.WebSocket != nil {
310                 return c.WebSocket
311         }
312         return c.Response
313 }
314
315 // Destroy the context
316 func (c *GoContext) Destroy() {
317         c.Response.Destroy()
318         c.Request.Destroy()
319         if c.WebSocket != nil {
320                 c.WebSocket.Destroy()
321                 c.WebSocket = nil
322         }
323 }
324
325 // Communicate with the server engine to exchange data
326 func (r *GoRequest) Get(key int) (value interface{}, err error) {
327         switch key {
328         case HTTP_SERVER_HEADER:
329                 value = r.GetHeader()
330         case HTTP_MULTIPART_FORM:
331                 value, err = r.GetMultipartForm()
332         case HTTP_QUERY:
333                 value = r.Original.URL.Query()
334         case HTTP_FORM:
335                 value, err = r.GetForm()
336         case HTTP_REQUEST_URI:
337                 value = r.Original.URL.String()
338         case HTTP_REQUEST_CONTEXT:
339                 value = r.Original.Context()
340         case HTTP_REMOTE_ADDR:
341                 value = r.Original.RemoteAddr
342         case HTTP_METHOD:
343                 value = r.Original.Method
344         case HTTP_PATH:
345                 value = r.Original.URL.Path
346         case HTTP_HOST:
347                 value = r.Original.Host
348         case HTTP_URL:
349                 value = r.Original.URL
350         case HTTP_BODY:
351                 value = r.Original.Body
352         default:
353                 err = ENGINE_UNKNOWN_GET
354         }
355
356         return
357 }
358
359 // Sets the request key with value
360 func (r *GoRequest) Set(key int, value interface{}) bool {
361         return false
362 }
363
364 // Returns the form
365 func (r *GoRequest) GetForm() (url.Values, error) {
366         if !r.FormParsed {
367                 if e := r.Original.ParseForm(); e != nil {
368                         return nil, e
369                 }
370                 r.FormParsed = true
371         }
372
373         return r.Original.Form, nil
374 }
375
376 // Returns the form
377 func (r *GoRequest) GetMultipartForm() (ServerMultipartForm, error) {
378         if !r.MultiFormParsed {
379                 if e := r.Original.ParseMultipartForm(r.Engine.MaxMultipartSize); e != nil {
380                         return nil, e
381                 }
382                 r.ParsedForm = r.Engine.goMultipartFormStack.Pop().(*GoMultipartForm)
383                 r.ParsedForm.Form = r.Original.MultipartForm
384         }
385
386         return r.ParsedForm, nil
387 }
388
389 // Returns the header
390 func (r *GoRequest) GetHeader() ServerHeader {
391         return r.Goheader
392 }
393
394 // Returns the raw value
395 func (r *GoRequest) GetRaw() interface{} {
396         return r.Original
397 }
398
399 // Sets the request
400 func (r *GoRequest) SetRequest(req *http.Request) {
401         r.Original = req
402         r.Goheader.Source = r
403         r.Goheader.isResponse = false
404
405 }
406
407 // Destroy the request
408 func (r *GoRequest) Destroy() {
409         r.Goheader.Source = nil
410         r.Original = nil
411         r.FormParsed = false
412         r.MultiFormParsed = false
413         r.ParsedForm = nil
414 }
415
416 // Gets the key from the response
417 func (r *GoResponse) Get(key int) (value interface{}, err error) {
418         switch key {
419         case HTTP_SERVER_HEADER:
420                 value = r.Header()
421         case HTTP_STREAM_WRITER:
422                 value = r
423         case HTTP_WRITER:
424                 value = r.Writer
425         default:
426                 err = ENGINE_UNKNOWN_GET
427         }
428         return
429 }
430
431 // Sets the key with the value
432 func (r *GoResponse) Set(key int, value interface{}) (set bool) {
433         switch key {
434         case ENGINE_RESPONSE_STATUS:
435                 r.Header().SetStatus(value.(int))
436                 set = true
437         case HTTP_WRITER:
438                 r.SetWriter(value.(io.Writer))
439                 set = true
440         }
441         return
442 }
443
444 // Sets the header
445 func (r *GoResponse) Header() ServerHeader {
446         return r.Goheader
447 }
448
449 // Gets the original response
450 func (r *GoResponse) GetRaw() interface{} {
451         return r.Original
452 }
453
454 // Sets the writer
455 func (r *GoResponse) SetWriter(writer io.Writer) {
456         r.Writer = writer
457 }
458
459 // Write output to stream
460 func (r *GoResponse) WriteStream(name string, contentlen int64, modtime time.Time, reader io.Reader) error {
461         // Check to see if the output stream is modified, if not send it using the
462         // Native writer
463         written := false
464         if _, ok := r.Writer.(http.ResponseWriter); ok {
465                 if rs, ok := reader.(io.ReadSeeker); ok {
466                         http.ServeContent(r.Original, r.Request.Original, name, modtime, rs)
467                         written = true
468                 }
469         }
470         if !written {
471                 // Else, do a simple io.Copy.
472                 ius := r.Request.Original.Header.Get("If-Unmodified-Since")
473                 if t, err := http.ParseTime(ius); err == nil && !modtime.IsZero() {
474                         // The Date-Modified header truncates sub-second precision, so
475                         // use mtime < t+1s instead of mtime <= t to check for unmodified.
476                         if modtime.Before(t.Add(1 * time.Second)) {
477                                 h := r.Original.Header()
478                                 delete(h, "Content-Type")
479                                 delete(h, "Content-Length")
480                                 if h.Get("Etag") != "" {
481                                         delete(h, "Last-Modified")
482                                 }
483                                 r.Original.WriteHeader(http.StatusNotModified)
484                                 return nil
485                         }
486                 }
487
488                 if contentlen != -1 {
489                         header := ServerHeader(r.Goheader)
490                         if writer, found := r.Writer.(*CompressResponseWriter); found {
491                                 header = ServerHeader(writer.Header)
492                         }
493                         header.Set("Content-Length", strconv.FormatInt(contentlen, 10))
494                 }
495                 if _, err := io.Copy(r.Writer, reader); err != nil {
496                         r.Original.WriteHeader(http.StatusInternalServerError)
497                         return err
498                 } else {
499                         r.Original.WriteHeader(http.StatusOK)
500                 }
501         }
502         return nil
503 }
504
505 // Frees response
506 func (r *GoResponse) Destroy() {
507         if c, ok := r.Writer.(io.Closer); ok {
508                 c.Close()
509         }
510         r.Goheader.Source = nil
511         r.Original = nil
512         r.Writer = nil
513 }
514
515 // Sets the response
516 func (r *GoResponse) SetResponse(w http.ResponseWriter) {
517         r.Original = w
518         r.Writer = w
519         r.Goheader.Source = r
520         r.Goheader.isResponse = true
521
522 }
523
524 // Sets the cookie
525 func (r *GoHeader) SetCookie(cookie string) {
526         if r.isResponse {
527                 r.Source.(*GoResponse).Original.Header().Add("Set-Cookie", cookie)
528         }
529 }
530
531 // Gets the cookie
532 func (r *GoHeader) GetCookie(key string) (value ServerCookie, err error) {
533         if !r.isResponse {
534                 var cookie *http.Cookie
535                 if cookie, err = r.Source.(*GoRequest).Original.Cookie(key); err == nil {
536                         value = GoCookie(*cookie)
537
538                 }
539
540         }
541         return
542 }
543
544 // Sets (replaces) header key
545 func (r *GoHeader) Set(key string, value string) {
546         if r.isResponse {
547                 r.Source.(*GoResponse).Original.Header().Set(key, value)
548         }
549 }
550
551 // Adds the header key
552 func (r *GoHeader) Add(key string, value string) {
553         if r.isResponse {
554                 r.Source.(*GoResponse).Original.Header().Add(key, value)
555         }
556 }
557
558 // Deletes the header key
559 func (r *GoHeader) Del(key string) {
560         if r.isResponse {
561                 r.Source.(*GoResponse).Original.Header().Del(key)
562         }
563 }
564
565 // Gets the header key
566 func (r *GoHeader) Get(key string) (value []string) {
567         if !r.isResponse {
568                 value = r.Source.(*GoRequest).Original.Header[key]
569                 if len(value) == 0 {
570                         if ihead := r.Source.(*GoRequest).Original.Header.Get(key); ihead != "" {
571                                 value = append(value, ihead)
572                         }
573                 }
574         } else {
575                 value = r.Source.(*GoResponse).Original.Header()[key]
576         }
577         return
578 }
579
580 // Returns list of header keys
581 func (r *GoHeader) GetKeys() (value []string) {
582         if !r.isResponse {
583                 for key := range r.Source.(*GoRequest).Original.Header {
584                         value = append(value, key)
585                 }
586         } else {
587                 for key := range r.Source.(*GoResponse).Original.Header() {
588                         value = append(value, key)
589                 }
590         }
591         return
592 }
593
594 // Sets the status of the header
595 func (r *GoHeader) SetStatus(statusCode int) {
596         if r.isResponse {
597                 r.Source.(*GoResponse).Original.WriteHeader(statusCode)
598         }
599 }
600
601 // Return cookies value
602 func (r GoCookie) GetValue() string {
603         return r.Value
604 }
605
606 // Return files from the form
607 func (f *GoMultipartForm) GetFiles() map[string][]*multipart.FileHeader {
608         return f.Form.File
609 }
610
611 // Return values from the form
612 func (f *GoMultipartForm) GetValues() url.Values {
613         return url.Values(f.Form.Value)
614 }
615
616 // Remove all values from the form freeing memory
617 func (f *GoMultipartForm) RemoveAll() error {
618         return f.Form.RemoveAll()
619 }
620
621 /**
622  * Message send JSON
623  */
624 func (g *GoWebSocket) MessageSendJSON(v interface{}) error {
625         return websocket.JSON.Send(g.Conn, v)
626 }
627
628 /**
629  * Message receive JSON
630  */
631 func (g *GoWebSocket) MessageReceiveJSON(v interface{}) error {
632         return websocket.JSON.Receive(g.Conn, v)
633 }
634
635 /**
636  * Message Send
637  */
638 func (g *GoWebSocket) MessageSend(v interface{}) error {
639         return websocket.Message.Send(g.Conn, v)
640 }
641
642 /**
643  * Message receive
644  */
645 func (g *GoWebSocket) MessageReceive(v interface{}) error {
646         return websocket.Message.Receive(g.Conn, v)
647 }