ws

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Dec 3, 2022 License: MIT, MIT Imports: 16 Imported by: 5

README

说明

本目录代码参考 gobwas/ws 相关实现修改而来。

Documentation

Index

Constants

View Source
const (
	// All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented.
	MaxControlFramePayloadSize = 125
)

Constants defined by specification.

View Source
const (
	MaxHeaderSize = 14
)

Header size length bounds in bytes.

Variables

View Source
var (
	ErrProtocolStatusCodeNotInUse         = ProtocolError("status code is not in use")
	ErrProtocolStatusCodeApplicationLevel = ProtocolError("status code is only application level")
	ErrProtocolStatusCodeNoMeaning        = ProtocolError("status code has no meaning yet")
	ErrProtocolStatusCodeUnknown          = ProtocolError("status code is not defined in spec")
	ErrProtocolInvalidUTF8                = ProtocolError("invalid utf8 sequence in close reason")
)

Errors used by the protocol checkers.

View Source
var (
	ErrHandshakeBadProtocol = RejectConnectionError(
		RejectionStatus(http.StatusHTTPVersionNotSupported),
		RejectionReason("handshake error: bad HTTP protocol version"),
	)
	ErrHandshakeBadMethod = RejectConnectionError(
		RejectionStatus(http.StatusMethodNotAllowed),
		RejectionReason("handshake error: bad HTTP request method"),
	)
	ErrHandshakeBadHost = RejectConnectionError(
		RejectionStatus(http.StatusBadRequest),
		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerHost)),
	)
	ErrHandshakeBadUpgrade = RejectConnectionError(
		RejectionStatus(http.StatusBadRequest),
		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerUpgrade)),
	)
	ErrHandshakeBadConnection = RejectConnectionError(
		RejectionStatus(http.StatusBadRequest),
		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerConnection)),
	)
	ErrHandshakeBadSecAccept = RejectConnectionError(
		RejectionStatus(http.StatusBadRequest),
		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecAccept)),
	)
	ErrHandshakeBadSecKey = RejectConnectionError(
		RejectionStatus(http.StatusBadRequest),
		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecKey)),
	)
	ErrHandshakeBadSecVersion = RejectConnectionError(
		RejectionStatus(http.StatusBadRequest),
		RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
	)
)

Errors used by both client and server when preparing WebSocket handshake.

View Source
var (
	StatusRangeNotInUse    = StatusCodeRange{0, 999}
	StatusRangeProtocol    = StatusCodeRange{1000, 2999}
	StatusRangeApplication = StatusCodeRange{3000, 3999}
	StatusRangePrivate     = StatusCodeRange{4000, 4999}
)

Status code ranges defined by specification. See https://tools.ietf.org/html/rfc6455#section-7.4.2

View Source
var (
	ErrHeaderLengthMSB        = fmt.Errorf("header error: the most significant bit must be 0")
	ErrHeaderLengthUnexpected = fmt.Errorf("header error: unexpected payload length bits")
	ErrHeaderNotReady         = fmt.Errorf("header error: not enough")
)

Errors used by frame reader.

View Source
var ErrHandshakeUpgradeRequired = RejectConnectionError(
	RejectionStatus(http.StatusUpgradeRequired),
	RejectionHeader(HandshakeHeaderString(headerSecVersion+": 13\r\n")),
	RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
)

ErrHandshakeUpgradeRequired is returned by Upgrader to indicate that connection is rejected because given WebSocket version is malformed.

According to RFC6455: If this version does not match a version understood by the server, the server MUST abort the WebSocket handshake described in this section and instead send an appropriate HTTP error code (such as 426 Upgrade Required) and a |Sec-WebSocket-Version| header field indicating the version(s) the server is capable of understanding.

View Source
var ErrMalformedRequest = RejectConnectionError(
	RejectionStatus(http.StatusBadRequest),
	RejectionReason("malformed HTTP request"),
)

ErrMalformedRequest is returned when HTTP request can not be parsed.

Functions

func Cipher

func Cipher(payload []byte, mask [4]byte, offset int)

Cipher applies XOR cipher to the payload using mask. Offset is used to cipher chunked data (e.g. in io.Reader implementations).

To convert masked data into unmasked data, or vice versa, the following algorithm is applied. The same algorithm applies regardless of the direction of the translation, e.g., the same steps are applied to mask the data as to unmask the data.

func FrameToBytes

func FrameToBytes(f *Frame) (ret []byte, err error)

FrameToBytes return bytes

func NewCloseFrameBody

func NewCloseFrameBody(code StatusCode, reason string) []byte

NewCloseFrameBody encodes a closure code and a reason into a binary representation.

It returns slice which is at most MaxControlFramePayloadSize bytes length. If the reason is too big it will be cropped to fit the limit defined by the spec.

