1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package websocket implements a client and server for the WebSocket protocol
6 // as specified in RFC 6455.
8 // This package currently lacks some features found in an alternative
9 // and more actively maintained WebSocket package:
11 // https://godoc.org/github.com/gorilla/websocket
13 package websocket // import "golang.org/x/net/websocket"
30 ProtocolVersionHybi13 = 13
31 ProtocolVersionHybi = ProtocolVersionHybi13
32 SupportedProtocolVersion = "13"
42 DefaultMaxPayloadBytes = 32 << 20 // 32MB
45 // ProtocolError represents WebSocket protocol errors.
46 type ProtocolError struct {
50 func (err *ProtocolError) Error() string { return err.ErrorString }
53 ErrBadProtocolVersion = &ProtocolError{"bad protocol version"}
54 ErrBadScheme = &ProtocolError{"bad scheme"}
55 ErrBadStatus = &ProtocolError{"bad status"}
56 ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
57 ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
58 ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
59 ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
60 ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"}
61 ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
62 ErrBadFrame = &ProtocolError{"bad frame"}
63 ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"}
64 ErrNotWebSocket = &ProtocolError{"not websocket protocol"}
65 ErrBadRequestMethod = &ProtocolError{"bad method"}
66 ErrNotSupported = &ProtocolError{"not supported"}
69 // ErrFrameTooLarge is returned by Codec's Receive method if payload size
70 // exceeds limit set by Conn.MaxPayloadBytes
71 var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit")
73 // Addr is an implementation of net.Addr for WebSocket.
78 // Network returns the network type for a WebSocket, "websocket".
79 func (addr *Addr) Network() string { return "websocket" }
81 // Config is a WebSocket configuration
83 // A WebSocket server address.
86 // A Websocket client origin.
89 // WebSocket subprotocols.
92 // WebSocket protocol version.
95 // TLS config for secure WebSocket (wss).
98 // Additional header fields to be sent in WebSocket opening handshake.
101 // Dialer used when opening websocket connections.
104 handshakeData map[string]string
107 // serverHandshaker is an interface to handle WebSocket server side handshake.
108 type serverHandshaker interface {
109 // ReadHandshake reads handshake request message from client.
110 // Returns http response code and error if any.
111 ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
113 // AcceptHandshake accepts the client handshake request and sends
114 // handshake response back to client.
115 AcceptHandshake(buf *bufio.Writer) (err error)
117 // NewServerConn creates a new WebSocket connection.
118 NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
121 // frameReader is an interface to read a WebSocket frame.
122 type frameReader interface {
123 // Reader is to read payload of the frame.
126 // PayloadType returns payload type.
129 // HeaderReader returns a reader to read header of the frame.
130 HeaderReader() io.Reader
132 // TrailerReader returns a reader to read trailer of the frame.
133 // If it returns nil, there is no trailer in the frame.
134 TrailerReader() io.Reader
136 // Len returns total length of the frame, including header and trailer.
140 // frameReaderFactory is an interface to creates new frame reader.
141 type frameReaderFactory interface {
142 NewFrameReader() (r frameReader, err error)
145 // frameWriter is an interface to write a WebSocket frame.
146 type frameWriter interface {
147 // Writer is to write payload of the frame.
151 // frameWriterFactory is an interface to create new frame writer.
152 type frameWriterFactory interface {
153 NewFrameWriter(payloadType byte) (w frameWriter, err error)
156 type frameHandler interface {
157 HandleFrame(frame frameReader) (r frameReader, err error)
158 WriteClose(status int) (err error)
161 // Conn represents a WebSocket connection.
163 // Multiple goroutines may invoke methods on a Conn simultaneously.
166 request *http.Request
168 buf *bufio.ReadWriter
169 rwc io.ReadWriteCloser
180 defaultCloseStatus int
182 // MaxPayloadBytes limits the size of frame payload received over Conn
183 // by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used.
187 // Read implements the io.Reader interface:
188 // it reads data of a frame from the WebSocket connection.
189 // if msg is not large enough for the frame data, it fills the msg and next Read
190 // will read the rest of the frame data.
191 // it reads Text frame or Binary frame.
192 func (ws *Conn) Read(msg []byte) (n int, err error) {
194 defer ws.rio.Unlock()
196 if ws.frameReader == nil {
197 frame, err := ws.frameReaderFactory.NewFrameReader()
201 ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
205 if ws.frameReader == nil {
209 n, err = ws.frameReader.Read(msg)
211 if trailer := ws.frameReader.TrailerReader(); trailer != nil {
212 io.Copy(ioutil.Discard, trailer)
220 // Write implements the io.Writer interface:
221 // it writes data as a frame to the WebSocket connection.
222 func (ws *Conn) Write(msg []byte) (n int, err error) {
224 defer ws.wio.Unlock()
225 w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
229 n, err = w.Write(msg)
234 // Close implements the io.Closer interface.
235 func (ws *Conn) Close() error {
236 err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
237 err1 := ws.rwc.Close()
244 func (ws *Conn) IsClientConn() bool { return ws.request == nil }
245 func (ws *Conn) IsServerConn() bool { return ws.request != nil }
247 // LocalAddr returns the WebSocket Origin for the connection for client, or
248 // the WebSocket location for server.
249 func (ws *Conn) LocalAddr() net.Addr {
250 if ws.IsClientConn() {
251 return &Addr{ws.config.Origin}
253 return &Addr{ws.config.Location}
256 // RemoteAddr returns the WebSocket location for the connection for client, or
257 // the Websocket Origin for server.
258 func (ws *Conn) RemoteAddr() net.Addr {
259 if ws.IsClientConn() {
260 return &Addr{ws.config.Location}
262 return &Addr{ws.config.Origin}
265 var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
267 // SetDeadline sets the connection's network read & write deadlines.
268 func (ws *Conn) SetDeadline(t time.Time) error {
269 if conn, ok := ws.rwc.(net.Conn); ok {
270 return conn.SetDeadline(t)
272 return errSetDeadline
275 // SetReadDeadline sets the connection's network read deadline.
276 func (ws *Conn) SetReadDeadline(t time.Time) error {
277 if conn, ok := ws.rwc.(net.Conn); ok {
278 return conn.SetReadDeadline(t)
280 return errSetDeadline
283 // SetWriteDeadline sets the connection's network write deadline.
284 func (ws *Conn) SetWriteDeadline(t time.Time) error {
285 if conn, ok := ws.rwc.(net.Conn); ok {
286 return conn.SetWriteDeadline(t)
288 return errSetDeadline
291 // Config returns the WebSocket config.
292 func (ws *Conn) Config() *Config { return ws.config }
294 // Request returns the http request upgraded to the WebSocket.
295 // It is nil for client side.
296 func (ws *Conn) Request() *http.Request { return ws.request }
298 // Codec represents a symmetric pair of functions that implement a codec.
300 Marshal func(v interface{}) (data []byte, payloadType byte, err error)
301 Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
304 // Send sends v marshaled by cd.Marshal as single frame to ws.
305 func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
306 data, payloadType, err := cd.Marshal(v)
311 defer ws.wio.Unlock()
312 w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
316 _, err = w.Write(data)
321 // Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores
322 // in v. The whole frame payload is read to an in-memory buffer; max size of
323 // payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds
324 // limit, ErrFrameTooLarge is returned; in this case frame is not read off wire
325 // completely. The next call to Receive would read and discard leftover data of
326 // previous oversized frame before processing next frame.
327 func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
329 defer ws.rio.Unlock()
330 if ws.frameReader != nil {
331 _, err = io.Copy(ioutil.Discard, ws.frameReader)
338 frame, err := ws.frameReaderFactory.NewFrameReader()
342 frame, err = ws.frameHandler.HandleFrame(frame)
349 maxPayloadBytes := ws.MaxPayloadBytes
350 if maxPayloadBytes == 0 {
351 maxPayloadBytes = DefaultMaxPayloadBytes
353 if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) {
354 // payload size exceeds limit, no need to call Unmarshal
356 // set frameReader to current oversized frame so that
357 // the next call to this function can drain leftover
358 // data before processing the next frame
359 ws.frameReader = frame
360 return ErrFrameTooLarge
362 payloadType := frame.PayloadType()
363 data, err := ioutil.ReadAll(frame)
367 return cd.Unmarshal(data, payloadType, v)
370 func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
371 switch data := v.(type) {
373 return []byte(data), TextFrame, nil
375 return data, BinaryFrame, nil
377 return nil, UnknownFrame, ErrNotSupported
380 func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
381 switch data := v.(type) {
389 return ErrNotSupported
393 Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
394 To send/receive text frame, use string type.
395 To send/receive binary frame, use []byte type.
401 // receive text frame
403 websocket.Message.Receive(ws, &message)
407 websocket.Message.Send(ws, message)
409 // receive binary frame
411 websocket.Message.Receive(ws, &data)
414 data = []byte{0, 1, 2}
415 websocket.Message.Send(ws, data)
418 var Message = Codec{marshal, unmarshal}
420 func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
421 msg, err = json.Marshal(v)
422 return msg, TextFrame, err
425 func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
426 return json.Unmarshal(msg, v)
430 JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
441 // receive JSON type T
443 websocket.JSON.Receive(ws, &data)
446 websocket.JSON.Send(ws, data)
448 var JSON = Codec{jsonMarshal, jsonUnmarshal}