Repository: traefik/traefik
File: pkg/middlewares/customerrors/custom_errors.go (Go)

Code before:
	for _, rsc := range c.statusRewrites {
		if rsc.fromCodes.Contains(code) {
			code = rsc.toCode
			break
		}
	}

	if code != originalCode {
		logger.Debug().Msgf("Caught HTTP Status Code %d (rewritten to %d), returning error page", originalCode, code)
	} else {
		logger.Debug().Msgf("Caught HTTP Status Code %d, returning error page", code)
	}

	var query string

	scheme := "http"
	if req.TLS != nil {
		scheme = "https"
	}
	originalURL := scheme + "://" + req.Host + req.URL.RequestURI()

	if len(c.backendQuery) > 0 {
		query = "/" + strings.TrimPrefix(c.backendQuery, "/")
		query = strings.ReplaceAll(query, "{status}", strconv.Itoa(code))
		query = strings.ReplaceAll(query, "{originalStatus}", strconv.Itoa(originalCode))
		query = strings.ReplaceAll(query, "{url}", url.QueryEscape(originalURL))
	}

	pageReq, err := newRequest("http://" + req.Host + query)
	if err != nil {
		logger.Error().Msgf("Unable to create error page request: %v", err)
		observability.SetStatusErrorf(req.Context(), "Unable to create error page request: %v", err)
		http.Error(rw, http.StatusText(code), code)
		return
	}

	utils.CopyHeaders(pageReq.Header, req.Header)
	c.backendHandler.ServeHTTP(newCodeModifier(rw, code),
		pageReq.WithContext(req.Context()))
}

func newRequest(baseURL string) (*http.Request, error) {
	u, err := url.Parse(baseURL)
	if err != nil {
		return nil, fmt.Errorf("error pages: error when parse URL: %w", err)
	}

	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error pages: error when create query: %w", err)
	}

Review comment (security):
```suggestion
    // Build the original URL in a robust way using net/url to avoid manual string concatenation.
	scheme := "http"
	if req.TLS != nil {
		scheme = "https"
	}
	orig := &url.URL{Scheme: scheme, Host: req.Host, Path: req.URL.Path, RawPath: req.URL.RawPath, RawQuery: req.URL.RawQuery, Fragment: req.URL.Fragment}

	if len(c.backendQuery) > 0 {
		query = "/" + strings.TrimPrefix(c.backendQuery, "/")
		query = strings.ReplaceAll(query, "{status}", strconv.Itoa(code))
		query = strings.ReplaceAll(query, "{originalStatus}", strconv.Itoa(originalCode))
		query = strings.ReplaceAll(query, "{url}", url.QueryEscape(orig.String()))
	}
```

Code after:
		if rsc.fromCodes.Contains(code) {
			code = rsc.toCode
			break
		}
	}

	if code != originalCode {
		logger.Debug().Msgf("Caught HTTP Status Code %d (rewritten to %d), returning error page", originalCode, code)
	} else {
		logger.Debug().Msgf("Caught HTTP Status Code %d, returning error page", code)
	}

	var query string

	scheme := "http"
	if req.TLS != nil {
		scheme = "https"
	}
	orig := &url.URL{Scheme: scheme, Host: req.Host, Path: req.URL.Path, RawPath: req.URL.RawPath, RawQuery: req.URL.RawQuery, Fragment: req.URL.Fragment}

	if len(c.backendQuery) > 0 {
		query = "/" + strings.TrimPrefix(c.backendQuery, "/")
		query = strings.ReplaceAll(query, "{status}", strconv.Itoa(code))
		query = strings.ReplaceAll(query, "{originalStatus}", strconv.Itoa(originalCode))
		query = strings.ReplaceAll(query, "{url}", url.QueryEscape(orig.String()))
	}

	pageReq, err := newRequest("http://" + req.Host + query)
	if err != nil {
		logger.Error().Msgf("Unable to create error page request: %v", err)
		observability.SetStatusErrorf(req.Context(), "Unable to create error page request: %v", err)
		http.Error(rw, http.StatusText(code), code)
		return
	}

	utils.CopyHeaders(pageReq.Header, req.Header)
	c.backendHandler.ServeHTTP(newCodeModifier(rw, code),
		pageReq.WithContext(req.Context()))
}

func newRequest(baseURL string) (*http.Request, error) {
	u, err := url.Parse(baseURL)
	if err != nil {
		return nil, fmt.Errorf("error pages: error when parse URL: %w", err)
	}

	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error pages: error when create query: %w", err)
	}