Skip to content

some code path didn't check closed state #216

Closed
@zhangyoufu

Description

@zhangyoufu

Everywhere we got an error when read from / write into underlying transport (incl. flush write buffer), we should check if we have closed the connection, and wrap a CloseError.

How to reproduce

package main

import (
	"context"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"time"

	"nhooyr.io/websocket"
)

func handleHTTP(w http.ResponseWriter, r *http.Request) {
	ws, err := websocket.Accept(w, r, nil)
	if err == nil {
		go handleWS(ws)
	}
}

func handleWS(conn *websocket.Conn) {
	defer conn.Close(websocket.StatusInternalError, "oops")
	ctx := context.Background()
	for {
		_, _, err := conn.Read(ctx)
		if err != nil {
			return
		}
	}
}

func main() {
	ctx := context.Background()

	server := httptest.NewServer(http.HandlerFunc(handleHTTP))
	defer server.Close()

	url := strings.Replace(server.URL, "http", "ws", 1)
	client, _, _ := websocket.Dial(ctx, url, nil)

	// write something in background
	joinCh := make(chan struct{})
	go func() {
		defer close(joinCh)
		for {
			err := client.Write(ctx, websocket.MessageText, []byte("test"))
			if err != nil {
				log.Print("client write error: ", err)
				log.Print("client close status code: ", websocket.CloseStatus(err))
				return
			}
		}
	}()

	// close after some time
	time.Sleep(time.Millisecond)
	_ = client.Close(websocket.StatusNormalClosure, "bye")

	<- joinCh
}

Expected output

2020/03/15 21:20:23 client write error: failed to write msg: failed to close writer: failed to write fin frame: failed to write frame: WebSocket closed: sent close frame: status = StatusNormalClosure and reason = "bye"
2020/03/15 21:20:23 client close status code: StatusNormalClosure

Unexpected output

2020/03/15 21:20:21 client write error: failed to write msg: failed to close writer: failed to write fin frame: failed to write frame: failed to flush: write tcp 127.0.0.1:59943->127.0.0.1:59942: use of closed network connection
2020/03/15 21:20:21 client close status code: StatusCode(-1)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions