easyws

package module
v0.0.0-...-ebcf0ed Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2023 License: MIT Imports: 20 Imported by: 0

README

easyws

easyws is a simple and easy-to-use WebSocket library for Go.

Documentation

Overview

Package httphead contains utils for parsing HTTP and HTTP-grammar compatible text protocols headers.

That is, this package first aim is to bring ability to easily parse constructions, described here https://tools.ietf.org/html/rfc2616#section-2

Index

Constants

View Source
const (
	DefaultClientReadBufferSize  = 4096
	DefaultClientWriteBufferSize = 4096
)

Constants used by Dialer.

View Source
const (
	MaxHeaderSize = 14
	MinHeaderSize = 2
)

Header size length bounds in bytes.

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.

Variables

View Source
var (
	ErrHandshakeBadStatus      = fmt.Errorf("unexpected http status")
	ErrHandshakeBadSubProtocol = fmt.Errorf("unexpected protocol in %q header", headerSecProtocol)
	ErrHandshakeBadExtensions  = fmt.Errorf("unexpected extensions in %q header", headerSecProtocol)
)

Errors used by the websocket client.

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 (
	CompiledPing  = MustCompileFrame(NewPingFrame(nil))
	CompiledPong  = MustCompileFrame(NewPongFrame(nil))
	CompiledClose = MustCompileFrame(NewCloseFrame(nil))

	CompiledCloseNormalClosure           = MustCompileFrame(closeFrameNormalClosure)
	CompiledCloseGoingAway               = MustCompileFrame(closeFrameGoingAway)
	CompiledCloseProtocolError           = MustCompileFrame(closeFrameProtocolError)
	CompiledCloseUnsupportedData         = MustCompileFrame(closeFrameUnsupportedData)
	CompiledCloseNoMeaningYet            = MustCompileFrame(closeFrameNoMeaningYet)
	CompiledCloseInvalidFramePayloadData = MustCompileFrame(closeFrameInvalidFramePayloadData)
	CompiledClosePolicyViolation         = MustCompileFrame(closeFramePolicyViolation)
	CompiledCloseMessageTooBig           = MustCompileFrame(closeFrameMessageTooBig)
	CompiledCloseMandatoryExt            = MustCompileFrame(closeFrameMandatoryExt)
	CompiledCloseInternalServerError     = MustCompileFrame(closeFrameInternalServerError)
	CompiledCloseTLSHandshake            = MustCompileFrame(closeFrameTLSHandshake)
)

Compiled control frames for common use cases. For construct-serialize optimizations.

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

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.

View Source
var ErrMalformedResponse = fmt.Errorf("malformed HTTP response")

ErrMalformedResponse is returned by Dialer to indicate that server response can not be parsed.

View Source
var ErrNotHijacker = RejectConnectionError(
	RejectionStatus(http.StatusInternalServerError),
	RejectionReason("given http.ResponseWriter is not a http.Hijacker"),
)

ErrNotHijacker is an error returned when http.ResponseWriter does not implement http.Hijacker interface.

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 CompileFrame

func CompileFrame(f Frame) (bts []byte, err error)

CompileFrame returns byte representation of given frame. In terms of memory consumption it is useful to precompile static frames which are often used.

func HeaderSize

func HeaderSize(h Header) (n int)

HeaderSize returns number of bytes that are needed to encode given header. It returns -1 if header is malformed.

func MustCompileFrame

func MustCompileFrame(f Frame) []byte

MustCompileFrame is like CompileFrame but panics if frame can not be encoded.

func MustWriteFrame

func MustWriteFrame(w io.Writer, f Frame)

MustWriteFrame is like WriteFrame but panics if frame can not be read.

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 NewMask

func NewMask() (ret [4]byte)

NewMask creates new random mask.

func ParseOptions

func ParseOptions(data []byte, options []httphead.Option) ([]httphead.Option, bool)

ParseOptions parses all header options and appends it to given slice of Option. It returns flag of successful (wellformed input) parsing.

Note that appended options are all consist of subslices of data. That is, mutation of data will mutate appended options.

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 RemoveByte

func RemoveByte(data []byte, c byte) []byte

