Skip to content
Snippets Groups Projects
Commit 8cedcb1d authored by ale's avatar ale
Browse files

Introduce a LineResponseWriter to the LineHandler interface

Modeled to follow the net/http ResponseWriter.
parent 3a0bd89b
No related branches found
No related tags found
No related merge requests found
package unix package unix
import ( import (
"bufio"
"context" "context"
"errors" "errors"
"io" "io"
...@@ -21,11 +22,6 @@ type Handler interface { ...@@ -21,11 +22,6 @@ type Handler interface {
ServeConnection(c net.Conn) ServeConnection(c net.Conn)
} }
// HandlerFunc is a function adapter for Handler.
type HandlerFunc func(net.Conn)
func (f HandlerFunc) ServeConnection(c net.Conn) { f(c) }
// SocketServer accepts connections on a UNIX socket, speaking the // SocketServer accepts connections on a UNIX socket, speaking the
// line-based wire protocol, and dispatches incoming requests to the // line-based wire protocol, and dispatches incoming requests to the
// wrapped Server. // wrapped Server.
...@@ -134,7 +130,22 @@ func (s *SocketServer) Serve() error { ...@@ -134,7 +130,22 @@ func (s *SocketServer) Serve() error {
// LineHandler is the handler for LineServer. // LineHandler is the handler for LineServer.
type LineHandler interface { type LineHandler interface {
ServeLine(context.Context, []byte) (string, error) ServeLine(context.Context, LineResponseWriter, []byte) error
}
// ErrCloseConnection must be returned by a LineHandler when we want
// to cleanly terminate the connection without raising an error.
var ErrCloseConnection = errors.New("close")
// LineResponseWriter writes a single-line response to the underlying
// connection.
type LineResponseWriter interface {
// WriteLine writes a response (which must include the
// line terminator).
WriteLine([]byte) error
// WriteLineCRLF writes a response and adds a line terminator.
WriteLineCRLF([]byte) error
} }
// LineServer implements a line-based text protocol. It satisfies the // LineServer implements a line-based text protocol. It satisfies the
...@@ -164,8 +175,32 @@ func NewLineServer(h LineHandler) *LineServer { ...@@ -164,8 +175,32 @@ func NewLineServer(h LineHandler) *LineServer {
} }
} }
var crlf = []byte{'\r', '\n'}
type lrWriter struct {
*bufio.Writer
}
func (w *lrWriter) WriteLine(data []byte) error {
if _, err := w.Writer.Write(data); err != nil {
return err
}
return w.Writer.Flush()
}
func (w *lrWriter) WriteLineCRLF(data []byte) error {
if _, err := w.Writer.Write(data); err != nil {
return err
}
if _, err := w.Writer.Write(crlf); err != nil {
return err
}
return w.Writer.Flush()
}
func (l *LineServer) ServeConnection(nc net.Conn) { func (l *LineServer) ServeConnection(nc net.Conn) {
c := textproto.NewConn(nc) c := textproto.NewConn(nc)
rw := &lrWriter{bufio.NewWriter(nc)}
for { for {
nc.SetReadDeadline(time.Now().Add(l.IdleTimeout)) nc.SetReadDeadline(time.Now().Add(l.IdleTimeout))
line, err := c.ReadLineBytes() line, err := c.ReadLineBytes()
...@@ -176,21 +211,20 @@ func (l *LineServer) ServeConnection(nc net.Conn) { ...@@ -176,21 +211,20 @@ func (l *LineServer) ServeConnection(nc net.Conn) {
break break
} }
// Create a context for the request and call the handler with it. // Create a context for the request and call the
// handler with it. Set a write deadline on the
// connection to allow the full RequestTimeout time to
// generate the response.
nc.SetWriteDeadline(time.Now().Add(l.RequestTimeout + l.WriteTimeout))
ctx, cancel := context.WithTimeout(context.Background(), l.RequestTimeout) ctx, cancel := context.WithTimeout(context.Background(), l.RequestTimeout)
response, err := l.handler.ServeLine(ctx, line) err = l.handler.ServeLine(ctx, rw, line)
cancel() cancel()
// Close the connection on error, or on empty response. // Close the connection on error, or on empty response.
if response != "" {
nc.SetWriteDeadline(time.Now().Add(l.WriteTimeout))
c.PrintfLine(response)
}
if err != nil { if err != nil {
log.Printf("request error: %v", err) if err != ErrCloseConnection {
break log.Printf("request error: %v", err)
} }
if response == "" {
break break
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment