Create CLI option to bind to UNIX socket (#265)

This commit is contained in:
Rémy Sanchez 2019-05-12 23:12:28 +02:00 committed by Marius
parent 9d693c93a3
commit 966711019b
3 changed files with 66 additions and 4 deletions

View File

@ -8,6 +8,7 @@ import (
var Flags struct {
HttpHost string
HttpPort string
HttpSock string
MaxSize int64
UploadDir string
StoreSize int64
@ -16,7 +17,7 @@ var Flags struct {
S3Bucket string
S3ObjectPrefix string
S3Endpoint string
GCSBucket string
GCSBucket string
FileHooksDir string
HttpHooksEndpoint string
HttpHooksRetry int
@ -33,6 +34,7 @@ var Flags struct {
func ParseFlags() {
flag.StringVar(&Flags.HttpHost, "host", "0.0.0.0", "Host to bind HTTP server to")
flag.StringVar(&Flags.HttpPort, "port", "1080", "Port to bind HTTP server to")
flag.StringVar(&Flags.HttpSock, "unix-sock", "", "If set, will listen to a UNIX socket at this location instead of a TCP socket")
flag.Int64Var(&Flags.MaxSize, "max-size", 0, "Maximum size of a single upload in bytes")
flag.StringVar(&Flags.UploadDir, "dir", "./data", "Directory to store uploads in")
flag.Int64Var(&Flags.StoreSize, "store-size", 0, "Size of space allowed for storage")

View File

@ -1,7 +1,9 @@
package cli
import (
"errors"
"net"
"os"
"time"
)
@ -98,3 +100,40 @@ func NewListener(addr string, readTimeout, writeTimeout time.Duration) (net.List
}
return tl, nil
}
// Binds to a UNIX socket. If the file already exists, try to remove it before
// binding again. This logic is borrowed from Gunicorn
// (see https://github.com/benoitc/gunicorn/blob/a8963ef1a5a76f3df75ce477b55fe0297e3b617d/gunicorn/sock.py#L106)
func NewUnixListener(path string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
stat, err := os.Stat(path)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
} else {
if stat.Mode()&os.ModeSocket != 0 {
err = os.Remove(path)
if err != nil {
return nil, err
}
} else {
return nil, errors.New("specified path is not a socket")
}
}
l, err := net.Listen("unix", path)
if err != nil {
return nil, err
}
tl := &Listener{
Listener: l,
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
}
return tl, nil
}

View File

@ -1,12 +1,19 @@
package cli
import (
"net"
"net/http"
"time"
"github.com/tus/tusd"
)
// Setups the different components, starts a Listener and give it to
// http.Serve().
//
// By default it will bind to the specified host/port, unless a UNIX socket is
// specified, in which case a different socket creation and binding mechanism
// is put in place.
func Serve() {
SetupPreHooks(Composer)
@ -24,10 +31,17 @@ func Serve() {
stderr.Fatalf("Unable to create handler: %s", err)
}
address := Flags.HttpHost + ":" + Flags.HttpPort
basepath := Flags.Basepath
address := ""
if Flags.HttpSock != "" {
address = Flags.HttpSock
stdout.Printf("Using %s as socket to listen.\n", address)
} else {
address = Flags.HttpHost + ":" + Flags.HttpPort
stdout.Printf("Using %s as address to listen.\n", address)
}
stdout.Printf("Using %s as address to listen.\n", address)
stdout.Printf("Using %s as the base path.\n", basepath)
SetupPostHooks(handler)
@ -47,8 +61,15 @@ func Serve() {
http.Handle(basepath, http.StripPrefix(basepath, handler))
var listener net.Listener
timeoutDuration := time.Duration(Flags.Timeout) * time.Millisecond
listener, err := NewListener(address, timeoutDuration, timeoutDuration)
if Flags.HttpSock != "" {
listener, err = NewUnixListener(address, timeoutDuration, timeoutDuration)
} else {
listener, err = NewListener(address, timeoutDuration, timeoutDuration)
}
if err != nil {
stderr.Fatalf("Unable to create listener: %s", err)
}