From 5906d5df84144293e8c5131626ebde1ccc7605e9 Mon Sep 17 00:00:00 2001 From: zackverham <96081108+zackverham@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:55:37 -0400 Subject: [PATCH 1/2] Remove unused AppMode methods and NewManifestFileMap function Remove 19 dead AppMode methods from internal/clients/types that were only exercised by tests but never called in production code. Also remove the unused NewManifestFileMap constructor (callers use make() directly). Co-Authored-By: Claude Opus 4.6 --- internal/bundles/manifest.go | 4 - internal/clients/types/apptypes.go | 125 ------ internal/clients/types/apptypes_test.go | 487 +----------------------- 3 files changed, 20 insertions(+), 596 deletions(-) diff --git a/internal/bundles/manifest.go b/internal/bundles/manifest.go index d9f51bbdd9..af9886a14e 100644 --- a/internal/bundles/manifest.go +++ b/internal/bundles/manifest.go @@ -116,10 +116,6 @@ type IntegrationRequest struct { Config map[string]any `json:"config,omitempty"` } -func NewManifestFileMap() ManifestFileMap { - return ManifestFileMap{} -} - type ManifestFile struct { Checksum string `json:"checksum"` } diff --git a/internal/clients/types/apptypes.go b/internal/clients/types/apptypes.go index 128054e9ae..6f8e800308 100644 --- a/internal/clients/types/apptypes.go +++ b/internal/clients/types/apptypes.go @@ -91,101 +91,6 @@ func (mode *AppMode) UnmarshalText(text []byte) error { return nil } -// IsWorkerApp returns true for any content that is serviced by worker -// processes. This includes Shiny applications, interactive R Markdown -// documents, Plumber/Python (flask/fastapi) APIs, and Python apps -// (Dash, Streamlit, Bokeh, PyShiny, Voila, Gradio, Panel). -func (mode AppMode) IsWorkerApp() bool { - return (mode.IsShinyApp() || - mode.IsPythonApp() || - mode.IsAPIApp()) -} - -// IsAPIApp returns true for any API apps (currently, Plumber, Flask, or FastAPI). -func (mode AppMode) IsAPIApp() bool { - return mode.IsPlumberAPI() || mode.IsPythonAPI() -} - -// IsPlumberAPI returns true for Plumber API applications. -func (mode AppMode) IsPlumberAPI() bool { - return mode == PlumberAPIMode -} - -// IsPythonAPI returns true for Python API applications. -func (mode AppMode) IsPythonAPI() bool { - return mode == PythonAPIMode || mode == PythonFastAPIMode -} - -// IsPythonApp returns true for Python applications (Dash, Streamlit, Bokeh, Voila) -func (mode AppMode) IsPythonApp() bool { - switch mode { - case PythonDashMode, PythonStreamlitMode, PythonGradioMode, PythonPanelMode, PythonShinyMode, PythonBokehMode, JupyterVoilaMode: - return true - } - return false -} - -// IsShinyApp returns true for Shiny applications and interactive R Markdown -// documents. -func (t AppMode) IsShinyApp() bool { - return t == ShinyMode || t == ShinyRmdMode || t == ShinyQuartoMode -} - -// IsDashApp returns true for Python Dash applications -func (t AppMode) IsDashApp() bool { - return t == PythonDashMode -} - -// IsStreamlitApp returns true for Python Streamlit applications -func (t AppMode) IsStreamlitApp() bool { - return t == PythonStreamlitMode -} - -// IsBokehApp returns true for Python Bokeh applications -func (t AppMode) IsBokehApp() bool { - return t == PythonBokehMode -} - -// IsGradioApp returns true for Python Gradio applications -func (t AppMode) IsGradioApp() bool { - return t == PythonGradioMode -} - -// IsPanelApp returns true for Python Panel applications -func (t AppMode) IsPanelApp() bool { - return t == PythonPanelMode -} - -// IsFastAPIApp returns true for Python FastAPI applications -func (t AppMode) IsFastAPIApp() bool { - return t == PythonFastAPIMode -} - -// IsPyShinyApp returns true for Python Shiny applications -func (mode AppMode) IsPyShinyApp() bool { - return mode == PythonShinyMode -} - -// IsVoilaApp returns true for Python Voila interactive notebooks -func (mode AppMode) IsVoilaApp() bool { - return mode == JupyterVoilaMode -} - -// IsStaticRmd returns true for any non-interactive R Markdown content. -func (mode AppMode) IsStaticRmd() bool { - return mode == StaticRmdMode -} - -// IsStaticJupyter returns true for any non-interactive Jupyter content. -func (t AppMode) IsStaticJupyter() bool { - return t == StaticJupyterMode -} - -// IsStaticReport returns true for any non-interactive R or Jupyter content. -func (t AppMode) IsStaticReport() bool { - return t == StaticRmdMode || t == StaticJupyterMode || t == StaticQuartoMode -} - // IsStaticContent returns true for any static content (deployed without // source). func (t AppMode) IsStaticContent() bool { @@ -199,36 +104,6 @@ func (mode AppMode) IsKnown() bool { return ok } -// IsRContent returns true if R is the primary interpreter for this content -// type. -func (t AppMode) IsRContent() bool { - switch t { - case ShinyMode, ShinyRmdMode, StaticRmdMode, PlumberAPIMode: - return true - } - return false -} - -// IsPythonContent returns true if Python is the primary interpreter for this -// content type. -func (t AppMode) IsPythonContent() bool { - switch t { - case StaticJupyterMode, PythonAPIMode, PythonDashMode, PythonStreamlitMode, PythonBokehMode, PythonFastAPIMode, PythonGradioMode, PythonPanelMode, PythonShinyMode, JupyterVoilaMode: - return true - } - return false -} - -// IsQuartoContent return true if Quarto is the primary driver of this content -// type. -func (t AppMode) IsQuartoContent() bool { - switch t { - case ShinyQuartoMode, StaticQuartoMode: - return true - } - return false -} - func (t AppMode) Description() string { switch t { case UnknownMode: diff --git a/internal/clients/types/apptypes_test.go b/internal/clients/types/apptypes_test.go index 5debe56c85..7836a6953b 100644 --- a/internal/clients/types/apptypes_test.go +++ b/internal/clients/types/apptypes_test.go @@ -19,473 +19,26 @@ func TestAppTypesSuite(t *testing.T) { suite.Run(t, new(AppTypesSuite)) } -func (s *AppTypesSuite) TestAppMode() { - for _, each := range []struct { - Mode AppMode - // primary interpreter inference checks - RContent bool - PythonContent bool - QuartoContent bool - // app-mode and "classification" checks - WorkerApp bool - APIApp bool - PlumberAPI bool - PythonAPI bool - PythonApp bool - ShinyApp bool - DashApp bool - StreamlitApp bool - BokehApp bool - FastAPIApp bool - GradioApp bool - PanelApp bool - PyShinyApp bool - VoilaApp bool - StaticRmd bool - StaticJupyter bool - StaticReport bool - StaticContent bool - }{ - { - Mode: UnknownMode, - RContent: false, - PythonContent: false, - QuartoContent: false, - WorkerApp: false, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: ShinyMode, - RContent: true, - PythonContent: false, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: true, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: ShinyRmdMode, - RContent: true, - PythonContent: false, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: true, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: StaticRmdMode, - RContent: true, - PythonContent: false, - QuartoContent: false, - WorkerApp: false, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: true, - StaticJupyter: false, - StaticReport: true, - StaticContent: false, - }, { - Mode: StaticMode, - RContent: false, - PythonContent: false, - QuartoContent: false, - WorkerApp: false, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: true, - }, { - Mode: PlumberAPIMode, - RContent: true, - PythonContent: false, - QuartoContent: false, - WorkerApp: true, - APIApp: true, - PlumberAPI: true, - PythonAPI: false, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: StaticJupyterMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: false, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: true, - StaticReport: true, - StaticContent: false, - }, { - Mode: PythonAPIMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: true, - PlumberAPI: false, - PythonAPI: true, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: PythonDashMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: true, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: PythonStreamlitMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: false, - StreamlitApp: true, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: PythonBokehMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: true, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: PythonFastAPIMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: true, - PlumberAPI: false, - PythonAPI: true, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: true, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: PythonGradioMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: true, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: PythonPanelMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: true, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: ShinyQuartoMode, - RContent: false, - PythonContent: false, - QuartoContent: true, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: true, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: StaticQuartoMode, - RContent: false, - PythonContent: false, - QuartoContent: true, - WorkerApp: false, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: false, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: true, - StaticContent: false, - }, { - Mode: PythonShinyMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: true, - VoilaApp: false, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, { - Mode: JupyterVoilaMode, - RContent: false, - PythonContent: true, - QuartoContent: false, - WorkerApp: true, - APIApp: false, - PlumberAPI: false, - PythonAPI: false, - PythonApp: true, - ShinyApp: false, - DashApp: false, - StreamlitApp: false, - BokehApp: false, - FastAPIApp: false, - GradioApp: false, - PanelApp: false, - PyShinyApp: false, - VoilaApp: true, - StaticRmd: false, - StaticJupyter: false, - StaticReport: false, - StaticContent: false, - }, - } { - comment := fmt.Sprintf("AppMode=%s (%s)", each.Mode, string(each.Mode)) - - s.Equal(each.RContent, each.Mode.IsRContent(), comment) - s.Equal(each.PythonContent, each.Mode.IsPythonContent(), comment) - s.Equal(each.QuartoContent, each.Mode.IsQuartoContent(), comment) - s.Equal(each.WorkerApp, each.Mode.IsWorkerApp(), comment) - s.Equal(each.APIApp, each.Mode.IsAPIApp(), comment) - s.Equal(each.PlumberAPI, each.Mode.IsPlumberAPI(), comment) - s.Equal(each.PythonAPI, each.Mode.IsPythonAPI(), comment) - s.Equal(each.PythonApp, each.Mode.IsPythonApp(), comment) - s.Equal(each.ShinyApp, each.Mode.IsShinyApp(), comment) - s.Equal(each.DashApp, each.Mode.IsDashApp(), comment) - s.Equal(each.StreamlitApp, each.Mode.IsStreamlitApp(), comment) - s.Equal(each.BokehApp, each.Mode.IsBokehApp(), comment) - s.Equal(each.FastAPIApp, each.Mode.IsFastAPIApp(), comment) - s.Equal(each.GradioApp, each.Mode.IsGradioApp(), comment) - s.Equal(each.PanelApp, each.Mode.IsPanelApp(), comment) - s.Equal(each.PyShinyApp, each.Mode.IsPyShinyApp(), comment) - s.Equal(each.VoilaApp, each.Mode.IsVoilaApp(), comment) - s.Equal(each.StaticRmd, each.Mode.IsStaticRmd(), comment) - s.Equal(each.StaticJupyter, each.Mode.IsStaticJupyter(), comment) - s.Equal(each.StaticReport, each.Mode.IsStaticReport(), comment) - s.Equal(each.StaticContent, each.Mode.IsStaticContent(), comment) - } +func (s *AppTypesSuite) TestIsStaticContent() { + s.True(StaticMode.IsStaticContent()) + + s.False(UnknownMode.IsStaticContent()) + s.False(ShinyMode.IsStaticContent()) + s.False(ShinyRmdMode.IsStaticContent()) + s.False(StaticRmdMode.IsStaticContent()) + s.False(PlumberAPIMode.IsStaticContent()) + s.False(StaticJupyterMode.IsStaticContent()) + s.False(PythonAPIMode.IsStaticContent()) + s.False(PythonDashMode.IsStaticContent()) + s.False(PythonStreamlitMode.IsStaticContent()) + s.False(PythonBokehMode.IsStaticContent()) + s.False(PythonFastAPIMode.IsStaticContent()) + s.False(PythonGradioMode.IsStaticContent()) + s.False(PythonPanelMode.IsStaticContent()) + s.False(ShinyQuartoMode.IsStaticContent()) + s.False(StaticQuartoMode.IsStaticContent()) + s.False(PythonShinyMode.IsStaticContent()) + s.False(JupyterVoilaMode.IsStaticContent()) } func (s *AppTypesSuite) TestAppModeStrings() { From c66ebe41db22fb652f9852114bc01975af56e36b Mon Sep 17 00:00:00 2001 From: zackverham <96081108+zackverham@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:15:59 -0400 Subject: [PATCH 2/2] Remove more dead code: proxy package, unused functions and methods - Remove entire internal/services/proxy/ package (never imported) - Remove unused WriteManifest and WriteManifestFile from bundles/manifest.go - Remove unused CanPublish method from connect/client_connect.go - Remove unused NewOptional constructor from types/optional.go Co-Authored-By: Claude Opus 4.6 --- internal/bundles/manifest.go | 20 --- internal/clients/connect/client_connect.go | 4 - internal/services/proxy/http_proxy.go | 148 --------------------- internal/types/optional.go | 7 - internal/types/optional_test.go | 46 +++---- 5 files changed, 16 insertions(+), 209 deletions(-) delete mode 100644 internal/services/proxy/http_proxy.go diff --git a/internal/bundles/manifest.go b/internal/bundles/manifest.go index af9886a14e..0a8662264f 100644 --- a/internal/bundles/manifest.go +++ b/internal/bundles/manifest.go @@ -131,26 +131,6 @@ func ReadManifest(r io.Reader) (*Manifest, error) { return manifest, nil } -// WriteManifest writes the manifest in JSON format. -func (m *Manifest) WriteManifest(w io.Writer) error { - manifestJSON, err := m.ToJSON() - if err != nil { - return err - } - _, err = w.Write(manifestJSON) - return err -} - -// WriteManifestFile writes the manifest to a file. -func (m *Manifest) WriteManifestFile(path util.Path) error { - f, err := path.Create() - if err != nil { - return err - } - defer f.Close() - return m.WriteManifest(f) -} - func NewManifest() *Manifest { return &Manifest{ Version: 1, diff --git a/internal/clients/connect/client_connect.go b/internal/clients/connect/client_connect.go index 42dcb29745..25a682bed3 100644 --- a/internal/clients/connect/client_connect.go +++ b/internal/clients/connect/client_connect.go @@ -83,10 +83,6 @@ func (u *UserDTO) CanAdmin() bool { return u.UserRole == AuthRoleAdmin } -func (u *UserDTO) CanPublish() bool { - return u.UserRole == AuthRoleAdmin || u.UserRole == AuthRolePublisher -} - var errInvalidServerOrCredentials = errors.New("could not validate credentials; check connectivity to the server, the URL, and authentication credentials") var errInvalidCredentials = errors.New("could not log in with the provided credentials") var errInvalidServer = errors.New("could not access the server; check the server URL and try again") diff --git a/internal/services/proxy/http_proxy.go b/internal/services/proxy/http_proxy.go deleted file mode 100644 index 23ee880ace..0000000000 --- a/internal/services/proxy/http_proxy.go +++ /dev/null @@ -1,148 +0,0 @@ -package proxy - -// Copyright (C) 2023 by Posit Software, PBC. - -import ( - "context" - "fmt" - "net/http" - "net/http/httputil" - "net/url" - "strings" - - "log/slog" - - "github.com/posit-dev/publisher/internal/logging" -) - -type proxy struct { - targetURL string - sourcePath string - baseProxy *httputil.ReverseProxy - log logging.Logger -} - -// NewProxy creates a proxy that will accept requests -// on the path `sourcePath` and proxy them to the -// server and path contained in `targetURL`. -// The `sourcePath` is removed during proxying. -func NewProxy( - targetURL *url.URL, - sourcePath string, - log logging.Logger) *httputil.ReverseProxy { - - p := proxy{ - targetURL: targetURL.String(), - sourcePath: sourcePath, - baseProxy: httputil.NewSingleHostReverseProxy(targetURL), - log: log, - } - return p.asReverseProxy() -} - -func (p *proxy) asReverseProxy() *httputil.ReverseProxy { - proxy := *p.baseProxy - //lint:ignore SA1019 Director deprecated in Go 1.26, migration to Rewrite tracked separately - proxy.Director = p.director - proxy.ModifyResponse = p.modifyResponse - proxy.ErrorHandler = p.handleError - return &proxy -} - -// fixReferer rewrites the referer to be on the Connect server. -func (p *proxy) fixReferer(req *http.Request) error { - referer := req.Header.Get("Referer") - if referer == "" { - return nil - } - targetURL, err := p.proxyURL(referer) - if err != nil { - return err - } - req.Header.Set("Referer", targetURL) - return nil -} - -// proxyURL uses the base proxy director to map an -// URL to the target server. -func (p *proxy) proxyURL(sourceURL string) (string, error) { - tempRequest, err := http.NewRequest("GET", sourceURL, nil) - if err != nil { - return "", err - } - p.stripSourcePrefix(tempRequest) - //lint:ignore SA1019 Director deprecated in Go 1.26, migration to Rewrite tracked separately - p.baseProxy.Director(tempRequest) - return tempRequest.URL.String(), nil -} - -func (p *proxy) director(req *http.Request) { - p.logRequest("Proxy request in", req) - p.stripSourcePrefix(req) - //lint:ignore SA1019 Director deprecated in Go 1.26, migration to Rewrite tracked separately - p.baseProxy.Director(req) - p.fixReferer(req) - req.Host = req.URL.Host - req.Header.Set("Host", req.Host) - - // Don't pass through cookies, since we only load - // unauthenticated resources (the publishing UI) - // from the target server. - req.Header.Del("Cookie") - p.logRequest("Proxy request out", req) -} - -func (p *proxy) modifyResponse(resp *http.Response) error { - // Rewrite outbound absolute redirects - location := resp.Header.Get("Location") - if strings.HasPrefix(location, p.targetURL) { - relativePath := strings.TrimPrefix(location, p.targetURL) - newLocation, err := url.JoinPath(p.sourcePath, relativePath) - if err != nil { - return err - } - resp.Header.Set("Location", newLocation) - p.log.Debug("Rewrite Location", "old", location, "new", newLocation) - } - return nil -} - -func (p *proxy) handleError(w http.ResponseWriter, req *http.Request, err error) { - p.log.Error("Proxy error", "url", req.URL, "error", err) - w.WriteHeader(http.StatusBadGateway) -} - -func (p *proxy) stripSourcePrefix(req *http.Request) { - path := strings.TrimPrefix(req.URL.Path, p.sourcePath) - if path == "" { - path = "/" - } - req.URL.Path = path -} - -func (p *proxy) logRequest(msg string, req *http.Request) { - if p.log.Enabled(context.Background(), slog.LevelDebug) { - p.log.Debug(msg, "method", req.Method, "url", req.URL.String()) - p.logHeader("Request headers", req.Header) - } -} - -type headerName string - -func (p *proxy) logHeader(msg string, header http.Header) { - log := p.log - for name, values := range header { - var value string - if name == "Cookie" || name == "Authorization" { - value = "REDACTED" - } else { - if len(values) == 1 { - value = values[0] - } else { - value = fmt.Sprintf("%v", values) - } - } - log = log.WithArgs(headerName(name), value) - } - log.Debug(msg) -} diff --git a/internal/types/optional.go b/internal/types/optional.go index 64de385bd1..d2654d2f7e 100644 --- a/internal/types/optional.go +++ b/internal/types/optional.go @@ -12,13 +12,6 @@ type Optional[T any] struct { valid bool } -func NewOptional[T any](value T) Optional[T] { - return Optional[T]{ - value: value, - valid: true, - } -} - func (opt *Optional[T]) Get() (T, bool) { return opt.value, opt.valid } diff --git a/internal/types/optional_test.go b/internal/types/optional_test.go index 51291b0e9c..cf79af0440 100644 --- a/internal/types/optional_test.go +++ b/internal/types/optional_test.go @@ -19,20 +19,6 @@ func TestOptionalSuite(t *testing.T) { suite.Run(t, new(OptionalSuite)) } -func (s *OptionalSuite) TestNewOptional() { - var opt NullString = NewOptional[string]("abc") - value, ok := opt.Get() - s.True(ok) - s.Equal("abc", value) -} - -func (s *OptionalSuite) TestNewOptionalEmptyString() { - var opt NullString = NewOptional[string]("") - value, ok := opt.Get() - s.True(ok) - s.Equal("", value) -} - func (s *OptionalSuite) TestOptionalZeroValue() { var opt NullString value, ok := opt.Get() @@ -68,13 +54,13 @@ func (s *OptionalSuite) TestUnmarshalJSONNotNull() { s.Nil(err) s.Equal(data, optionalData{ - S: NewOptional[string]("abc"), - I32: NewOptional[int32](123), - I64: NewOptional[int64](456), - F64: NewOptional[float64](3.14159), - Guid: NewOptional[GUID]("a-bad-1dea"), - I64str: NewOptional[Int64Str]("8878273897198738917"), - T: NewOptional[Time](ts), + S: Optional[string]{value: "abc", valid: true}, + I32: Optional[int32]{value: 123, valid: true}, + I64: Optional[int64]{value: 456, valid: true}, + F64: Optional[float64]{value: 3.14159, valid: true}, + Guid: Optional[GUID]{value: "a-bad-1dea", valid: true}, + I64str: Optional[Int64Str]{value: "8878273897198738917", valid: true}, + T: Optional[Time]{value: ts, valid: true}, }) str, ok := data.S.Get() @@ -138,13 +124,13 @@ func (s *OptionalSuite) TestMarshalJSONNotNull() { s.Nil(err) data := optionalData{ - S: NewOptional[string]("abc"), - I32: NewOptional[int32](123), - I64: NewOptional[int64](456), - F64: NewOptional[float64](3.14159), - Guid: NewOptional[GUID]("a-bad-1dea"), - I64str: NewOptional[Int64Str]("8878273897198738917"), - T: NewOptional[Time](ts), + S: Optional[string]{value: "abc", valid: true}, + I32: Optional[int32]{value: 123, valid: true}, + I64: Optional[int64]{value: 456, valid: true}, + F64: Optional[float64]{value: 3.14159, valid: true}, + Guid: Optional[GUID]{value: "a-bad-1dea", valid: true}, + I64str: Optional[Int64Str]{value: "8878273897198738917", valid: true}, + T: Optional[Time]{value: ts, valid: true}, } jsonOutput, err := json.Marshal(&data) s.Nil(err) @@ -175,11 +161,11 @@ func (s *OptionalSuite) TestNotValid() { } func (s *OptionalSuite) TestValid() { - value := NewOptional("hi there") + value := Optional[string]{value: "hi there", valid: true} s.Equal(value.Valid(), true) } func (s *OptionalSuite) TestValidEmpty() { - value := NewOptional("") + value := Optional[string]{value: "", valid: true} s.Equal(value.Valid(), true) }