RemoveByte returns data without c. If c is not present in data it returns the same slice. If not, it copies data without c.

func Rsv

func Rsv(r1, r2, r3 bool) (rsv byte)

Rsv creates rsv byte representation from bits.

func RsvBits

func RsvBits(rsv byte) (r1, r2, r3 bool)

RsvBits returns rsv bits from bytes representation.

func ScanOptions

func ScanOptions(data []byte, it func(index int, option, attribute, value []byte) Control) bool

ScanOptions parses data in this form:

values = 1#value value = token *( ";" param ) param = token [ "=" (token | quoted-string) ]

It calls given callback with the index of the option, option itself and its parameter (attribute and its value, both could be nil). Index is useful when header contains multiple choises for the same named option.

Given callback should return one of the defined Control* values. ControlSkip means that passed key is not in caller's interest. That is, all parameters of that key will be skipped. ControlBreak means that no more keys and parameters should be parsed. That is, it must break parsing immediately. ControlContinue means that caller want to receive next parameter and its value or the next key.

It returns false if data is malformed.

func ScanPairGreedy

func ScanPairGreedy(data []byte, open, close byte) (n int)

ScanPairGreedy scans for complete pair of opening and closing chars in greedy manner. Note that first opening byte must not be present in data.

func ScanTokens

func ScanTokens(data []byte, it func([]byte) bool) bool

ScanTokens parses data in this form:

list = 1#token

It returns false if data is malformed.

func ScanUntil

func ScanUntil(data []byte, c byte) (n int)

ScanUntil scans for first non-escaped character c in given data. It returns index of matched c and -1 if c is not found.

func SelectEqual

func SelectEqual(v string) func(string) bool

SelectEqual creates accept function that could be used as Protocol/Extension select during upgrade.

func SelectFromSlice

func SelectFromSlice(accept []string) func(string) bool

SelectFromSlice creates accept function that could be used as Protocol/Extension select during upgrade.

func SkipSpace

func SkipSpace(p []byte) (n int)

SkipSpace skips spaces and lws-sequences from p. It returns number ob bytes skipped.

func WriteFrame

func WriteFrame(w io.Writer, f Frame) error

WriteFrame writes frame binary representation into w.

func WriteHeader

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

WriteHeader writes header binary representation into w.

Types

type ConnectionRejectedError

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

ConnectionRejectedError represents a rejection of connection during WebSocket handshake error.

It can be returned by Upgrader's On* hooks to indicate that WebSocket handshake should be rejected.

func (*ConnectionRejectedError) Error

func (r *ConnectionRejectedError) Error() string

Error implements error interface.

func (*ConnectionRejectedError) StatusCode

func (r *ConnectionRejectedError) StatusCode() int

type Control

type Control byte

Control represents operation that scanner should perform.

const (
	// ControlContinue causes scanner to continue scan tokens.
	ControlContinue Control = iota
	// ControlBreak causes scanner to stop scan tokens.
	ControlBreak
	// ControlSkip causes scanner to skip current entity.
	ControlSkip
)

type Dialer