See https://tools.ietf.org/html/rfc6455#section-5.5

func PutCloseFrameBody

func PutCloseFrameBody(p []byte, code StatusCode, reason string)

PutCloseFrameBody encodes code and reason into buf.

It will panic if the buffer is too small to accommodate a code or a reason.

PutCloseFrameBody does not check buffer to be RFC compliant, but note that by RFC it must be at most MaxControlFramePayloadSize.

func RejectConnectionError

func RejectConnectionError(options ...RejectOption) error

RejectConnectionError constructs an error that could be used to control the way handshake is rejected by Upgrader.

func WriteHeader

func WriteHeader(h *Header) ([]byte, error)

WriteHeader writes header binary representation into w.

Types

type Frame

type Frame struct {
	Header  Header
	Payload []byte
}

Frame represents websocket frame. See https://tools.ietf.org/html/rfc6455#section-5.2

func NewBinaryFrame

func NewBinaryFrame(p []byte) *Frame

NewBinaryFrame creates binary frame with p as payload. Note that p is not copied.

func NewCloseFrame

func NewCloseFrame(p []byte) *Frame

NewCloseFrame creates close frame with given close body. Note that p is not copied. Note that p must have length of MaxControlFramePayloadSize bytes or less due to RFC.

func NewFrame

func NewFrame(op OpCode, fin bool, p []byte) *Frame

NewFrame creates frame with given operation code, flag of completeness and payload bytes.

func NewPingFrame

func NewPingFrame(p []byte) *Frame

NewPingFrame creates ping frame with p as payload. Note that p is not copied. Note that p must have length of MaxControlFramePayloadSize bytes or less due to RFC.

func NewPongFrame

func NewPongFrame(p []byte) *Frame

NewPongFrame creates pong frame with p as payload. Note that p is not copied. Note that p must have length of MaxControlFramePayloadSize bytes or less due to RFC.

func NewTextFrame

func NewTextFrame(p []byte) *Frame

NewTextFrame creates text frame with p as payload. Note that p is not copied.

type Handshake

type Handshake struct {
	// Protocol is the subprotocol selected during handshake.
	Protocol string

	// Extensions is the list of negotiated extensions.
	Extensions []httphead.Option
}

Handshake represents handshake result.

type HandshakeHeader

type HandshakeHeader interface {
	io.WriterTo
}

HandshakeHeader is the interface that writes both upgrade request or response headers into a given io.Writer.

type HandshakeHeaderBytes

type HandshakeHeaderBytes []byte

HandshakeHeaderBytes is an adapter to allow the use of headers represented by ordinary slice of bytes as HandshakeHeader.

func (HandshakeHeaderBytes) WriteTo

func (b HandshakeHeaderBytes) WriteTo(w io.Writer) (int64, error)

WriteTo implements HandshakeHeader (and io.WriterTo) interface.

type HandshakeHeaderFunc

type HandshakeHeaderFunc func(io.Writer) (int64, error)

HandshakeHeaderFunc is an adapter to allow the use of headers represented by ordinary function as HandshakeHeader.

func (HandshakeHeaderFunc) WriteTo

func (f HandshakeHeaderFunc) WriteTo(w io.Writer) (int64, error)

WriteTo implements HandshakeHeader (and io.WriterTo) interface.

type HandshakeHeaderHTTP

type HandshakeHeaderHTTP http.Header

HandshakeHeaderHTTP is an adapter to allow the use of http.Header as HandshakeHeader.

func (HandshakeHeaderHTTP) WriteTo

func (h HandshakeHeaderHTTP) WriteTo(w io.Writer) (int64, error)

WriteTo implements HandshakeHeader (and io.WriterTo) interface.

type HandshakeHeaderString

type HandshakeHeaderString string

HandshakeHeaderString is an adapter to allow the use of headers represented by ordinary string as HandshakeHeader.

func (HandshakeHeaderString) WriteTo

func (s HandshakeHeaderString) WriteTo(w io.Writer) (int64, error)

WriteTo implements HandshakeHeader (and io.WriterTo) interface.

type Header struct {
	Fin    bool
	Rsv    byte
	OpCode OpCode
	Masked bool
	Mask   [4]byte
	Length int64
}

Header represents websocket frame header. See https://tools.ietf.org/html/rfc6455#section-5.2

func VirtualReadHeader

func VirtualReadHeader(bts []byte, in *ringbuffer.RingBuffer) (h Header, err error)

VirtualReadHeader reads a frame header from r.

func (Header) Rsv1

func (h Header) Rsv1() bool

Rsv1 reports whether the header has first rsv bit set.

func (Header) Rsv2

func (h Header) Rsv2() bool

Rsv2 reports whether the header has second rsv bit set.

func (Header) Rsv3

func (h Header) Rsv3() bool

Rsv3 reports whether the header has third rsv bit set.

type MessageType

type MessageType int

MessageType represents the type of a WebSocket message. See https://tools.ietf.org/html/rfc6455#section-5.6

const (
	// MessageText Text
	MessageText MessageType = iota + 1
	// MessageBinary Binary
	MessageBinary
)

type OpCode

type OpCode byte

OpCode represents operation code.

const (
	OpContinuation OpCode = 0x0
	OpText         OpCode = 0x1
	OpBinary       OpCode = 0x2
	OpClose        OpCode = 0x8
	OpPing         OpCode = 0x9
	OpPong         OpCode = 0xa
)

Operation codes defined by specification. See https://tools.ietf.org/html/rfc6455#section-5.2

func (OpCode) IsControl

func (c OpCode) IsControl() bool

IsControl checks whether the c is control operation code. See https://tools.ietf.org/html/rfc6455#section-5.5

func (OpCode) IsData

func (c OpCode) IsData() bool

IsData checks whether the c is data operation code. See https://tools.ietf.org/html/rfc6455#section-5.6

func (OpCode) IsReserved

func (c OpCode) IsReserved() bool

IsReserved checks whether the c is reserved operation code. See https://tools.ietf.org/html/rfc6455#section-5.2

type ProtocolError

type ProtocolError string

ProtocolError describes error during checking/parsing websocket frames or headers.

func (ProtocolError) Error

func (p ProtocolError) Error() string

Error implements error interface.

type RejectOption

type RejectOption func(*rejectConnectionError)

RejectOption represents an option used to control the way connection is rejected.

func RejectionHeader

func RejectionHeader(h HandshakeHeader) RejectOption

RejectionHeader returns an option that makes connection to be rejected with given HTTP headers.

func RejectionReason

func RejectionReason(reason string) RejectOption

RejectionReason returns an option that makes connection to be rejected with given reason.

func RejectionStatus

func RejectionStatus(code int) RejectOption

RejectionStatus returns an option that makes connection to be rejected with given HTTP status code.

type StatusCode

type StatusCode uint16

StatusCode represents the encoded reason for closure of websocket connection.

There are few helper methods on StatusCode that helps to define a range in which given code is lay in. accordingly to ranges defined in specification.

See https://tools.ietf.org/html/rfc6455#section-7.4

const (
	StatusNormalClosure           StatusCode = 1000
	StatusGoingAway               StatusCode = 1001
	StatusProtocolError           StatusCode = 1002
	StatusUnsupportedData         StatusCode = 1003
	StatusNoMeaningYet            StatusCode = 1004
	StatusInvalidFramePayloadData StatusCode = 1007
	StatusPolicyViolation         StatusCode = 1008
	StatusMessageTooBig           StatusCode = 1009
	StatusMandatoryExt            StatusCode = 1010
	StatusInternalServerError     StatusCode = 1011
	StatusTLSHandshake            StatusCode = 1015

	// StatusAbnormalClosure is a special code designated for use in
	// applications.
	StatusAbnormalClosure StatusCode = 1006

	// StatusNoStatusRcvd is a special code designated for use in applications.
	StatusNoStatusRcvd StatusCode = 1005
)

Status codes defined by specification. See https://tools.ietf.org/html/rfc6455#section-7.4.1

func ParseCloseFrameData

func ParseCloseFrameData(payload []byte) (code StatusCode, reason string)

ParseCloseFrameData parses close frame status code and closure reason if any provided. If there is no status code in the payload the empty status code is returned (code.Empty()) with empty string as a reason.

func (StatusCode) Empty

func (s StatusCode) Empty() bool

Empty reports whether the code is empty. Empty code has no any meaning neither app level codes nor other. This method is useful just to check that code is golang default value 0.

func (StatusCode) In

In reports whether the code is defined in given range.

func (StatusCode) IsApplicationSpec

func (s StatusCode) IsApplicationSpec() bool

IsApplicationSpec reports whether the code should be defined by application, framework or libraries specification.

func (StatusCode) IsNotUsed

func (s StatusCode) IsNotUsed() bool

IsNotUsed reports whether the code is predefined in not used range.

func (StatusCode) IsPrivateSpec

func (s StatusCode) IsPrivateSpec() bool

IsPrivateSpec reports whether the code should be defined privately.

func (StatusCode) IsProtocolDefined

func (s StatusCode) IsProtocolDefined() bool

IsProtocolDefined reports whether the code is already defined by protocol specification.

func (StatusCode) IsProtocolReserved

func (s StatusCode) IsProtocolReserved() bool

IsProtocolReserved reports whether the code is defined by protocol specification to be reserved only for application usage purpose.

func (StatusCode) IsProtocolSpec

