Documentation
¶
Overview ¶
Package websocket implements the WebSocket protocol (RFC 6455) on top of the standard library, with no third-party dependencies. It provides a server-side upgrade, a client-side dial, the permessage-deflate extension (RFC 7692) and subprotocol negotiation.
A connection is represented by Conn. Because the package name is websocket, the natural variable name for a connection is ws:
ws, err := websocket.Upgrade(w, r)
if err != nil {
return
}
defer ws.Close()
for {
mt, data, err := ws.ReadMessage()
if err != nil {
break
}
if err := ws.WriteMessage(mt, data); err != nil {
break
}
}
Server upgrade. Use the package Upgrade for a one-off, or NewUpgrader for a reusable configuration:
up := websocket.NewUpgrader(websocket.WithReadLimit(1 << 20)) ws, err := up.Upgrade(w, r)
By default the upgrade only accepts same-origin requests, which guards against cross-site WebSocket hijacking. Allow other origins explicitly with WithOriginChecker.
Client dial. Dial connects to a server, negotiating TLS for wss URLs:
ws, resp, err := websocket.Dial(ctx, "wss://example.com/ws")
Concurrency. A connection supports one concurrent reader and one concurrent writer. That is, ReadMessage or NextReader may run in one goroutine while WriteMessage or NextWriter runs in another, but you must not call two readers or two writers at the same time. WriteControl may be called concurrently with a writer.
Control frames. Ping, pong and close frames are handled by the reader: a ping is answered with a pong automatically, and a close starts the closing handshake. Install SetPingHandler, SetPongHandler or SetCloseHandler to observe or override this.
Example ¶
Example runs a tiny echo server and a client against it.
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"github.com/goloop/websocket"
)
func main() {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ws, err := websocket.Upgrade(w, r,
websocket.WithOriginChecker(func(*http.Request) bool { return true }))
if err != nil {
return
}
defer ws.Close()
mt, data, err := ws.ReadMessage()
if err != nil {
return
}
_ = ws.WriteMessage(mt, data)
}))
defer srv.Close()
url := "ws" + strings.TrimPrefix(srv.URL, "http")
ws, _, err := websocket.Dial(context.Background(), url)
if err != nil {
fmt.Println("dial:", err)
return
}
defer ws.Close()
if err := ws.WriteMessage(websocket.TextMessage, []byte("ping")); err != nil {
fmt.Println("write:", err)
return
}
_, data, err := ws.ReadMessage()
if err != nil {
fmt.Println("read:", err)
return
}
fmt.Println(string(data))
}
Output: ping
Index ¶
- Variables
- func IsCloseError(err error, codes ...CloseCode) bool
- func IsUnexpectedCloseError(err error, expected ...CloseCode) bool
- func IsWebSocketUpgrade(r *http.Request) bool
- func Subprotocols(r *http.Request) []string
- type CloseCode
- type CloseError
- type Conn
- func (c *Conn) Close() error
- func (c *Conn) CloseWithStatus(code CloseCode, reason string) error
- func (c *Conn) LocalAddr() net.Addr
- func (c *Conn) NetConn() net.Conn
- func (c *Conn) NextReader() (MessageType, io.Reader, error)
- func (c *Conn) NextWriter(mt MessageType) (io.WriteCloser, error)
- func (c *Conn) ReadJSON(v any) error
- func (c *Conn) ReadMessage() (MessageType, []byte, error)
- func (c *Conn) RemoteAddr() net.Addr
- func (c *Conn) SetCloseHandler(fn func(code CloseCode, text string) error)
- func (c *Conn) SetPingHandler(fn func(appData string) error)
- func (c *Conn) SetPongHandler(fn func(appData string) error)
- func (c *Conn) SetReadDeadline(t time.Time) error
- func (c *Conn) SetReadLimit(n int64)
- func (c *Conn) SetWriteDeadline(t time.Time) error
- func (c *Conn) Subprotocol() string
- func (c *Conn) WriteControl(mt MessageType, data []byte, deadline time.Time) error
- func (c *Conn) WriteJSON(v any) error
- func (c *Conn) WriteMessage(mt MessageType, data []byte) error
- type DialOption
- type HandshakeError
- type MessageType
- type Option
- type Upgrader
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrBadHandshake = errors.New("websocket: bad handshake")
ErrBadHandshake is returned by Dial when the server does not complete the WebSocket handshake. The returned *http.Response carries the server's reply so the caller can inspect the status and headers.
var ErrCloseSent = errors.New("websocket: close sent")
ErrCloseSent is returned by a write after the closing handshake has started.
Functions ¶
func IsCloseError ¶
IsCloseError reports whether err is a *CloseError with one of the given codes.
func IsUnexpectedCloseError ¶
IsUnexpectedCloseError reports whether err is a *CloseError whose code is not one of the expected ones. It is the usual way to tell a clean shutdown from a surprising one in a read loop.
func IsWebSocketUpgrade ¶
IsWebSocketUpgrade reports whether r is a WebSocket upgrade request.
func Subprotocols ¶
Subprotocols returns the subprotocols listed in the request's Sec-WebSocket-Protocol header. The header may be split across several field lines, all of which are considered.
Types ¶
type CloseCode ¶
type CloseCode uint16
CloseCode is a WebSocket close status code (RFC 6455 section 7.4).
const ( CloseNormalClosure CloseCode = 1000 CloseGoingAway CloseCode = 1001 CloseProtocolError CloseCode = 1002 CloseUnsupportedData CloseCode = 1003 CloseNoStatusReceived CloseCode = 1005 CloseAbnormalClosure CloseCode = 1006 CloseInvalidFramePayloadData CloseCode = 1007 ClosePolicyViolation CloseCode = 1008 CloseMessageTooBig CloseCode = 1009 CloseMandatoryExtension CloseCode = 1010 CloseInternalServerErr CloseCode = 1011 CloseServiceRestart CloseCode = 1012 CloseTryAgainLater CloseCode = 1013 CloseTLSHandshake CloseCode = 1015 )
Close status codes defined by RFC 6455. Codes 1005, 1006 and 1015 are reserved and must not be sent on the wire; they only appear as locally generated values.
type CloseError ¶
CloseError records the close code and reason received from the peer.
func (*CloseError) Error ¶
func (e *CloseError) Error() string
Error implements the error interface, formatting the close code and, when present, the reason text the peer sent with the close frame.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn is a WebSocket connection. It carries a single logical stream of messages in each direction over a hijacked net.Conn.
A Conn supports one concurrent reader and one concurrent writer; see the package documentation. WriteControl may be called concurrently with a writer.
func Dial ¶
Dial connects to a WebSocket server. The URL scheme must be ws or wss; wss connections are negotiated over TLS. On success it returns the connection and the server's handshake response. On a non-101 reply it returns ErrBadHandshake together with the response.
func (*Conn) Close ¶
Close closes the underlying network connection without performing the closing handshake. For a graceful shutdown, call CloseWithStatus first, then Close.
func (*Conn) CloseWithStatus ¶
CloseWithStatus sends a close frame with the given code and reason. It does not close the network connection; the peer is expected to answer with its own close, after which the reader returns a *CloseError and the caller should call Close. A code of 0 sends an empty close payload.
func (*Conn) NetConn ¶
NetConn returns the underlying network connection. Reading from or writing to it directly will corrupt the WebSocket stream; it is an escape hatch for deadlines, addresses and similar low-level needs.
func (*Conn) NextReader ¶
func (c *Conn) NextReader() (MessageType, io.Reader, error)
NextReader returns a reader for the next data message. Only one reader may be active at a time; opening a new one discards any unread bytes of the previous message. A compressed message is fully inflated and returned as an in-memory reader; an uncompressed one is streamed.
func (*Conn) NextWriter ¶
func (c *Conn) NextWriter(mt MessageType) (io.WriteCloser, error)
NextWriter returns a writer for the next message of the given data type. The message is sent when the writer is closed. Only one writer may be open at a time.
func (*Conn) ReadJSON ¶
ReadJSON reads the next data message and unmarshals it into v. Control frames are handled transparently by the underlying read.
func (*Conn) ReadMessage ¶
func (c *Conn) ReadMessage() (MessageType, []byte, error)
ReadMessage reads the next complete data message. It transparently handles interleaved control frames (answering pings, tracking pongs and closes) and, if negotiated, decompresses the message. A text message is validated as UTF-8.
func (*Conn) RemoteAddr ¶
RemoteAddr returns the remote network address.
func (*Conn) SetCloseHandler ¶
SetCloseHandler sets the handler for received close frames. The default sends a close frame back. A custom handler replaces that behaviour.
func (*Conn) SetPingHandler ¶
SetPingHandler sets the handler for received ping frames. The default sends a pong with the same payload. Setting a handler disables the automatic pong, so a custom handler that wants to reply must do so itself.
func (*Conn) SetPongHandler ¶
SetPongHandler sets the handler for received pong frames. The default ignores them.
func (*Conn) SetReadDeadline ¶
SetReadDeadline sets the deadline for future reads. A zero value clears it.
func (*Conn) SetReadLimit ¶
SetReadLimit sets the maximum size in bytes of a single received message. A message that would exceed it fails the read and closes the connection with 1009. A value <= 0 restores the default.
func (*Conn) SetWriteDeadline ¶
SetWriteDeadline sets the deadline for future writes. A zero value clears it. The deadline is remembered so that the connection's own control writes (auto-pong, close echo) can restore it instead of leaving a stale deadline.
func (*Conn) Subprotocol ¶
Subprotocol returns the negotiated subprotocol, or an empty string if none was selected.
func (*Conn) WriteControl ¶
WriteControl sends a control frame (close, ping or pong). The deadline bounds the write; a zero deadline means no timeout. WriteControl may be called from a goroutine other than the one writing messages.
func (*Conn) WriteMessage ¶
func (c *Conn) WriteMessage(mt MessageType, data []byte) error
WriteMessage sends data as a single, unfragmented message of the given type. If write compression is enabled, a data message is compressed with permessage-deflate. For control types it is equivalent to WriteControl with the write deadline already set on the connection.
type DialOption ¶
type DialOption func(*dialConfig)
DialOption configures a client Dial.
func WithDialCompression ¶
func WithDialCompression() DialOption
WithDialCompression offers the permessage-deflate extension to the server.
func WithDialHandshakeTimeout ¶
func WithDialHandshakeTimeout(d time.Duration) DialOption
WithDialHandshakeTimeout bounds the time spent on the WebSocket handshake (writing the request and reading the response) when the context carries no deadline of its own. The default is 45s; a value <= 0 disables the bound.
func WithDialHeader ¶
func WithDialHeader(h http.Header) DialOption
WithDialHeader adds extra HTTP headers to the client handshake request (for example Authorization or Cookie).
func WithDialNetDialer ¶
func WithDialNetDialer(d *net.Dialer) DialOption
WithDialNetDialer sets the net.Dialer used to establish the TCP connection.
func WithDialSubprotocols ¶
func WithDialSubprotocols(names ...string) DialOption
WithDialSubprotocols sets the subprotocols the client offers.
func WithDialTLSConfig ¶
func WithDialTLSConfig(cfg *tls.Config) DialOption
WithDialTLSConfig sets the TLS configuration used for wss URLs.
type HandshakeError ¶
type HandshakeError struct {
// contains filtered or unexported fields
}
HandshakeError describes a failed WebSocket upgrade. When Upgrade returns one, it has already written an HTTP error response to the client.
func (HandshakeError) Error ¶
func (e HandshakeError) Error() string
Error implements the error interface, returning the reason the upgrade failed.
type MessageType ¶
type MessageType int
MessageType identifies a WebSocket frame opcode as defined in RFC 6455 section 5.2. The data types TextMessage and BinaryMessage are what an application normally sends and receives; the control types are handled by the connection but are also accepted by WriteControl.
const ( // TextMessage denotes a UTF-8 encoded text message. TextMessage MessageType = 1 // BinaryMessage denotes a binary message. BinaryMessage MessageType = 2 // CloseMessage denotes a close control message. CloseMessage MessageType = 8 // PingMessage denotes a ping control message. PingMessage MessageType = 9 // PongMessage denotes a pong control message. PongMessage MessageType = 10 )
type Option ¶
type Option func(*Upgrader)
Option configures an Upgrader (server side).
func WithCompression ¶
func WithCompression() Option
WithCompression enables the permessage-deflate extension when the client offers it.
func WithCompressionLevel ¶
WithCompressionLevel sets the flate level used for outgoing messages (flate.HuffmanOnly to flate.BestCompression).
func WithHandshakeTimeout ¶
WithHandshakeTimeout bounds the time spent writing the upgrade response.
func WithOriginChecker ¶
WithOriginChecker sets the function that decides whether a request's Origin is allowed. The default accepts only same-origin requests, which guards against cross-site WebSocket hijacking. To allow any origin (for example a public API or local development) pass a function that always returns true.
func WithReadLimit ¶
WithReadLimit sets the maximum size of a single received message.
func WithSubprotocols ¶
WithSubprotocols sets the subprotocols the server supports, in order of preference. The first one the client also offers is selected.
type Upgrader ¶
type Upgrader struct {
// contains filtered or unexported fields
}
Upgrader holds a reusable server-side upgrade configuration.
func NewUpgrader ¶
NewUpgrader returns an Upgrader configured with the given options. By default it accepts only same-origin requests and does not enable compression.