package wsutil
Import Path
github.com/gobwas/ws/wsutil (on go.dev)
Dependency Relation
imports 13 packages, and imported by one package
Involved Source Files
cipher.go
dialer.go
extenstion.go
handler.go
helper.go
reader.go
upgrader.go
utf8.go
writer.go
Package wsutil provides utilities for working with WebSocket protocol.
Overview:
// Read masked text message from peer and check utf8 encoding.
header, err := ws.ReadHeader(conn)
if err != nil {
// handle err
}
// Prepare to read payload.
r := io.LimitReader(conn, header.Length)
r = wsutil.NewCipherReader(r, header.Mask)
r = wsutil.NewUTF8Reader(r)
payload, err := ioutil.ReadAll(r)
if err != nil {
// handle err
}
You could get the same behavior using just `wsutil.Reader`:
r := wsutil.Reader{
Source: conn,
CheckUTF8: true,
}
payload, err := ioutil.ReadAll(r)
if err != nil {
// handle err
}
Or even simplest:
payload, err := wsutil.ReadClientText(conn)
if err != nil {
// handle err
}
Package is also exports tools for buffered writing:
// Create buffered writer, that will buffer output bytes and send them as
// 128-length fragments (with exception on large writes, see the doc).
writer := wsutil.NewWriterSize(conn, ws.StateServerSide, ws.OpText, 128)
_, err := io.CopyN(writer, rand.Reader, 100)
if err == nil {
err = writer.Flush()
}
if err != nil {
// handle error
}
For more utils and helpers see the documentation.
Package-Level Type Names (total 16)
CipherReader implements io.Reader that applies xor-cipher to the bytes read
from source.
It could help to unmask WebSocket frame payload on the fly.
Read implements io.Reader interface. It applies mask given during
initialization to every read byte.
Reset resets CipherReader to read from r with given mask.
*CipherReader : io.Reader
func NewCipherReader(r io.Reader, mask [4]byte) *CipherReader
CipherWriter implements io.Writer that applies xor-cipher to the bytes
written to the destination writer. It does not modify the original bytes.
Reset reset CipherWriter to write to w with given mask.
Write implements io.Writer interface. It applies masking during
initialization to every sent byte. It does not modify original slice.
*CipherWriter : github.com/miekg/dns.Writer
*CipherWriter : internal/bisect.Writer
*CipherWriter : io.Writer
func NewCipherWriter(w io.Writer, mask [4]byte) *CipherWriter
ClosedError returned when peer has closed the connection with appropriate
code and a textual reason.
Code ws.StatusCode
Reason string
Error implements error interface.
ClosedError : error
ControlHandler contains logic of handling control frames.
The intentional way to use it is to read the next frame header from the
connection, optionally check its validity via ws.CheckHeader() and if it is
not a ws.OpText of ws.OpBinary (or ws.OpContinuation) – pass it to Handle()
method.
That is, passed header should be checked to get rid of unexpected errors.
The Handle() method will read out all control frame payload (if any) and
write necessary bytes as a rfc compatible response.
DisableSrcCiphering disables unmasking payload data read from Src.
It is useful when wsutil.Reader is used or when frame payload already
pulled and ciphered out from the connection (and introduced by
bytes.Reader, for example).
Dst io.Writer
Src io.Reader
State ws.State
Handle handles control frames regarding to the c.State and writes responses
to the c.Dst when needed.
It returns ErrNotControlFrame when given header is not of ws.OpClose,
ws.OpPing or ws.OpPong operation code.
HandleClose handles close frame, makes protocol validity checks and writes
specification compatible response to the c.Dst.
HandlePing handles ping frame and writes specification compatible response
to the c.Dst.
HandlePong handles pong frame by discarding it.
ControlWriter is a wrapper around Writer that contains some guards for
buffered writes of control frames.
Flush flushes all buffered data to the underlying io.Writer.
Write implements io.Writer. It writes to the underlying Writer until it
returns error or until ControlWriter write limit will be exceeded.
*ControlWriter : github.com/apache/thrift/lib/go/thrift.Flusher
*ControlWriter : github.com/miekg/dns.Writer
*ControlWriter : internal/bisect.Writer
*ControlWriter : io.Writer
func NewControlWriter(dest io.Writer, state ws.State, op ws.OpCode) *ControlWriter
func NewControlWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *ControlWriter
DebugDialer is a wrapper around ws.Dialer. It tracks i/o of WebSocket
handshake. That is, it gives ability to receive copied HTTP request and
response bytes that made inside Dialer.Dial().
Note that it must not be used in production applications that requires
Dial() to be efficient.
Dialer contains WebSocket connection establishment options.
OnRequest and OnResponse are the callbacks that will be called with the
HTTP request and response respectively.
OnRequest and OnResponse are the callbacks that will be called with the
HTTP request and response respectively.
Dial connects to the url host and upgrades connection to WebSocket. It makes
it by calling d.Dialer.Dial().
DebugUpgrader is a wrapper around ws.Upgrader. It tracks I/O of a
WebSocket handshake.
Note that it must not be used in production applications that requires
Upgrade() to be efficient.
OnRequest and OnResponse are the callbacks that will be called with the
HTTP request and response respectively.
OnRequest and OnResponse are the callbacks that will be called with the
HTTP request and response respectively.
Upgrader contains upgrade to WebSocket options.
Upgrade calls Upgrade() on underlying ws.Upgrader and tracks I/O on conn.
FrameHandlerFunc handles parsed frame header and its body represented by
io.Reader.
Note that reader represents already unmasked body.
func ControlFrameHandler(w io.Writer, state ws.State) FrameHandlerFunc
Message represents a message from peer, that could be presented in one or
more frames. That is, it contains payload of all message fragments and
operation code of initial frame for this message.
OpCode ws.OpCode
Payload []byte
func ReadClientMessage(r io.Reader, m []Message) ([]Message, error)
func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error)
func ReadServerMessage(r io.Reader, m []Message) ([]Message, error)
func HandleClientControlMessage(conn io.Writer, msg Message) error
func HandleControlMessage(conn io.Writer, state ws.State, msg Message) error
func HandleServerControlMessage(conn io.Writer, msg Message) error
func ReadClientMessage(r io.Reader, m []Message) ([]Message, error)
func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error)
func ReadServerMessage(r io.Reader, m []Message) ([]Message, error)
Reader is a wrapper around source io.Reader which represents WebSocket
connection. It contains options for reading messages from source.
Reader implements io.Reader, which Read() method reads payload of incoming
WebSocket frames. It also takes care on fragmented frames and possibly
intermediate control frames between them.
Note that Reader's methods are not goroutine safe.
CheckUTF8 enables UTF-8 checks for text frames payload. If incoming
bytes are not valid UTF-8 sequence, ErrInvalidUTF8 returned.
Extensions is a list of negotiated extensions for reader Source.
It is used to meet the specs and clear appropriate bits in fragment
header RSV segment.
MaxFrameSize controls the maximum frame size in bytes
that can be read. A message exceeding that size will return
a ErrFrameTooLarge to the application.
Not setting this field means there is no limit.
OnContinuation FrameHandlerFunc
OnIntermediate FrameHandlerFunc
SkipHeaderCheck disables checking header bits to be RFC6455 compliant.
Source io.Reader
State ws.State
Discard discards current message unread bytes.
It discards all frames of fragmented message.
NextFrame prepares r to read next message. It returns received frame header
and non-nil error on failure.
Note that next NextFrame() call must be done after receiving or discarding
all current message bytes.
Read implements io.Reader. It reads the next message payload into p.
It takes care on fragmented messages.
The error is io.EOF only if all of message bytes were read.
If an io.EOF happens during reading some but not all the message bytes
Read() returns io.ErrUnexpectedEOF.
The error is ErrNoFrameAdvance if no NextFrame() call was made before
reading next message bytes.
*Reader : io.Reader
func NewClientSideReader(r io.Reader) *Reader
func NewReader(r io.Reader, s ws.State) *Reader
func NewServerSideReader(r io.Reader) *Reader
RecvExtension is an interface for clearing fragment header RSV bits.
( RecvExtension) UnsetBits(ws.Header) (ws.Header, error)
RecvExtensionFunc
RecvExtensionFunc is an adapter to allow the use of ordinary functions as
RecvExtension.
BitsRecv implements RecvExtension.
RecvExtensionFunc : RecvExtension
SendExtension is an interface for setting fragment header RSV bits.
( SendExtension) SetBits(ws.Header) (ws.Header, error)
SendExtensionFunc
func (*Writer).SetExtensions(xs ...SendExtension)
SendExtensionFunc is an adapter to allow the use of ordinary functions as
SendExtension.
BitsSend implements SendExtension.
SendExtensionFunc : SendExtension
UTF8Reader implements io.Reader that calculates utf8 validity state after
every read byte from Source.
Note that in some cases client must call r.Valid() after all bytes are read
to ensure that all of them are valid utf8 sequences. That is, some io helper
functions such io.ReadAtLeast or io.ReadFull could discard the error
information returned by the reader when they receive all of requested bytes.
For example, the last read sequence is invalid and UTF8Reader returns number
of bytes read and an error. But helper function decides to discard received
error due to all requested bytes are completely read from the source.
Another possible case is when some valid sequence become split by the read
bound. Then UTF8Reader can not make decision about validity of the last
sequence cause it is not fully read yet. And if the read stops, Valid() will
return false, even if Read() by itself dit not.
Source io.Reader
Accepted returns number of valid bytes in last Read().
Read implements io.Reader.
Reset resets utf8 reader to read from r.
Valid checks current reader state. It returns true if all read bytes are
valid UTF-8 sequences, and false if not.
*UTF8Reader : io.Reader
func NewUTF8Reader(r io.Reader) *UTF8Reader
Writer contains logic of buffering output data into a WebSocket fragments.
It is much the same as bufio.Writer, except the thing that it works with
WebSocket frames, not the raw data.
Writer writes frames with specified OpCode.
It uses ws.State to decide whether the output frames must be masked.
Note that it does not check control frame size or other RFC rules.
That is, it must be used with special care to write control frames without
violation of RFC. You could use ControlWriter that wraps Writer and contains
some guards for writing control frames.
If an error occurs writing to a Writer, no more data will be accepted and
all subsequent writes will return the error.
After all data has been written, the client should call the Flush() method
to guarantee all data has been forwarded to the underlying io.Writer.
Available returns how many bytes are unused in the buffer.
Buffered returns the number of bytes that have been written into the current
buffer.
DisableFlush denies Writer to write fragments.
Flush writes any buffered data to the underlying io.Writer.
It sends the frame with "fin" flag set to true.
If no Write() or ReadFrom() was made, then Flush() does nothing.
FlushFragment writes any buffered data to the underlying io.Writer.
It sends the frame with "fin" flag set to false.
Grow grows Writer's internal buffer capacity to guarantee space for another
n bytes of _payload_ -- that is, frame header is not included in n.
ReadFrom implements io.ReaderFrom.
Reset resets Writer as it was created by New() methods.
Note that Reset does reset extensions and other options was set after
Writer initialization.
ResetOp is an quick version of Reset().
ResetOp does reset unwritten fragments and does not reset results of
SetExtensions() or DisableFlush() methods.
SetExtensions adds xs as extensions to be used during writes.
Size returns the size of the underlying buffer in bytes (not including
WebSocket header bytes).
Write implements io.Writer.
Note that even if the Writer was created to have N-sized buffer, Write()
with payload of N bytes will not fit into that buffer. Writer reserves some
space to fit WebSocket header data.
WriteThrough writes data bypassing the buffer.
Note that Writer's buffer must be empty before calling WriteThrough().
*Writer : github.com/apache/thrift/lib/go/thrift.Flusher
*Writer : github.com/gogo/protobuf/proto.Sizer
*Writer : github.com/miekg/dns.Writer
*Writer : internal/bisect.Writer
*Writer : io.ReaderFrom
*Writer : io.Writer
func GetWriter(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer
func NewWriter(dest io.Writer, state ws.State, op ws.OpCode) *Writer
func NewWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *Writer
func NewWriterBufferSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer
func NewWriterSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer
func PutWriter(w *Writer)
Package-Level Functions (total 36)
ControlFrameHandler returns FrameHandlerFunc for handling control frames.
For more info see ControlHandler docs.
GetWriter tries to reuse Writer getting it from the pool.
This function is intended for memory consumption optimizations, because
NewWriter*() functions make allocations for inner buffer.
Note the it ceils n to the power of two.
If you have your own bytes buffer pool you could use NewWriterBuffer to use
pooled bytes in writer.
HandleClientControlMessage handles control frame from conn and writes
response when needed.
It considers that caller represents server side.
HandleControlMessage handles message which was read by ReadMessage()
functions.
That is, it is expected, that payload is already unmasked and frame header
were checked by ws.CheckHeader() call.
HandleServerControlMessage handles control frame from conn and writes
response when needed.
It considers that caller represents client side.
NewCipherReader creates xor-cipher reader from r with given mask.
NewCipherWriter creates xor-cipher writer to w with given mask.
NewClientSideReader is a helper function that calls NewReader with r and
ws.StateClientSide.
NewControlWriter contains ControlWriter with Writer inside whose buffer size
is at most ws.MaxControlFramePayloadSize + ws.MaxHeaderSize.
NewControlWriterBuffer returns a new ControlWriter with buf as a buffer.
Note that it reserves x bytes of buf for header data, where x could be
ws.MinHeaderSize or ws.MinHeaderSize+4 (depending on state). At most
(ws.MaxControlFramePayloadSize + x) bytes of buf will be used.
It panics if len(buf) <= ws.MinHeaderSize + x.
NewReader creates new frame reader that reads from r keeping given state to
make some protocol validity checks when it needed.
NewServerSideReader is a helper function that calls NewReader with r and
ws.StateServerSide.
NewUTF8Reader creates utf8 reader that reads from r.
NewWriter returns a new Writer whose buffer has the DefaultWriteBuffer size.
NewWriterBuffer returns a new Writer with buf as a buffer.
Note that it reserves x bytes of buf for header data, where x is in range
[ws.MinHeaderSize,ws.MaxHeaderSize] (depending on state and buf size).
You could use ws.HeaderSize() to calculate number of bytes needed to store
header data.
It panics if len(buf) is too small to fit header and payload data.
NewWriterBufferSize returns a new Writer whose buffer size is equal to n.
If n <= ws.MinHeaderSize then the default buffer size is used.
Note that Writer will reserve x bytes for header data, where x is in range
[ws.MinHeaderSize,ws.MaxHeaderSize]. That is, frames flushed by Writer
will not have payload length equal to n, except the case when Write() is
called on empty Writer with len(p) > n.
NewWriterSize returns a new Writer whose buffer size is at most n + ws.MaxHeaderSize.
That is, output frames payload length could be up to n, except the case when
Write() is called on empty Writer with len(p) > n.
If n <= 0 then the default buffer size is used as Writer's buffer size.
NextReader prepares next message read from r. It returns header that
describes the message and io.Reader to read message's payload. It returns
non-nil error when it is not possible to read message's initial frame.
Note that next NextReader() on the same r should be done after reading all
bytes from previously returned io.Reader. For more performant way to discard
message use Reader and its Discard() method.
Note that it will not handle any "intermediate" frames, that possibly could
be received between text/binary continuation frames. That is, if peer sent
text/binary frame with fin flag "false", then it could send ping frame, and
eventually remaining part of text/binary frame with fin "true" – with
NextReader() the ping frame will be dropped without any notice. To handle
this rare, but possible situation (and if you do not know exactly which
frames peer could send), you could use Reader with OnIntermediate field set.
PutWriter puts w for future reuse by GetWriter().
ReadClientBinary reads next binary message from rw, considering that caller
represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
It discards received text messages.
Note this may handle and write control frames into the writer part of a given
io.ReadWriter.
ReadClientData reads next data message from rw, considering that caller
represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
Note this may handle and write control frames into the writer part of a
given io.ReadWriter.
ReadClientMessage reads next message from r, considering that caller
represents server side.
It is a shortcut for ReadMessage(r, ws.StateServerSide, m).
ReadClientText reads next text message from rw, considering that caller
represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
It discards received binary messages.
Note this may handle and write control frames into the writer part of a
given io.ReadWriter.
ReadData is a helper function that reads next data (non-control) message
from rw.
It takes care on handling all control frames. It will write response on
control frames to the write part of rw. It blocks until some data frame
will be received.
Note this may handle and write control frames into the writer part of a
given io.ReadWriter.
ReadMessage is a helper function that reads next message from r. It appends
received message(s) to the third argument and returns the result of it and
an error if some failure happened. That is, it probably could receive more
than one message when peer sending fragmented message in multiple frames and
want to send some control frame between fragments. Then returned slice will
contain those control frames at first, and then result of gluing fragments.
TODO(gobwas): add DefaultReader with buffer size options.
ReadServerBinary reads next binary message from rw, considering that caller
represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
It discards received text messages.
Note this may handle and write control frames into the writer part of a
given io.ReadWriter.
ReadServerData reads next data message from rw, considering that caller
represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
Note this may handle and write control frames into the writer part of a
given io.ReadWriter.
ReadServerMessage reads next message from r, considering that caller
represents client side.
It is a shortcut for ReadMessage(r, ws.StateClientSide, m).
ReadServerText reads next text message from rw, considering that caller
represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
It discards received binary messages.
Note this may handle and write control frames into the writer part of a given
io.ReadWriter.
WriteClientBinary is the same as WriteClientMessage with
ws.OpBinary.
WriteClientMessage writes message to w, considering that caller
represents client side.
WriteClientText is the same as WriteClientMessage with
ws.OpText.
WriteMessage is a helper function that writes message to the w. It
constructs single frame with given operation code and payload.
It uses given state to prepare side-dependent things, like cipher
payload bytes from client to server. It will not mutate p bytes if
cipher must be made.
If you want to write message in fragmented frames, use Writer instead.
WriteServerBinary is the same as WriteServerMessage with
ws.OpBinary.
WriteServerMessage writes message to w, considering that caller
represents server side.
WriteServerText is the same as WriteServerMessage with
ws.OpText.
Package-Level Variables (total 7)
DefaultWriteBuffer contains size of Writer's default buffer. It used by
Writer constructor functions.
ErrControlOverflow is returned by ControlWriter.Write() to indicate that
no more data could be written to the underlying io.Writer because
MaxControlFramePayloadSize limit is reached.
ErrFrameTooLarge indicates that a message of length higher than
MaxFrameSize was being read.
ErrInvalidUTF8 is returned by UTF8 reader on invalid utf8 sequence.
ErrNoFrameAdvance means that Reader's Read() method was called without
preceding NextFrame() call.
ErrNotControlFrame is returned by ControlHandler to indicate that given
header could not be handled.
ErrNotEmpty is returned by Writer.WriteThrough() to indicate that buffer is
not empty and write through could not be done. That is, caller should call
Writer.FlushFragment() to make buffer empty.
![]() |
The pages are generated with Golds v0.8.2. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |