diff options
author | Fumitoshi Ukai <ukai@google.com> | 2009-11-29 14:22:44 -0800 |
---|---|---|
committer | Fumitoshi Ukai <ukai@google.com> | 2009-11-29 14:22:44 -0800 |
commit | 44b0d5999a8b20630701fda866a5ee416e9fe862 (patch) | |
tree | 4d591b2d0afc51c45cbc88d8731ce936f5e58fb7 /src/pkg/websocket/websocket.go | |
parent | 72695b377fe6061eef5dfc26ea52d43732c7e972 (diff) | |
download | golang-44b0d5999a8b20630701fda866a5ee416e9fe862.tar.gz |
Add WebSocket server framework hooked into http.
R=r, rsc
http://codereview.appspot.com/156071
Committer: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/pkg/websocket/websocket.go')
-rw-r--r-- | src/pkg/websocket/websocket.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/pkg/websocket/websocket.go b/src/pkg/websocket/websocket.go new file mode 100644 index 000000000..0fd32cd4c --- /dev/null +++ b/src/pkg/websocket/websocket.go @@ -0,0 +1,138 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The websocket package implements Web Socket protocol server. +package websocket + +// References: +// The Web Socket protocol: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol + +// TODO(ukai): +// better logging. + +import ( + "bufio"; + "io"; + "net"; + "os"; +) + +type WebSocketAddr string + +func (addr WebSocketAddr) Network() string { return "websocket" } + +func (addr WebSocketAddr) String() string { return string(addr) } + +// Conn is an channels to communicate over Web Socket. +type Conn struct { + // An origin URI of the Web Socket. + Origin string; + // A location URI of the Web Socket. + Location string; + // A subprotocol of the Web Socket. + Protocol string; + + buf *bufio.ReadWriter; + rwc io.ReadWriteCloser; +} + +// newConn creates a new Web Socket. +func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { + if buf == nil { + br := bufio.NewReader(rwc); + bw := bufio.NewWriter(rwc); + buf = bufio.NewReadWriter(br, bw); + } + ws := &Conn{origin, location, protocol, buf, rwc}; + return ws; +} + +func (ws *Conn) Read(msg []byte) (n int, err os.Error) { + for { + frameByte, err := ws.buf.ReadByte(); + if err != nil { + return + } + if (frameByte & 0x80) == 0x80 { + length := 0; + for { + c, err := ws.buf.ReadByte(); + if err != nil { + return + } + if (c & 0x80) == 0x80 { + length = length*128 + int(c&0x7f) + } else { + break + } + } + for length > 0 { + _, err := ws.buf.ReadByte(); + if err != nil { + return + } + length--; + } + } else { + for { + c, err := ws.buf.ReadByte(); + if err != nil { + return + } + if c == '\xff' { + return + } + if frameByte == 0 { + if n+1 <= cap(msg) { + msg = msg[0 : n+1] + } + msg[n] = c; + n++; + } + if n >= cap(msg) { + err = os.E2BIG; + return; + } + } + } + } + return; +} + +func (ws *Conn) Write(msg []byte) (n int, err os.Error) { + ws.buf.WriteByte(0); + ws.buf.Write(msg); + ws.buf.WriteByte(0xff); + err = ws.buf.Flush(); + return len(msg), err; +} + +func (ws *Conn) Close() os.Error { return ws.rwc.Close() } + +func (ws *Conn) LocalAddr() net.Addr { return WebSocketAddr(ws.Origin) } + +func (ws *Conn) RemoteAddr() net.Addr { return WebSocketAddr(ws.Location) } + +func (ws *Conn) SetTimeout(nsec int64) os.Error { + if conn, ok := ws.rwc.(net.Conn); ok { + return conn.SetTimeout(nsec) + } + return os.EINVAL; +} + +func (ws *Conn) SetReadTimeout(nsec int64) os.Error { + if conn, ok := ws.rwc.(net.Conn); ok { + return conn.SetReadTimeout(nsec) + } + return os.EINVAL; +} + +func (ws *Conn) SetWriteTimeout(nsec int64) os.Error { + if conn, ok := ws.rwc.(net.Conn); ok { + return conn.SetWriteTimeout(nsec) + } + return os.EINVAL; +} + +var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn. |