|
@@ -5,6 +5,7 @@ package irc
|
5
|
5
|
|
6
|
6
|
import (
|
7
|
7
|
"bytes"
|
|
8
|
+ "io"
|
8
|
9
|
"net"
|
9
|
10
|
"unicode/utf8"
|
10
|
11
|
|
|
@@ -93,21 +94,25 @@ func (cc *IRCStreamConn) Close() (err error) {
|
93
|
94
|
// IRCWSConn is an IRCConn over a websocket.
|
94
|
95
|
type IRCWSConn struct {
|
95
|
96
|
conn *websocket.Conn
|
|
97
|
+ buf []byte
|
96
|
98
|
binary bool
|
97
|
99
|
}
|
98
|
100
|
|
99
|
|
-func NewIRCWSConn(conn *websocket.Conn) IRCWSConn {
|
100
|
|
- binary := conn.Subprotocol() == "binary.ircv3.net"
|
101
|
|
- return IRCWSConn{conn: conn, binary: binary}
|
|
101
|
+func NewIRCWSConn(conn *websocket.Conn) *IRCWSConn {
|
|
102
|
+ return &IRCWSConn{
|
|
103
|
+ conn: conn,
|
|
104
|
+ binary: conn.Subprotocol() == "binary.ircv3.net",
|
|
105
|
+ buf: make([]byte, maxReadQBytes()),
|
|
106
|
+ }
|
102
|
107
|
}
|
103
|
108
|
|
104
|
|
-func (wc IRCWSConn) UnderlyingConn() *utils.WrappedConn {
|
|
109
|
+func (wc *IRCWSConn) UnderlyingConn() *utils.WrappedConn {
|
105
|
110
|
// just assume that the type is OK
|
106
|
111
|
wConn, _ := wc.conn.UnderlyingConn().(*utils.WrappedConn)
|
107
|
112
|
return wConn
|
108
|
113
|
}
|
109
|
114
|
|
110
|
|
-func (wc IRCWSConn) WriteLine(buf []byte) (err error) {
|
|
115
|
+func (wc *IRCWSConn) WriteLine(buf []byte) (err error) {
|
111
|
116
|
buf = bytes.TrimSuffix(buf, crlf)
|
112
|
117
|
// #1483: if we have websockets at all, then we're enforcing utf8
|
113
|
118
|
messageType := websocket.TextMessage
|
|
@@ -117,7 +122,7 @@ func (wc IRCWSConn) WriteLine(buf []byte) (err error) {
|
117
|
122
|
return wc.conn.WriteMessage(messageType, buf)
|
118
|
123
|
}
|
119
|
124
|
|
120
|
|
-func (wc IRCWSConn) WriteLines(buffers [][]byte) (err error) {
|
|
125
|
+func (wc *IRCWSConn) WriteLines(buffers [][]byte) (err error) {
|
121
|
126
|
for _, buf := range buffers {
|
122
|
127
|
err = wc.WriteLine(buf)
|
123
|
128
|
if err != nil {
|
|
@@ -127,20 +132,35 @@ func (wc IRCWSConn) WriteLines(buffers [][]byte) (err error) {
|
127
|
132
|
return
|
128
|
133
|
}
|
129
|
134
|
|
130
|
|
-func (wc IRCWSConn) ReadLine() (line []byte, err error) {
|
131
|
|
- messageType, line, err := wc.conn.ReadMessage()
|
132
|
|
- if err == nil {
|
|
135
|
+func (wc *IRCWSConn) ReadLine() (line []byte, err error) {
|
|
136
|
+ messageType, reader, err := wc.conn.NextReader()
|
|
137
|
+ switch err {
|
|
138
|
+ case nil:
|
|
139
|
+ // OK
|
|
140
|
+ case websocket.ErrReadLimit:
|
|
141
|
+ return line, ircreader.ErrReadQ
|
|
142
|
+ default:
|
|
143
|
+ return line, err
|
|
144
|
+ }
|
|
145
|
+
|
|
146
|
+ n, err := io.ReadFull(reader, wc.buf)
|
|
147
|
+ line = wc.buf[:n]
|
|
148
|
+ switch err {
|
|
149
|
+ case io.ErrUnexpectedEOF, io.EOF:
|
|
150
|
+ // these are OK. io.ErrUnexpectedEOF is the good case:
|
|
151
|
+ // it means we read the full message and it consumed less than the full wc.buf
|
133
|
152
|
if messageType == websocket.BinaryMessage && !utf8.Valid(line) {
|
134
|
153
|
return line, errInvalidUtf8
|
135
|
154
|
}
|
136
|
155
|
return line, nil
|
137
|
|
- } else if err == websocket.ErrReadLimit {
|
|
156
|
+ case nil, websocket.ErrReadLimit:
|
|
157
|
+ // nil means we filled wc.buf without exhausting the reader:
|
138
|
158
|
return line, ircreader.ErrReadQ
|
139
|
|
- } else {
|
|
159
|
+ default:
|
140
|
160
|
return line, err
|
141
|
161
|
}
|
142
|
162
|
}
|
143
|
163
|
|
144
|
|
-func (wc IRCWSConn) Close() (err error) {
|
|
164
|
+func (wc *IRCWSConn) Close() (err error) {
|
145
|
165
|
return wc.conn.Close()
|
146
|
166
|
}
|