@@ -178,6 +178,11 @@ type ServiceConfig struct {
178
178
// Headers if provided, the headers list will be added on all
179
179
// outgoing requests for this service config.
180
180
Headers []Header `yaml:"headers"`
181
+
182
+ // PreservePath if true, will preserve the full original path when proxying
183
+ // requests instead of stripping the extension prefix. Default is false to
184
+ // maintain backward compatibility.
185
+ PreservePath bool `yaml:"preservePath,omitempty"`
181
186
}
182
187
183
188
// Header defines the header to be added in the proxy requests.
@@ -383,15 +388,21 @@ func NewManager(log *log.Entry, namespace string, sg SettingsGetter, ag Applicat
383
388
// the Argo CD configmap.
384
389
type ExtensionRegistry map [string ]ProxyRegistry
385
390
391
+ // Proxy extends httputil.ReverseProxy with additional configuration
392
+ type Proxy struct {
393
+ * httputil.ReverseProxy
394
+ PreservePath bool
395
+ }
396
+
386
397
// ProxyRegistry is an in memory registry that contains all proxies for a
387
398
// given extension. Different extensions will have independent proxy registries.
388
399
// This is required to address the use case when one extension is configured with
389
400
// multiple backend services in different clusters.
390
- type ProxyRegistry map [ProxyKey ]* httputil. ReverseProxy
401
+ type ProxyRegistry map [ProxyKey ]* Proxy
391
402
392
403
// NewProxyRegistry will instantiate a new in memory registry for proxies.
393
404
func NewProxyRegistry () ProxyRegistry {
394
- r := make (map [ProxyKey ]* httputil. ReverseProxy )
405
+ r := make (map [ProxyKey ]* Proxy )
395
406
return r
396
407
}
397
408
@@ -511,12 +522,12 @@ func validateConfigs(configs *ExtensionConfigs) error {
511
522
// NewProxy will instantiate a new reverse proxy based on the provided
512
523
// targetURL and config. It will remove sensitive information from the
513
524
// incoming request such as the Authorization and Cookie headers.
514
- func NewProxy (targetURL string , headers []Header , config ProxyConfig ) (* httputil. ReverseProxy , error ) {
525
+ func NewProxy (targetURL string , headers []Header , config ProxyConfig , preservePath bool ) (* Proxy , error ) {
515
526
url , err := url .Parse (targetURL )
516
527
if err != nil {
517
528
return nil , fmt .Errorf ("failed to parse proxy URL: %w" , err )
518
529
}
519
- proxy := & httputil.ReverseProxy {
530
+ reverseProxy := & httputil.ReverseProxy {
520
531
Transport : newTransport (config ),
521
532
Director : func (req * http.Request ) {
522
533
req .Host = url .Host
@@ -530,6 +541,10 @@ func NewProxy(targetURL string, headers []Header, config ProxyConfig) (*httputil
530
541
}
531
542
},
532
543
}
544
+ proxy := & Proxy {
545
+ ReverseProxy : reverseProxy ,
546
+ PreservePath : preservePath ,
547
+ }
533
548
return proxy , nil
534
549
}
535
550
@@ -596,7 +611,7 @@ func (m *Manager) UpdateExtensionRegistry(s *settings.ArgoCDSettings) error {
596
611
proxyReg := NewProxyRegistry ()
597
612
singleBackend := len (ext .Backend .Services ) == 1
598
613
for _ , service := range ext .Backend .Services {
599
- proxy , err := NewProxy (service .URL , service .Headers , ext .Backend .ProxyConfig )
614
+ proxy , err := NewProxy (service .URL , service .Headers , ext .Backend .ProxyConfig , service . PreservePath )
600
615
if err != nil {
601
616
return fmt .Errorf ("error creating proxy: %w" , err )
602
617
}
@@ -617,7 +632,7 @@ func (m *Manager) UpdateExtensionRegistry(s *settings.ArgoCDSettings) error {
617
632
func appendProxy (registry ProxyRegistry ,
618
633
extName string ,
619
634
service ServiceConfig ,
620
- proxy * httputil. ReverseProxy ,
635
+ proxy * Proxy ,
621
636
singleBackend bool ,
622
637
) error {
623
638
if singleBackend {
@@ -717,7 +732,7 @@ func (m *Manager) authorize(ctx context.Context, rr *RequestResources, extName s
717
732
718
733
// findProxy will search the given registry to find the correct proxy to use
719
734
// based on the given extName and dest.
720
- func findProxy (registry ProxyRegistry , extName string , dest v1alpha1.ApplicationDestination ) (* httputil. ReverseProxy , error ) {
735
+ func findProxy (registry ProxyRegistry , extName string , dest v1alpha1.ApplicationDestination ) (* Proxy , error ) {
721
736
// First try to find the proxy in the registry just by the extension name.
722
737
// This is the simple case for extensions with only one backend service.
723
738
key := proxyKey (extName , "" , "" )
@@ -785,7 +800,7 @@ func (m *Manager) CallExtension() func(http.ResponseWriter, *http.Request) {
785
800
786
801
user := m .userGetter .GetUser (r .Context ())
787
802
groups := m .userGetter .GetGroups (r .Context ())
788
- prepareRequest (r , m .namespace , extName , app , user , groups )
803
+ prepareRequest (r , m .namespace , extName , app , user , groups , proxy . PreservePath )
789
804
m .log .WithFields (log.Fields {
790
805
HeaderArgoCDUsername : user ,
791
806
HeaderArgoCDGroups : strings .Join (groups , "," ),
@@ -819,8 +834,13 @@ func registerMetrics(extName string, metrics httpsnoop.Metrics, extensionMetrics
819
834
// - Cluster destination name
820
835
// - Cluster destination server
821
836
// - Argo CD authenticated username
822
- func prepareRequest (r * http.Request , namespace string , extName string , app * v1alpha1.Application , username string , groups []string ) {
823
- r .URL .Path = strings .TrimPrefix (r .URL .Path , fmt .Sprintf ("%s/%s" , URLPrefix , extName ))
837
+ func prepareRequest (r * http.Request , namespace string , extName string , app * v1alpha1.Application , username string , groups []string , preservePath bool ) {
838
+ if ! preservePath {
839
+ // Default behavior: strip the extension prefix from the path
840
+ r .URL .Path = strings .TrimPrefix (r .URL .Path , fmt .Sprintf ("%s/%s" , URLPrefix , extName ))
841
+ }
842
+ // If preservePath is true, keep the original path as-is
843
+
824
844
r .Header .Set (HeaderArgoCDNamespace , namespace )
825
845
if app .Spec .Destination .Name != "" {
826
846
r .Header .Set (HeaderArgoCDTargetClusterName , app .Spec .Destination .Name )
0 commit comments