Skip to content

Commit f804d2f

Browse files
authored
server: Improved error handling (#116)
* Factor error handling into seperate function * Rename error handler and change status for too many errors * Make error threshold a global const * Switches protocolError status codes to 500 5.5.1 * Patches too many invalid commands test Now matches the 500 code thrown by protocolError
1 parent 53ebaff commit f804d2f

File tree

2 files changed

+28
-20
lines changed

2 files changed

+28
-20
lines changed

conn.go

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import (
1717
"time"
1818
)
1919

20+
// Number of errors we'll tolerate per connection before closing. Defaults to 3.
21+
const errThreshold = 3
22+
2023
type ConnectionState struct {
2124
Hostname string
2225
LocalAddr net.Addr
@@ -25,11 +28,14 @@ type ConnectionState struct {
2528
}
2629

2730
type Conn struct {
28-
conn net.Conn
29-
text *textproto.Conn
30-
server *Server
31-
helo string
32-
nbrErrors int
31+
conn net.Conn
32+
text *textproto.Conn
33+
server *Server
34+
helo string
35+
36+
// Number of errors witnessed on this connection
37+
errCount int
38+
3339
session Session
3440
locker sync.Mutex
3541
binarymime bool
@@ -82,16 +88,6 @@ func (c *Conn) init() {
8288
c.text = textproto.NewConn(rwc)
8389
}
8490

85-
func (c *Conn) unrecognizedCommand(cmd string) {
86-
c.WriteResponse(500, EnhancedCode{5, 5, 2}, fmt.Sprintf("Syntax error, %v command unrecognized", cmd))
87-
88-
c.nbrErrors++
89-
if c.nbrErrors > 3 {
90-
c.WriteResponse(500, EnhancedCode{5, 5, 2}, "Too many unrecognized commands")
91-
c.Close()
92-
}
93-
}
94-
9591
// Commands are dispatched to the appropriate handler functions.
9692
func (c *Conn) handle(cmd string, arg string) {
9793
// If panic happens during command handling - send 421 response
@@ -107,7 +103,7 @@ func (c *Conn) handle(cmd string, arg string) {
107103
}()
108104

109105
if cmd == "" {
110-
c.WriteResponse(500, EnhancedCode{5, 5, 2}, "Speak up")
106+
c.protocolError(500, EnhancedCode{5, 5, 2}, "Speak up")
111107
return
112108
}
113109

@@ -148,14 +144,15 @@ func (c *Conn) handle(cmd string, arg string) {
148144
c.Close()
149145
case "AUTH":
150146
if c.server.AuthDisabled {
151-
c.unrecognizedCommand(cmd)
147+
c.protocolError(500, EnhancedCode{5, 5, 2}, "Syntax error, AUTH command unrecognized")
152148
} else {
153149
c.handleAuth(arg)
154150
}
155151
case "STARTTLS":
156152
c.handleStartTLS()
157153
default:
158-
c.unrecognizedCommand(cmd)
154+
msg := fmt.Sprintf("Syntax errors, %v command unrecognized", cmd)
155+
c.protocolError(500, EnhancedCode{5, 5, 2}, msg)
159156
}
160157
}
161158

@@ -222,6 +219,18 @@ func (c *Conn) authAllowed() bool {
222219
return !c.server.AuthDisabled && (isTLS || c.server.AllowInsecureAuth)
223220
}
224221

222+
// protocolError writes errors responses and closes the connection once too many
223+
// have occurred.
224+
func (c *Conn) protocolError(code int, ec EnhancedCode, msg string) {
225+
c.WriteResponse(code, ec, msg)
226+
227+
c.errCount++
228+
if c.errCount > errThreshold {
229+
c.WriteResponse(500, EnhancedCode{5, 5, 1}, "Too many errors. Quiting now")
230+
c.Close()
231+
}
232+
}
233+
225234
// GREET state -> waiting for HELO
226235
func (c *Conn) handleGreet(enhanced bool, arg string) {
227236
if !enhanced {

server.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,7 @@ func (s *Server) handleConn(c *Conn) error {
147147
if err == nil {
148148
cmd, arg, err := parseCmd(line)
149149
if err != nil {
150-
c.nbrErrors++
151-
c.WriteResponse(501, EnhancedCode{5, 5, 2}, "Bad command")
150+
c.protocolError(501, EnhancedCode{5, 5, 2}, "Bad command")
152151
continue
153152
}
154153

0 commit comments

Comments
 (0)