From 87b05a88c1931becb2f99c29710398a412fd8158 Mon Sep 17 00:00:00 2001 From: Alan Norton Date: Thu, 29 Oct 2020 08:28:21 -0400 Subject: [PATCH] add `no-serve-public-paths` flag (#262) * allow config to ignore static paths inside /public, upgrade ci add static files to try to resolve but ignore add configuration for linux and macos add field broken impl. clean up bad impl if request path should be ignored by the static server, don't serve it forgotten flag rename slightly better description upgrades * Add logging of no-serve-public-paths and add -install support for it (#263) * Add logging of no-serve-public-paths settings * Add the NoServePublicPaths settings to the plist template * Fix missing , causing test failures Co-authored-by: Pez Cuckow --- .github/workflows/ci.yml | 4 +-- Makefile | 10 ++++++- cmd/puma-dev/main_darwin.go | 7 +++++ cmd/puma-dev/main_darwin_test.go | 11 ++++---- cmd/puma-dev/main_linux.go | 21 +++++++++------ cmd/puma-dev/main_linux_test.go | 7 ++--- cmd/puma-dev/main_test.go | 14 ++++++++++ dev/http.go | 36 ++++++++++++++++++++----- dev/setup_darwin.go | 5 +++- dev/setup_darwin_test.go | 2 ++ etc/static-hi-puma/public/config.json | 3 +++ etc/static-hi-puma/public/packs/site.js | 1 + 12 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 etc/static-hi-puma/public/config.json create mode 100644 etc/static-hi-puma/public/packs/site.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f89e90d..16168136 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest] - go-version: [1.13.x, 1.14.x] - ruby-version: [2.5] + go-version: [1.14, 1.15] + ruby-version: [2.7] name: ${{ matrix.os }} / go-${{ matrix.go-version }} steps: diff --git a/Makefile b/Makefile index fd1cdcbe..79f26754 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,14 @@ release: test: go test -v -race -coverprofile=coverage.out -covermode=atomic ./... +clean-test: + rm -rf ~/.gotest-macos-puma-dev + +test-macos-filesystem-setup: + sudo mkdir -p /etc/resolver; + sudo chmod 0775 /etc/resolver; + sudo chown :staff /etc/resolver; + coverage: test go tool cover -html=coverage.out -o coverage.html @@ -50,4 +58,4 @@ test-macos-manual-setup-install: clean build test -f "$$HOME/Library/Logs/puma-dev.log" test 'Hi Puma!' == "$$(curl -s https://rack-hi-puma.puma)" && echo "PASS" -.PHONY: all release +.PHONY: release diff --git a/cmd/puma-dev/main_darwin.go b/cmd/puma-dev/main_darwin.go index 6a75e1a2..1d730ee3 100644 --- a/cmd/puma-dev/main_darwin.go +++ b/cmd/puma-dev/main_darwin.go @@ -25,6 +25,8 @@ var ( fPow = flag.Bool("pow", false, "Mimic pow's settings") fLaunch = flag.Bool("launchd", false, "Use socket from launchd") + fNoServePublicPaths = flag.String("no-serve-public-paths", "", "Disable static file server for specific paths under /public") + fSetup = flag.Bool("setup", false, "Run system setup") fStop = flag.Bool("stop", false, "Stop all puma-dev servers") @@ -78,6 +80,7 @@ func main() { LogfilePath: LogFilePath, Timeout: (*fTimeout).String(), TlsPort: *fInstallTLS, + NoServePublicPaths: *fNoServePublicPaths, }) if err != nil { @@ -176,6 +179,10 @@ func main() { http.Pool = &pool http.Debug = *fDebug http.Events = &events + if len(*fNoServePublicPaths) > 0 { + http.IgnoredStaticPaths = strings.Split(*fNoServePublicPaths, ":") + fmt.Printf("* Ignoring files under: public{%s}\n", strings.Join(http.IgnoredStaticPaths, ", ")) + } http.Setup() diff --git a/cmd/puma-dev/main_darwin_test.go b/cmd/puma-dev/main_darwin_test.go index 0146401b..7d023a5c 100644 --- a/cmd/puma-dev/main_darwin_test.go +++ b/cmd/puma-dev/main_darwin_test.go @@ -24,11 +24,12 @@ func TestMainPumaDev_Darwin(t *testing.T) { defer linkAllTestApps(t, appLinkDir)() serveErr := configureAndBootPumaDevServer(t, map[string]string{ - "d": "test:puma", - "dir": appLinkDir, - "dns-port": "65053", - "http-port": "65080", - "https-port": "65443", + "d": "test:puma", + "dir": appLinkDir, + "dns-port": "65053", + "http-port": "65080", + "https-port": "65443", + "no-serve-public-paths": "/packs:/config.json", }) assert.NoError(t, serveErr) diff --git a/cmd/puma-dev/main_linux.go b/cmd/puma-dev/main_linux.go index 7d183be8..1c1e5be9 100644 --- a/cmd/puma-dev/main_linux.go +++ b/cmd/puma-dev/main_linux.go @@ -15,14 +15,15 @@ import ( ) var ( - fDebug = flag.Bool("debug", false, "enable debug output") - fDomains = flag.String("d", "test", "domains to handle, separate with :, defaults to test") - fHTTPPort = flag.Int("http-port", 9280, "port to listen on http for") - fTLSPort = flag.Int("https-port", 9283, "port to listen on https for") - fSysBind = flag.Bool("sysbind", false, "bind to ports 80 and 443") - fDir = flag.String("dir", "~/.puma-dev", "directory to watch for apps") - fTimeout = flag.Duration("timeout", 15*60*time.Second, "how long to let an app idle for") - fStop = flag.Bool("stop", false, "Stop all puma-dev servers") + fDebug = flag.Bool("debug", false, "enable debug output") + fDir = flag.String("dir", "~/.puma-dev", "directory to watch for apps") + fDomains = flag.String("d", "test", "domains to handle, separate with :, defaults to test") + fHTTPPort = flag.Int("http-port", 9280, "port to listen on http for") + fNoServePublicPaths = flag.String("no-serve-public-paths", "", "Disable static file server for specific paths under /public") + fStop = flag.Bool("stop", false, "Stop all puma-dev servers") + fSysBind = flag.Bool("sysbind", false, "bind to ports 80 and 443") + fTimeout = flag.Duration("timeout", 15*60*time.Second, "how long to let an app idle for") + fTLSPort = flag.Int("https-port", 9283, "port to listen on https for") ) func main() { @@ -99,6 +100,10 @@ func main() { http.Pool = &pool http.Debug = *fDebug http.Events = &events + if len(*fNoServePublicPaths) > 0 { + http.IgnoredStaticPaths = strings.Split(*fNoServePublicPaths, ":") + fmt.Printf("* Ignoring files under: public{%s}\n", strings.Join(http.IgnoredStaticPaths, ", ")) + } http.Setup() diff --git a/cmd/puma-dev/main_linux_test.go b/cmd/puma-dev/main_linux_test.go index 96410747..dd288a08 100644 --- a/cmd/puma-dev/main_linux_test.go +++ b/cmd/puma-dev/main_linux_test.go @@ -12,9 +12,10 @@ func TestMainPumaDev_Linux(t *testing.T) { defer linkAllTestApps(t, appLinkDir)() configureAndBootPumaDevServer(t, map[string]string{ - "dir": appLinkDir, - "http-port": "65080", - "https-port": "65443", + "dir": appLinkDir, + "http-port": "65080", + "https-port": "65443", + "no-serve-public-paths": "/packs:/config", }) runPlatformAgnosticTestScenarios(t) diff --git a/cmd/puma-dev/main_test.go b/cmd/puma-dev/main_test.go index 4854e37e..2cab7460 100644 --- a/cmd/puma-dev/main_test.go +++ b/cmd/puma-dev/main_test.go @@ -296,4 +296,18 @@ func runPlatformAgnosticTestScenarios(t *testing.T) { assert.Equal(t, "rack wuz here", getURLWithHost(t, reqURL, statusHost)) }) + + t.Run("static-site ignore packs", func(t *testing.T) { + reqURL := fmt.Sprintf("http://localhost:%d/packs/site.js", *fHTTPPort) + statusHost := "static-site" + + assert.Equal(t, "rack wuz here", getURLWithHost(t, reqURL, statusHost)) + }) + + t.Run("static-site ignore config", func(t *testing.T) { + reqURL := fmt.Sprintf("http://localhost:%d/config.json", *fHTTPPort) + statusHost := "static-site" + + assert.Equal(t, "rack wuz here", getURLWithHost(t, reqURL, statusHost)) + }) } diff --git a/dev/http.go b/dev/http.go index 40509431..7446f6c3 100644 --- a/dev/http.go +++ b/dev/http.go @@ -18,11 +18,12 @@ import ( ) type HTTPServer struct { - Address string - TLSAddress string - Pool *AppPool - Debug bool - Events *Events + Address string + TLSAddress string + Pool *AppPool + Debug bool + Events *Events + IgnoredStaticPaths []string mux *pat.PatternServeMux transport *httpu.Transport @@ -147,7 +148,7 @@ func (h *HTTPServer) proxyReq(w http.ResponseWriter, req *http.Request) error { return err } - if app.Public && req.URL.Path != "/" { + if h.shouldServePublicPathForApp(app, req) { safeURLPath := path.Clean(req.URL.Path) path := filepath.Join(app.dir, "public", safeURLPath) @@ -178,6 +179,29 @@ func (h *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { } } +func (h *HTTPServer) shouldServePublicPathForApp(a *App, req *http.Request) bool { + reqPath := path.Clean(req.URL.Path) + + if !a.Public { + return false + } + + if reqPath == "/" { + return false + } + + for _, ignoredPath := range h.IgnoredStaticPaths { + if strings.HasPrefix(reqPath, ignoredPath) { + if h.Debug { + fmt.Fprintf(os.Stdout, "Not serving '%s' as it matches a path in no-serve-public-paths\n", reqPath) + } + return false + } + } + + return true +} + func (h *HTTPServer) status(w http.ResponseWriter, req *http.Request) { type appStatus struct { Scheme string `json:"scheme"` diff --git a/dev/setup_darwin.go b/dev/setup_darwin.go index 62ef2ccb..63f7e539 100644 --- a/dev/setup_darwin.go +++ b/dev/setup_darwin.go @@ -103,6 +103,7 @@ type InstallIntoSystemArgs struct { LaunchAgentDirPath string Domains string Timeout string + NoServePublicPaths string } func InstallIntoSystem(config *InstallIntoSystemArgs) error { @@ -138,6 +139,8 @@ func InstallIntoSystem(config *InstallIntoSystemArgs) error { %s -timeout %s + -no-serve-public-paths + %s KeepAlive @@ -181,7 +184,7 @@ func InstallIntoSystem(config *InstallIntoSystemArgs) error { err = ioutil.WriteFile( plist, - []byte(fmt.Sprintf(userTemplate, binPath, dir, config.Domains, config.Timeout, config.ListenPort, config.TlsPort, logPath, logPath)), + []byte(fmt.Sprintf(userTemplate, binPath, dir, config.Domains, config.Timeout, config.NoServePublicPaths, config.ListenPort, config.TlsPort, logPath, logPath)), 0644, ) diff --git a/dev/setup_darwin_test.go b/dev/setup_darwin_test.go index 82b242a5..5c7885be 100644 --- a/dev/setup_darwin_test.go +++ b/dev/setup_darwin_test.go @@ -49,6 +49,7 @@ func TestInstallIntoSystem_FailsAsSuperuser(t *testing.T) { TlsPort: 10443, Domains: "test:localhost", Timeout: "5s", + NoServePublicPaths: "", ApplinkDirPath: "/tmp/gotest-dummy-applinkdir", LaunchAgentDirPath: "/tmp/gotest-dummy-launchagent", LogfilePath: "/tmp/gotest-dummy-logs/dummy.log", @@ -80,6 +81,7 @@ func installIntoTestContext(t *testing.T) (string, string, func()) { TlsPort: 10443, Domains: "test:localhost", Timeout: "5s", + NoServePublicPaths: "", ApplinkDirPath: appLinkDir, LaunchAgentDirPath: launchAgentDir, LogfilePath: logFilePath, diff --git a/etc/static-hi-puma/public/config.json b/etc/static-hi-puma/public/config.json new file mode 100644 index 00000000..5df5e437 --- /dev/null +++ b/etc/static-hi-puma/public/config.json @@ -0,0 +1,3 @@ +{ + "path": "/public/config.json" +} diff --git a/etc/static-hi-puma/public/packs/site.js b/etc/static-hi-puma/public/packs/site.js new file mode 100644 index 00000000..3f3ca0e0 --- /dev/null +++ b/etc/static-hi-puma/public/packs/site.js @@ -0,0 +1 @@ +/* /public/packs/site.js */