8 "golang.org/x/net/websocket"
18 "github.com/revel/revel/utils"
21 // Register the GoHttpServer engine
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{} })
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
40 signalChan chan os.Signal
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),
49 return NewGoContext(g)
51 g.goMultipartFormStack = utils.NewStackLock(Config.IntDefault("server.form.stack", 100),
52 Config.IntDefault("server.form.maxstack", 200),
53 func() interface{} { return &GoMultipartForm{} })
56 revelHandler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
57 g.Handle(writer, request)
61 g.HttpMuxList = init.HTTPMuxList
62 sort.Sort(g.HttpMuxList)
63 g.HasAppMux = len(g.HttpMuxList) > 0
64 g.signalChan = make(chan os.Signal)
66 g.Server = &http.Server{
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,
75 // Handler is assigned in the Init
76 func (g *GoHttpServer) Start() {
78 time.Sleep(100 * time.Millisecond)
79 serverLogger.Debugf("Start: Listening on %s...", g.Server.Addr)
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.")
87 serverLogger.Fatal("Failed to listen:", "error",
88 g.Server.ListenAndServeTLS(HTTPSslCert, HTTPSslKey))
90 listener, err := net.Listen(g.ServerInit.Network, g.Server.Addr)
92 serverLogger.Fatal("Failed to listen:", "error", err)
94 serverLogger.Warn("Server exiting:", "error", g.Server.Serve(listener))
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) {
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)
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)
122 handler.(http.HandlerFunc)(w, r)
123 localLog.Info("Request Stats",
125 "duration_seconds", time.Since(start).Seconds(), "section", "requestlog",
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)
138 upgrade := r.Header.Get("Upgrade")
139 context := g.goContextStack.Pop().(*GoContext)
141 g.goContextStack.Push(context)
143 context.Request.SetRequest(r)
144 context.Response.SetResponse(w)
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)
153 context.Request.WebSocket = ws
154 context.WebSocket = &GoWebSocket{Conn: ws, GoResponse: *context.Response}
155 g.ServerInit.Callback(context)
158 g.ServerInit.Callback(context)
162 // ClientIP method returns client IP address from HTTP request.
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.
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, ",")
178 return fwdFor[:index]
182 if realIP := strings.TrimSpace(r.Header.Get(HdrRealIP)); realIP != "" {
187 if remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
194 // The server key name
195 const GO_NATIVE_SERVER_ENGINE = "go"
197 // Returns the name of this engine
198 func (g *GoHttpServer) Name() string {
199 return GO_NATIVE_SERVER_ENGINE
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(),
210 // Return the engine instance
211 func (g *GoHttpServer) Engine() interface{} {
215 // Handles an event from Revel
216 func (g *GoHttpServer) Event(event Event, args interface{}) (r EventResponse) {
219 signal.Notify(g.signalChan, os.Interrupt, os.Kill)
222 serverLogger.Info("Received quit singal Please wait ... ")
223 RaiseEvent(ENGINE_SHUTDOWN_REQUEST, nil)
225 case ENGINE_SHUTDOWN_REQUEST:
226 ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(Config.IntDefault("app.cancel.timeout", 60)))
228 g.Server.Shutdown(ctx)
239 Request *GoRequest // The request
240 Response *GoResponse // The response
241 WebSocket *GoWebSocket // The websocket
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
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
264 // The multipart form
265 GoMultipartForm struct {
266 Form *multipart.Form // The form
271 Source interface{} // The source
272 isResponse bool // True if response header
277 Conn *websocket.Conn // The connection
278 GoResponse // The response
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
289 instance = &GoHttpServer{MaxMultipartSize: 32 << 20}
290 instance.goContextStack = utils.NewStackLock(100, 200,
292 return NewGoContext(instance)
294 instance.goMultipartFormStack = utils.NewStackLock(100, 200,
295 func() interface{} { return &GoMultipartForm{} })
297 c := &GoContext{Request: &GoRequest{Goheader: &GoHeader{}, Engine: instance}}
298 c.Response = &GoResponse{Goheader: &GoHeader{}, Request: c.Request, Engine: instance}
303 func (c *GoContext) GetRequest() ServerRequest {
308 func (c *GoContext) GetResponse() ServerResponse {
309 if c.WebSocket != nil {
315 // Destroy the context
316 func (c *GoContext) Destroy() {
319 if c.WebSocket != nil {
320 c.WebSocket.Destroy()
325 // Communicate with the server engine to exchange data
326 func (r *GoRequest) Get(key int) (value interface{}, err error) {
328 case HTTP_SERVER_HEADER:
329 value = r.GetHeader()
330 case HTTP_MULTIPART_FORM:
331 value, err = r.GetMultipartForm()
333 value = r.Original.URL.Query()
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
343 value = r.Original.Method
345 value = r.Original.URL.Path
347 value = r.Original.Host
349 value = r.Original.URL
351 value = r.Original.Body
353 err = ENGINE_UNKNOWN_GET
359 // Sets the request key with value
360 func (r *GoRequest) Set(key int, value interface{}) bool {
365 func (r *GoRequest) GetForm() (url.Values, error) {
367 if e := r.Original.ParseForm(); e != nil {
373 return r.Original.Form, nil
377 func (r *GoRequest) GetMultipartForm() (ServerMultipartForm, error) {
378 if !r.MultiFormParsed {
379 if e := r.Original.ParseMultipartForm(r.Engine.MaxMultipartSize); e != nil {
382 r.ParsedForm = r.Engine.goMultipartFormStack.Pop().(*GoMultipartForm)
383 r.ParsedForm.Form = r.Original.MultipartForm
386 return r.ParsedForm, nil
389 // Returns the header
390 func (r *GoRequest) GetHeader() ServerHeader {
394 // Returns the raw value
395 func (r *GoRequest) GetRaw() interface{} {
400 func (r *GoRequest) SetRequest(req *http.Request) {
402 r.Goheader.Source = r
403 r.Goheader.isResponse = false
407 // Destroy the request
408 func (r *GoRequest) Destroy() {
409 r.Goheader.Source = nil
412 r.MultiFormParsed = false
416 // Gets the key from the response
417 func (r *GoResponse) Get(key int) (value interface{}, err error) {
419 case HTTP_SERVER_HEADER:
421 case HTTP_STREAM_WRITER:
426 err = ENGINE_UNKNOWN_GET
431 // Sets the key with the value
432 func (r *GoResponse) Set(key int, value interface{}) (set bool) {
434 case ENGINE_RESPONSE_STATUS:
435 r.Header().SetStatus(value.(int))
438 r.SetWriter(value.(io.Writer))
445 func (r *GoResponse) Header() ServerHeader {
449 // Gets the original response
450 func (r *GoResponse) GetRaw() interface{} {
455 func (r *GoResponse) SetWriter(writer io.Writer) {
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
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)
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")
483 r.Original.WriteHeader(http.StatusNotModified)
488 if contentlen != -1 {
489 header := ServerHeader(r.Goheader)
490 if writer, found := r.Writer.(*CompressResponseWriter); found {
491 header = ServerHeader(writer.Header)
493 header.Set("Content-Length", strconv.FormatInt(contentlen, 10))
495 if _, err := io.Copy(r.Writer, reader); err != nil {
496 r.Original.WriteHeader(http.StatusInternalServerError)
499 r.Original.WriteHeader(http.StatusOK)
506 func (r *GoResponse) Destroy() {
507 if c, ok := r.Writer.(io.Closer); ok {
510 r.Goheader.Source = nil
516 func (r *GoResponse) SetResponse(w http.ResponseWriter) {
519 r.Goheader.Source = r
520 r.Goheader.isResponse = true
525 func (r *GoHeader) SetCookie(cookie string) {
527 r.Source.(*GoResponse).Original.Header().Add("Set-Cookie", cookie)
532 func (r *GoHeader) GetCookie(key string) (value ServerCookie, err error) {
534 var cookie *http.Cookie
535 if cookie, err = r.Source.(*GoRequest).Original.Cookie(key); err == nil {
536 value = GoCookie(*cookie)
544 // Sets (replaces) header key
545 func (r *GoHeader) Set(key string, value string) {
547 r.Source.(*GoResponse).Original.Header().Set(key, value)
551 // Adds the header key
552 func (r *GoHeader) Add(key string, value string) {
554 r.Source.(*GoResponse).Original.Header().Add(key, value)
558 // Deletes the header key
559 func (r *GoHeader) Del(key string) {
561 r.Source.(*GoResponse).Original.Header().Del(key)
565 // Gets the header key
566 func (r *GoHeader) Get(key string) (value []string) {
568 value = r.Source.(*GoRequest).Original.Header[key]
570 if ihead := r.Source.(*GoRequest).Original.Header.Get(key); ihead != "" {
571 value = append(value, ihead)
575 value = r.Source.(*GoResponse).Original.Header()[key]
580 // Returns list of header keys
581 func (r *GoHeader) GetKeys() (value []string) {
583 for key := range r.Source.(*GoRequest).Original.Header {
584 value = append(value, key)
587 for key := range r.Source.(*GoResponse).Original.Header() {
588 value = append(value, key)
594 // Sets the status of the header
595 func (r *GoHeader) SetStatus(statusCode int) {
597 r.Source.(*GoResponse).Original.WriteHeader(statusCode)
601 // Return cookies value
602 func (r GoCookie) GetValue() string {
606 // Return files from the form
607 func (f *GoMultipartForm) GetFiles() map[string][]*multipart.FileHeader {
611 // Return values from the form
612 func (f *GoMultipartForm) GetValues() url.Values {
613 return url.Values(f.Form.Value)
616 // Remove all values from the form freeing memory
617 func (f *GoMultipartForm) RemoveAll() error {
618 return f.Form.RemoveAll()
624 func (g *GoWebSocket) MessageSendJSON(v interface{}) error {
625 return websocket.JSON.Send(g.Conn, v)
629 * Message receive JSON
631 func (g *GoWebSocket) MessageReceiveJSON(v interface{}) error {
632 return websocket.JSON.Receive(g.Conn, v)
638 func (g *GoWebSocket) MessageSend(v interface{}) error {
639 return websocket.Message.Send(g.Conn, v)
645 func (g *GoWebSocket) MessageReceive(v interface{}) error {
646 return websocket.Message.Receive(g.Conn, v)