Documentation ¶
Overview ¶
Package websocket provides a handler for websockets
Index ¶
- Constants
- Variables
- func RequireProtocols(protocols ...string) func(*http.Request) error
- type CloseCause
- type CloseFrame
- type Connection
- func (conn *Connection) Close() error
- func (conn *Connection) Context() context.Context
- func (conn *Connection) Read() <-chan Message
- func (conn *Connection) Request() *http.Request
- func (conn *Connection) Shutdown()
- func (conn *Connection) ShutdownWith(frame CloseFrame)
- func (conn *Connection) Subprotocol() string
- func (conn *Connection) Write(message Message) error
- func (conn *Connection) WriteBinary(source []byte) error
- func (conn *Connection) WritePrepared(message PreparedMessage) error
- func (sh *Connection) WriteText(text string) error
- type ConnectionState
- type Handler
- type Message
- type Options
- type PreparedMessage
- type Server
- type StatusCode
Examples ¶
Constants ¶
const ( DefaultWriteInterval = 10 * time.Second DefaultReadInterval = time.Minute DefaultHandshakeTimeout = time.Second DefaultPingInterval = (DefaultReadInterval * 9) / 10 DefaultReadLimit = 2048 // bytes )
Defaults for Options
const MsgFailedCloseFrame = "error writing close frame"
Variables ¶
var ( // ErrConnectionShutdownWith indicates the connection closed because connection.ShutdownWith was called. ErrConnectionShutdownWith = errors.New("Connection.ShutdownWith called") // ErrConnectionClose indicates that the connection closed because connection.Close was called. ErrConnectionClose = errors.New("connection.Close called") )
Functions ¶
Types ¶
type CloseCause ¶
type CloseCause struct { // CloseFrame is the close frame that cause the closure. // If no close frame was received, contains the [StatusAbnormalClosure] code. Frame CloseFrame // WasClean indicates if the connection is closed after receiving a close frame // from the client, or after having sent a close frame. // // NOTE: This roughly corresponds to the websocket JavaScript API's CloseEvent's wasClean. // However in situations where the server sends a close frame, but never receives a response // the WasClean field may still be true. // This detail is not considered part of the public API of this package, and may change in the future. WasClean bool // Err contains the error that caused the closure of this connection. // This may be an error returned from the read or write end of the connection, // or a server-side error. // // A special value contained in this field is ErrShuttingDown. Err error }
CloseCause is returned by calling [close.Cause] on the context of a connection. It indicates the reason why the server was closed.
func (CloseCause) Error ¶
func (cc CloseCause) Error() string
CloseCause implements the error interface.
func (CloseCause) Unwrap ¶
func (cc CloseCause) Unwrap() error
Unwrap implements the underlying Unwrap interface.
type CloseFrame ¶
type CloseFrame struct { Code StatusCode Reason string }
CloseFrame represents a closing control frame of a websocket connection. It is defined RFC 6455, section 5.5.1.
func (CloseFrame) Body ¶
func (cf CloseFrame) Body() []byte
Message returns the message body used to send this frame to a remote endpoint.
func (CloseFrame) IsZero ¶
func (cf CloseFrame) IsZero() bool
IsZero checks if this CloseFrame has the zero value
type Connection ¶
type Connection struct {
// contains filtered or unexported fields
}
Connection represents a connection to a single websocket client.
func (*Connection) Close ¶
func (conn *Connection) Close() error
Close closes the connection to the peer without sending a specific close message. See [CloseWith] for providing the client with a reason for the closure.
func (*Connection) Context ¶
func (conn *Connection) Context() context.Context
Context returns a context for operations on this context. Once it is closed, no more read or write operations are permitted.
The context.Cause will return an error of type CloseCause, representing the reason for the closure.
The Context may close before the Handler function has returned. To wait for the handler function to return, use Wait() instead.
func (*Connection) Read ¶
func (conn *Connection) Read() <-chan Message
Read returns a channel that receives Text and Binary Messages from the peer. Once the websocket connection state is corrupted or closed, the channel is closed.
Multiple invocations of Read returns the same channel.
func (*Connection) Request ¶
func (conn *Connection) Request() *http.Request
Request returns a clone of the original request used for upgrading the connection. It can be used to e.g. check for authentication.
Multiple calls to Request may return the same Request.
func (*Connection) Shutdown ¶
func (conn *Connection) Shutdown()
Shutdown waits until the connection has been closed and the handler returns.
NOTE: This name exists to correspond to the graceful server shutdown.
func (*Connection) ShutdownWith ¶
func (conn *Connection) ShutdownWith(frame CloseFrame)
ShutdownWith shuts down this connection with the given code and text for the client.
ShutdownWith automatically formats a close message, sends it, and waits for the close handshake to complete or timeout. The timeout used is the normal ReadInterval timeout.
When closeCode is 0, uses CloseNormalClosure.
func (*Connection) Subprotocol ¶
func (conn *Connection) Subprotocol() string
Subprotocol returns the negotiated protocol for the connection. If no subprotocol has been negotiated, returns the empty string.
func (*Connection) Write ¶
func (conn *Connection) Write(message Message) error
Write queues the provided message for sending and blocks until the given message has been sent.
Write returns a non-nil error if and only if the message failed to send. In such a case, Write will internally close the connection and return an error of type CancelCause.
Call Write concurrently with other read and write calls is safe. When multiple calls to Write are in-progress, all messages will be sent, but their order is undefined unless the callers explicitly coordinate.
func (*Connection) WriteBinary ¶
func (conn *Connection) WriteBinary(source []byte) error
WriteBinary is like Write, but it sends a BinaryMessage with the given text.
func (*Connection) WritePrepared ¶
func (conn *Connection) WritePrepared(message PreparedMessage) error
WritePrepared is like Write, but sends a PreparedMessage instead.
func (*Connection) WriteText ¶
func (sh *Connection) WriteText(text string) error
WriteText is like Write, but is sends a TextMessage with the given text.
type ConnectionState ¶
type ConnectionState int
ConnectionState is the state of the connection
const ( CONNECTING ConnectionState = iota OPEN CLOSING CLOSED )
Different connection states
type Handler ¶
type Handler func(*Connection)
Handler handles a connection sent to the server. It should exit as soon as possible once the connection's context is closed. Handler may not retain a reference to its' argument past the function returning.
type Message ¶
Message represents a message sent between client and server.
func NewBinaryMessage ¶
NewBinaryMessage creates a new binary message with the given text
func NewTextMessage ¶
NewTextMessage creates a new text message with the given text
func (Message) MustPrepare ¶
func (msg Message) MustPrepare() PreparedMessage
MustPrepare is like Prepare, but panic()s when preparing fails.
func (Message) Prepare ¶
func (msg Message) Prepare() (PreparedMessage, error)
Prepare prepares a message for sending
type Options ¶
type Options struct { // HandshakeTimeout specifies the duration for the open and close handshakes to complete. // If the handshakes fail within this time, the connection is closed immediately with an error. HandshakeTimeout time.Duration // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer // size is zero, then buffers allocated by the HTTP server are used. The // I/O buffer sizes do not limit the size of the messages that can be sent // or received. ReadBufferSize, WriteBufferSize int // ReadInterval is the maximum amount of time to wait for a new packet on // the underlying network connection. // After a read has timed out, the websocket connection state is corrupt and // the connection will be closed. // // To ensure that the client sends at least some packet within this time, use [PingInterval]. ReadInterval time.Duration // WriteInterval is the write deadline on the underlying network // connection. After a write has timed out, the websocket state is corrupt and // the connection will be closed. WriteInterval time.Duration // WriteBufferPool is a pool of buffers for write operations. If the value // is not set, then write buffers are allocated to the connection for the // lifetime of the connection. // // A pool is most useful when the application has a modest volume of writes // across a large number of connections. // // Applications should use a single pool for each unique value of // WriteBufferSize. WriteBufferPool websocket.BufferPool // Subprotocols specifies the server's supported protocols in order of // preference. If this field is not nil, then the server negotiates a // subprotocol by selecting the first match in this list with a protocol // requested by the client. If there's no match, then no protocol is // negotiated (the Sec-Websocket-Protocol header is not included in the // handshake response). Subprotocols []string // PingInterval is the amount of time between successive Ping messages sent to be sent to the peer. // A ping message is intended to invoke a Poke response from the client, ensuring that the connection // has not been corrupted, and a package is received in at most [ReadInterval]. // // For this purpose, PingInterval should be less than [ReadInterval]. PingInterval time.Duration // ReadLimit is the maximum size in bytes for a message read from the peer. If a // message exceeds the limit, the connection sends a close message to the peer // and returns an error to the application. ReadLimit int64 // CompressionLevel is the compression level of packages received to and from the peer. // See the [compress/flate] package for compression levels. // // A compression level of [flate.NoCompression] means that compression is disabled. // This is ignored if compression has not been negotiated with the client. CompressionLevel int }
Options describes options for connections made to a Server. It is not guaranteed that options changed after the first call to [ServeHTTP] are accepted.
See [Options.SetDefault] for appropriate defaults.
func (Options) CompressionEnabled ¶
CompressionEnabled determines if the server should attempt to negotiate per message compression (RFC 7692). This method returning true does not guarantee that compression will be supported; only that the server will attempt to negotiate enabling it.
This is enabled when the CompressionLevel is not set to flate.NoCompression.
func (*Options) SetDefaults ¶
func (opt *Options) SetDefaults()
SetDefaults sets defaults for options. See the appropriate default constants for this package.
type PreparedMessage ¶
type PreparedMessage struct {
// contains filtered or unexported fields
}
PreparedMessage represents a message that caches its' on-the-wire encoding. This saves re-applying compression.
type Server ¶
type Server struct { // Handler is called for incoming client connections. // It must not be nil. Handler Handler // Fallback specifies the handler for generating HTTP responses if the client // did not request an upgrade to a websocket connection. // If Fallback is nil, sends an appropriate [http.StatusUpgradeRequired] Fallback http.Handler // Check check if additional client requirements are met before establishing // a websocket connection and returns a caller-exposed error if // this is not the case. If Check is nil, every potential client is // allowed to connect. // // A client that is rejected will receive a [http.StatusForbidden] response // with a body of the error returned by this function. // // A typical use case includes enforcing a specific subprotocol, // before even reaching the handler, see [RequireProtocols]. // // Check is called before CheckOrigin. Check func(r *http.Request) error // CheckOrigin returns true if the request Origin header is acceptable. If // CheckOrigin is nil, then a safe default is used: return false if the // Origin request header is present and the origin host is not equal to // request Host header. // // A CheckOrigin function should carefully validate the request origin to // prevent cross-site request forgery. // // CheckOrigin is only called if the Check function passes. CheckOrigin func(r *http.Request) bool // Error specifies the function for generating HTTP error responses. If Error // is nil, then http.Error is used to generate the HTTP response. Error func(w http.ResponseWriter, r *http.Request, status int, reason error) // Options determine further options for future connections. Options Options // contains filtered or unexported fields }
Server implements a websocket server.
Example (Echo) ¶
A simple echo server for messages
package main import ( "fmt" "github.com/tkw1536/pkglib/websocketx" "github.com/tkw1536/pkglib/websocketx/websockettest" "github.com/gorilla/websocket" ) func main() { // create a very simple websocket server that just echoes back messages var server websocketx.Server done := make(chan struct{}) server.Handler = func(ws *websocketx.Connection) { // when finished, print that the handler exited // and close the done channel defer fmt.Println("Handler() returned") defer close(done) // read and write messages back forever for { select { case <-ws.Context().Done(): return case msg := <-ws.Read(): if err := ws.Write(msg); err != nil { panic(err) } } } } // The following code below is just for connection to the server. // It is just used to make sure that everything works. // create an actual server // create a new test server wss := websockettest.NewServer(&server) defer wss.Close() // create a new test client client, _ := wss.Dial(nil, nil) defer client.Close() // send a bunch of example messages messageCount := 1000 // send it a lot of times for i := range messageCount { // generate an example message to send message := fmt.Sprintf("message %d", i) var kind int if i%2 == 0 { kind = websocket.BinaryMessage } else { kind = websocket.TextMessage } // write it or die if err := client.WriteMessage(kind, []byte(message)); err != nil { panic(err) } // read the message tp, p, err := client.ReadMessage() if err != nil { panic(err) } if tp != kind { panic("incorrect type received") } if string(p) != message { panic("incorrect answer received") } } client.Close() <-done }
Output: Handler() returned
Example (Panic) ¶
Demonstrates how panic()ing handlers are handled handler
package main import ( "fmt" "github.com/tkw1536/pkglib/websocketx" "github.com/tkw1536/pkglib/websocketx/websockettest" "github.com/gorilla/websocket" ) func main() { var server websocketx.Server server.Handler = func(ws *websocketx.Connection) { _ = ws.WriteText("normal message") // ignore error, we're panic()ing in the next line anyways panic("test panic") } // The following code below is just for connection to the server. // It is just used to make sure that everything works. // create an actual server wss := websockettest.NewServer(&server) defer wss.Close() // Connect to the server client, _, err := websocket.DefaultDialer.Dial(wss.URL, nil) if err != nil { panic(err) } defer client.Close() // print text messages for { tp, p, err := client.ReadMessage() if err != nil { return } // ignore non-text-messages if tp != websocket.TextMessage { continue } fmt.Println(string(p)) } }
Output: normal message
Example (Prepared) ¶
package main import ( "fmt" "github.com/tkw1536/pkglib/websocketx" "github.com/tkw1536/pkglib/websocketx/websockettest" "github.com/gorilla/websocket" ) func main() { var server websocketx.Server // prepare a message to send msg := websocketx.NewTextMessage("i am prepared").MustPrepare() server.Handler = func(ws *websocketx.Connection) { if err := ws.WritePrepared(msg); err != nil { panic(err) } } // The following code below is just for connection to the server. // It is just used to make sure that everything works. // create an actual server wss := websockettest.NewServer(&server) defer wss.Close() client, _ := wss.Dial(nil, nil) defer client.Close() // print text messages for { tp, p, err := client.ReadMessage() if err != nil { return } // ignore non-text-messages if tp != websocket.TextMessage { continue } fmt.Println(string(p)) } }
Output: i am prepared
Example (Send) ¶
A simple server that sends data to the client.
package main import ( "fmt" "github.com/tkw1536/pkglib/websocketx" "github.com/tkw1536/pkglib/websocketx/websockettest" "github.com/gorilla/websocket" ) func main() { var server websocketx.Server server.Handler = func(ws *websocketx.Connection) { if err := ws.WriteText("hello"); err != nil { panic(err) } if err := ws.WriteText("world"); err != nil { panic(err) } } // The following code below is just for connection to the server. // It is just used to make sure that everything works. // create a new test server wss := websockettest.NewServer(&server) defer wss.Close() // create a new test client client, _ := wss.Dial(nil, nil) defer client.Close() // print text messages for { tp, p, err := client.ReadMessage() if err != nil { return } // ignore non-text-messages if tp != websocket.TextMessage { continue } fmt.Println(string(p)) } }
Output: hello world
func (*Server) Close ¶
func (server *Server) Close()
Close immediately closes the server by closing all client connections. Close does not wait for any existing connections to finish their shutdown.
To force shutdown, and then wait for any active handlers, use a call to Close followed by a call to Shutdown.
Use [Shutdown] or [ShutdownWith] instead.
func (*Server) RequireProtocols ¶
func (server *Server) RequireProtocols()
RequireProtocols enforces that for any client to connect, at least one of the subprotocols has to be supported.
This overrides the server.Check function.
func (*Server) ServeHTTP ¶
func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements the http.Handler interface.
This is typically a websocket upgrade request. If a non http-client
func (*Server) Shutdown ¶
func (server *Server) Shutdown()
Shutdown gracefully shuts down the server.
Shutdown first informs the server to stop accepting new connection attempts. Then it waits (indefinitely) for all existing connections to stop.
See also [ShutdownWith] and [Close].
func (*Server) ShutdownWith ¶
func (server *Server) ShutdownWith(frame CloseFrame)
ShutdownWith gracefully shuts down the server by sending each client the given CloseFrame. If frame is the zero value, uses a default frame indicating that the server is shutting down instead.
ShutdownWith first informs the server to stop accepting new connection attempts. Then it closes all existing connections by sending the given error. Finally it waits (indefinitely) for all existing connections to stop.
See also [Shutdown] and [Close].
type StatusCode ¶
type StatusCode uint16
StatusCode is a status code as defined in RFC 6455, Section 7.4.
const ( // Indicates a normal closure, meaning that the purpose for // which the connection was established has been fulfilled. StatusNormalClosure StatusCode = 1000 // Indicates that an endpoint is "going away", such as a server // going down or a browser having navigated away from a page. StatusGoingAway StatusCode = 1001 // indicates that an endpoint is terminating the connection due // to a protocol error. StatusProtocolError StatusCode = 1002 // indicates that an endpoint is terminating the connection // because it has received a type of data it cannot accept (e.g., an // endpoint that understands only text data MAY send this if it // receives a binary message). StatusUnsupportedData StatusCode = 1003 // A reserved value and MUST NOT be set as a status code in a // Close control frame by an endpoint. It is designated for use in // applications expecting a status code to indicate that no status // code was actually present. StatusNoStatusReceived StatusCode = 1005 // A reserved value and MUST NOT be set as a status code in a // Close control frame by an endpoint. It is designated for use in // applications expecting a status code to indicate that the // connection was closed abnormally, e.g., without sending or // receiving a Close control frame. StatusAbnormalClosure StatusCode = 1006 // Indicates that an endpoint is terminating the connection // because it has received data within a message that was not // consistent with the type of the message (e.g., non-UTF-8 [RFC3629] // data within a text message). StatusInvalidFramePayloadData StatusCode = 1007 // Indicates that an endpoint is terminating the connection // because it has received a message that violates its policy. This // is a generic status code that can be returned when there is no // other more suitable status code (e.g., [StatusUnsupportedData] or [StatusCloseMessageTooBig]) or if there // is a need to hide specific details about the policy. StatusPolicyViolation StatusCode = 1008 // Indicates that an endpoint is terminating the connection // because it has received a message that is too big for it to // process. StatusMessageTooBig StatusCode = 1009 // Indicates that an endpoint (client) is terminating the // connection because it has expected the server to negotiate one or // more extension, but the server didn't return them in the response // message of the WebSocket handshake. The list of extensions that // are needed SHOULD appear in the /reason/ part of the Close frame. // Note that this status code is not used by the server, because it // can fail the WebSocket handshake instead. StatusMandatoryExtension StatusCode = 1010 // Indicates that a remote endpoint is terminating the connection // because it encountered an unexpected condition that prevented it from // fulfilling the request. StatusInternalErr StatusCode = 1011 // Indicates that the service is restarted. A client may reconnect, // and if it choses to do, should reconnect using a randomized delay // of 5 - 30s. StatusServiceRestart StatusCode = 1012 // Indicates that the service is experiencing overload. A client // should only connect to a different IP (when there are multiple for the // target) or reconnect to the same IP upon user action. StatusTryAgainLater StatusCode = 1013 // Indicates that the server was acting as a gateway or proxy and // received an invalid response from the upstream server. StatusBadGateway StatusCode = 1014 // Additional status codes registered in the IANA registry. StatusForbidden StatusCode = 3003 StatusTimeout StatusCode = 3008 )
Defined Websocket status codes as per RFC 6455, Section 7.4.1. Primarily from rfc, see also iana.
func (StatusCode) Name ¶
func (st StatusCode) Name() string
Name returns the name of this status code, if it is known. If the name is not known, returns the empty string.
func (StatusCode) String ¶
func (st StatusCode) String() string
String turns this status code in human-readable form for display.
Directories ¶
Path | Synopsis |
---|---|
websockettest provides a server for testing.
|
websockettest provides a server for testing. |