func (s StatusCode) IsProtocolSpec() bool

IsProtocolSpec reports whether the code should be defined by protocol specification.

type StatusCodeRange

type StatusCodeRange struct {
	Min, Max StatusCode
}

StatusCodeRange describes range of StatusCode values.

type Upgrader

type Upgrader struct {
	// Protocol is a select function that is used to select subprotocol
	// from list requested by client. If this field is set, then the first matched
	// protocol is sent to a client as negotiated.
	//
	// The argument is only valid until the callback returns.
	Protocol func([]byte) bool

	// ProtocolCustrom allow user to parse Sec-WebSocket-Protocol header manually.
	// Note that returned bytes must be valid until Upgrade returns.
	// If ProtocolCustom is set, it used instead of Protocol function.
	ProtocolCustom func(*gev.Connection, []byte) (string, bool)

	// Extension is a select function that is used to select extensions
	// from list requested by client. If this field is set, then the all matched
	// extensions are sent to a client as negotiated.
	//
	// The argument is only valid until the callback returns.
	//
	// According to the RFC6455 order of extensions passed by a client is
	// significant. That is, returning true from this function means that no
	// other extension with the same name should be checked because server
	// accepted the most preferable extension right now:
	// "Note that the order of extensions is significant.  Any interactions between
	// multiple extensions MAY be defined in the documents defining the extensions.
	// In the absence of such definitions, the interpretation is that the header
	// fields listed by the client in its request represent a preference of the
	// header fields it wishes to use, with the first options listed being most
	// preferable."
	Extension func(httphead.Option) bool

	// ExtensionCustorm allow user to parse Sec-WebSocket-Extensions header manually.
	// Note that returned options should be valid until Upgrade returns.
	// If ExtensionCustom is set, it used instead of Extension function.
	ExtensionCustom func(*gev.Connection, []byte, []httphead.Option) ([]httphead.Option, bool)

	// Header is an optional HandshakeHeader instance that could be used to
	// write additional headers to the handshake response.
	//
	// It used instead of any key-value mappings to avoid allocations in user
	// land.
	//
	// Note that if present, it will be written in any result of handshake.
	Header HandshakeHeader

	// OnRequest is a callback that will be called after request line
	// successful parsing.
	//
	// The arguments are only valid until the callback returns.
	//
	// If returned error is non-nil then connection is rejected and response is
	// sent with appropriate HTTP error code and body set to error message.
	//
	// RejectConnectionError could be used to get more control on response.
	OnRequest func(c *gev.Connection, uri []byte) error

	// OnHost is a callback that will be called after "Host" header successful
	// parsing.
	//
	// It is separated from OnHeader callback because the Host header must be
	// present in each request since HTTP/1.1. Thus Host header is non-optional
	// and required for every WebSocket handshake.
	//
	// The arguments are only valid until the callback returns.
	//
	// If returned error is non-nil then connection is rejected and response is
	// sent with appropriate HTTP error code and body set to error message.
	//
	// RejectConnectionError could be used to get more control on response.
	OnHost func(c *gev.Connection, host []byte) error

	// OnHeader is a callback that will be called after successful parsing of
	// header, that is not used during WebSocket handshake procedure. That is,
	// it will be called with non-websocket headers, which could be relevant
	// for application-level logic.
	//
	// The arguments are only valid until the callback returns.
	//
	// If returned error is non-nil then connection is rejected and response is
	// sent with appropriate HTTP error code and body set to error message.
	//
	// RejectConnectionError could be used to get more control on response.
	OnHeader func(c *gev.Connection, key, value []byte) error

	// OnBeforeUpgrade is a callback that will be called before sending
	// successful upgrade response.
	//
	// Setting OnBeforeUpgrade allows user to make final application-level
	// checks and decide whether this connection is allowed to successfully
	// upgrade to WebSocket.
	//
	// It must return non-nil either HandshakeHeader or error and never both.
	//
	// If returned error is non-nil then connection is rejected and response is
	// sent with appropriate HTTP error code and body set to error message.
	//
	// RejectConnectionError could be used to get more control on response.
	OnBeforeUpgrade func(c *gev.Connection) (header HandshakeHeader, err error)
}

Upgrader contains options for upgrading connection to websocket.

func (*Upgrader) Upgrade

func (u *Upgrader) Upgrade(c *gev.Connection, in *ringbuffer.RingBuffer) (out []byte, hs Handshake, err error)

Upgrade zero-copy upgrades connection to WebSocket. It interprets given conn as connection with incoming HTTP Upgrade request.

It is a caller responsibility to manage i/o timeouts on conn.

Non-nil error means that request for the WebSocket upgrade is invalid or malformed and usually connection should be closed. Even when error is non-nil Upgrade will write appropriate response into connection in compliance with RFC.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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