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.
17 /* Minimum Engine Type Values */
19 ENGINE_RESPONSE_STATUS
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
45 ServerContext interface {
46 GetRequest() ServerRequest
47 GetResponse() ServerResponse
50 // Callback ServerRequest type
51 ServerRequest interface {
53 Get(theType int) (interface{}, error)
54 Set(theType int, theValue interface{}) bool
56 // Callback ServerResponse type
57 ServerResponse interface {
60 // Callback WebSocket type
61 ServerWebSocket interface {
63 MessageSendJSON(v interface{}) error
64 MessageReceiveJSON(v interface{}) error
65 MessageSend(v interface{}) error
66 MessageReceive(v interface{}) error
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)
76 Get(key string) (value []string)
77 GetKeys() (headerKeys []string)
78 SetStatus(statusCode int)
81 // Expected response for FROM_HTTP_COOKIE type (if implemented)
82 ServerCookie interface {
86 // Expected response for HTTP_MULTIPART_FORM
87 ServerMultipartForm interface {
88 GetFiles() map[string][]*multipart.FileHeader
89 GetValues() url.Values
92 StreamWriter interface {
93 WriteStream(name string, contentlen int64, modtime time.Time, reader io.Reader) error
96 ServerEngine interface {
97 // Initialize the server (non blocking)
98 Init(init *EngineInit)
99 // Starts the server. This will block until server is stopped
101 // Fires a new event to the server
102 Event(event Event, args interface{}) EventResponse
103 // Returns the engine instance for specific calls
105 // Returns the engine Name
108 Stats() map[string]interface{}
111 // The initialization structure passed into the engine
113 Address, // The address
114 Network string // The network
116 HTTPMuxList ServerMuxList // The HTTPMux
117 Callback func(ServerContext) // The ServerContext callback endpoint
120 // An empty server engine
121 ServerEngineEmpty struct {
124 // The route handler structure
126 PathPrefix string // The path prefix
127 Callback interface{} // The callback interface as appropriate to the server
130 // A list of handlers used for adding special route functions
131 ServerMuxList []ServerMux
135 func (r ServerMuxList) Len() int {
140 func (r ServerMuxList) Less(i, j int) bool {
141 return len(r[i].PathPrefix) > len(r[j].PathPrefix)
145 func (r ServerMuxList) Swap(i, j int) {
146 r[i], r[j] = r[j], r[i]
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
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})
165 // Callback point for the server to handle the
166 func handleInternal(ctx ServerContext) {
169 if RevelConfig.Controller.Reuse {
170 c = RevelConfig.Controller.Stack.Pop().(*Controller)
172 RevelConfig.Controller.Stack.Push(c)
175 c = NewControllerEmpty()
180 req, resp = c.Request, c.Response
183 req.WebSocket, _ = ctx.GetResponse().(ServerWebSocket)
185 clientIP := ClientIP(req)
187 // Once finished in the internal, we can return these to the stack
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:])
195 c.Result.Apply(req, resp)
196 } else if c.Response.Status != 0 {
197 c.Response.SetStatus(c.Response.Status)
199 // Close the Writer if we can
200 if w, ok := resp.GetWriter().(io.Closer); ok {
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"}
213 c.Log.Info("Request Stats",
215 "status", c.Response.Status,
216 "duration_seconds", time.Since(start).Seconds(), "section", "requestlog",
221 ENGINE_UNKNOWN_GET = errors.New("Server Engine Invalid Get")
224 func (e *ServerEngineEmpty) Get(_ string) interface{} {
227 func (e *ServerEngineEmpty) Set(_ string, _ interface{}) bool {