drone/internal/request/request.go

64 lines
2.2 KiB
Go

// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
// Package request provides http handlers for serving the
// web applications and API endpoints.
package request
import (
"fmt"
"net/http"
"net/url"
)
// ReplacePrefix replaces the path of the request.
// IMPORTANT:
// - both prefix are unescaped for path, and used as is for RawPath!
// - only called by top level handler!!
func ReplacePrefix(r *http.Request, oldPrefix string, newPrefix string) error {
/*
* According to official documentation, we can change anything in the request but the body:
* https://pkg.go.dev/net/http#Handler
*
* ASSUMPTION:
* This is called by a top level handler (no router or middleware above it)
* Therefore, we don't have to worry about getting any routing metadata out of sync.
*
* This is different to returning a shallow clone with updated URL, which is what
* http.StripPrefix or earlier versions of request.WithContext are doing:
* https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/net/http/server.go;l=2138
* https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/net/http/request.go;l=355
*
* http.StripPrefix initially changed the path only, but that was updated because of official recommendations:
* https://github.com/golang/go/issues/18952
*/
unOldPrefix, err := url.PathUnescape(oldPrefix)
if err != nil {
return fmt.Errorf("failed to unescape old prefix '%s'", oldPrefix)
}
unNewPrefix, err := url.PathUnescape(newPrefix)
if err != nil {
return fmt.Errorf("failed to unescape new prefix '%s'", newPrefix)
}
unl := len(unOldPrefix)
if len(r.URL.Path) < unl || r.URL.Path[0:unl] != unOldPrefix {
return fmt.Errorf("path '%s' doesn't contain prefix '%s'", r.URL.Path, unOldPrefix)
}
// only change RawPath if it exists
if r.URL.RawPath != "" {
l := len(oldPrefix)
if len(r.URL.RawPath) < l || r.URL.RawPath[0:l] != oldPrefix {
return fmt.Errorf("raw path '%s' doesn't contain prefix '%s'", r.URL.RawPath, oldPrefix)
}
r.URL.RawPath = newPrefix + r.URL.RawPath[l:]
}
r.URL.Path = unNewPrefix + r.URL.Path[unl:]
return nil
}