Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / server-engine.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         "errors"
9         "io"
10         "mime/multipart"
11         "net/url"
12         "strings"
13         "time"
14 )
15
16 const (
17         /* Minimum Engine Type Values */
18         _ = iota
19         ENGINE_RESPONSE_STATUS
20         ENGINE_WRITER
21         ENGINE_PARAMETERS
22         ENGINE_PATH
23         ENGINE_REQUEST
24         ENGINE_RESPONSE
25 )
26 const (
27         /* HTTP Engine Type Values Starts at 1000 */
28         HTTP_QUERY           = ENGINE_PARAMETERS
29         HTTP_PATH            = ENGINE_PATH
30         HTTP_BODY            = iota + 1000
31         HTTP_FORM            = iota + 1000
32         HTTP_MULTIPART_FORM  = iota + 1000
33         HTTP_METHOD          = iota + 1000
34         HTTP_REQUEST_URI     = iota + 1000
35         HTTP_REQUEST_CONTEXT = iota + 1000
36         HTTP_REMOTE_ADDR     = iota + 1000
37         HTTP_HOST            = iota + 1000
38         HTTP_URL             = iota + 1000
39         HTTP_SERVER_HEADER   = iota + 1000
40         HTTP_STREAM_WRITER   = iota + 1000
41         HTTP_WRITER          = ENGINE_WRITER
42 )
43
44 type (
45         ServerContext interface {
46                 GetRequest() ServerRequest
47                 GetResponse() ServerResponse
48         }
49
50         // Callback ServerRequest type
51         ServerRequest interface {
52                 GetRaw() interface{}
53                 Get(theType int) (interface{}, error)
54                 Set(theType int, theValue interface{}) bool
55         }
56         // Callback ServerResponse type
57         ServerResponse interface {
58                 ServerRequest
59         }
60         // Callback WebSocket type
61         ServerWebSocket interface {
62                 ServerResponse
63                 MessageSendJSON(v interface{}) error
64                 MessageReceiveJSON(v interface{}) error
65                 MessageSend(v interface{}) error
66                 MessageReceive(v interface{}) error
67         }
68
69         // Expected response for HTTP_SERVER_HEADER type (if implemented)
70         ServerHeader interface {
71                 SetCookie(cookie string) // Sets the cookie
72                 GetCookie(key string) (value ServerCookie, err error) // Gets the cookie
73                 Set(key string, value string)
74                 Add(key string, value string)
75                 Del(key string)
76                 Get(key string) (value []string)
77                 GetKeys() (headerKeys []string)
78                 SetStatus(statusCode int)
79         }
80
81         // Expected response for FROM_HTTP_COOKIE type (if implemented)
82         ServerCookie interface {
83                 GetValue() string
84         }
85
86         // Expected response for HTTP_MULTIPART_FORM
87         ServerMultipartForm interface {
88                 GetFiles() map[string][]*multipart.FileHeader
89                 GetValues() url.Values
90                 RemoveAll() error
91         }
92         StreamWriter interface {
93                 WriteStream(name string, contentlen int64, modtime time.Time, reader io.Reader) error
94         }
95
96         ServerEngine interface {
97                 // Initialize the server (non blocking)
98                 Init(init *EngineInit)
99                 // Starts the server. This will block until server is stopped
100                 Start()
101                 // Fires a new event to the server
102                 Event(event Event, args interface{}) EventResponse
103                 // Returns the engine instance for specific calls
104                 Engine() interface{}
105                 // Returns the engine Name
106                 Name() string
107                 // Returns any stats
108                 Stats() map[string]interface{}
109         }
110
111         // The initialization structure passed into the engine
112         EngineInit struct {
113                 Address, // The address
114                 Network string // The network
115                 Port        int                 // The port
116                 HTTPMuxList ServerMuxList       // The HTTPMux
117                 Callback    func(ServerContext) // The ServerContext callback endpoint
118         }
119
120         // An empty server engine
121         ServerEngineEmpty struct {
122         }
123
124         // The route handler structure
125         ServerMux struct {
126                 PathPrefix string      // The path prefix
127                 Callback   interface{} // The callback interface as appropriate to the server
128         }
129
130         // A list of handlers used for adding special route functions
131         ServerMuxList []ServerMux
132 )
133
134 // Sorting function
135 func (r ServerMuxList) Len() int {
136         return len(r)
137 }
138
139 // Sorting function
140 func (r ServerMuxList) Less(i, j int) bool {
141         return len(r[i].PathPrefix) > len(r[j].PathPrefix)
142 }
143
144 // Sorting function
145 func (r ServerMuxList) Swap(i, j int) {
146         r[i], r[j] = r[j], r[i]
147 }
148
149 // Search function, returns the largest path matching this
150 func (r ServerMuxList) Find(path string) (interface{}, bool) {
151         for _, p := range r {
152                 if p.PathPrefix == path || strings.HasPrefix(path, p.PathPrefix) {
153                         return p.Callback, true
154                 }
155         }
156         return nil, false
157 }
158
159 // Adds this routehandler to the route table. It will be called (if the path prefix matches)
160 // before the Revel mux, this can only be called after the ENGINE_BEFORE_INITIALIZED event
161 func AddHTTPMux(path string, callback interface{}) {
162         ServerEngineInit.HTTPMuxList = append(ServerEngineInit.HTTPMuxList, ServerMux{PathPrefix: path, Callback: callback})
163 }
164
165 // Callback point for the server to handle the
166 func handleInternal(ctx ServerContext) {
167         start := time.Now()
168         var c *Controller
169         if RevelConfig.Controller.Reuse {
170                 c         = RevelConfig.Controller.Stack.Pop().(*Controller)
171                 defer func() {
172                         RevelConfig.Controller.Stack.Push(c)
173                 }()
174         } else {
175                 c = NewControllerEmpty()
176         }
177
178         var (
179
180                 req, resp = c.Request, c.Response
181         )
182         c.SetController(ctx)
183         req.WebSocket, _ = ctx.GetResponse().(ServerWebSocket)
184
185         clientIP := ClientIP(req)
186
187         // Once finished in the internal, we can return these to the stack
188
189         c.ClientIP = clientIP
190         c.Log = AppLog.New("ip", clientIP,
191                 "path", req.GetPath(), "method", req.Method)
192         // Call the first filter, this will process the request
193         Filters[0](c, Filters[1:])
194         if c.Result != nil {
195                 c.Result.Apply(req, resp)
196         } else if c.Response.Status != 0 {
197                 c.Response.SetStatus(c.Response.Status)
198         }
199         // Close the Writer if we can
200         if w, ok := resp.GetWriter().(io.Closer); ok {
201                 _ = w.Close()
202         }
203
204         // Revel request access log format
205         // RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
206         // Sample format: terminal format
207         // INFO 2017/08/02 22:31:41 server-engine.go:168: Request Stats                            ip=::1 path=/public/img/favicon.png method=GET action=Static.Serve namespace=static\\ start=2017/08/02 22:31:41 status=200 duration_seconds=0.0007656
208         // Recommended storing format to json code which looks like
209         // {"action":"Static.Serve","caller":"server-engine.go:168","duration_seconds":0.00058336,"ip":"::1","lvl":3,
210         // "method":"GET","msg":"Request Stats","namespace":"static\\","path":"/public/img/favicon.png",
211         // "start":"2017-08-02T22:34:08-0700","status":200,"t":"2017-08-02T22:34:08.303112145-07:00"}
212
213         c.Log.Info("Request Stats",
214                 "start", start,
215                 "status", c.Response.Status,
216                 "duration_seconds", time.Since(start).Seconds(), "section", "requestlog",
217         )
218 }
219
220 var (
221         ENGINE_UNKNOWN_GET = errors.New("Server Engine Invalid Get")
222 )
223
224 func (e *ServerEngineEmpty) Get(_ string) interface{} {
225         return nil
226 }
227 func (e *ServerEngineEmpty) Set(_ string, _ interface{}) bool {
228         return false
229 }