Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 48 additions & 37 deletions internal/services/proxy/http_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ import (
)

type proxy struct {
targetURL string
targetURL *url.URL
sourcePath string
baseProxy *httputil.ReverseProxy
log logging.Logger
}

Expand All @@ -32,21 +31,19 @@ func NewProxy(
log logging.Logger) *httputil.ReverseProxy {

p := proxy{
targetURL: targetURL.String(),
targetURL: targetURL,
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
return &httputil.ReverseProxy{
Rewrite: p.rewrite,
ModifyResponse: p.modifyResponse,
ErrorHandler: p.handleError,
}
}

// fixReferer rewrites the referer to be on the Connect server.
Expand All @@ -63,40 +60,62 @@ func (p *proxy) fixReferer(req *http.Request) error {
return nil
}

// proxyURL uses the base proxy director to map an
// URL to the target server.
// proxyURL maps a URL to the target server.
func (p *proxy) proxyURL(sourceURL string) (string, error) {
tempRequest, err := http.NewRequest("GET", sourceURL, nil)
parsed, err := url.Parse(sourceURL)
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

// Strip source prefix from path
path := strings.TrimPrefix(parsed.Path, p.sourcePath)
if path == "" {
path = "/"
}

// Build target URL
result := *p.targetURL
result.Path = path
result.RawQuery = parsed.RawQuery
return result.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)
func (p *proxy) rewrite(pr *httputil.ProxyRequest) {
p.logRequest("Proxy request in", pr.In)

// Set the target URL (scheme and host)
pr.SetURL(p.targetURL)

// Strip source prefix from path
path := strings.TrimPrefix(pr.In.URL.Path, p.sourcePath)
if path == "" {
path = "/"
}
pr.Out.URL.Path = path

// Preserve query string
pr.Out.URL.RawQuery = pr.In.URL.RawQuery

// Fix referer header
p.fixReferer(pr.Out)

// Set host headers
pr.Out.Host = pr.Out.URL.Host
pr.Out.Header.Set("Host", pr.Out.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)
pr.Out.Header.Del("Cookie")
p.logRequest("Proxy request out", pr.Out)
}

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)
targetURLStr := p.targetURL.String()
if strings.HasPrefix(location, targetURLStr) {
relativePath := strings.TrimPrefix(location, targetURLStr)
newLocation, err := url.JoinPath(p.sourcePath, relativePath)
if err != nil {
return err
Expand All @@ -112,14 +131,6 @@ func (p *proxy) handleError(w http.ResponseWriter, req *http.Request, err error)
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())
Expand Down
Loading
Loading