type Dialer struct {
	// ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
	// They used to read and write http data while upgrading to WebSocket.
	// Allocated buffers are pooled with sync.Pool to avoid extra allocations.
	//
	// If a size is zero then default value is used.
	ReadBufferSize, WriteBufferSize int

	// Timeout is the maximum amount of time a Dial() will wait for a connect
	// and an handshake to complete.
	//
	// The default is no timeout.
	Timeout time.Duration

	// Protocols is the list of subprotocols that the client wants to speak,
	// ordered by preference.
	//
	// See https://tools.ietf.org/html/rfc6455#section-4.1
	Protocols []string

	// Extensions is the list of extensions that client wants to speak.
	//
	// Note that if server decides to use some of this extensions, Dial() will
	// return Handshake struct containing a slice of items, which are the
	// shallow copies of the items from this list. That is, internals of
	// Extensions items are shared during Dial().
	//
	// See https://tools.ietf.org/html/rfc6455#section-4.1
	// See https://tools.ietf.org/html/rfc6455#section-9.1
	Extensions []httphead.Option

	// Header is an optional HandshakeHeader instance that could be used to
	// write additional headers to the handshake request.
	//
	// It used instead of any key-value mappings to avoid allocations in user
	// land.
	Header HandshakeHeader

	// OnStatusError is the callback that will be called after receiving non
	// "101 Continue" HTTP response status. It receives an io.Reader object
	// representing server response bytes. That is, it gives ability to parse
	// HTTP response somehow (probably with http.ReadResponse call) and make a
	// decision of further logic.
	//
	// The arguments are only valid until the callback returns.
	OnStatusError func(status int, reason []byte, resp io.Reader)

	// OnHeader is the 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.
	//
	// Returned value could be used to prevent processing response.
	OnHeader func(key, value []byte) (err error)

	// NetDial is the function that is used to get plain tcp connection.
	// If it is not nil, then it is used instead of net.Dialer.
	NetDial func(ctx context.Context, network, addr string) (net.Conn, error)

	// TLSClient is the callback that will be called after successful dial with
	// received connection and its remote host name. If it is nil, then the
	// default tls.Client() will be used.
	// If it is not nil, then TLSConfig field is ignored.
	TLSClient func(conn net.Conn, hostname string) net.Conn

	// TLSConfig is passed to tls.Client() to start TLS over established
	// connection. If TLSClient is not nil, then it is ignored. If TLSConfig is
	// non-nil and its ServerName is empty, then for every Dial() it will be
	// cloned and appropriate ServerName will be set.
	TLSConfig *tls.Config

	// WrapConn is the optional callback that will be called when connection is
	// ready for an i/o. That is, it will be called after successful dial and
	// TLS initialization (for "wss" schemes). It may be helpful for different
	// user land purposes such as end to end encryption.
	//
	// Note that for debugging purposes of an http handshake (e.g. sent request
	// and received response), there is an wsutil.DebugDialer struct.
	WrapConn func(conn net.Conn) net.Conn
}

Dialer contains options for establishing websocket connection to an url.

var DefaultDialer Dialer

DefaultDialer is dialer that holds no options and is used by Dial function.

func (Dialer) Dial

func (d Dialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *bufio.Reader, hs Handshake, err error)

Dial connects to the url host and upgrades connection to WebSocket.

If server has sent frames right after successful handshake then returned buffer will be non-nil. In other cases buffer is always nil. For better memory efficiency received non-nil bufio.Reader should be returned to the inner pool with PutReader() function after use.

Note that Dialer does not implement IDNA (RFC5895) logic as net/http does. If you want to dial non-ascii host name, take care of its name serialization avoiding bad request issues. For more info see net/http Request.Write() implementation, especially cleanHost() function.

func (Dialer) Upgrade

func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Handshake, err error)

Upgrade writes an upgrade request to the given io.ReadWriter conn at given url u and reads a response from it.

It is a caller responsibility to manage I/O deadlines on conn.

It returns handshake info and some bytes which could be written by the peer right after response and be caught by us during buffered read.

type EasyWs

type EasyWs struct {
	EasyNetHandler *NetHandler

	EasyNet *easynet.EasyNet

	EasyWsHandler IEasyWs
}

func NewEasyWs

func NewEasyWs(easyWsHanler IEasyWs, ip string, port int32) *EasyWs

type Frame

type Frame struct {
	Header  Header
	Payload []byte
}

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

func MaskFrame

func MaskFrame(f Frame) Frame

MaskFrame masks frame and returns frame with masked payload and Mask header's field set. Note that it copies f payload to prevent collisions. For less allocations you could use MaskFrameInPlace or construct frame manually.

func MaskFrameInPlace

func MaskFrameInPlace(f Frame) Frame

MaskFrameInPlace masks frame and returns frame with masked payload and Mask header's field set. Note that it applies xor cipher to f.Payload without copying, that is, it modifies f.Payload inplace.

func MaskFrameInPlaceWith

func MaskFrameInPlaceWith(f Frame, m [4]byte) Frame

MaskFrameInPlaceWith masks frame with given mask and returns frame with masked payload and Mask header's field set. Note that it applies xor cipher to f.Payload without copying, that is, it modifies f.Payload inplace.

