ws

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package ws is a minimal, dependency-free RFC 6455 WebSocket implementation, sufficient to carry Engine.IO/Socket.IO traffic. It provides both sides of a connection: a server that upgrades an incoming net/http request and a client that dials a remote endpoint. It supports the opening handshake, fragmented data messages, and the control frames (ping/pong/close). Only what Socket.IO needs is implemented; it is not a general-purpose WebSocket library, and it is an internal package with no compatibility guarantees for outside importers.

It exists so that the surrounding module can offer WebSocket transport using nothing but the Go standard library — no gorilla/websocket, no nhooyr, no cgo. The socketio server calls Upgrade to turn a hijacked HTTP connection into a *Conn; the client package calls Dial to obtain a *Conn to a remote server. Both then exchange Engine.IO frames through the same small message API, so the rest of the stack is transport-agnostic.

The server handshake works by validating the Upgrade/Connection headers and Sec-WebSocket-Version (13), hijacking the underlying net.Conn via http.Hijacker, and replying with the 101 Switching Protocols response whose Sec-WebSocket-Accept is the SHA-1/base64 digest of the client key plus the RFC 6455 GUID. IsWebSocketUpgrade reports whether a request is a WebSocket upgrade so callers can branch before attempting Upgrade. Dial performs the mirror image: it opens a TCP connection, sends the GET upgrade request with a random key, and verifies the server's accept value.

Messages are exchanged with ReadMessage and WriteMessage (or the WriteText convenience), which speak whole logical messages rather than raw frames. ReadMessage reassembles fragmented messages, transparently answers ping control frames with a pong, and responds to a close frame by echoing it and returning ErrClosed. MessageType distinguishes TextMessage from BinaryMessage, which matches Engine.IO's split between string packets and binary attachments. Per RFC 6455, client-originated frames are masked with a fresh random key (Conn tracks whether it is a client), while server frames are sent unmasked.

A Conn is safe for one concurrent reader and one concurrent writer: writes are serialized by an internal mutex and the closed flag is atomic, so a reader that observes a close while a writer is mid-flight will not race. It is not safe to call ReadMessage from two goroutines at once. Close sends a normal (1000) close frame and tears down the transport; subsequent writes return ErrClosed. Notably absent, because Socket.IO does not require them, are permessage-deflate compression, subprotocol negotiation, and read/write deadlines — callers that need timeouts should manage them on the underlying connection or via request context.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("ws: connection closed")

ErrClosed is returned once the connection has been closed.

Functions

func IsWebSocketUpgrade

func IsWebSocketUpgrade(r *http.Request) bool

IsWebSocketUpgrade reports whether r is a WebSocket upgrade request.

Types

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a WebSocket connection (server- or client-side).

func Dial

func Dial(rawURL string, header http.Header) (*Conn, error)

Dial opens a client WebSocket connection to a ws:// or http:// URL. The returned Conn masks outgoing frames as required for clients.

func Upgrade

func Upgrade(w http.ResponseWriter, r *http.Request) (*Conn, error)

Upgrade completes the server handshake and hijacks the connection, returning a *Conn ready for ReadMessage/WriteMessage.

Example

ExampleUpgrade shows how to accept a WebSocket connection inside an ordinary net/http handler. The handler first calls IsWebSocketUpgrade to confirm the request is a genuine upgrade (rejecting anything else with a 400), then calls Upgrade to complete the RFC 6455 handshake and hijack the connection, yielding a *Conn. It then loops with ReadMessage — which transparently answers ping control frames and reassembles fragmented messages — and echoes every text message back to the client with WriteText, breaking out of the loop (and closing the connection via the deferred Close) as soon as the peer goes away. The reader should take away the minimal server recipe: check, Upgrade, then read/write whole messages. (This example is compiled to verify the API surface but is not executed here, because it needs a real WebSocket peer to drive it.)

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if !IsWebSocketUpgrade(r) {
		http.Error(w, "expected websocket upgrade", http.StatusBadRequest)
		return
	}
	conn, err := Upgrade(w, r)
	if err != nil {
		return
	}
	defer conn.Close()

	for {
		mt, data, err := conn.ReadMessage()
		if err != nil {
			return // peer closed or read failed
		}
		if mt == TextMessage {
			if err := conn.WriteText("echo: " + string(data)); err != nil {
				return
			}
		}
	}
})

// Mount the handler; ListenAndServe is omitted so the example stays
// self-contained.
http.Handle("/ws", handler)

func (*Conn) Close

func (c *Conn) Close() error

Close sends a close frame and tears down the connection.

func (*Conn) ReadMessage

func (c *Conn) ReadMessage() (MessageType, []byte, error)

ReadMessage reads the next data message, transparently answering ping and close control frames. It reassembles fragmented messages.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

RemoteAddr returns the underlying connection's remote address.

func (*Conn) WriteMessage

func (c *Conn) WriteMessage(t MessageType, data []byte) error

WriteMessage writes a complete data message (single, unmasked frame).

func (*Conn) WriteText

func (c *Conn) WriteText(s string) error

WriteText is a convenience for sending a text message.

type MessageType

type MessageType int

MessageType distinguishes text and binary data messages.

const (
	// TextMessage is a UTF-8 text message.
	TextMessage MessageType = iota
	// BinaryMessage is a binary message.
	BinaryMessage
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL