serve restic: Print actual listener address

This commit is contained in:
Matt Holt 2018-04-04 07:56:26 -06:00 committed by Nick Craig-Wood
parent 5b8977a053
commit e13f65b953
5 changed files with 80 additions and 15 deletions

View file

@ -72,8 +72,12 @@ func newServer(f fs.Fs, opt *httplib.Options) *server {
// serve runs the http server - doesn't return // serve runs the http server - doesn't return
func (s *server) serve() { func (s *server) serve() {
err := s.srv.Serve()
if err != nil {
fs.Errorf(s.f, "Opening listener: %v", err)
}
fs.Logf(s.f, "Serving on %s", s.srv.URL()) fs.Logf(s.f, "Serving on %s", s.srv.URL())
s.srv.Serve() s.srv.Wait()
} }
// handler reads incoming requests and dispatches them // handler reads incoming requests and dispatches them

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net"
"net/http" "net/http"
"time" "time"
@ -24,10 +25,11 @@ var Help = `
Use --addr to specify which IP address and port the server should Use --addr to specify which IP address and port the server should
listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all
IPs. By default it only listens on localhost. IPs. By default it only listens on localhost. You can use port
:0 to let the OS choose an available port.
If you set --addr to listen on a public or LAN accessible IP address If you set --addr to listen on a public or LAN accessible IP address
then using Authentication if advised - see the next section for info. then using Authentication is advised - see the next section for info.
--server-read-timeout and --server-write-timeout can be used to --server-read-timeout and --server-write-timeout can be used to
control the timeouts on the server. Note that this is the total time control the timeouts on the server. Note that this is the total time
@ -98,6 +100,8 @@ var DefaultOpt = Options{
type Server struct { type Server struct {
Opt Options Opt Options
handler http.Handler // original handler handler http.Handler // original handler
listener net.Listener
waitChan chan struct{} // for waiting on the listener to close
httpServer *http.Server httpServer *http.Server
basicPassHashed string basicPassHashed string
useSSL bool // if server is configured for SSL/TLS useSSL bool // if server is configured for SSL/TLS
@ -178,15 +182,52 @@ func NewServer(handler http.Handler, opt *Options) *Server {
return s return s
} }
// Serve runs the server - doesn't return // Serve runs the server - returns an error only if
func (s *Server) Serve() { // the listener was not started; does not block, so
// use s.Wait() to block on the listener indefinitely.
func (s *Server) Serve() error {
ln, err := net.Listen("tcp", s.httpServer.Addr)
if err != nil {
return err
}
s.listener = ln
s.waitChan = make(chan struct{})
go func() {
var err error var err error
if s.useSSL { if s.useSSL {
err = s.httpServer.ListenAndServeTLS(s.Opt.SslCert, s.Opt.SslKey) // hacky hack to get this to work with old Go versions, which
} else { // don't have ServeTLS on http.Server; see PR #2194.
err = s.httpServer.ListenAndServe() type tlsServer interface {
ServeTLS(ln net.Listener, cert, key string) error
} }
log.Printf("Error while serving HTTP: %v", err) srvIface := interface{}(s.httpServer)
if tlsSrv, ok := srvIface.(tlsServer); ok {
// yay -- we get easy TLS support with HTTP/2
err = tlsSrv.ServeTLS(s.listener, s.Opt.SslCert, s.Opt.SslKey)
} else {
// oh well -- we can still do TLS but might not have HTTP/2
tlsConfig := new(tls.Config)
tlsConfig.Certificates = make([]tls.Certificate, 1)
tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(s.Opt.SslCert, s.Opt.SslKey)
if err != nil {
log.Printf("Error loading key pair: %v", err)
}
tlsLn := tls.NewListener(s.listener, tlsConfig)
err = s.httpServer.Serve(tlsLn)
}
} else {
err = s.httpServer.Serve(s.listener)
}
if err != nil {
log.Printf("Error on serving HTTP server: %v", err)
}
}()
return nil
}
// Wait blocks while the listener is open.
func (s *Server) Wait() {
<-s.waitChan
} }
// Close shuts the running server down // Close shuts the running server down
@ -194,7 +235,9 @@ func (s *Server) Close() {
err := closeServer(s.httpServer) err := closeServer(s.httpServer)
if err != nil { if err != nil {
log.Printf("Error on closing HTTP server: %v", err) log.Printf("Error on closing HTTP server: %v", err)
return
} }
close(s.waitChan)
} }
// URL returns the serving address of this server // URL returns the serving address of this server
@ -203,5 +246,11 @@ func (s *Server) URL() string {
if s.useSSL { if s.useSSL {
proto = "https" proto = "https"
} }
return fmt.Sprintf("%s://%s/", proto, s.Opt.ListenAddr) addr := s.Opt.ListenAddr
if s.listener != nil {
// prefer actual listener address; required if using 0-port
// (i.e. port assigned by operating system)
addr = s.listener.Addr().String()
}
return fmt.Sprintf("%s://%s/", proto, addr)
} }

View file

@ -169,8 +169,12 @@ func newServer(f fs.Fs, opt *httplib.Options) *server {
// serve runs the http server - doesn't return // serve runs the http server - doesn't return
func (s *server) serve() { func (s *server) serve() {
err := s.srv.Serve()
if err != nil {
fs.Errorf(s.f, "Opening listener: %v", err)
}
fs.Logf(s.f, "Serving restic REST API on %s", s.srv.URL()) fs.Logf(s.f, "Serving restic REST API on %s", s.srv.URL())
s.srv.Serve() s.srv.Wait()
} }
var matchData = regexp.MustCompile("(?:^|/)data/([^/]{2,})$") var matchData = regexp.MustCompile("(?:^|/)data/([^/]{2,})$")

View file

@ -88,8 +88,12 @@ func newWebDAV(f fs.Fs, opt *httplib.Options) *WebDAV {
// serve runs the http server - doesn't return // serve runs the http server - doesn't return
func (w *WebDAV) serve() { func (w *WebDAV) serve() {
err := w.srv.Serve()
if err != nil {
fs.Errorf(w.f, "Opening listener: %v", err)
}
fs.Logf(w.f, "WebDav Server started on %s", w.srv.URL()) fs.Logf(w.f, "WebDav Server started on %s", w.srv.URL())
w.srv.Serve() w.srv.Wait()
} }
// logRequest is called by the webdav module on every request // logRequest is called by the webdav module on every request

View file

@ -58,8 +58,12 @@ func newServer(opt *Options) *server {
// serve runs the http server - doesn't return // serve runs the http server - doesn't return
func (s *server) serve() { func (s *server) serve() {
err := s.srv.Serve()
if err != nil {
fs.Errorf(nil, "Opening listener: %v", err)
}
fs.Logf(nil, "Serving remote control on %s", s.srv.URL()) fs.Logf(nil, "Serving remote control on %s", s.srv.URL())
s.srv.Serve() s.srv.Wait()
} }
// handler reads incoming requests and dispatches them // handler reads incoming requests and dispatches them