aboutsummaryrefslogtreecommitdiff
path: root/internal/net/conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/net/conn.go')
-rw-r--r--internal/net/conn.go37
1 files changed, 31 insertions, 6 deletions
diff --git a/internal/net/conn.go b/internal/net/conn.go
index e46031b..2fff0bc 100644
--- a/internal/net/conn.go
+++ b/internal/net/conn.go
@@ -24,21 +24,46 @@ type tcpConn struct {
func newTCPConn(conn net.Conn) *tcpConn {
return &tcpConn{
conn: conn,
- reader: bufio.NewReader(conn),
+ reader: bufio.NewReaderSize(conn, maxLineLength*4),
}
}
+// maxLineLength bounds how much of an incoming line is accepted. Longer
+// lines are drained from the socket and truncated so a client cannot grow
+// the read buffer without limit.
+const maxLineLength = 1024
+
func (t *tcpConn) ReadMessage() (string, error) {
- line, err := t.reader.ReadString('\n')
- if err != nil {
+ line, err := t.reader.ReadSlice('\n')
+ if err == bufio.ErrBufferFull {
+ // Copy the bounded prefix out of the reusable read buffer BEFORE
+ // draining the rest of the oversized line; further reads overwrite the
+ // buffer the slice points into.
+ prefixLen := len(line)
+ if prefixLen > maxLineLength {
+ prefixLen = maxLineLength
+ }
+ prefix := make([]byte, prefixLen)
+ copy(prefix, line[:prefixLen])
+ for {
+ _, err = t.reader.ReadSlice('\n')
+ if err == nil {
+ break
+ }
+ if err != bufio.ErrBufferFull {
+ return "", err
+ }
+ }
+ line = prefix
+ } else if err != nil {
return "", err
}
- line = strings.TrimRight(line, "\r\n")
- line = stripIAC(line)
+ text := strings.TrimRight(string(line), "\r\n")
+ text = stripIAC(text)
if t.echoOff {
t.conn.Write([]byte("\r\n"))
}
- return line, nil
+ return text, nil
}
func (t *tcpConn) Write(b []byte) (int, error) {