func MaskFrameWith

func MaskFrameWith(f Frame, mask [4]byte) Frame

MaskFrameWith masks frame with given mask and returns frame with masked payload and Mask header's field set. Note that it copies f payload to prevent collisions. For less allocations you could use MaskFrameInPlaceWith or construct frame manually.

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.

func UnmaskFrame

func UnmaskFrame(f Frame) Frame

UnmaskFrame unmasks frame and returns frame with unmasked payload and Mask header's field cleared. Note that it copies f payload.

func UnmaskFrameInPlace

func UnmaskFrameInPlace(f Frame) Frame

UnmaskFrameInPlace unmasks frame and returns frame with unmasked payload and Mask header's field cleared. Note that it applies xor cipher to f.Payload without copying, that is, it modifies f.Payload inplace.

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.

func Dial

func Dial(ctx context.Context, urlstr string) (net.Conn, *bufio.Reader, Handshake, error)

Dial is like Dialer{}.Dial().

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 ReadHeader

func ReadHeader(stream _interface.IInputStream) (h Header, err error)

ReadHeader 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 IEasyWs

type IEasyWs interface {
	OnStart() (OpCode, error)

	OnConnect() (OpCode, error)

	OnUpgraded() (OpCode, error)

	OnReceive(msg []byte) ([]byte, OpCode, error)

	OnShutdown() (OpCode, error)

	OnClose(err error) (OpCode, error)
}

type ItemType

type ItemType int

ItemType encodes type of the lexing token.

const (
	// ItemUndef reports that token is undefined.
	ItemUndef ItemType = iota
	// ItemToken reports that token is RFC2616 token.
	ItemToken
	// ItemSeparator reports that token is RFC2616 separator.
	ItemSeparator
	// ItemString reports that token is RFC2616 quouted string.
	ItemString
	// ItemComment reports that token is RFC2616 comment.
	ItemComment
	// ItemOctet reports that token is octet slice.
	ItemOctet
)

func ScanToken

func ScanToken(p []byte) (n int, t ItemType)

ScanToken scan for next token in p. It returns length of the token and its type. It do not trim p.

type NetHandler

type NetHandler struct {
	IsUpgrade     map[string]bool
	EasyWsHandler IEasyWs
}

func (NetHandler) OnClose

func (h NetHandler) OnClose(conn _interface.IConnection, err error) error

func (NetHandler) OnConnect

func (h NetHandler) OnConnect(conn _interface.IConnection) error

func (NetHandler) OnReceive

func (h NetHandler) OnReceive(conn _interface.IConnection, stream _interface.IInputStream) ([]byte, error)

func (NetHandler) OnShutdown

func (h NetHandler) OnShutdown(conn _interface.IConnection) error

func (NetHandler) OnStart

func (h NetHandler) OnStart(conn _interface.IConnection) error

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 OptionSelector

type OptionSelector struct {
	// Check is a filter function that applied to every Option that possibly
	// could be selected.
	// If Check is nil all options will be selected.
	Check func(httphead.Option) bool

	// Flags contains flags for options selection.
	Flags SelectFlag

	// Alloc used to allocate slice of bytes when selector is configured with
	// SelectCopy flag. It will be called with number of bytes needed for copy
	// of single Option.
	// If Alloc is nil make is used.
	Alloc func(n int) []byte
}

OptionSelector contains configuration for selecting Options from header value.

func (OptionSelector) Select

func (s OptionSelector) Select(data []byte, options []httphead.Option) ([]httphead.Option, bool)

Select parses header data and appends it to given slice of Option. It also returns flag of successful (wellformed input) parsing.

type RejectOption

type RejectOption func(*ConnectionRejectedError)

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 Scanner

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

Scanner represents header tokens scanner. See https://tools.ietf.org/html/rfc2616#section-2

func NewScanner

func NewScanner(data []byte) *Scanner

NewScanner creates new RFC2616 data scanner.

func (*Scanner) Advance

func (l *Scanner) Advance(n int) bool

Advance moves current position index at n bytes. It returns true on successful move.

func (*Scanner) Buffered

func (l *Scanner) Buffered() int

Buffered reporst how many bytes there are left to scan.

func (*Scanner) Bytes

func (l *Scanner) Bytes() []byte

Bytes returns current token bytes.

func (*Scanner) FetchUntil

func (l *Scanner) FetchUntil(c byte) bool

FetchUntil fetches ItemOctet from current scanner position to first occurence of the c or to the end of the underlying data.

func (*Scanner) Next

func (l *Scanner) Next() bool

Next scans for next token. It returns true on successful scanning, and false on error or EOF.

func (*Scanner) Peek

func (l *Scanner) Peek() byte

Peek reads byte at current position without advancing it. On end of data it returns 0.

func (*Scanner) Peek2

func (l *Scanner) Peek2() (a, b byte)

Peek2 reads two first bytes at current position without advancing it. If there not enough data it returs 0.

func (*Scanner) Skip

func (l *Scanner) Skip(c byte)

Skip skips all bytes until first occurence of c.

func (*Scanner) SkipEscaped

func (l *Scanner) SkipEscaped(c byte)

SkipEscaped skips all bytes until first occurence of non-escaped c.

func (*Scanner) Type

func (l *Scanner) Type() ItemType

Type reports current token type.

type SelectFlag

type SelectFlag byte

SelectFlag encodes way of options selection.

const (
	// SelectCopy causes selector to copy selected option before appending it
	// to resulting slice.
	// If SelectCopy flag is not passed to selector, then appended options will
	// contain sub-slices of the initial data.
	SelectCopy SelectFlag = 1 << iota

	// SelectUnique causes selector to append only not yet existing option to
	// resulting slice. Unique is checked by comparing option names.
	SelectUnique
)

func (SelectFlag) String

func (f SelectFlag) String() string

String represetns flag as string.

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 ParseCloseFrameDataUnsafe

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

ParseCloseFrameDataUnsafe is like ParseCloseFrameData except the thing that it does not copies payload bytes into reason, but prepares unsafe cast.

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 StatusError

type StatusError int

StatusError contains an unexpected status-line code from the server.

func (StatusError) Error

func (s StatusError) Error() string

type Upgrader

type Upgrader struct {
	// ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
	// They used to read and write http data while upgrading to WebSocket.
	// Allocated buffers are pooled with sync.Pool to avoid extra allocations.
	//
	// If a size is zero then default value is used.
	//
	// Usually it is useful to set read buffer size bigger than write buffer
	// size because incoming request could contain long header values, such as
	// Cookie. Response, in other way, could be big only if user write multiple
	// custom headers. Usually response takes less than 256 bytes.
	ReadBufferSize, WriteBufferSize int

	// 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([]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.
	//
	// Note that Extension may be called multiple times and implementations
	// must track uniqueness of accepted extensions manually.
	//
	// 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."
	//
	// Deprecated: use Negotiate instead.
	Extension func(httphead.Option) bool

	// ExtensionCustom allow user to parse Sec-WebSocket-Extensions header
	// manually.
	//
	// If ExtensionCustom() decides to accept received extension, it must
	// append appropriate option to the given slice of Option.
	// It returns results of append() to the given slice and a flag that
	// reports whether given header value is wellformed or not.
	//
	// Note that ExtensionCustom may be called multiple times and
	// implementations must track uniqueness of accepted extensions manually.
	//
	// Note that returned options should be valid until Upgrade returns.
	// If ExtensionCustom is set, it used instead of Extension function.
	ExtensionCustom func([]byte, []httphead.Option) ([]httphead.Option, bool)

	// Negotiate is the callback that is used to negotiate extensions from
	// the client's offer. If this field is set, then the returned non-zero
	// extensions are sent to the client as accepted extensions in the
	// response.
	//
	// The argument is only valid until the Negotiate 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.
	Negotiate func(httphead.Option) (httphead.Option, error)

	// 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(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(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(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() (header HandshakeHeader, err error)
}

Upgrader contains options for upgrading connection to websocket.

func (Upgrader) Upgrade

func (u Upgrader) Upgrade(stream _interface.IInputStream) (hs Handshake, out []byte, 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
example
net

Jump to

Keyboard shortcuts

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