Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timeout errors are unrecoverable #11

Closed
tve opened this issue Dec 21, 2013 · 2 comments
Closed

timeout errors are unrecoverable #11

tve opened this issue Dec 21, 2013 · 2 comments

Comments

@tve
Copy link

tve commented Dec 21, 2013

Once websocket.nextReader returns a timeout error it will always do so. That makes it impossible to poll a websocket and periodically check whether the socket should be closing or something like that. Basically what I wanted to do is to have the sender set a flag when it sends a close message and have the reader continue reading until a one minute timeout is reached. What I tried is below, but perhaps there's a much more elegant way to do this?

closing := false
for {
  // check whether the writer has closed
  if !closing {
    select {
    case code := <-ch:
        closing = true
    default:
    }
  }
  // set a deadline on the NextReader so we periodically go around the loop
  // and check the closing channel (see code above)
  ws.SetReadDeadline(time.Now().Add(time.Minute))
  // read a message from the websocket
  t, r, err := ws.NextReader()
  if err != nil {
    // if we get a timeout and we're told to close then it's time to give up
    netErr, ok := err.(net.Error)
    if ok && netErr.Timeout() && !closing {
      continue // just a timeout, that's OK
    }
    break
  }
  // continue reading message
}

@garyburd
Copy link
Contributor

It is not idiomatic to poll connections with timeouts in Go.

Close the websocket connection one minute after writing the close message. This will cause a blocked reader to return with an error.

@garyburd
Copy link
Contributor

garyburd commented Jan 3, 2014

Recoverable timeouts are difficult to implement. I am not aware of other Go network protocol libraries that support recoverable timeouts.

The application can implement timeout polling in a net.Conn shim between the websocket.Conn and the underlying net.Conn. A sketch for creating the shim is:

type appResponseWriter struct {  http.ResponseWriter }

func (w appResponseWriter)  Hijack() (net.Conn, *bufio.ReadWriter, error) {
    if h, ok := w.ResponseWriter.(http.Hijacker); ok {
        c, brw, err := h.Hijack()
        c = appConn(c)
        return c, brw, err
   } else {
        return nil, nil, errors.New("not supported")
   }
}

type appConn struct {
    net.Conn
}

func (c appConn) Read(p []byte) (int, err) {
    // implement timeout polling here.
}

func handler(w http.ResponseWriter, r *http.Request) {
    ws, err := websocket.Upgrade(appResponseWriter{w}, r, nil, 1024, 1024)
    if _, ok := err.(websocket.HandshakeError); ok {
        http.Error(w, "Not a websocket handshake", 400)
        return
    } else if err != nil {
        log.Println(err)
        return
    }
    ... Use conn to send and receive messages.
}

@garyburd garyburd closed this as completed Jan 3, 2014
@gorilla gorilla locked and limited conversation to collaborators Feb 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants