Browse Source

implement candidate compromise proposal for websockets

1. Text and binary frames are accepted
2. Text frames are sent by default
3. Binary frames are sent to clients who negotiate `binary.ircv3.net`
4. Non-UTF8 data is not accepted (enabling websockets still enables UTFONLY)
tags/v2.6.0-rc1
Shivaram Lingamneni 3 years ago
parent
commit
d547d05205
3 changed files with 17 additions and 12 deletions
  1. 1
    1
      irc/client.go
  2. 15
    10
      irc/ircconn.go
  3. 1
    1
      irc/listeners.go

+ 1
- 1
irc/client.go View File

@@ -691,7 +691,7 @@ func (client *Client) run(session *Session) {
691 691
 		} else if err != nil {
692 692
 			var quitMessage string
693 693
 			switch err {
694
-			case ircreader.ErrReadQ, errWSBinaryMessage:
694
+			case ircreader.ErrReadQ:
695 695
 				quitMessage = err.Error()
696 696
 			default:
697 697
 				quitMessage = "connection closed"

+ 15
- 10
irc/ircconn.go View File

@@ -5,7 +5,6 @@ package irc
5 5
 
6 6
 import (
7 7
 	"bytes"
8
-	"errors"
9 8
 	"net"
10 9
 	"unicode/utf8"
11 10
 
@@ -22,8 +21,7 @@ const (
22 21
 )
23 22
 
24 23
 var (
25
-	crlf               = []byte{'\r', '\n'}
26
-	errWSBinaryMessage = errors.New("WebSocket binary messages are unsupported")
24
+	crlf = []byte{'\r', '\n'}
27 25
 )
28 26
 
29 27
 // IRCConn abstracts away the distinction between a regular
@@ -90,11 +88,13 @@ func (cc *IRCStreamConn) Close() (err error) {
90 88
 
91 89
 // IRCWSConn is an IRCConn over a websocket.
92 90
 type IRCWSConn struct {
93
-	conn *websocket.Conn
91
+	conn   *websocket.Conn
92
+	binary bool
94 93
 }
95 94
 
96 95
 func NewIRCWSConn(conn *websocket.Conn) IRCWSConn {
97
-	return IRCWSConn{conn: conn}
96
+	binary := conn.Subprotocol() == "binary.ircv3.net"
97
+	return IRCWSConn{conn: conn, binary: binary}
98 98
 }
99 99
 
100 100
 func (wc IRCWSConn) UnderlyingConn() *utils.WrappedConn {
@@ -106,7 +106,11 @@ func (wc IRCWSConn) UnderlyingConn() *utils.WrappedConn {
106 106
 func (wc IRCWSConn) WriteLine(buf []byte) (err error) {
107 107
 	buf = bytes.TrimSuffix(buf, crlf)
108 108
 	// #1483: if we have websockets at all, then we're enforcing utf8
109
-	return wc.conn.WriteMessage(websocket.TextMessage, buf)
109
+	messageType := websocket.TextMessage
110
+	if wc.binary {
111
+		messageType = websocket.BinaryMessage
112
+	}
113
+	return wc.conn.WriteMessage(messageType, buf)
110 114
 }
111 115
 
112 116
 func (wc IRCWSConn) WriteLines(buffers [][]byte) (err error) {
@@ -122,11 +126,12 @@ func (wc IRCWSConn) WriteLines(buffers [][]byte) (err error) {
122 126
 func (wc IRCWSConn) ReadLine() (line []byte, err error) {
123 127
 	messageType, line, err := wc.conn.ReadMessage()
124 128
 	if err == nil {
125
-		if messageType == websocket.TextMessage {
126
-			return line, nil
127
-		} else {
128
-			return nil, errWSBinaryMessage
129
+		if messageType == websocket.BinaryMessage && globalUtf8EnforcementSetting {
130
+			if !utf8.Valid(line) {
131
+				return line, errInvalidUtf8
132
+			}
129 133
 		}
134
+		return line, nil
130 135
 	} else if err == websocket.ErrReadLimit {
131 136
 		return line, ircreader.ErrReadQ
132 137
 	} else {

+ 1
- 1
irc/listeners.go View File

@@ -166,7 +166,7 @@ func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) {
166 166
 			}
167 167
 			return false
168 168
 		},
169
-		Subprotocols: []string{"text.ircv3.net"},
169
+		Subprotocols: []string{"text.ircv3.net", "binary.ircv3.net"},
170 170
 	}
171 171
 
172 172
 	conn, err := wsUpgrader.Upgrade(w, r, nil)

Loading…
Cancel
Save