labstack / echo

High performance, minimalist Go web framework
https://echo.labstack.com
MIT License
29.9k stars 2.23k forks source link

echo v2 websocket stack overflow #447

Closed steveoc64 closed 8 years ago

steveoc64 commented 8 years ago

Porting my app from echo v1 to v2. Everything proceeding well, but I am stuck on getting websockets working under v2.

Should be pretty straightforward, as everything works sweet under v1, I figure that I am missing something obvious in porting to v2.

Environment :

Getting this runtime error as soon as the client makes the initial websocket request, with v2 :

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0xa28910, 0xe)
    /usr/local/go/src/runtime/panic.go:530 +0x90
runtime.newstack()
    /usr/local/go/src/runtime/stack.go:940 +0xb11
runtime.morestack()
    /usr/local/go/src/runtime/asm_amd64.s:359 +0x7f

goroutine 13 [stack growth]:
runtime.getitab(0x935c20, 0x9d66a0, 0x7f36f4157800, 0x3be00000000)
    /usr/local/go/src/runtime/iface.go:22 fp=0xc840700308 sp=0xc840700300
runtime.assertI2I(0x935c20, 0x7f36f755a4b8, 0xc8201e4c20, 0xc840700368)
    /usr/local/go/src/runtime/iface.go:313 +0x135 fp=0xc840700338 sp=0xc840700308
github.com/labstack/echo/engine/standard.(*Response).Hijack(0xc8203aa000, 0x0, 0x0, 0x0, 0x0, 0x0)
    $GOPATH/src/github.com/labstack/echo/engine/standard/response.go:90 +0x6d fp=0xc840700380 sp=0xc840700338
github.com/labstack/echo/engine/standard.(*Response).Hijack(0xc8203aa000, 0x0, 0x0, 0x0, 0x0, 0x0)
    $GOPATH/src/github.com/labstack/echo/engine/standard/response.go:90 +0x81 fp=0xc8407003c8 sp=0xc840700380
github.com/labstack/echo/engine/standard.(*Response).Hijack(0xc8203aa000, 0x0, 0x0, 0x0, 0x0, 0x0)

... which continues down the page, in each case the Hijack call appears to call itself, ad infinitum, as the stack pointers match the frame pointers for each successive row in the stack trace.

Code in engine/standard/response.go : 90 =

func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
    return r.ResponseWriter.(http.Hijacker).Hijack()
}

.... looks like something is getting messed up to the point where the call to Hijack() on the responseWriter ends up calling itself ? Not sure.

Relevant parts of my code at the back end looks like this :

in func main()
    e = echo.New()
    _initRoutes()
    e.Static("/", "build")
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.Gzip())
    e.Run(standard.New(":80"))

in func _initRoutes()
       ... lots of vanilla e.Get() statements
    e.Get("/ws", standard.WrapHandler(websocket.Handler(webSocket)))

func webSocket(ws *websocket.Conn) {
    fmt.Println("This statement never gets reached, because the stack gets blown first")
}      
vishr commented 8 years ago

Please verify and if you like the project consider to star it.

steveoc64 commented 8 years ago

Tested, all works 100% Thanks a million, great work.

:+1: V2 is looking good

vishr commented 8 years ago

Excellent!

steveoc64 commented 8 years ago

Another followup .... more good news

I have another port of this application that uses echo v1, which really hammers the use of websockets. This app uses modified Go RPC calls over a socket connection between the front end (web browser) and the backend.

The frontend is also written in Go, and compiles to JS using GopherJS. Bit complicated, but I figured if anything is going to break, then this app will. This app is functionally equivalent to the other app, but its written in pure Go, and uses sockets rather than HTTP requests.

Long story short ... after a few minor changes to the code, both front and back compile with v2, all loads up and runs, no probs, and passes internal test. V2 is working well.

It actually appears to run a little bit faster than the v1 code ? Not sure, but its certainly super quick, with sub-millisecond response times for complex page builds. Comms throughput is generally 4-8x faster than the same app that uses HTTP. Happy with that.

Can mark #447 as closed whenever you want.

EwanValentine commented 8 years ago

Can you do... e.Get("/ws", fasthttp.WrapHandler(websocket.Handler(webSocket)))? (fasthttp).

steveoc64 commented 8 years ago

cant try it now from this machine ... will try that tomorrow and report back