summaryrefslogtreecommitdiff
path: root/src/pkg/websocket/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/websocket/client.go')
-rw-r--r--src/pkg/websocket/client.go136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
new file mode 100644
index 000000000..bedaec02f
--- /dev/null
+++ b/src/pkg/websocket/client.go
@@ -0,0 +1,136 @@
+// 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.
+
+package websocket
+
+import (
+ "bufio";
+ "http";
+ "io";
+ "net";
+ "os";
+)
+
+type ProtocolError struct {
+ os.ErrorString;
+}
+
+var (
+ ErrBadStatus = &ProtocolError{"bad status"};
+ ErrNoUpgrade = &ProtocolError{"no upgrade"};
+ ErrBadUpgrade = &ProtocolError{"bad upgrade"};
+ ErrNoWebSocketOrigin = &ProtocolError{"no WebSocket-Origin"};
+ ErrBadWebSocketOrigin = &ProtocolError{"bad WebSocket-Origin"};
+ ErrNoWebSocketLocation = &ProtocolError{"no WebSocket-Location"};
+ ErrBadWebSocketLocation = &ProtocolError{"bad WebSocket-Location"};
+ ErrNoWebSocketProtocol = &ProtocolError{"no WebSocket-Protocol"};
+ ErrBadWebSocketProtocol = &ProtocolError{"bad WebSocket-Protocol"};
+)
+
+// newClient creates a new Web Socket client connection.
+func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser) (ws *Conn, err os.Error) {
+ br := bufio.NewReader(rwc);
+ bw := bufio.NewWriter(rwc);
+ err = handshake(resourceName, host, origin, location, protocol, br, bw);
+ if err != nil {
+ return
+ }
+ buf := bufio.NewReadWriter(br, bw);
+ ws = newConn(origin, location, protocol, buf, rwc);
+ return;
+}
+
+// Dial opens new Web Socket client connection.
+//
+// A trivial example client is:
+//
+// package main
+//
+// import (
+// "websocket"
+// "strings"
+// )
+//
+// func main() {
+// ws, err := websocket.Dial("ws://localhost/ws", "", "http://localhost/");
+// if err != nil {
+// panic("Dial: ", err.String())
+// }
+// if _, err := ws.Write(strings.Bytes("hello, world!\n")); err != nil {
+// panic("Write: ", err.String())
+// }
+// var msg = make([]byte, 512);
+// if n, err := ws.Read(msg); err != nil {
+// panic("Read: ", err.String())
+// }
+// // msg[0:n]
+// }
+
+func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
+ parsedUrl, err := http.ParseURL(url);
+ if err != nil {
+ return
+ }
+ client, err := net.Dial("tcp", "", parsedUrl.Host);
+ if err != nil {
+ return
+ }
+ return newClient(parsedUrl.Path, parsedUrl.Host, origin, url, protocol, client);
+}
+
+func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+ bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n");
+ bw.WriteString("Upgrade: WebSocket\r\n");
+ bw.WriteString("Connection: Upgrade\r\n");
+ bw.WriteString("Host: " + host + "\r\n");
+ bw.WriteString("Origin: " + origin + "\r\n");
+ if protocol != "" {
+ bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ bw.WriteString("\r\n");
+ bw.Flush();
+ resp, err := http.ReadResponse(br);
+ if err != nil {
+ return
+ }
+ if resp.Status != "101 Web Socket Protocol Handshake" {
+ return ErrBadStatus
+ }
+ upgrade, found := resp.Header["Upgrade"];
+ if !found {
+ return ErrNoUpgrade
+ }
+ if upgrade != "WebSocket" {
+ return ErrBadUpgrade
+ }
+ connection, found := resp.Header["Connection"];
+ if !found || connection != "Upgrade" {
+ return ErrBadUpgrade
+ }
+
+ ws_origin, found := resp.Header["Websocket-Origin"];
+ if !found {
+ return ErrNoWebSocketOrigin
+ }
+ if ws_origin != origin {
+ return ErrBadWebSocketOrigin
+ }
+ ws_location, found := resp.Header["Websocket-Location"];
+ if !found {
+ return ErrNoWebSocketLocation
+ }
+ if ws_location != location {
+ return ErrBadWebSocketLocation
+ }
+ if protocol != "" {
+ ws_protocol, found := resp.Header["Websocket-Protocol"];
+ if !found {
+ return ErrNoWebSocketProtocol
+ }
+ if ws_protocol != protocol {
+ return ErrBadWebSocketProtocol
+ }
+ }
+ return;
+}