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 */