Plan 9 from Bell Labs’s /usr/web/sources/contrib/ericvh/go-plan9/src/pkg/websocket/client.go

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


// 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;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.