When HTTP listening address starts with unix: and contains /, listen at given path instead of a TCP socket. TLS or AutoTLS will not work since there is no TLS layer when using the unix domain socket.
This commit is contained in:
parent
77b5996640
commit
2bf50082f5
|
@ -3,6 +3,7 @@ package commands
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -32,6 +33,15 @@ func statusAction(ctx *cli.Context) error {
|
|||
// interrupt reading of the Response.Body.
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
|
||||
// make a dial function for unix socket
|
||||
if unixSocketPath := conf.HttpHostAsSocketPath(); unixSocketPath != "" {
|
||||
client.Transport = &http.Transport{
|
||||
Dial: func(network, addr string) (net.Conn, error) {
|
||||
return net.Dial("unix", unixSocketPath)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d/api/v1/status", conf.HttpHost(), conf.HttpPort())
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
|
|
|
@ -104,7 +104,8 @@ func (c *Config) HttpCachePublic() bool {
|
|||
|
||||
// HttpHost returns the built-in HTTP server host name or IP address (empty for all interfaces).
|
||||
func (c *Config) HttpHost() string {
|
||||
if c.options.HttpHost == "" {
|
||||
// when unix socket used as host, make host as default value. or http client will act weirdly.
|
||||
if c.options.HttpHost == "" || c.HttpHostAsSocketPath() != "" {
|
||||
return "0.0.0.0"
|
||||
}
|
||||
|
||||
|
@ -120,6 +121,15 @@ func (c *Config) HttpPort() int {
|
|||
return c.options.HttpPort
|
||||
}
|
||||
|
||||
// HttpHostAsSocketPath tries to parse the HttpHost as unix socket path. If failed, return empty string.
|
||||
func (c *Config) HttpHostAsSocketPath() string {
|
||||
host := c.options.HttpHost
|
||||
if strings.HasPrefix(host, "unix:") && strings.Contains(host, "/") {
|
||||
return strings.TrimPrefix(host, "unix:")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TemplatesPath returns the server templates path.
|
||||
func (c *Config) TemplatesPath() string {
|
||||
return filepath.Join(c.AssetsPath(), "templates")
|
||||
|
|
|
@ -8,12 +8,22 @@ import (
|
|||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
)
|
||||
|
||||
func TestConfig_HttpHostAsSocketPath(t *testing.T) {
|
||||
c := NewConfig(CliTestContext())
|
||||
|
||||
assert.Equal(t, "", c.HttpHostAsSocketPath())
|
||||
c.options.HttpHost = "unix:/tmp/photoprism.sock"
|
||||
assert.Equal(t, "/tmp/photoprism.sock", c.HttpHostAsSocketPath())
|
||||
}
|
||||
|
||||
func TestConfig_HttpServerHost2(t *testing.T) {
|
||||
c := NewConfig(CliTestContext())
|
||||
|
||||
assert.Equal(t, "0.0.0.0", c.HttpHost())
|
||||
c.options.HttpHost = "test"
|
||||
assert.Equal(t, "test", c.HttpHost())
|
||||
c.options.HttpHost = "unix:/tmp/photoprism.sock"
|
||||
assert.Equal(t, "0.0.0.0", c.HttpHost())
|
||||
}
|
||||
|
||||
func TestConfig_HttpServerPort2(t *testing.T) {
|
||||
|
|
|
@ -503,7 +503,7 @@ var Flags = CliFlags{
|
|||
}}, {
|
||||
Flag: cli.StringFlag{
|
||||
Name: "http-host, ip",
|
||||
Usage: "Web server `IP` address",
|
||||
Usage: "Web server `IP` address. If start with unix:, path followed is treated as unix socket path for listening.",
|
||||
EnvVar: EnvVar("HTTP_HOST"),
|
||||
}}, {
|
||||
Flag: cli.IntFlag{
|
||||
|
|
|
@ -16,6 +16,8 @@ func AutoTLS(conf *config.Config) (*autocert.Manager, error) {
|
|||
// Enable automatic HTTPS via Let's Encrypt?
|
||||
if !conf.SiteHttps() {
|
||||
return nil, fmt.Errorf("disabled tls")
|
||||
} else if conf.HttpHostAsSocketPath() != "" {
|
||||
return nil, fmt.Errorf("unix socket not work with auto https")
|
||||
} else if siteDomain = conf.SiteDomain(); !strings.Contains(siteDomain, ".") {
|
||||
return nil, fmt.Errorf("fully qualified domain required to enable tls")
|
||||
} else if tlsEmail = conf.TLSEmail(); tlsEmail == "" {
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
|
@ -86,6 +87,9 @@ func Start(ctx context.Context, conf *config.Config) {
|
|||
go StartAutoTLS(server, tlsManager, conf)
|
||||
} else if publicCert, privateKey := conf.TLS(); publicCert != "" && privateKey != "" {
|
||||
log.Infof("server: starting in tls mode")
|
||||
if unixSocketPath := conf.HttpHostAsSocketPath(); unixSocketPath != "" {
|
||||
log.Errorf("both unix socket and tls cert provided")
|
||||
}
|
||||
server = &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", conf.HttpHost(), conf.HttpPort()),
|
||||
Handler: router,
|
||||
|
@ -94,12 +98,30 @@ func Start(ctx context.Context, conf *config.Config) {
|
|||
go StartTLS(server, publicCert, privateKey)
|
||||
} else {
|
||||
log.Infof("server: %s", tlsErr)
|
||||
var listener net.Listener
|
||||
var listenPath string
|
||||
var err error
|
||||
if unixSocketPath := conf.HttpHostAsSocketPath(); unixSocketPath != "" {
|
||||
var unixAddr *net.UnixAddr
|
||||
unixAddr, err = net.ResolveUnixAddr("unix", unixSocketPath)
|
||||
if err != nil {
|
||||
log.Errorf("server: resolve unix address failed (%s)", err)
|
||||
}
|
||||
listenPath = unixSocketPath
|
||||
listener, err = net.ListenUnix("unix", unixAddr)
|
||||
} else {
|
||||
listenPath = fmt.Sprintf("%s:%d", conf.HttpHost(), conf.HttpPort())
|
||||
listener, err = net.Listen("tcp", listenPath)
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("server: listen unix address failed (%s)", err)
|
||||
}
|
||||
server = &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", conf.HttpHost(), conf.HttpPort()),
|
||||
Addr: listenPath,
|
||||
Handler: router,
|
||||
}
|
||||
log.Infof("server: listening on %s [%s]", server.Addr, time.Since(start))
|
||||
go StartHttp(server)
|
||||
log.Infof("server: listening on %s [%s]", listenPath, time.Since(start))
|
||||
go StartHttp(server, listener)
|
||||
}
|
||||
|
||||
// Graceful HTTP server shutdown.
|
||||
|
@ -112,8 +134,8 @@ func Start(ctx context.Context, conf *config.Config) {
|
|||
}
|
||||
|
||||
// StartHttp starts the web server in http mode.
|
||||
func StartHttp(s *http.Server) {
|
||||
if err := s.ListenAndServe(); err != nil {
|
||||
func StartHttp(s *http.Server, l net.Listener) {
|
||||
if err := s.Serve(l); err != nil {
|
||||
if err == http.ErrServerClosed {
|
||||
log.Info("server: shutdown complete")
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue