websocket

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 26, 2023 License: CC0-1.0 Imports: 10 Imported by: 0

README

About

A high-performance WebSocket library for the Go programming language with built-in retry logic and timeout protection.

This is free and unencumbered software released into the public domain.

API CI

Use

Most implementations will boot from an HTTP Upgrade.

http.HandleFunc("/echo", func(resp http.ResponseWriter, req *http.Request) {
	// client safety support
	originCheck := func(s string, o *httpws.Origin) (pass bool) {
		return o != nil && o.Host == "example.com" && o.Scheme == "https"
	}
	if !httpws.AllowOrigin(req, originCheck) {
		http.Error(w, "HTTP Origin rejected", http.StatusForbidden)
		return
	}

	// switch protocol to WebSocket
	conn, err := httpws.Upgrade(resp, req, nil, time.Second)
	if err != nil {
		return
	}
	defer conn.Close()

	// limit to standard types
	conn.Accept = websocket.AcceptV13

	var buf [2048]byte
	for {
		// read message
		opcode, n, err := conn.Receive(buf[:], time.Second, time.Minute)
		if err != nil {
			if _, ok := err.(websocket.ClosedError); !ok && err != io.EOF {
				log.Print("receive error: ", err)
			}
			return
		}

		// write message
		err = conn.Send(opcode, buf[:n], time.Second)
		if err != nil {
			if _, ok := err.(websocket.ClosedError); !ok {
				log.Print("send error: ", err)
			}
			return
		}
	}
})

Performance

The /tcp variants wire the raw messages to display WebSocket protocol overhead.

name               time/op
Receive/buffer-12   6.73µs ± 5%
Receive/stream-12   45.7µs ± 3%
Receive/tcp-12      6.28µs ± 3%
Send/buffer-12      10.0µs ± 1%
Send/stream-12      23.0µs ± 1%
Send/tcp-12         10.0µs ± 1%

name               speed
Receive/buffer-12  888MB/s ± 5%
Receive/stream-12  131MB/s ± 3%
Receive/tcp-12     951MB/s ± 3%
Send/buffer-12     598MB/s ± 1%
Send/stream-12     260MB/s ± 1%
Send/tcp-12        595MB/s ± 1%

name               alloc/op
Receive/buffer-12    0.00B     
Receive/stream-12    34.0B ± 0%
Receive/tcp-12       0.00B     
Send/buffer-12       0.00B     
Send/stream-12       32.0B ± 0%
Send/tcp-12          0.00B     

name               allocs/op
Receive/buffer-12     0.00     
Receive/stream-12     0.00     
Receive/tcp-12        0.00     
Send/buffer-12        0.00     
Send/stream-12        1.00 ± 0%
Send/tcp-12           0.00     

Documentation

Overview

Package websocket implements “The WebSocket Protocol” RFC 6455, version 13.

Index

Constants

View Source
const (
	// Continuation for streaming data.
	Continuation = iota
	// Text for UTF-8 encoded data.
	Text
	// Binary for opaque data.
	Binary
	// Reserved3 is reserved for further non-control frames.
	Reserved3
	// Reserved4 is reserved for further non-control frames.
	Reserved4
	// Reserved5 is reserved for further non-control frames.
	Reserved5
	// Reserved6 is reserved for further non-control frames.
	Reserved6
	// Reserved7 is reserved for further non-control frames.
	Reserved7
	// Close for disconnect notification.
	Close
	// Ping to request Pong.
	Ping
	// Pong may be send unsolicited too.
	Pong
	// Reserved11 is reserved for further control frames.
	Reserved11
	// Reserved12 is reserved for further control frames.
	Reserved12
	// Reserved13 is reserved for further control frames.
	Reserved13
	// Reserved14 is reserved for further control frames.
	Reserved14
	// Reserved15 is reserved for further control frames.
	Reserved15
)

Opcode defines the interpretation of a frame payload.

View Source
const (
	// NormalClose means that the purpose for which the connection was
	// established has been fulfilled.
	NormalClose = 1000
	// GoingAway is a leave like a server going down or a browser moving on.
	GoingAway = 1001
	// ProtocolError rejects standard violation.
	ProtocolError = 1002
	// CannotAccept rejects a data type receival.
	CannotAccept = 1003
	// NoStatusCode is allowed by the protocol.
	NoStatusCode = 1005
	// AbnormalClose signals a disconnect without Close.
	AbnormalClose = 1006
	// Malformed rejects data that is not consistent with it's type, like an
	// illegal UTF-8 sequence for Text.
	Malformed = 1007
	// Policy rejects a message due to a violation.
	Policy = 1008
	// TooBig rejects a message due to size constraints.
	TooBig = 1009
	// WantExtension signals the client's demand for the server to negotiate
	// one or more extensions.
	WantExtension = 1010
	// Unexpected condition prevented the server from fulfilling the request.
	Unexpected = 1011
)

Defined Status Codes

View Source
const AcceptV13 = 1<<Continuation | 1<<Text | 1<<Binary | 1<<Close | 1<<Ping | 1<<Pong

AcceptV13 is a Conn.Accept value for all non-reserved opcodes from version 13.

Variables

View Source
var ErrOverflow = errors.New("websocket: message exceeds buffer size")

ErrOverflow signals an incomming message larger than the provided buffer.

Functions

This section is empty.

Types

type ClosedError

type ClosedError uint

ClosedError is a status code. Atomic Close support prevents Go issue 4373. Even after receiving a ClosedError, Conn.Close must still be called.

func (ClosedError) Error

func (e ClosedError) Error() string

Error honors the error interface.

func (ClosedError) Temporary

func (e ClosedError) Temporary() bool

Temporary honors the net.Error interface.

