Commit 66f3bb51 authored by ale's avatar ale
Browse files

Update unix.LineHandler interface

parent 7bc37e1c
Pipeline #712 passed with stages
in 1 minute
......@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"git.autistici.org/ai3/go-common/unix"
"git.autistici.org/id/auth"
)
......@@ -25,7 +26,7 @@ func NewSocketServer(authServer *Server) *SocketServer {
}
}
func (s *SocketServer) ServeLine(ctx context.Context, line []byte) (string, error) {
func (s *SocketServer) ServeLine(ctx context.Context, lw unix.LineResponseWriter, line []byte) error {
// Parse the incoming command. The only two known
// commands are 'auth' for an authentication request,
// and 'quit' to terminate the connection (closing the
......@@ -36,21 +37,21 @@ func (s *SocketServer) ServeLine(ctx context.Context, line []byte) (string, erro
cmd := string(parts[0])
switch {
case nargs == 1 && cmd == "quit":
return "", nil
return unix.ErrCloseConnection
case nargs == 2 && cmd == "auth":
return s.handleAuth(ctx, parts[1])
return s.handleAuth(ctx, lw, parts[1])
default:
return "", errors.New("syntax error")
return errors.New("syntax error")
}
}
func (s *SocketServer) handleAuth(ctx context.Context, arg []byte) (string, error) {
func (s *SocketServer) handleAuth(ctx context.Context, lw unix.LineResponseWriter, arg []byte) error {
var req auth.Request
if err := s.codec.Decode(arg, &req); err != nil {
return "", fmt.Errorf("decoding error: %v", err)
return fmt.Errorf("decoding error: %v", err)
}
resp := s.auth.Authenticate(ctx, &req)
return string(s.codec.Encode(resp)), nil
return lw.WriteLineCRLF(s.codec.Encode(resp))
}
package unix
import (
"bufio"
"context"
"errors"
"io"
......@@ -21,11 +22,6 @@ type Handler interface {
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
// line-based wire protocol, and dispatches incoming requests to the
// wrapped Server.
......@@ -134,7 +130,22 @@ func (s *SocketServer) Serve() error {
// LineHandler is the handler for LineServer.
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
......@@ -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) {
c := textproto.NewConn(nc)
rw := &lrWriter{bufio.NewWriter(nc)}
for {
nc.SetReadDeadline(time.Now().Add(l.IdleTimeout))
line, err := c.ReadLineBytes()
......@@ -176,21 +211,20 @@ func (l *LineServer) ServeConnection(nc net.Conn) {
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)
response, err := l.handler.ServeLine(ctx, line)
err = l.handler.ServeLine(ctx, rw, line)
cancel()
// Close the connection on error, or on empty response.
if response != "" {
nc.SetWriteDeadline(time.Now().Add(l.WriteTimeout))
c.PrintfLine(response)
}
if err != nil {
log.Printf("request error: %v", err)
break
}
if response == "" {
if err != ErrCloseConnection {
log.Printf("request error: %v", err)
}
break
}
}
......
......@@ -5,8 +5,8 @@
{
"checksumSHA1": "raJx5BjBbVQG0ylGSjPpi+JvqjU=",
"path": "git.autistici.org/ai3/go-common",
"revision": "3a0bd89b95cb0c323a1e067f085f72467063ed31",
"revisionTime": "2017-12-16T11:26:05Z"
"revision": "8cedcb1d73128f5566216cb3e39ad1ccea318213",
"revisionTime": "2017-12-16T15:39:23Z"
},
{
"checksumSHA1": "jFlhSIit/5+VAIUu1cc7EVVlw0M=",
......@@ -21,10 +21,10 @@
"revisionTime": "2017-12-10T11:04:55Z"
},
{
"checksumSHA1": "hi5IyuRelE5KfRjd1ZOZMe0U5h8=",
"checksumSHA1": "T2vf4xzKRqoIjfXlofMgudKA8rA=",
"path": "git.autistici.org/ai3/go-common/unix",
"revision": "3a0bd89b95cb0c323a1e067f085f72467063ed31",
"revisionTime": "2017-12-16T11:26:05Z"
"revision": "8cedcb1d73128f5566216cb3e39ad1ccea318213",
"revisionTime": "2017-12-16T15:39:23Z"
},
{
"checksumSHA1": "7Kbb9vTjqcQhhxtSGpmp9rk6PUk=",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment