diff options
Diffstat (limited to 'internal/net/conn.go')
| -rw-r--r-- | internal/net/conn.go | 37 |
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) { |