func (ClosedError) Timeout

func (e ClosedError) Timeout() bool

Timeout honors the net.Error interface.

type Conn

type Conn struct {
	net.Conn

	// When not zero, then receival of opcodes without a flag are rejected
	// with a connection Close, status code 1003—CannotAccept. Flags follow
	// little-endian bit order as in 1 << opcode. Use AcceptV13 to disable
	// all reserved opcodes.
	Accept uint
	// contains filtered or unexported fields
}

Conn offers a low-level network abstraction confrom the net.Conn interface. Conn also offers high-level protocol abstraction with the Receive and Send methods. These operations offer network error recovery, timeout protection and Text validation.

The low-level deals with frames. No action is taken uppon the actual content or meaning, except for Close. Write returns a ClosedError after a Close frame was either send or received. Write also returns a ClosedError NoStatusCode when Read got io.EOF without any Close frame occurrence.

Connections must be read consecutively for correct operation and closure.

func (*Conn) Read

func (c *Conn) Read(p []byte) (n int, err error)

Read receives WebSocket frames confrom the io.Reader interface. ReadMode is updated on each call.

func (*Conn) ReadMode

func (c *Conn) ReadMode() (opcode uint, final bool)

ReadMode returns state information about the last Read. Read spans one message at a time. Final indicates that message is received in full.

func (*Conn) Receive

func (c *Conn) Receive(buf []byte, wireTimeout, idleTimeout time.Duration) (opcode uint, n int, err error)

Receive is a high-level abstraction (from Read) for safety and convenience. The opcode return is in range [1, 7]. Control frames are dealed with. Size defines the amount of bytes in Reader or negative when unknown.

Receive must be called sequentially. Reader must be fully consumed before the next call to Receive. Interruptions from other calls to Receive or Read may cause protocol violations.

WireTimeout is the limit for Read [frame receival] and idleTimeout limits the amount of time to wait for arrival.

func (*Conn) ReceiveStream

func (c *Conn) ReceiveStream(wireTimeout, idleTimeout time.Duration) (opcode uint, r io.Reader, err error)

ReceiveStream is a high-level abstraction (from Read) for safety and convenience. The opcode return is in range [1, 7]. Control frames are dealed with.

Receive must be called sequentially. Reader must be fully consumed before the next call to Receive. Interruptions from other calls to Receive or Read may cause protocol violations.

WireTimeout is the limit for Read [frame receival] and idleTimeout limits the amount of time to wait for arrival.

func (*Conn) Send

func (c *Conn) Send(opcode uint, message []byte, wireTimeout time.Duration) error

Send is a high-level abstraction for safety and convenience. The opcode must be in range [1, 15] like Text, Binary or Ping. WireTimeout limits the frame transmission time. On expiry, the connection is closed with status code 1008 Policy. All error returns are fatal to the connection.

Multiple goroutines may invoke Send simultaneously. Send may be invoked simultaneously with any other high-level method from Conn. Note that when Send interrupts SendStream, then the opcode of Send is further reduced to range [8, 15]. Simultaneous invokation of any of the low-level net.Conn methods can currupt the connection state.

func (*Conn) SendClose

func (c *Conn) SendClose(statusCode uint, reason string) error

SendClose is a high-level abstraction for safety and convenience. The client is notified on best effort basis, including the optional free-form reason. Use 123 bytes of UTF-8 or less for submission.

When the connectection already received or send a Close then only the first status code remains in effect. Redundant status codes are discarded. The return always is a CloseError with the first status code.

Multiple goroutines may invoke SendClose simultaneously. SendClose may be invoked simultaneously with any other method from Conn.

func (*Conn) SendStream

func (c *Conn) SendStream(opcode uint, wireTimeout time.Duration) io.WriteCloser

SendStream is an alternative to Send. The opcode must be in range [1, 7] like Text or Binary. WireTimeout limits the frame transmission time. On expiry, the connection is closed with status code 1008 Policy. All errors from the io.WriteCloser other than io.ErrClosedPipe are fatal to the connection. Check Close for errors too!

The stream must be closed before any other invocation to SendStream is made and Send may only interrupt with control frames—opcode range [8, 15]. Multiple goroutines may invoke the io.WriteCloser methods simultaneously. Simultaneous invokation of either SendStream or the io.WriteCloser with any of the low-level net.Conn methods can currupt the connection state.

func (*Conn) SetWriteMode

func (c *Conn) SetWriteMode(opcode uint, final bool)

SetWriteMode controls the send frame/fragment layout. When final, then each Write sends a message of the given type. The opcode must be in range [1, 15] like Text, Binary or Ping.

// send two text messages
c.SetWriteMode(websocket.Text, true)
io.WriteString(c, "hello")
io.WriteString(c, "👋")

When not final then each Write sends a fragment of the message until a final Write concludes the message. This mode allows for sending a message that is of unknown size when the message is started without having to buffer. Another use-case is messages that would block the channel for too long, as control frames would have to wait in such case.

// send a binary message/stream
c.SetWriteMode(websocket.Binary, false)
io.Copy(c, blob)
c.SetWriteMode(websocket.Binary, true)
c.Write(nil)

The opcode is written on the first Write after SetWriteMode. For the previous example, in case Copy did not receive any data, then the opcode of the second call to SetWriteMode would apply. Therefore it is recommended to use the same opcode when finalizing a message.

func (*Conn) Write

func (c *Conn) Write(p []byte) (n int, err error)

Write sends p in one frame conform the io.Writer interface. Error retries must continue with the same p(ayload), minus the n(umber) of bytes done. Control frames—opcode range [8, 15]—must not exceed 125 bytes. Zero payload causes an empty frame/fragment.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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