From 98b65fcc8ba659934581996aecab6dbc07daa26d Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 4 Feb 2025 11:23:31 +0200 Subject: [PATCH 1/6] TT-12638, added PreserveHostHeader to OAS functionality --- apidef/oas/oas_test.go | 1 - apidef/oas/schema/x-tyk-api-gateway.json | 14 ++++ apidef/oas/upstream.go | 34 ++++++++++ apidef/oas/upstream_test.go | 85 ++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) diff --git a/apidef/oas/oas_test.go b/apidef/oas/oas_test.go index 85ada5facc5..4064f4185cb 100644 --- a/apidef/oas/oas_test.go +++ b/apidef/oas/oas_test.go @@ -241,7 +241,6 @@ func TestOAS_ExtractTo_ResetAPIDefinition(t *testing.T) { "APIDefinition.UptimeTests.Config.ExpireUptimeAnalyticsAfter", "APIDefinition.UptimeTests.Config.ServiceDiscovery.CacheDisabled", "APIDefinition.UptimeTests.Config.RecheckWait", - "APIDefinition.Proxy.PreserveHostHeader", "APIDefinition.Proxy.DisableStripSlash", "APIDefinition.Proxy.CheckHostAgainstUptimeTests", "APIDefinition.Proxy.Transport.SSLInsecureSkipVerify", diff --git a/apidef/oas/schema/x-tyk-api-gateway.json b/apidef/oas/schema/x-tyk-api-gateway.json index 2cac954d79e..66f06f6f784 100644 --- a/apidef/oas/schema/x-tyk-api-gateway.json +++ b/apidef/oas/schema/x-tyk-api-gateway.json @@ -1346,6 +1346,9 @@ }, "loadBalancing": { "$ref": "#/definitions/X-Tyk-LoadBalancing" + }, + "preserveHostHeader": { + "$ref": "#/definitions/X-Tyk-PreserveHostHeader" } }, "required": [ @@ -2292,6 +2295,17 @@ "enabled" ] }, + "X-Tyk-PreserveHostHeader": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + }, "X-Tyk-LoadBalancingTarget": { "type": "object", "properties": { diff --git a/apidef/oas/upstream.go b/apidef/oas/upstream.go index fa9758c5633..438f0df4683 100644 --- a/apidef/oas/upstream.go +++ b/apidef/oas/upstream.go @@ -35,6 +35,9 @@ type Upstream struct { // LoadBalancing contains configuration for load balancing between multiple upstream targets. LoadBalancing *LoadBalancing `bson:"loadBalancing,omitempty" json:"loadBalancing,omitempty"` + + // PreserveHostHeader contains the configuration for preserving the host header. + PreserveHostHeader *PreserveHostHeader `bson:"preserveHostHeader,omitempty" json:"preserveHostHeader,omitempty"` } // Fill fills *Upstream from apidef.APIDefinition. @@ -96,6 +99,14 @@ func (u *Upstream) Fill(api apidef.APIDefinition) { } u.fillLoadBalancing(api) + + if u.PreserveHostHeader == nil { + u.PreserveHostHeader = &PreserveHostHeader{} + } + u.PreserveHostHeader.Fill(api) + if ShouldOmit(u.PreserveHostHeader) { + u.PreserveHostHeader = nil + } } // ExtractTo extracts *Upstream into *apidef.APIDefinition. @@ -157,6 +168,14 @@ func (u *Upstream) ExtractTo(api *apidef.APIDefinition) { u.Authentication.ExtractTo(&api.UpstreamAuth) u.loadBalancingExtractTo(api) + + if u.PreserveHostHeader == nil { + u.PreserveHostHeader = &PreserveHostHeader{} + defer func() { + u.PreserveHostHeader = nil + }() + } + u.PreserveHostHeader.ExtractTo(api) } func (u *Upstream) fillLoadBalancing(api apidef.APIDefinition) { @@ -905,3 +924,18 @@ func (l *LoadBalancing) ExtractTo(api *apidef.APIDefinition) { api.Proxy.Targets = proxyConfTargets } + +// PreserveHostHeader holds the configuration for preserving the host header. +type PreserveHostHeader struct { + Enabled bool `json:"enabled" bson:"enabled"` +} + +// Fill fills *PreserveHostHeader from apidef.APIDefinition. +func (p *PreserveHostHeader) Fill(api apidef.APIDefinition) { + p.Enabled = api.Proxy.PreserveHostHeader +} + +// ExtractTo extracts *PreserveHostHeader into *apidef.APIDefinition. +func (p *PreserveHostHeader) ExtractTo(api *apidef.APIDefinition) { + api.Proxy.PreserveHostHeader = p.Enabled +} diff --git a/apidef/oas/upstream_test.go b/apidef/oas/upstream_test.go index 8150c39b085..ce6852efe5f 100644 --- a/apidef/oas/upstream_test.go +++ b/apidef/oas/upstream_test.go @@ -668,3 +668,88 @@ func TestLoadBalancing(t *testing.T) { } }) } + +func TestPreserveHostHeader(t *testing.T) { + t.Parallel() + t.Run("fill", func(t *testing.T) { + t.Parallel() + testcases := []struct { + title string + input apidef.APIDefinition + expected *PreserveHostHeader + }{ + { + title: "preserve host header disabled", + input: apidef.APIDefinition{ + Proxy: apidef.ProxyConfig{ + PreserveHostHeader: false, + }, + }, + expected: nil, + }, + { + title: "preserve host header enabled", + input: apidef.APIDefinition{ + Proxy: apidef.ProxyConfig{ + PreserveHostHeader: true, + }, + }, + expected: &PreserveHostHeader{ + Enabled: true, + }, + }, + } + for _, tc := range testcases { + tc := tc + t.Run(tc.title, func(t *testing.T) { + t.Parallel() + + g := new(Upstream) + g.Fill(tc.input) + + assert.Equal(t, tc.expected, g.PreserveHostHeader) + }) + } + }) + + t.Run("extractTo", func(t *testing.T) { + t.Parallel() + + testcases := []struct { + title string + input *PreserveHostHeader + expectedEnabled bool + }{ + { + title: "preserve host header disabled", + input: &PreserveHostHeader{ + Enabled: false, + }, + expectedEnabled: false, + }, + { + title: "preserve host header enabled", + input: &PreserveHostHeader{ + Enabled: true, + }, + expectedEnabled: true, + }, + } + + for _, tc := range testcases { + tc := tc // Creating a new 'tc' scoped to the loop + t.Run(tc.title, func(t *testing.T) { + t.Parallel() + + g := new(Upstream) + g.PreserveHostHeader = tc.input + + var apiDef apidef.APIDefinition + apiDef.Proxy.PreserveHostHeader = true + g.ExtractTo(&apiDef) + + assert.Equal(t, tc.expectedEnabled, apiDef.Proxy.PreserveHostHeader) + }) + } + }) +} From 6cc862ccf3dc780c2e6305175d2d12b9a78b2f58 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 4 Feb 2025 11:46:07 +0200 Subject: [PATCH 2/6] TT-12638, cr feedback --- apidef/oas/upstream_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apidef/oas/upstream_test.go b/apidef/oas/upstream_test.go index ce6852efe5f..312e0f94151 100644 --- a/apidef/oas/upstream_test.go +++ b/apidef/oas/upstream_test.go @@ -673,11 +673,13 @@ func TestPreserveHostHeader(t *testing.T) { t.Parallel() t.Run("fill", func(t *testing.T) { t.Parallel() - testcases := []struct { + + type testCase struct { title string input apidef.APIDefinition expected *PreserveHostHeader - }{ + } + testCases := []testCase{ { title: "preserve host header disabled", input: apidef.APIDefinition{ @@ -699,7 +701,7 @@ func TestPreserveHostHeader(t *testing.T) { }, }, } - for _, tc := range testcases { + for _, tc := range testCases { tc := tc t.Run(tc.title, func(t *testing.T) { t.Parallel() @@ -715,11 +717,12 @@ func TestPreserveHostHeader(t *testing.T) { t.Run("extractTo", func(t *testing.T) { t.Parallel() - testcases := []struct { + type testCase struct { title string input *PreserveHostHeader expectedEnabled bool - }{ + } + testcases := []testCase{ { title: "preserve host header disabled", input: &PreserveHostHeader{ From a4df1abed97b515724fb251c1bed469e0e10e311 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 4 Feb 2025 11:49:21 +0200 Subject: [PATCH 3/6] TT-12638, linting issues --- apidef/oas/upstream.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apidef/oas/upstream.go b/apidef/oas/upstream.go index 438f0df4683..6e6eb1d7175 100644 --- a/apidef/oas/upstream.go +++ b/apidef/oas/upstream.go @@ -103,7 +103,9 @@ func (u *Upstream) Fill(api apidef.APIDefinition) { if u.PreserveHostHeader == nil { u.PreserveHostHeader = &PreserveHostHeader{} } + u.PreserveHostHeader.Fill(api) + if ShouldOmit(u.PreserveHostHeader) { u.PreserveHostHeader = nil } @@ -175,6 +177,7 @@ func (u *Upstream) ExtractTo(api *apidef.APIDefinition) { u.PreserveHostHeader = nil }() } + u.PreserveHostHeader.ExtractTo(api) } From e3528d9b372f52d4fe02372bed569c767cfe5eb8 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 4 Feb 2025 12:39:02 +0200 Subject: [PATCH 4/6] TT-12638, CR feedback --- apidef/oas/upstream.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apidef/oas/upstream.go b/apidef/oas/upstream.go index 6e6eb1d7175..1ebcf6b82b9 100644 --- a/apidef/oas/upstream.go +++ b/apidef/oas/upstream.go @@ -100,6 +100,10 @@ func (u *Upstream) Fill(api apidef.APIDefinition) { u.fillLoadBalancing(api) + u.fillPreserveHostHeader(api) +} + +func (u *Upstream) fillPreserveHostHeader(api apidef.APIDefinition) { if u.PreserveHostHeader == nil { u.PreserveHostHeader = &PreserveHostHeader{} } @@ -171,6 +175,10 @@ func (u *Upstream) ExtractTo(api *apidef.APIDefinition) { u.loadBalancingExtractTo(api) + u.preserveHostHeaderExtractTo(api) +} + +func (u *Upstream) preserveHostHeaderExtractTo(api *apidef.APIDefinition) { if u.PreserveHostHeader == nil { u.PreserveHostHeader = &PreserveHostHeader{} defer func() { From d8b981b2bf300a9313b03b6d48e74ea27630f649 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 4 Feb 2025 14:22:26 +0200 Subject: [PATCH 5/6] TT-12638, CR feedback --- apidef/oas/upstream_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apidef/oas/upstream_test.go b/apidef/oas/upstream_test.go index 312e0f94151..46fc59be7c0 100644 --- a/apidef/oas/upstream_test.go +++ b/apidef/oas/upstream_test.go @@ -670,10 +670,7 @@ func TestLoadBalancing(t *testing.T) { } func TestPreserveHostHeader(t *testing.T) { - t.Parallel() t.Run("fill", func(t *testing.T) { - t.Parallel() - type testCase struct { title string input apidef.APIDefinition @@ -715,8 +712,6 @@ func TestPreserveHostHeader(t *testing.T) { }) t.Run("extractTo", func(t *testing.T) { - t.Parallel() - type testCase struct { title string input *PreserveHostHeader @@ -742,8 +737,6 @@ func TestPreserveHostHeader(t *testing.T) { for _, tc := range testcases { tc := tc // Creating a new 'tc' scoped to the loop t.Run(tc.title, func(t *testing.T) { - t.Parallel() - g := new(Upstream) g.PreserveHostHeader = tc.input From 9391a49e265c8d38da43f788a0cc8c4885da6a2f Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 4 Feb 2025 16:08:21 +0200 Subject: [PATCH 6/6] TT-12638, fixed linting issue --- apidef/oas/upstream.go | 1 + 1 file changed, 1 insertion(+) diff --git a/apidef/oas/upstream.go b/apidef/oas/upstream.go index 1ebcf6b82b9..2b7ecfb0c51 100644 --- a/apidef/oas/upstream.go +++ b/apidef/oas/upstream.go @@ -938,6 +938,7 @@ func (l *LoadBalancing) ExtractTo(api *apidef.APIDefinition) { // PreserveHostHeader holds the configuration for preserving the host header. type PreserveHostHeader struct { + // Enabled activates preserving the host header. Enabled bool `json:"enabled" bson:"enabled"` }