Merge branch v3.4 into master
This commit is contained in:
commit
289d6e5dca
195 changed files with 1963 additions and 892 deletions
|
|
@ -1,7 +1,6 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -1004,8 +1003,8 @@ func TestHandler_HTTP(t *testing.T) {
|
|||
rtConf := &test.conf
|
||||
// To lazily initialize the Statuses.
|
||||
rtConf.PopulateUsedBy()
|
||||
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, false)
|
||||
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, true)
|
||||
rtConf.GetRoutersByEntryPoints(t.Context(), []string{"web"}, false)
|
||||
rtConf.GetRoutersByEntryPoints(t.Context(), []string{"web"}, true)
|
||||
|
||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||
server := httptest.NewServer(handler.createRouter())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -880,7 +879,7 @@ func TestHandler_TCP(t *testing.T) {
|
|||
rtConf := &test.conf
|
||||
// To lazily initialize the Statuses.
|
||||
rtConf.PopulateUsedBy()
|
||||
rtConf.GetTCPRoutersByEntryPoints(context.Background(), []string{"web"})
|
||||
rtConf.GetTCPRoutersByEntryPoints(t.Context(), []string{"web"})
|
||||
|
||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||
server := httptest.NewServer(handler.createRouter())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -570,7 +569,7 @@ func TestHandler_UDP(t *testing.T) {
|
|||
rtConf := &test.conf
|
||||
// To lazily initialize the Statuses.
|
||||
rtConf.PopulateUsedBy()
|
||||
rtConf.GetUDPRoutersByEntryPoints(context.Background(), []string{"web"})
|
||||
rtConf.GetUDPRoutersByEntryPoints(t.Context(), []string{"web"})
|
||||
|
||||
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
|
||||
server := httptest.NewServer(handler.createRouter())
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -211,7 +210,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runtimeConfig := NewConfig(test.conf)
|
||||
actual := runtimeConfig.GetRoutersByEntryPoints(context.Background(), test.entryPoints, false)
|
||||
actual := runtimeConfig.GetRoutersByEntryPoints(t.Context(), test.entryPoints, false)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -211,7 +210,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runtimeConfig := NewConfig(test.conf)
|
||||
actual := runtimeConfig.GetTCPRoutersByEntryPoints(context.Background(), test.entryPoints)
|
||||
actual := runtimeConfig.GetTCPRoutersByEntryPoints(t.Context(), test.entryPoints)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -192,7 +191,7 @@ func TestGetUDPRoutersByEntryPoints(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runtimeConfig := NewConfig(test.conf)
|
||||
actual := runtimeConfig.GetUDPRoutersByEntryPoints(context.Background(), test.entryPoints)
|
||||
actual := runtimeConfig.GetUDPRoutersByEntryPoints(t.Context(), test.entryPoints)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func TestNewServiceHealthChecker_durations(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
healthChecker := NewServiceHealthChecker(context.Background(), nil, test.config, nil, nil, http.DefaultTransport, nil, "")
|
||||
healthChecker := NewServiceHealthChecker(t.Context(), nil, test.config, nil, nil, http.DefaultTransport, nil, "")
|
||||
assert.Equal(t, test.expInterval, healthChecker.interval)
|
||||
assert.Equal(t, test.expTimeout, healthChecker.timeout)
|
||||
})
|
||||
|
|
@ -251,7 +251,7 @@ func TestServiceHealthChecker_newRequest(t *testing.T) {
|
|||
shc := ServiceHealthChecker{config: &test.config}
|
||||
|
||||
u := testhelpers.MustParseURL(test.targetURL)
|
||||
req, err := shc.newRequest(context.Background(), u)
|
||||
req, err := shc.newRequest(t.Context(), u)
|
||||
|
||||
if test.expError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -276,7 +276,7 @@ func TestServiceHealthChecker_checkHealthHTTP_NotFollowingRedirects(t *testing.T
|
|||
}))
|
||||
defer redirectTestServer.Close()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(dynamic.DefaultHealthCheckTimeout))
|
||||
ctx, cancel := context.WithTimeout(t.Context(), time.Duration(dynamic.DefaultHealthCheckTimeout))
|
||||
defer cancel()
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
|
@ -411,7 +411,7 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
|
|||
|
||||
// The context is passed to the health check and
|
||||
// canonically canceled by the test server once all expected requests have been received.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
targetURL, timeout := test.server.Start(t, cancel)
|
||||
|
|
@ -461,7 +461,7 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
|
|||
func TestDifferentIntervals(t *testing.T) {
|
||||
// The context is passed to the health check and
|
||||
// canonically canceled by the test server once all expected requests have been received.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
healthyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package logs
|
|||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -175,7 +174,7 @@ func TestLog(t *testing.T) {
|
|||
logger, err := SetupOTelLogger(logger, config)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
|
||||
ctx := trace.ContextWithSpanContext(t.Context(), trace.NewSpanContext(trace.SpanContextConfig{
|
||||
TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
|
@ -20,7 +19,7 @@ func TestDatadog(t *testing.T) {
|
|||
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
||||
udp.Timeout = 5 * time.Second
|
||||
|
||||
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||
datadogRegistry := RegisterDatadog(t.Context(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||
|
||||
if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsRouterEnabled() || !datadogRegistry.IsSvcEnabled() {
|
||||
t.Errorf("DatadogRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
|
||||
|
|
@ -35,7 +34,7 @@ func TestDatadogWithPrefix(t *testing.T) {
|
|||
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
||||
udp.Timeout = 5 * time.Second
|
||||
|
||||
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Prefix: "testPrefix", Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||
datadogRegistry := RegisterDatadog(t.Context(), &types.Datadog{Prefix: "testPrefix", Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||
|
||||
testDatadogRegistry(t, "testPrefix", datadogRegistry)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -26,7 +25,7 @@ func TestInfluxDB2(t *testing.T) {
|
|||
_, _ = fmt.Fprintln(w, "ok")
|
||||
}))
|
||||
|
||||
influxDB2Registry := RegisterInfluxDB2(context.Background(),
|
||||
influxDB2Registry := RegisterInfluxDB2(t.Context(),
|
||||
&types.InfluxDB2{
|
||||
Address: ts.URL,
|
||||
Token: "test-token",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package metrics
|
|||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -338,7 +337,7 @@ func TestOpenTelemetry(t *testing.T) {
|
|||
wantServiceName = test.serviceName
|
||||
}
|
||||
|
||||
registry := RegisterOpenTelemetry(context.Background(), &cfg)
|
||||
registry := RegisterOpenTelemetry(t.Context(), &cfg)
|
||||
require.NotNil(t, registry)
|
||||
|
||||
if !registry.IsEpEnabled() || !registry.IsRouterEnabled() || !registry.IsSvcEnabled() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
|
@ -70,7 +69,7 @@ func TestRegisterPromState(t *testing.T) {
|
|||
if test.initPromState {
|
||||
initStandardRegistry(prom)
|
||||
}
|
||||
if registerPromState(context.Background()) {
|
||||
if registerPromState(t.Context()) {
|
||||
actualNbRegistries++
|
||||
}
|
||||
if test.unregisterPromState {
|
||||
|
|
@ -91,7 +90,7 @@ func TestPrometheus(t *testing.T) {
|
|||
promRegistry = prometheus.NewRegistry()
|
||||
t.Cleanup(promState.reset)
|
||||
|
||||
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{
|
||||
prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{
|
||||
AddEntryPointsLabels: true,
|
||||
AddRoutersLabels: true,
|
||||
AddServicesLabels: true,
|
||||
|
|
@ -405,7 +404,7 @@ func TestPrometheusMetricRemoval(t *testing.T) {
|
|||
promRegistry = prometheus.NewRegistry()
|
||||
t.Cleanup(promState.reset)
|
||||
|
||||
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true, AddRoutersLabels: true})
|
||||
prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true, AddRoutersLabels: true})
|
||||
defer promRegistry.Unregister(promState)
|
||||
|
||||
conf1 := dynamic.Configuration{
|
||||
|
|
@ -496,7 +495,7 @@ func TestPrometheusMetricRemoveEndpointForRecoveredService(t *testing.T) {
|
|||
promRegistry = prometheus.NewRegistry()
|
||||
t.Cleanup(promState.reset)
|
||||
|
||||
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddServicesLabels: true})
|
||||
prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{AddServicesLabels: true})
|
||||
defer promRegistry.Unregister(promState)
|
||||
|
||||
conf1 := dynamic.Configuration{
|
||||
|
|
@ -535,7 +534,7 @@ func TestPrometheusMetricRemoveEndpointForRecoveredService(t *testing.T) {
|
|||
func TestPrometheusRemovedMetricsReset(t *testing.T) {
|
||||
t.Cleanup(promState.reset)
|
||||
|
||||
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true})
|
||||
prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true})
|
||||
defer promRegistry.Unregister(promState)
|
||||
|
||||
conf1 := dynamic.Configuration{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
|
@ -21,7 +20,7 @@ func TestStatsD(t *testing.T) {
|
|||
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
||||
udp.Timeout = 5 * time.Second
|
||||
|
||||
statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||
statsdRegistry := RegisterStatsd(t.Context(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
|
||||
|
||||
testRegistry(t, defaultMetricsPrefix, statsdRegistry)
|
||||
}
|
||||
|
|
@ -35,7 +34,7 @@ func TestStatsDWithPrefix(t *testing.T) {
|
|||
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
|
||||
udp.Timeout = 5 * time.Second
|
||||
|
||||
statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true, Prefix: "testPrefix"})
|
||||
statsdRegistry := RegisterStatsd(t.Context(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true, Prefix: "testPrefix"})
|
||||
|
||||
testRegistry(t, "testPrefix", statsdRegistry)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ func TestOTelAccessLog(t *testing.T) {
|
|||
Path: testPath,
|
||||
},
|
||||
}
|
||||
ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
|
||||
ctx := trace.ContextWithSpanContext(t.Context(), trace.NewSpanContext(trace.SpanContextConfig{
|
||||
TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
|
||||
}))
|
||||
|
|
@ -1055,7 +1055,7 @@ func doLoggingWithAbortedStream(t *testing.T, config *types.AccessLog) {
|
|||
require.NoError(t, err, "logger should create "+config.FilePath)
|
||||
}
|
||||
|
||||
reqContext, cancelRequest := context.WithCancel(context.Background())
|
||||
reqContext, cancelRequest := context.WithCancel(t.Context())
|
||||
|
||||
req := &http.Request{
|
||||
Header: map[string][]string{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package addprefix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ func TestNewAddPrefix(t *testing.T) {
|
|||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
_, err := New(context.Background(), next, test.prefix, "foo-add-prefix")
|
||||
_, err := New(t.Context(), next, test.prefix, "foo-add-prefix")
|
||||
if test.expectsError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
|
|
@ -87,7 +86,7 @@ func TestAddPrefix(t *testing.T) {
|
|||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+test.path, nil)
|
||||
|
||||
handler, err := New(context.Background(), next, test.prefix, "foo-add-prefix")
|
||||
handler, err := New(t.Context(), next, test.prefix, "foo-add-prefix")
|
||||
require.NoError(t, err)
|
||||
|
||||
handler.ServeHTTP(nil, req)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -25,13 +24,13 @@ func TestBasicAuthFail(t *testing.T) {
|
|||
auth := dynamic.BasicAuth{
|
||||
Users: []string{"test"},
|
||||
}
|
||||
_, err := NewBasic(context.Background(), next, auth, "authName")
|
||||
_, err := NewBasic(t.Context(), next, auth, "authName")
|
||||
require.Error(t, err)
|
||||
|
||||
auth2 := dynamic.BasicAuth{
|
||||
Users: []string{"test:test"},
|
||||
}
|
||||
authMiddleware, err := NewBasic(context.Background(), next, auth2, "authTest")
|
||||
authMiddleware, err := NewBasic(t.Context(), next, auth2, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authMiddleware)
|
||||
|
|
@ -54,7 +53,7 @@ func TestBasicAuthSuccess(t *testing.T) {
|
|||
auth := dynamic.BasicAuth{
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
}
|
||||
authMiddleware, err := NewBasic(context.Background(), next, auth, "authName")
|
||||
authMiddleware, err := NewBasic(t.Context(), next, auth, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authMiddleware)
|
||||
|
|
@ -85,7 +84,7 @@ func TestBasicAuthUserHeader(t *testing.T) {
|
|||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
HeaderField: "X-Webauth-User",
|
||||
}
|
||||
middleware, err := NewBasic(context.Background(), next, auth, "authName")
|
||||
middleware, err := NewBasic(t.Context(), next, auth, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -116,7 +115,7 @@ func TestBasicAuthHeaderRemoved(t *testing.T) {
|
|||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
}
|
||||
middleware, err := NewBasic(context.Background(), next, auth, "authName")
|
||||
middleware, err := NewBasic(t.Context(), next, auth, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -147,7 +146,7 @@ func TestBasicAuthHeaderPresent(t *testing.T) {
|
|||
auth := dynamic.BasicAuth{
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
}
|
||||
middleware, err := NewBasic(context.Background(), next, auth, "authName")
|
||||
middleware, err := NewBasic(t.Context(), next, auth, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -177,7 +176,7 @@ func TestBasicAuthConcurrentHashOnce(t *testing.T) {
|
|||
Users: []string{"test:$2a$04$.8sTYfcxbSplCtoxt5TdJOgpBYkarKtZYsYfYxQ1edbYRuO1DNi0e"},
|
||||
}
|
||||
|
||||
authMiddleware, err := NewBasic(context.Background(), next, auth, "authName")
|
||||
authMiddleware, err := NewBasic(t.Context(), next, auth, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
hashCount := 0
|
||||
|
|
@ -277,7 +276,7 @@ func TestBasicAuthUsersFromFile(t *testing.T) {
|
|||
fmt.Fprintln(w, "traefik")
|
||||
})
|
||||
|
||||
authenticator, err := NewBasic(context.Background(), next, authenticatorConfiguration, "authName")
|
||||
authenticator, err := NewBasic(t.Context(), next, authenticatorConfiguration, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authenticator)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -23,7 +22,7 @@ func TestDigestAuthError(t *testing.T) {
|
|||
auth := dynamic.DigestAuth{
|
||||
Users: []string{"test"},
|
||||
}
|
||||
_, err := NewDigest(context.Background(), next, auth, "authName")
|
||||
_, err := NewDigest(t.Context(), next, auth, "authName")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +34,7 @@ func TestDigestAuthFail(t *testing.T) {
|
|||
auth := dynamic.DigestAuth{
|
||||
Users: []string{"test:traefik:a2688e031edb4be6a3797f3882655c05"},
|
||||
}
|
||||
authMiddleware, err := NewDigest(context.Background(), next, auth, "authName")
|
||||
authMiddleware, err := NewDigest(t.Context(), next, auth, "authName")
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, authMiddleware, "this should not be nil")
|
||||
|
||||
|
|
@ -109,7 +108,7 @@ func TestDigestAuthUsersFromFile(t *testing.T) {
|
|||
fmt.Fprintln(w, "traefik")
|
||||
})
|
||||
|
||||
authenticator, err := NewDigest(context.Background(), next, authenticatorConfiguration, "authName")
|
||||
authenticator, err := NewDigest(t.Context(), next, authenticatorConfiguration, "authName")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authenticator)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func TestForwardAuthFail(t *testing.T) {
|
|||
}))
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
middleware, err := NewForward(context.Background(), next, dynamic.ForwardAuth{
|
||||
middleware, err := NewForward(t.Context(), next, dynamic.ForwardAuth{
|
||||
Address: server.URL,
|
||||
}, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
|
@ -90,7 +90,7 @@ func TestForwardAuthSuccess(t *testing.T) {
|
|||
AuthResponseHeadersRegex: "^Foo-",
|
||||
AddAuthCookiesToResponse: []string{"authCookie"},
|
||||
}
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -135,7 +135,7 @@ func TestForwardAuthForwardBody(t *testing.T) {
|
|||
maxBodySize := int64(len(data))
|
||||
auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true, MaxBodySize: &maxBodySize}
|
||||
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -170,7 +170,7 @@ func TestForwardAuthForwardBodyEmptyBody(t *testing.T) {
|
|||
|
||||
auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true}
|
||||
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -208,7 +208,7 @@ func TestForwardAuthForwardBodySizeLimit(t *testing.T) {
|
|||
maxBodySize := int64(len(data)) - 1
|
||||
auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true, MaxBodySize: &maxBodySize}
|
||||
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -245,7 +245,7 @@ func TestForwardAuthNotForwardBody(t *testing.T) {
|
|||
|
||||
auth := dynamic.ForwardAuth{Address: server.URL}
|
||||
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -273,7 +273,7 @@ func TestForwardAuthRedirect(t *testing.T) {
|
|||
|
||||
auth := dynamic.ForwardAuth{Address: authTs.URL}
|
||||
|
||||
authMiddleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
authMiddleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authMiddleware)
|
||||
|
|
@ -324,7 +324,7 @@ func TestForwardAuthRemoveHopByHopHeaders(t *testing.T) {
|
|||
|
||||
auth := dynamic.ForwardAuth{Address: authTs.URL}
|
||||
|
||||
authMiddleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
authMiddleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authMiddleware)
|
||||
|
|
@ -370,7 +370,7 @@ func TestForwardAuthFailResponseHeaders(t *testing.T) {
|
|||
auth := dynamic.ForwardAuth{
|
||||
Address: authTs.URL,
|
||||
}
|
||||
authMiddleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
authMiddleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(authMiddleware)
|
||||
|
|
@ -682,7 +682,7 @@ func TestForwardAuthTracing(t *testing.T) {
|
|||
Address: server.URL,
|
||||
AuthRequestHeaders: []string{"X-Foo"},
|
||||
}
|
||||
next, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
next, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://www.test.com/search?q=Opentelemetry", nil)
|
||||
|
|
@ -725,7 +725,7 @@ func TestForwardAuthPreserveLocationHeader(t *testing.T) {
|
|||
Address: server.URL,
|
||||
PreserveLocationHeader: true,
|
||||
}
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
@ -779,7 +779,7 @@ func TestForwardAuthPreserveRequestMethod(t *testing.T) {
|
|||
PreserveRequestMethod: test.preserveRequestMethod,
|
||||
}
|
||||
|
||||
middleware, err := NewForward(context.Background(), next, auth, "authTest")
|
||||
middleware, err := NewForward(t.Context(), next, auth, "authTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(middleware)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package buffering
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"math"
|
||||
"net/http"
|
||||
|
|
@ -57,7 +56,7 @@ func TestBuffering(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
buffMiddleware, err := New(context.Background(), next, test.config, "foo")
|
||||
buffMiddleware, err := New(t.Context(), next, test.config, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "http://localhost", bytes.NewBuffer(test.body))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package compress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -153,7 +152,7 @@ func Test_getCompressionEncoding(t *testing.T) {
|
|||
DefaultEncoding: test.defaultEncoding,
|
||||
}
|
||||
|
||||
h, err := New(context.Background(), nil, conf, "test")
|
||||
h, err := New(t.Context(), nil, conf, "test")
|
||||
require.NoError(t, err)
|
||||
|
||||
c, ok := h.(*compress)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package compress
|
|||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -116,7 +115,7 @@ func TestNegotiation(t *testing.T) {
|
|||
MinResponseBodyBytes: 1,
|
||||
Encodings: defaultSupportedEncodings,
|
||||
}
|
||||
handler, err := New(context.Background(), next, cfg, "testing")
|
||||
handler, err := New(t.Context(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -137,7 +136,7 @@ func TestShouldCompressWhenNoContentEncodingHeader(t *testing.T) {
|
|||
_, err := rw.Write(baseBody)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -167,7 +166,7 @@ func TestShouldNotCompressWhenContentEncodingHeader(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -189,7 +188,7 @@ func TestShouldNotCompressWhenNoAcceptEncodingHeader(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -211,7 +210,7 @@ func TestEmptyAcceptEncoding(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -238,7 +237,7 @@ func TestShouldNotCompressWhenIdentityAcceptEncodingHeader(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -265,7 +264,7 @@ func TestShouldNotCompressWhenEmptyAcceptEncodingHeader(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -287,7 +286,7 @@ func TestShouldNotCompressHeadRequest(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -377,7 +376,7 @@ func TestShouldNotCompressWhenSpecificContentType(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
handler, err := New(context.Background(), next, test.conf, "test")
|
||||
handler, err := New(t.Context(), next, test.conf, "test")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -423,7 +422,7 @@ func TestShouldCompressWhenSpecificContentType(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
handler, err := New(context.Background(), next, test.conf, "test")
|
||||
handler, err := New(t.Context(), next, test.conf, "test")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -473,7 +472,7 @@ func TestIntegrationShouldNotCompress(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
compress, err := New(context.Background(), test.handler, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
compress, err := New(t.Context(), test.handler, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(compress)
|
||||
|
|
@ -508,7 +507,7 @@ func TestShouldWriteHeaderWhenFlush(t *testing.T) {
|
|||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
handler, err := New(t.Context(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(handler)
|
||||
|
|
@ -559,7 +558,7 @@ func TestIntegrationShouldCompress(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
compress, err := New(context.Background(), test.handler, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
compress, err := New(t.Context(), test.handler, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
ts := httptest.NewServer(compress)
|
||||
|
|
@ -619,7 +618,7 @@ func TestMinResponseBodyBytes(t *testing.T) {
|
|||
MinResponseBodyBytes: test.minResponseBodyBytes,
|
||||
Encodings: defaultSupportedEncodings,
|
||||
}
|
||||
handler, err := New(context.Background(), next, cfg, "testing")
|
||||
handler, err := New(t.Context(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
|
|
@ -679,7 +678,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
MinResponseBodyBytes: 1024,
|
||||
Encodings: defaultSupportedEncodings,
|
||||
}
|
||||
compress, err := New(context.Background(), next, cfg, "testing")
|
||||
compress, err := New(t.Context(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(compress)
|
||||
|
|
@ -723,7 +722,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
return nil
|
||||
},
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(context.Background(), trace), http.MethodGet, server.URL, nil)
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(t.Context(), trace), http.MethodGet, server.URL, nil)
|
||||
req.Header.Add(acceptEncodingHeader, test.encoding)
|
||||
|
||||
res, err := frontendClient.Do(req)
|
||||
|
|
@ -779,7 +778,7 @@ func runCompressionBenchmark(b *testing.B, algorithm string) {
|
|||
_, err := rw.Write(baseBody)
|
||||
assert.NoError(b, err)
|
||||
})
|
||||
handler, _ := New(context.Background(), next, dynamic.Compress{}, "testing")
|
||||
handler, _ := New(b.Context(), next, dynamic.Compress{}, "testing")
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
|
||||
req.Header.Set("Accept-Encoding", algorithm)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package contenttype
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -60,7 +59,7 @@ func TestAutoDetection(t *testing.T) {
|
|||
|
||||
if test.autoDetect {
|
||||
var err error
|
||||
next, err = New(context.Background(), next, dynamic.ContentType{}, "foo-content-type")
|
||||
next, err = New(t.Context(), next, dynamic.ContentType{}, "foo-content-type")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ func TestHandler(t *testing.T) {
|
|||
}
|
||||
_, _ = fmt.Fprintln(w, http.StatusText(test.backendCode))
|
||||
})
|
||||
errorPageHandler, err := New(context.Background(), handler, *test.errorPage, serviceBuilderMock, "test")
|
||||
errorPageHandler, err := New(t.Context(), handler, *test.errorPage, serviceBuilderMock, "test")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost/test?foo=bar&baz=buz", nil)
|
||||
|
|
@ -205,7 +205,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
|
||||
config := dynamic.ErrorPage{Service: "error", Query: "/", Status: []string{"200"}}
|
||||
|
||||
errorPageHandler, err := New(context.Background(), next, config, serviceBuilderMock, "test")
|
||||
errorPageHandler, err := New(t.Context(), next, config, serviceBuilderMock, "test")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(errorPageHandler)
|
||||
|
|
@ -249,7 +249,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
return nil
|
||||
},
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(context.Background(), trace), http.MethodGet, server.URL, nil)
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(t.Context(), trace), http.MethodGet, server.URL, nil)
|
||||
|
||||
res, err := frontendClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package headermodifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -103,7 +102,7 @@ func TestRequestHeaderModifier(t *testing.T) {
|
|||
gotHeaders = r.Header
|
||||
})
|
||||
|
||||
handler := NewRequestHeaderModifier(context.Background(), next, test.config, "foo-request-header-modifier")
|
||||
handler := NewRequestHeaderModifier(t.Context(), next, test.config, "foo-request-header-modifier")
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||
for h, v := range test.requestHeaders {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package headermodifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -104,7 +103,7 @@ func TestResponseHeaderModifier(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
handler := NewResponseHeaderModifier(context.Background(), next, test.config, "foo-response-header-modifier")
|
||||
handler := NewResponseHeaderModifier(t.Context(), next, test.config, "foo-response-header-modifier")
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -185,7 +184,7 @@ func TestRequestRedirectHandler(t *testing.T) {
|
|||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
handler, err := NewRequestRedirect(context.Background(), next, test.config, "traefikTest")
|
||||
handler, err := NewRequestRedirect(t.Context(), next, test.config, "traefikTest")
|
||||
if test.wantErr {
|
||||
require.Error(t, err)
|
||||
require.Nil(t, handler)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package urlrewrite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -113,7 +112,7 @@ func TestURLRewriteHandler(t *testing.T) {
|
|||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
handler := NewURLRewrite(context.Background(), next, test.config, "traefikTest")
|
||||
handler := NewURLRewrite(t.Context(), next, test.config, "traefikTest")
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, test.url, nil)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package headers
|
|||
// Middleware tests based on https://github.com/unrolled/secure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -20,7 +19,7 @@ import (
|
|||
func TestNew_withoutOptions(t *testing.T) {
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })
|
||||
|
||||
mid, err := New(context.Background(), next, dynamic.Headers{}, "testing")
|
||||
mid, err := New(t.Context(), next, dynamic.Headers{}, "testing")
|
||||
require.Errorf(t, err, "headers configuration not valid")
|
||||
|
||||
assert.Nil(t, mid)
|
||||
|
|
@ -55,7 +54,7 @@ func TestNew_allowedHosts(t *testing.T) {
|
|||
AllowedHosts: []string{"foo.com", "bar.com"},
|
||||
}
|
||||
|
||||
mid, err := New(context.Background(), emptyHandler, cfg, "foo")
|
||||
mid, err := New(t.Context(), emptyHandler, cfg, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, test := range testCases {
|
||||
|
|
@ -86,7 +85,7 @@ func TestNew_customHeaders(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
mid, err := New(context.Background(), next, cfg, "testing")
|
||||
mid, err := New(t.Context(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/foo", nil)
|
||||
|
|
@ -135,7 +134,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
mid, err := New(context.Background(), next, cfg, "testing")
|
||||
mid, err := New(t.Context(), next, cfg, "testing")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(mid)
|
||||
|
|
@ -179,7 +178,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
return nil
|
||||
},
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(context.Background(), trace), http.MethodGet, server.URL, nil)
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(t.Context(), trace), http.MethodGet, server.URL, nil)
|
||||
|
||||
res, err := frontendClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ipallowlist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -45,7 +44,7 @@ func TestNewIPAllowLister(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
|
||||
allowLister, err := New(t.Context(), next, test.allowList, "traefikTest")
|
||||
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
|
|
@ -105,7 +104,7 @@ func TestIPAllowLister_ServeHTTP(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
|
||||
allowLister, err := New(t.Context(), next, test.allowList, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -37,7 +36,7 @@ func TestNewIPWhiteLister(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
whiteLister, err := New(t.Context(), next, test.whiteList, "traefikTest")
|
||||
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
|
|
@ -79,7 +78,7 @@ func TestIPWhiteLister_ServeHTTP(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
whiteLister, err := New(t.Context(), next, test.whiteList, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package observability
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -68,7 +67,7 @@ func TestEntryPointMiddleware_tracing(t *testing.T) {
|
|||
|
||||
tracer := &mockTracer{}
|
||||
|
||||
handler := newEntryPoint(context.Background(), tracing.NewTracer(tracer, []string{"X-Foo"}, []string{"X-Bar"}, []string{"q"}), test.entryPoint, next)
|
||||
handler := newEntryPoint(t.Context(), tracing.NewTracer(tracer, []string{"X-Foo"}, []string{"X-Bar"}, []string{"q"}), test.entryPoint, next)
|
||||
handler.ServeHTTP(rw, req)
|
||||
|
||||
for _, span := range tracer.spans {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package observability
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -74,7 +73,7 @@ func TestNewRouter(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusNotFound)
|
||||
})
|
||||
|
||||
handler := newRouter(context.Background(), test.router, test.routerRule, test.service, next)
|
||||
handler := newRouter(t.Context(), test.router, test.routerRule, test.service, next)
|
||||
handler.ServeHTTP(rw, req)
|
||||
|
||||
for i, span := range tracer.spans {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package observability
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -65,7 +64,7 @@ func TestSemConvServerMetrics(t *testing.T) {
|
|||
// force the meter provider with manual reader to collect metrics for the test.
|
||||
metrics.SetMeterProvider(meterProvider)
|
||||
|
||||
semConvMetricRegistry, err := metrics.NewSemConvMetricRegistry(context.Background(), &cfg)
|
||||
semConvMetricRegistry, err := metrics.NewSemConvMetricRegistry(t.Context(), &cfg)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, semConvMetricRegistry)
|
||||
|
||||
|
|
@ -79,7 +78,7 @@ func TestSemConvServerMetrics(t *testing.T) {
|
|||
rw.WriteHeader(test.statusCode)
|
||||
})
|
||||
|
||||
handler := newServerMetricsSemConv(context.Background(), semConvMetricRegistry, next)
|
||||
handler := newServerMetricsSemConv(t.Context(), semConvMetricRegistry, next)
|
||||
|
||||
handler, err = capture.Wrap(handler)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -87,7 +86,7 @@ func TestSemConvServerMetrics(t *testing.T) {
|
|||
handler.ServeHTTP(rw, req)
|
||||
|
||||
got := metricdata.ResourceMetrics{}
|
||||
err = rdr.Collect(context.Background(), &got)
|
||||
err = rdr.Collect(t.Context(), &got)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, got.ScopeMetrics, 1)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package observability
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -68,7 +67,7 @@ func TestNewService(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusNotFound)
|
||||
})
|
||||
|
||||
handler := NewService(context.Background(), test.service, next)
|
||||
handler := NewService(t.Context(), test.service, next)
|
||||
handler.ServeHTTP(rw, req)
|
||||
|
||||
for i, span := range tracer.spans {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package passtlsclientcert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
|
@ -313,7 +312,7 @@ func TestPassTLSClientCert_PEM(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tlsClientHeaders, err := New(context.Background(), next, test.config, "foo")
|
||||
tlsClientHeaders, err := New(t.Context(), next, test.config, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
|
|
@ -535,7 +534,7 @@ func TestPassTLSClientCert_certInfo(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tlsClientHeaders, err := New(context.Background(), next, test.config, "foo")
|
||||
tlsClientHeaders, err := New(t.Context(), next, test.config, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
|
|
|
|||
|
|
@ -146,7 +146,12 @@ func (rl *rateLimiter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
logger.Info().Msgf("ignoring token bucket amount > 1: %d", amount)
|
||||
}
|
||||
|
||||
delay, err := rl.limiter.Allow(ctx, source)
|
||||
// Each rate limiter has its own source space,
|
||||
// ensuring independence between rate limiters,
|
||||
// i.e., rate limit rules are only applied based on traffic
|
||||
// where the rate limiter is active.
|
||||
rlSource := fmt.Sprintf("%s:%s", rl.name, source)
|
||||
delay, err := rl.limiter.Allow(ctx, rlSource)
|
||||
if err != nil {
|
||||
rl.logger.Error().Err(err).Msg("Could not insert/update bucket")
|
||||
observability.SetStatusErrorf(ctx, "Could not insert/update bucket")
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ func TestNewRateLimiter(t *testing.T) {
|
|||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
h, err := New(context.Background(), next, test.config, "rate-limiter")
|
||||
h, err := New(t.Context(), next, test.config, "rate-limiter")
|
||||
if test.expectedError != "" {
|
||||
assert.EqualError(t, err, test.expectedError)
|
||||
} else {
|
||||
|
|
@ -274,7 +274,7 @@ func TestInMemoryRateLimit(t *testing.T) {
|
|||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
reqCount++
|
||||
})
|
||||
h, err := New(context.Background(), next, test.config, "rate-limiter")
|
||||
h, err := New(t.Context(), next, test.config, "rate-limiter")
|
||||
require.NoError(t, err)
|
||||
|
||||
loadPeriod := time.Duration(1e9 / test.incomingLoad)
|
||||
|
|
@ -477,7 +477,7 @@ func TestRedisRateLimit(t *testing.T) {
|
|||
test.config.Redis = &dynamic.Redis{
|
||||
Endpoints: []string{"localhost:6379"},
|
||||
}
|
||||
h, err := New(context.Background(), next, test.config, "rate-limiter")
|
||||
h, err := New(t.Context(), next, test.config, "rate-limiter")
|
||||
require.NoError(t, err)
|
||||
|
||||
l := h.(*rateLimiter)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package recovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -47,7 +46,7 @@ func TestRecoverHandler(t *testing.T) {
|
|||
}
|
||||
panic(test.panicErr)
|
||||
}
|
||||
recovery, err := New(context.Background(), http.HandlerFunc(fn))
|
||||
recovery, err := New(t.Context(), http.HandlerFunc(fn))
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(recovery)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -158,7 +157,7 @@ func TestRedirectRegexHandler(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
handler, err := NewRedirectRegex(context.Background(), next, test.config, "traefikTest")
|
||||
handler, err := NewRedirectRegex(t.Context(), next, test.config, "traefikTest")
|
||||
|
||||
if test.errorExpected {
|
||||
require.Error(t, err)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -287,7 +286,7 @@ func TestRedirectSchemeHandler(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
handler, err := NewRedirectScheme(context.Background(), next, test.config, "traefikTest")
|
||||
handler, err := NewRedirectScheme(t.Context(), next, test.config, "traefikTest")
|
||||
|
||||
if test.errorExpected {
|
||||
require.Error(t, err)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package replacepath
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -82,7 +81,7 @@ func TestReplacePath(t *testing.T) {
|
|||
requestURI = r.RequestURI
|
||||
})
|
||||
|
||||
handler, err := New(context.Background(), next, test.config, "foo-replace-path")
|
||||
handler, err := New(t.Context(), next, test.config, "foo-replace-path")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(handler)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package replacepathregex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -150,7 +149,7 @@ func TestReplacePathRegex(t *testing.T) {
|
|||
requestURI = r.RequestURI
|
||||
})
|
||||
|
||||
handler, err := New(context.Background(), next, test.config, "foo-replace-path-regexp")
|
||||
handler, err := New(t.Context(), next, test.config, "foo-replace-path-regexp")
|
||||
if test.expectsError {
|
||||
require.Error(t, err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package requestdecorator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -43,7 +42,7 @@ func TestCNAMEFlatten(t *testing.T) {
|
|||
ResolvDepth: 5,
|
||||
}
|
||||
|
||||
flatH := hostResolver.CNAMEFlatten(context.Background(), test.domain)
|
||||
flatH := hostResolver.CNAMEFlatten(t.Context(), test.domain)
|
||||
assert.Equal(t, test.expectedDomain, flatH)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -129,7 +128,7 @@ func TestRetry(t *testing.T) {
|
|||
})
|
||||
|
||||
retryListener := &countingRetryListener{}
|
||||
retry, err := New(context.Background(), next, test.config, retryListener, "traefikTest")
|
||||
retry, err := New(t.Context(), next, test.config, retryListener, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
|
@ -149,7 +148,7 @@ func TestRetryEmptyServerList(t *testing.T) {
|
|||
})
|
||||
|
||||
retryListener := &countingRetryListener{}
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 3}, retryListener, "traefikTest")
|
||||
retry, err := New(t.Context(), next, dynamic.Retry{Attempts: 3}, retryListener, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
|
@ -185,7 +184,7 @@ func TestMultipleRetriesShouldNotLooseHeaders(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 3}, &countingRetryListener{}, "traefikTest")
|
||||
retry, err := New(t.Context(), next, dynamic.Retry{Attempts: 3}, &countingRetryListener{}, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
|
|
@ -219,7 +218,7 @@ func TestRetryShouldNotLooseHeadersOnWrite(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 3}, &countingRetryListener{}, "traefikTest")
|
||||
retry, err := New(t.Context(), next, dynamic.Retry{Attempts: 3}, &countingRetryListener{}, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
|
|
@ -243,7 +242,7 @@ func TestRetryWithFlush(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 1}, &countingRetryListener{}, "traefikTest")
|
||||
retry, err := New(t.Context(), next, dynamic.Retry{Attempts: 1}, &countingRetryListener{}, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
responseRecorder := httptest.NewRecorder()
|
||||
|
|
@ -312,7 +311,7 @@ func TestRetryWebsocket(t *testing.T) {
|
|||
})
|
||||
|
||||
retryListener := &countingRetryListener{}
|
||||
retryH, err := New(context.Background(), next, dynamic.Retry{Attempts: test.maxRequestAttempts}, retryListener, "traefikTest")
|
||||
retryH, err := New(t.Context(), next, dynamic.Retry{Attempts: test.maxRequestAttempts}, retryListener, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
retryServer := httptest.NewServer(retryH)
|
||||
|
|
@ -345,7 +344,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
})
|
||||
|
||||
retryListener := &countingRetryListener{}
|
||||
retry, err := New(context.Background(), next, dynamic.Retry{Attempts: 1}, retryListener, "traefikTest")
|
||||
retry, err := New(t.Context(), next, dynamic.Retry{Attempts: 1}, retryListener, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
server := httptest.NewServer(retry)
|
||||
|
|
@ -389,7 +388,7 @@ func Test1xxResponses(t *testing.T) {
|
|||
return nil
|
||||
},
|
||||
}
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(context.Background(), trace), http.MethodGet, server.URL, nil)
|
||||
req, _ := http.NewRequestWithContext(httptrace.WithClientTrace(t.Context(), trace), http.MethodGet, server.URL, nil)
|
||||
|
||||
res, err := frontendClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package stripprefix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -148,7 +147,7 @@ func TestStripPrefix(t *testing.T) {
|
|||
pointer := func(v bool) *bool { return &v }
|
||||
test.config.ForceSlash = pointer(false)
|
||||
|
||||
handler, err := New(context.Background(), next, test.config, "foo-strip-prefix")
|
||||
handler, err := New(t.Context(), next, test.config, "foo-strip-prefix")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+test.path, nil)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package stripprefixregex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -118,7 +117,7 @@ func TestStripPrefixRegex(t *testing.T) {
|
|||
actualHeader = r.Header.Get(stripprefix.ForwardedPrefixHeader)
|
||||
requestURI = r.RequestURI
|
||||
})
|
||||
handler, err := New(context.Background(), handlerPath, testPrefixRegex, "foo-strip-prefix-regex")
|
||||
handler, err := New(t.Context(), handlerPath, testPrefixRegex, "foo-strip-prefix-regex")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+test.path, nil)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package inflightconn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -27,7 +26,7 @@ func TestInFlightConn_ServeTCP(t *testing.T) {
|
|||
finishCh <- struct{}{}
|
||||
})
|
||||
|
||||
middleware, err := New(context.Background(), next, dynamic.TCPInFlightConn{Amount: 1}, "foo")
|
||||
middleware, err := New(t.Context(), next, dynamic.TCPInFlightConn{Amount: 1}, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
// The first connection should succeed and wait.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func TestNewIPAllowLister(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := tcp.HandlerFunc(func(conn tcp.WriteCloser) {})
|
||||
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
|
||||
allowLister, err := New(t.Context(), next, test.allowList, "traefikTest")
|
||||
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
|
|
@ -92,7 +92,7 @@ func TestIPAllowLister_ServeHTTP(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
allowLister, err := New(context.Background(), next, test.allowList, "traefikTest")
|
||||
allowLister, err := New(t.Context(), next, test.allowList, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
server, client := net.Pipe()
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func TestNewIPWhiteLister(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := tcp.HandlerFunc(func(conn tcp.WriteCloser) {})
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
whiteLister, err := New(t.Context(), next, test.whiteList, "traefikTest")
|
||||
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
|
|
@ -92,7 +92,7 @@ func TestIPWhiteLister_ServeHTTP(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
whiteLister, err := New(context.Background(), next, test.whiteList, "traefikTest")
|
||||
whiteLister, err := New(t.Context(), next, test.whiteList, "traefikTest")
|
||||
require.NoError(t, err)
|
||||
|
||||
server, client := net.Pipe()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
|
||||
)
|
||||
|
||||
var httpFuncs = map[string]func(*matchersTree, ...string) error{
|
||||
var httpFuncs = matcherBuilderFuncs{
|
||||
"ClientIP": expectNParameters(clientIP, 1),
|
||||
"Method": expectNParameters(method, 1),
|
||||
"Host": expectNParameters(host, 1),
|
||||
|
|
@ -142,7 +142,8 @@ func path(tree *matchersTree, paths ...string) error {
|
|||
}
|
||||
|
||||
tree.matcher = func(req *http.Request) bool {
|
||||
return req.URL.Path == path
|
||||
routingPath := getRoutingPath(req)
|
||||
return routingPath != nil && *routingPath == path
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -157,7 +158,8 @@ func pathRegexp(tree *matchersTree, paths ...string) error {
|
|||
}
|
||||
|
||||
tree.matcher = func(req *http.Request) bool {
|
||||
return re.MatchString(req.URL.Path)
|
||||
routingPath := getRoutingPath(req)
|
||||
return routingPath != nil && re.MatchString(*routingPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -171,7 +173,8 @@ func pathPrefix(tree *matchersTree, paths ...string) error {
|
|||
}
|
||||
|
||||
tree.matcher = func(req *http.Request) bool {
|
||||
return strings.HasPrefix(req.URL.Path, path)
|
||||
routingPath := getRoutingPath(req)
|
||||
return routingPath != nil && strings.HasPrefix(*routingPath, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -69,9 +69,11 @@ func TestClientIPMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -142,9 +144,11 @@ func TestMethodMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -259,9 +263,11 @@ func TestHostMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -358,9 +364,11 @@ func TestHostRegexpMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -431,9 +439,11 @@ func TestPathMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -523,9 +533,11 @@ func TestPathRegexpMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -594,9 +606,11 @@ func TestPathPrefixMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -680,9 +694,11 @@ func TestHeaderMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -787,9 +803,11 @@ func TestHeaderRegexpMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -875,9 +893,11 @@ func TestQueryMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -988,9 +1008,11 @@ func TestQueryRegexpMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
|
||||
)
|
||||
|
||||
var httpFuncsV2 = map[string]func(*matchersTree, ...string) error{
|
||||
var httpFuncsV2 = matcherBuilderFuncs{
|
||||
"Host": hostV2,
|
||||
"HostHeader": hostV2,
|
||||
"HostRegexp": hostRegexpV2,
|
||||
|
|
@ -28,7 +28,7 @@ func pathV2(tree *matchersTree, paths ...string) error {
|
|||
var routes []*mux.Route
|
||||
|
||||
for _, path := range paths {
|
||||
route := mux.NewRouter().NewRoute()
|
||||
route := mux.NewRouter().UseRoutingPath().NewRoute()
|
||||
|
||||
if err := route.Path(path).GetError(); err != nil {
|
||||
return err
|
||||
|
|
@ -54,7 +54,7 @@ func pathPrefixV2(tree *matchersTree, paths ...string) error {
|
|||
var routes []*mux.Route
|
||||
|
||||
for _, path := range paths {
|
||||
route := mux.NewRouter().NewRoute()
|
||||
route := mux.NewRouter().UseRoutingPath().NewRoute()
|
||||
|
||||
if err := route.PathPrefix(path).GetError(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -73,9 +73,11 @@ func TestClientIPV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -149,9 +151,11 @@ func TestMethodV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -273,9 +277,11 @@ func TestHostV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -375,9 +381,11 @@ func TestHostRegexpV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -469,9 +477,11 @@ func TestPathV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -561,9 +571,11 @@ func TestPathPrefixV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -647,9 +659,11 @@ func TestHeadersMatcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -754,9 +768,11 @@ func TestHeaderRegexpV2Matcher(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
@ -846,9 +862,11 @@ func TestHostRegexp(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.hostExp, "v2", 0, handler)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -1513,9 +1531,11 @@ func Test_addRoute(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "v2", 0, handler)
|
||||
if test.expectedError {
|
||||
require.Error(t, err)
|
||||
|
|
|
|||
|
|
@ -1,55 +1,53 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/rules"
|
||||
"github.com/vulcand/predicate"
|
||||
)
|
||||
|
||||
type matcherBuilderFuncs map[string]matcherBuilderFunc
|
||||
|
||||
type matcherBuilderFunc func(*matchersTree, ...string) error
|
||||
|
||||
type MatcherFunc func(*http.Request) bool
|
||||
|
||||
// Muxer handles routing with rules.
|
||||
type Muxer struct {
|
||||
routes routes
|
||||
parser predicate.Parser
|
||||
parserV2 predicate.Parser
|
||||
parser SyntaxParser
|
||||
defaultHandler http.Handler
|
||||
}
|
||||
|
||||
// NewMuxer returns a new muxer instance.
|
||||
func NewMuxer() (*Muxer, error) {
|
||||
var matchers []string
|
||||
for matcher := range httpFuncs {
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
|
||||
parser, err := rules.NewParser(matchers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while creating parser: %w", err)
|
||||
}
|
||||
|
||||
var matchersV2 []string
|
||||
for matcher := range httpFuncsV2 {
|
||||
matchersV2 = append(matchersV2, matcher)
|
||||
}
|
||||
|
||||
parserV2, err := rules.NewParser(matchersV2)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while creating v2 parser: %w", err)
|
||||
}
|
||||
|
||||
func NewMuxer(parser SyntaxParser) *Muxer {
|
||||
return &Muxer{
|
||||
parser: parser,
|
||||
parserV2: parserV2,
|
||||
defaultHandler: http.NotFoundHandler(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP forwards the connection to the matching HTTP handler.
|
||||
// Serves 404 if no handler is found.
|
||||
func (m *Muxer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
logger := log.Ctx(req.Context())
|
||||
|
||||
var err error
|
||||
req, err = withRoutingPath(req)
|
||||
if err != nil {
|
||||
logger.Debug().Err(err).Msg("Unable to add routing path to request context")
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
for _, route := range m.routes {
|
||||
if route.matchers.match(req) {
|
||||
route.handler.ServeHTTP(rw, req)
|
||||
|
|
@ -73,36 +71,9 @@ func GetRulePriority(rule string) int {
|
|||
|
||||
// AddRoute add a new route to the router.
|
||||
func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler http.Handler) error {
|
||||
var parse interface{}
|
||||
var err error
|
||||
var matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||
|
||||
switch syntax {
|
||||
case "v2":
|
||||
parse, err = m.parserV2.Parse(rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||
}
|
||||
|
||||
matcherFuncs = httpFuncsV2
|
||||
default:
|
||||
parse, err = m.parser.Parse(rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||
}
|
||||
|
||||
matcherFuncs = httpFuncs
|
||||
}
|
||||
|
||||
buildTree, ok := parse.(rules.TreeBuilder)
|
||||
if !ok {
|
||||
return fmt.Errorf("error while parsing rule %s", rule)
|
||||
}
|
||||
|
||||
var matchers matchersTree
|
||||
err = matchers.addRule(buildTree(), matcherFuncs)
|
||||
matchers, err := m.parser.parse(syntax, rule)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while adding rule %s: %w", rule, err)
|
||||
return fmt.Errorf("error while parsing rule %s: %w", rule, err)
|
||||
}
|
||||
|
||||
m.routes = append(m.routes, &route{
|
||||
|
|
@ -116,6 +87,86 @@ func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler http.
|
|||
return nil
|
||||
}
|
||||
|
||||
// reservedCharacters contains the mapping of the percent-encoded form to the ASCII form
|
||||
// of the reserved characters according to https://datatracker.ietf.org/doc/html/rfc3986#section-2.2.
|
||||
// By extension to https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 the percent character is also considered a reserved character.
|
||||
// Because decoding the percent character would change the meaning of the URL.
|
||||
var reservedCharacters = map[string]rune{
|
||||
"%3A": ':',
|
||||
"%2F": '/',
|
||||
"%3F": '?',
|
||||
"%23": '#',
|
||||
"%5B": '[',
|
||||
"%5D": ']',
|
||||
"%40": '@',
|
||||
"%21": '!',
|
||||
"%24": '$',
|
||||
"%26": '&',
|
||||
"%27": '\'',
|
||||
"%28": '(',
|
||||
"%29": ')',
|
||||
"%2A": '*',
|
||||
"%2B": '+',
|
||||
"%2C": ',',
|
||||
"%3B": ';',
|
||||
"%3D": '=',
|
||||
"%25": '%',
|
||||
}
|
||||
|
||||
// getRoutingPath retrieves the routing path from the request context.
|
||||
// It returns nil if the routing path is not set in the context.
|
||||
func getRoutingPath(req *http.Request) *string {
|
||||
routingPath := req.Context().Value(mux.RoutingPathKey)
|
||||
if routingPath != nil {
|
||||
rp := routingPath.(string)
|
||||
return &rp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// withRoutingPath decodes non-allowed characters in the EscapedPath and stores it in the request context to be able to use it for routing.
|
||||
// This allows using the decoded version of the non-allowed characters in the routing rules for a better UX.
|
||||
// For example, the rule PathPrefix(`/foo bar`) will match the following request path `/foo%20bar`.
|
||||
func withRoutingPath(req *http.Request) (*http.Request, error) {
|
||||
escapedPath := req.URL.EscapedPath()
|
||||
|
||||
var routingPathBuilder strings.Builder
|
||||
for i := 0; i < len(escapedPath); i++ {
|
||||
if escapedPath[i] != '%' {
|
||||
routingPathBuilder.WriteString(string(escapedPath[i]))
|
||||
continue
|
||||
}
|
||||
|
||||
// This should never happen as the standard library will reject requests containing invalid percent-encodings.
|
||||
// This discards URLs with a percent character at the end.
|
||||
if i+2 >= len(escapedPath) {
|
||||
return nil, errors.New("invalid percent-encoding at the end of the URL path")
|
||||
}
|
||||
|
||||
encodedCharacter := escapedPath[i : i+3]
|
||||
if _, reserved := reservedCharacters[encodedCharacter]; reserved {
|
||||
routingPathBuilder.WriteString(encodedCharacter)
|
||||
} else {
|
||||
// This should never happen as the standard library will reject requests containing invalid percent-encodings.
|
||||
decodedCharacter, err := url.PathUnescape(encodedCharacter)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid percent-encoding in URL path")
|
||||
}
|
||||
routingPathBuilder.WriteString(decodedCharacter)
|
||||
}
|
||||
|
||||
i += 2
|
||||
}
|
||||
|
||||
return req.WithContext(
|
||||
context.WithValue(
|
||||
req.Context(),
|
||||
mux.RoutingPathKey,
|
||||
routingPathBuilder.String(),
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
||||
// ParseDomains extract domains from rule.
|
||||
func ParseDomains(rule string) ([]string, error) {
|
||||
var matchers []string
|
||||
|
|
@ -173,7 +224,7 @@ type matchersTree struct {
|
|||
// matcher is a matcher func used to match HTTP request properties.
|
||||
// If matcher is not nil, it means that this matcherTree is a leaf of the tree.
|
||||
// It is therefore mutually exclusive with left and right.
|
||||
matcher func(*http.Request) bool
|
||||
matcher MatcherFunc
|
||||
// operator to combine the evaluation of left and right leaves.
|
||||
operator string
|
||||
// Mutually exclusive with matcher.
|
||||
|
|
@ -204,9 +255,7 @@ func (m *matchersTree) match(req *http.Request) bool {
|
|||
}
|
||||
}
|
||||
|
||||
type matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||
|
||||
func (m *matchersTree) addRule(rule *rules.Tree, funcs matcherFuncs) error {
|
||||
func (m *matchersTree) addRule(rule *rules.Tree, funcs matcherBuilderFuncs) error {
|
||||
switch rule.Matcher {
|
||||
case "and", "or":
|
||||
m.operator = rule.Matcher
|
||||
|
|
|
|||
|
|
@ -225,9 +225,11 @@ func TestMuxer(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
if test.expectedError {
|
||||
|
|
@ -378,9 +380,11 @@ func Test_addRoutePriority(t *testing.T) {
|
|||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
for _, route := range test.cases {
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-From", route.xFrom)
|
||||
|
|
@ -510,9 +514,11 @@ func TestEmptyHost(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := NewMuxer()
|
||||
parser, err := NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := NewMuxer(parser)
|
||||
|
||||
err = muxer.AddRoute(test.rule, "", 0, handler)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -551,3 +557,43 @@ func TestGetRulePriority(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoutingPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
path string
|
||||
expectedRoutingPath string
|
||||
}{
|
||||
{
|
||||
desc: "unallowed percent-encoded character is decoded",
|
||||
path: "/foo%20bar",
|
||||
expectedRoutingPath: "/foo bar",
|
||||
},
|
||||
{
|
||||
desc: "reserved percent-encoded character is kept encoded",
|
||||
path: "/foo%2Fbar",
|
||||
expectedRoutingPath: "/foo%2Fbar",
|
||||
},
|
||||
{
|
||||
desc: "multiple mixed characters",
|
||||
path: "/foo%20bar%2Fbaz%23qux",
|
||||
expectedRoutingPath: "/foo bar%2Fbaz%23qux",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://foo"+test.path, http.NoBody)
|
||||
|
||||
var err error
|
||||
req, err = withRoutingPath(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
gotRoutingPath := getRoutingPath(req)
|
||||
assert.NotNil(t, gotRoutingPath)
|
||||
assert.Equal(t, test.expectedRoutingPath, *gotRoutingPath)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
103
pkg/muxer/http/parser.go
Normal file
103
pkg/muxer/http/parser.go
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/traefik/traefik/v3/pkg/rules"
|
||||
"github.com/vulcand/predicate"
|
||||
)
|
||||
|
||||
type SyntaxParser struct {
|
||||
parsers map[string]*parser
|
||||
}
|
||||
|
||||
type Options func(map[string]matcherBuilderFuncs)
|
||||
|
||||
func WithMatcher(syntax, matcherName string, builderFunc func(params ...string) (MatcherFunc, error)) Options {
|
||||
return func(syntaxFuncs map[string]matcherBuilderFuncs) {
|
||||
syntax = strings.ToLower(syntax)
|
||||
|
||||
syntaxFuncs[syntax][matcherName] = func(tree *matchersTree, s ...string) error {
|
||||
matcher, err := builderFunc(s...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("building matcher: %w", err)
|
||||
}
|
||||
|
||||
tree.matcher = matcher
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewSyntaxParser(opts ...Options) (SyntaxParser, error) {
|
||||
syntaxFuncs := map[string]matcherBuilderFuncs{
|
||||
"v2": httpFuncsV2,
|
||||
"v3": httpFuncs,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(syntaxFuncs)
|
||||
}
|
||||
|
||||
parsers := map[string]*parser{}
|
||||
for syntax, funcs := range syntaxFuncs {
|
||||
var err error
|
||||
parsers[syntax], err = newParser(funcs)
|
||||
if err != nil {
|
||||
return SyntaxParser{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return SyntaxParser{
|
||||
parsers: parsers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s SyntaxParser) parse(syntax string, rule string) (matchersTree, error) {
|
||||
parser, ok := s.parsers[syntax]
|
||||
if !ok {
|
||||
parser = s.parsers["v3"]
|
||||
}
|
||||
|
||||
return parser.parse(rule)
|
||||
}
|
||||
|
||||
func newParser(funcs matcherBuilderFuncs) (*parser, error) {
|
||||
p, err := rules.NewParser(slices.Collect(maps.Keys(funcs)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &parser{
|
||||
parser: p,
|
||||
matcherFuncs: funcs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
parser predicate.Parser
|
||||
matcherFuncs matcherBuilderFuncs
|
||||
}
|
||||
|
||||
func (p *parser) parse(rule string) (matchersTree, error) {
|
||||
parse, err := p.parser.Parse(rule)
|
||||
if err != nil {
|
||||
return matchersTree{}, fmt.Errorf("parsing rule %s: %w", rule, err)
|
||||
}
|
||||
buildTree, ok := parse.(rules.TreeBuilder)
|
||||
if !ok {
|
||||
return matchersTree{}, errors.New("obtaining build tree")
|
||||
}
|
||||
|
||||
var matchers matchersTree
|
||||
err = matchers.addRule(buildTree(), p.matcherFuncs)
|
||||
if err != nil {
|
||||
return matchersTree{}, fmt.Errorf("adding rule %s: %w", rule, err)
|
||||
}
|
||||
|
||||
return matchers, nil
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
|
|
@ -21,7 +20,7 @@ func TestSettingsWithoutSocket(t *testing.T) {
|
|||
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
|
||||
ctx := log.Logger.WithContext(context.Background())
|
||||
ctx := log.Logger.WithContext(t.Context())
|
||||
|
||||
t.Setenv("PLUGIN_TEST", "MY-TEST")
|
||||
t.Setenv("PLUGIN_TEST_B", "MY-TEST_B")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -47,7 +46,7 @@ func TestLocalStore_GetAccount(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
s := NewLocalStore(test.filename, safe.NewPool(context.Background()))
|
||||
s := NewLocalStore(test.filename, safe.NewPool(t.Context()))
|
||||
|
||||
account, err := s.GetAccount("test")
|
||||
require.NoError(t, err)
|
||||
|
|
@ -60,7 +59,7 @@ func TestLocalStore_GetAccount(t *testing.T) {
|
|||
func TestLocalStore_SaveAccount(t *testing.T) {
|
||||
acmeFile := filepath.Join(t.TempDir(), "acme.json")
|
||||
|
||||
s := NewLocalStore(acmeFile, safe.NewPool(context.Background()))
|
||||
s := NewLocalStore(acmeFile, safe.NewPool(t.Context()))
|
||||
|
||||
email := "some@email.com"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package acme
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -181,7 +180,7 @@ func TestGetUncheckedCertificates(t *testing.T) {
|
|||
resolvingDomains: test.resolvingDomains,
|
||||
}
|
||||
|
||||
domains := acmeProvider.getUncheckedDomains(context.Background(), test.domains, "default")
|
||||
domains := acmeProvider.getUncheckedDomains(t.Context(), test.domains, "default")
|
||||
assert.Len(t, domains, len(test.expectedDomains), "Unexpected domains.")
|
||||
})
|
||||
}
|
||||
|
|
@ -245,7 +244,7 @@ func TestProvider_sanitizeDomains(t *testing.T) {
|
|||
|
||||
acmeProvider := Provider{Configuration: &Configuration{DNSChallenge: test.dnsChallenge}}
|
||||
|
||||
domains, err := acmeProvider.sanitizeDomains(context.Background(), test.domains)
|
||||
domains, err := acmeProvider.sanitizeDomains(t.Context(), test.domains)
|
||||
|
||||
if len(test.expectedErr) > 0 {
|
||||
assert.EqualError(t, err, test.expectedErr, "Unexpected error.")
|
||||
|
|
@ -424,7 +423,7 @@ func TestDeleteUnnecessaryDomains(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
domains := deleteUnnecessaryDomains(context.Background(), test.domains)
|
||||
domains := deleteUnnecessaryDomains(t.Context(), test.domains)
|
||||
assert.Equal(t, test.expectedDomains, domains, "unexpected domain")
|
||||
})
|
||||
}
|
||||
|
|
@ -497,7 +496,7 @@ func TestIsAccountMatchingCaServer(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result := isAccountMatchingCaServer(context.Background(), test.accountURI, test.serverURI)
|
||||
result := isAccountMatchingCaServer(t.Context(), test.accountURI, test.serverURI)
|
||||
|
||||
assert.Equal(t, test.expected, result)
|
||||
})
|
||||
|
|
@ -574,7 +573,7 @@ func TestInitAccount(t *testing.T) {
|
|||
|
||||
acmeProvider := Provider{account: test.account, Configuration: &Configuration{Email: test.email, KeyType: test.keyType}}
|
||||
|
||||
actualAccount, err := acmeProvider.initAccount(context.Background())
|
||||
actualAccount, err := acmeProvider.initAccount(t.Context())
|
||||
assert.NoError(t, err, "Init account in error")
|
||||
assert.Equal(t, test.expectedAccount.Email, actualAccount.Email, "unexpected email account")
|
||||
assert.Equal(t, test.expectedAccount.KeyType, actualAccount.KeyType, "unexpected keyType account")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package aggregator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ func TestProviderAggregator_Provide(t *testing.T) {
|
|||
|
||||
cfgCh := make(chan dynamic.Message)
|
||||
errCh := make(chan error)
|
||||
pool := safe.NewPool(context.Background())
|
||||
pool := safe.NewPool(t.Context())
|
||||
|
||||
t.Cleanup(pool.Stop)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package consulcatalog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -323,7 +322,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configuration := p.buildConfiguration(context.Background(), test.items, nil)
|
||||
configuration := p.buildConfiguration(t.Context(), test.items, nil)
|
||||
|
||||
assert.Equal(t, test.expected, configuration)
|
||||
})
|
||||
|
|
@ -3602,7 +3601,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
test.items[i].Tags = tags
|
||||
}
|
||||
|
||||
configuration := p.buildConfiguration(context.Background(), test.items, &connectCert{
|
||||
configuration := p.buildConfiguration(t.Context(), test.items, &connectCert{
|
||||
root: []string{"root"},
|
||||
leaf: keyPair{
|
||||
cert: "cert",
|
||||
|
|
@ -4120,7 +4119,7 @@ func TestFilterHealthStatuses(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configuration := p.buildConfiguration(context.Background(), test.items, nil)
|
||||
configuration := p.buildConfiguration(t.Context(), test.items, nil)
|
||||
|
||||
assert.Equal(t, test.expected, configuration)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -340,7 +340,6 @@ func (p *DynConfBuilder) getIPAddress(ctx context.Context, container dockerData)
|
|||
}
|
||||
|
||||
netNotFound = true
|
||||
logger.Warn().Msgf("Could not find network named %q for container %q. Maybe you're missing the project's prefix in the label?", container.ExtraConf.Network, container.Name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,6 +381,9 @@ func (p *DynConfBuilder) getIPAddress(ctx context.Context, container dockerData)
|
|||
return p.getIPAddress(ctx, containerParsed)
|
||||
}
|
||||
|
||||
if netNotFound {
|
||||
logger.Warn().Msgf("Could not find network named %q for container %q. Maybe you're missing the project's prefix in the label?", container.ExtraConf.Network, container.Name)
|
||||
}
|
||||
for _, network := range container.NetworkSettings.Networks {
|
||||
if netNotFound {
|
||||
logger.Warn().Msgf("Defaulting to first available network (%q) for container %q.", network, container.Name)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -421,7 +420,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configuration := builder.build(context.Background(), test.containers)
|
||||
configuration := builder.build(t.Context(), test.containers)
|
||||
|
||||
assert.Equal(t, test.expected, configuration)
|
||||
})
|
||||
|
|
@ -3929,7 +3928,7 @@ func TestDynConfBuilder_build(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configuration := builder.build(context.Background(), test.containers)
|
||||
configuration := builder.build(t.Context(), test.containers)
|
||||
|
||||
assert.Equal(t, test.expected, configuration)
|
||||
})
|
||||
|
|
@ -4101,7 +4100,7 @@ func TestDynConfBuilder_getIPPort_docker(t *testing.T) {
|
|||
UseBindPortIP: true,
|
||||
}, nil, false)
|
||||
|
||||
actualIP, actualPort, actualError := builder.getIPPort(context.Background(), dData, test.serverPort)
|
||||
actualIP, actualPort, actualError := builder.getIPPort(t.Context(), dData, test.serverPort)
|
||||
if test.expected.error {
|
||||
require.Error(t, actualError)
|
||||
} else {
|
||||
|
|
@ -4219,7 +4218,7 @@ func TestDynConfBuilder_getIPAddress_docker(t *testing.T) {
|
|||
|
||||
builder := NewDynConfBuilder(conf, nil, false)
|
||||
|
||||
actual := builder.getIPAddress(context.Background(), dData)
|
||||
actual := builder.getIPAddress(t.Context(), dData)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
|
|
@ -4278,11 +4277,11 @@ func TestDynConfBuilder_getIPAddress_swarm(t *testing.T) {
|
|||
var p SwarmProvider
|
||||
require.NoError(t, p.Init())
|
||||
|
||||
dData, err := p.parseService(context.Background(), test.service, test.networks)
|
||||
dData, err := p.parseService(t.Context(), test.service, test.networks)
|
||||
require.NoError(t, err)
|
||||
|
||||
builder := NewDynConfBuilder(p.Shared, nil, false)
|
||||
actual := builder.getIPAddress(context.Background(), dData)
|
||||
actual := builder.getIPAddress(t.Context(), dData)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -68,11 +67,11 @@ func TestListTasks(t *testing.T) {
|
|||
var p SwarmProvider
|
||||
require.NoError(t, p.Init())
|
||||
|
||||
dockerData, err := p.parseService(context.Background(), test.service, test.networks)
|
||||
dockerData, err := p.parseService(t.Context(), test.service, test.networks)
|
||||
require.NoError(t, err)
|
||||
|
||||
dockerClient := &fakeTasksClient{tasks: test.tasks}
|
||||
taskDockerData, _ := listTasks(context.Background(), dockerClient, test.service.ID, dockerData, test.networks, test.isGlobalSVC)
|
||||
taskDockerData, _ := listTasks(t.Context(), dockerClient, test.service.ID, dockerData, test.networks, test.isGlobalSVC)
|
||||
|
||||
if len(test.expectedTasks) != len(taskDockerData) {
|
||||
t.Errorf("expected tasks %v, got %v", test.expectedTasks, taskDockerData)
|
||||
|
|
@ -238,7 +237,7 @@ func TestSwarmProvider_listServices(t *testing.T) {
|
|||
var p SwarmProvider
|
||||
require.NoError(t, p.Init())
|
||||
|
||||
serviceDockerData, err := p.listServices(context.Background(), dockerClient)
|
||||
serviceDockerData, err := p.listServices(t.Context(), dockerClient)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, serviceDockerData, len(test.expectedServices))
|
||||
|
|
@ -357,11 +356,11 @@ func TestSwarmProvider_parseService_task(t *testing.T) {
|
|||
var p SwarmProvider
|
||||
require.NoError(t, p.Init())
|
||||
|
||||
dData, err := p.parseService(context.Background(), test.service, test.networks)
|
||||
dData, err := p.parseService(t.Context(), test.service, test.networks)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, task := range test.tasks {
|
||||
taskDockerData := parseTasks(context.Background(), task, dData, test.networks, test.isGlobalSVC)
|
||||
taskDockerData := parseTasks(t.Context(), task, dData, test.networks, test.isGlobalSVC)
|
||||
expected := test.expected[task.ID]
|
||||
assert.Equal(t, expected.Name, taskDockerData.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
|
|
@ -101,7 +100,7 @@ func Test_getPort_swarm(t *testing.T) {
|
|||
var p SwarmProvider
|
||||
require.NoError(t, p.Init())
|
||||
|
||||
dData, err := p.parseService(context.Background(), test.service, test.networks)
|
||||
dData, err := p.parseService(t.Context(), test.service, test.networks)
|
||||
require.NoError(t, err)
|
||||
|
||||
actual := getPort(dData, test.serverPort)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -390,7 +389,7 @@ func TestDefaultRule(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configuration := p.buildConfiguration(context.Background(), test.instances)
|
||||
configuration := p.buildConfiguration(t.Context(), test.instances)
|
||||
|
||||
assert.Equal(t, test.expected, configuration)
|
||||
})
|
||||
|
|
@ -3491,7 +3490,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
configuration := p.buildConfiguration(context.Background(), test.containers)
|
||||
configuration := p.buildConfiguration(t.Context(), test.containers)
|
||||
|
||||
assert.Equal(t, test.expected, configuration)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -67,7 +66,7 @@ func TestTLSCertificateContent(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
provider := &Provider{}
|
||||
configuration, err := provider.loadFileConfig(context.Background(), fileConfig.Name(), true)
|
||||
configuration, err := provider.loadFileConfig(t.Context(), fileConfig.Name(), true)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "CONTENT", configuration.TLS.Certificates[0].Certificate.CertFile.String())
|
||||
|
|
@ -92,7 +91,7 @@ func TestErrorWhenEmptyConfig(t *testing.T) {
|
|||
configChan := make(chan dynamic.Message)
|
||||
errorChan := make(chan struct{})
|
||||
go func() {
|
||||
err := provider.Provide(configChan, safe.NewPool(context.Background()))
|
||||
err := provider.Provide(configChan, safe.NewPool(t.Context()))
|
||||
assert.Error(t, err)
|
||||
close(errorChan)
|
||||
}()
|
||||
|
|
@ -116,7 +115,7 @@ func TestProvideWithoutWatch(t *testing.T) {
|
|||
provider.DebugLogGeneratedTemplate = true
|
||||
|
||||
go func() {
|
||||
err := provider.Provide(configChan, safe.NewPool(context.Background()))
|
||||
err := provider.Provide(configChan, safe.NewPool(t.Context()))
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
|
|
@ -146,7 +145,7 @@ func TestProvideWithWatch(t *testing.T) {
|
|||
configChan := make(chan dynamic.Message)
|
||||
|
||||
go func() {
|
||||
err := provider.Provide(configChan, safe.NewPool(context.Background()))
|
||||
err := provider.Provide(configChan, safe.NewPool(t.Context()))
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -235,7 +234,7 @@ func TestProvider_Provide(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
err = provider.Provide(configurationChan, safe.NewPool(context.Background()))
|
||||
err = provider.Provide(configurationChan, safe.NewPool(t.Context()))
|
||||
require.NoError(t, err)
|
||||
|
||||
timeout := time.After(time.Second)
|
||||
|
|
@ -269,7 +268,7 @@ func TestProvider_ProvideConfigurationOnlyOnceIfUnchanged(t *testing.T) {
|
|||
|
||||
configurationChan := make(chan dynamic.Message, 10)
|
||||
|
||||
err = provider.Provide(configurationChan, safe.NewPool(context.Background()))
|
||||
err = provider.Provide(configurationChan, safe.NewPool(t.Context()))
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -1677,7 +1676,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
|||
AllowEmptyServices: test.allowEmptyServices,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -5313,7 +5312,7 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||
AllowEmptyServices: test.allowEmptyServices,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -5389,7 +5388,7 @@ func TestLoadIngressRoutes_multipleEndpointAddresses(t *testing.T) {
|
|||
}
|
||||
|
||||
p := Provider{}
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
|
||||
service, ok := conf.HTTP.Services["default-test-route-6b204d94623b3df4370c"]
|
||||
require.True(t, ok)
|
||||
|
|
@ -5904,7 +5903,7 @@ func TestLoadIngressRouteUDPs(t *testing.T) {
|
|||
AllowEmptyServices: test.allowEmptyServices,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -7402,7 +7401,7 @@ func TestCrossNamespace(t *testing.T) {
|
|||
|
||||
p := Provider{AllowCrossNamespace: test.allowCrossNamespace}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -7672,7 +7671,7 @@ func TestExternalNameService(t *testing.T) {
|
|||
|
||||
p := Provider{AllowExternalNameServices: test.allowExternalNameService}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -7854,7 +7853,7 @@ func TestNativeLB(t *testing.T) {
|
|||
|
||||
p := Provider{}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -8122,7 +8121,7 @@ func TestNodePortLB(t *testing.T) {
|
|||
DisableClusterScopeResources: test.disableClusterScope,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -8634,7 +8633,7 @@ func TestGlobalNativeLB(t *testing.T) {
|
|||
|
||||
p := Provider{NativeLBByDefault: test.NativeLBByDefault}
|
||||
|
||||
conf := p.loadConfigurationFromCRD(context.Background(), client)
|
||||
conf := p.loadConfigurationFromCRD(t.Context(), client)
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ type ForwardingTimeouts struct {
|
|||
|
||||
// RootCA defines a reference to a Secret or a ConfigMap that holds a CA certificate.
|
||||
// If both a Secret and a ConfigMap reference are defined, the Secret reference takes precedence.
|
||||
// +kubebuilder:validation:XValidation:rule="has(self.secret) && has(self.configMap)",message="RootCA cannot have both Secret and ConfigMap defined."
|
||||
// +kubebuilder:validation:XValidation:rule="!has(self.secret) || !has(self.configMap)",message="RootCA cannot have both Secret and ConfigMap defined."
|
||||
type RootCA struct {
|
||||
// Secret defines the name of a Secret that holds a CA certificate.
|
||||
// The referenced Secret must contain a certificate under either a tls.ca or a ca.crt key.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package gateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
|
|
@ -75,14 +74,14 @@ func TestGatewayClassLabelSelector(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
_ = p.loadConfigurationFromGateways(context.Background())
|
||||
_ = p.loadConfigurationFromGateways(t.Context())
|
||||
|
||||
gw, err := gwClient.GatewayV1().Gateways("default").Get(context.Background(), "traefik-external", metav1.GetOptions{})
|
||||
gw, err := gwClient.GatewayV1().Gateways("default").Get(t.Context(), "traefik-external", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Empty(t, gw.Status.Addresses)
|
||||
|
||||
gw, err = gwClient.GatewayV1().Gateways("default").Get(context.Background(), "traefik-internal", metav1.GetOptions{})
|
||||
gw, err = gwClient.GatewayV1().Gateways("default").Get(t.Context(), "traefik-internal", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, gw.Status.Addresses, 1)
|
||||
require.NotNil(t, gw.Status.Addresses[0].Type)
|
||||
|
|
@ -2556,7 +2555,7 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -2983,7 +2982,7 @@ func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) {
|
|||
p.RegisterBackendFuncs(group, kind, backendFunc)
|
||||
}
|
||||
}
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -3269,7 +3268,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
|
|||
p.RegisterFilterFuncs(group, kind, filterFunc)
|
||||
}
|
||||
}
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -3561,7 +3560,7 @@ func TestLoadGRPCRoutes_filterExtensionRef(t *testing.T) {
|
|||
p.RegisterFilterFuncs(group, kind, filterFunc)
|
||||
}
|
||||
}
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -4463,7 +4462,7 @@ func TestLoadTCPRoutes(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -5742,7 +5741,7 @@ func TestLoadTLSRoutes(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -6798,7 +6797,7 @@ func TestLoadMixedRoutes(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -7134,7 +7133,7 @@ func TestLoadRoutesWithReferenceGrants(t *testing.T) {
|
|||
client: client,
|
||||
}
|
||||
|
||||
conf := p.loadConfigurationFromGateways(context.Background())
|
||||
conf := p.loadConfigurationFromGateways(t.Context())
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
|
|
@ -8186,7 +8185,7 @@ func newGatewaySimpleClientSet(t *testing.T, objects ...runtime.Object) *gatefak
|
|||
continue
|
||||
}
|
||||
|
||||
_, err := client.GatewayV1().Gateways(gateway.Namespace).Create(context.Background(), gateway, metav1.CreateOptions{})
|
||||
_, err := client.GatewayV1().Gateways(gateway.Namespace).Create(t.Context(), gateway, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ingress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -249,7 +248,7 @@ func TestClientIgnoresEmptyEndpointSliceUpdates(t *testing.T) {
|
|||
assert.Fail(t, "expected to receive event for endpointslices")
|
||||
}
|
||||
|
||||
emptyEndpointSlice, err = kubeClient.DiscoveryV1().EndpointSlices("test").Get(context.TODO(), "empty-endpointslice", metav1.GetOptions{})
|
||||
emptyEndpointSlice, err = kubeClient.DiscoveryV1().EndpointSlices("test").Get(t.Context(), "empty-endpointslice", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Update endpoint annotation and resource version (apparently not done by fake client itself)
|
||||
|
|
@ -257,7 +256,7 @@ func TestClientIgnoresEmptyEndpointSliceUpdates(t *testing.T) {
|
|||
// This reflects the behavior of kubernetes controllers which use endpoint annotations for leader election.
|
||||
emptyEndpointSlice.Annotations["test-annotation"] = "___"
|
||||
emptyEndpointSlice.ResourceVersion = "1245"
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(context.TODO(), emptyEndpointSlice, metav1.UpdateOptions{})
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(t.Context(), emptyEndpointSlice, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
|
|
@ -269,12 +268,12 @@ func TestClientIgnoresEmptyEndpointSliceUpdates(t *testing.T) {
|
|||
case <-time.After(50 * time.Millisecond):
|
||||
}
|
||||
|
||||
filledEndpointSlice, err = kubeClient.DiscoveryV1().EndpointSlices("test").Get(context.TODO(), "filled-endpointslice", metav1.GetOptions{})
|
||||
filledEndpointSlice, err = kubeClient.DiscoveryV1().EndpointSlices("test").Get(t.Context(), "filled-endpointslice", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
filledEndpointSlice.Endpoints[0].Addresses[0] = "10.13.37.2"
|
||||
filledEndpointSlice.ResourceVersion = "1235"
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(context.TODO(), filledEndpointSlice, metav1.UpdateOptions{})
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(t.Context(), filledEndpointSlice, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
|
|
@ -296,7 +295,7 @@ func TestClientIgnoresEmptyEndpointSliceUpdates(t *testing.T) {
|
|||
newPortNumber := int32(42)
|
||||
filledEndpointSlice.Ports[0].Port = &newPortNumber
|
||||
filledEndpointSlice.ResourceVersion = "1236"
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(context.TODO(), filledEndpointSlice, metav1.UpdateOptions{})
|
||||
_, err = kubeClient.DiscoveryV1().EndpointSlices("test").Update(t.Context(), filledEndpointSlice, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
kind: Ingress
|
||||
apiVersion: networking.k8s.io/v1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
resource:
|
||||
kind: Service
|
||||
name: service1
|
||||
pathType: Prefix
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
kind: Ingress
|
||||
apiVersion: networking.k8s.io/v1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend: {}
|
||||
pathType: Prefix
|
||||
|
||||
|
|
@ -316,6 +316,17 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
|
|||
}
|
||||
|
||||
for _, pa := range rule.HTTP.Paths {
|
||||
if pa.Backend.Resource != nil {
|
||||
// https://kubernetes.io/docs/concepts/services-networking/ingress/#resource-backend
|
||||
logger.Error().Msg("Resource backends are not supported")
|
||||
continue
|
||||
}
|
||||
|
||||
if pa.Backend.Service == nil {
|
||||
logger.Error().Msg("Missing service definition")
|
||||
continue
|
||||
}
|
||||
|
||||
service, err := p.loadService(client, ingress.Namespace, pa.Backend)
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
|
|
@ -493,15 +504,6 @@ func (p *Provider) shouldProcessIngress(ingress *netv1.Ingress, ingressClasses [
|
|||
}
|
||||
|
||||
func (p *Provider) loadService(client Client, namespace string, backend netv1.IngressBackend) (*dynamic.Service, error) {
|
||||
if backend.Resource != nil {
|
||||
// https://kubernetes.io/docs/concepts/services-networking/ingress/#resource-backend
|
||||
return nil, errors.New("resource backends are not supported")
|
||||
}
|
||||
|
||||
if backend.Service == nil {
|
||||
return nil, errors.New("missing service definition")
|
||||
}
|
||||
|
||||
service, exists, err := client.GetService(namespace, backend.Service.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package ingress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
|
@ -527,6 +526,28 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Ingress with backend resource",
|
||||
allowEmptyServices: true,
|
||||
expected: &dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Ingress without backend",
|
||||
allowEmptyServices: true,
|
||||
expected: &dynamic.Configuration{
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Ingress with one service without endpoint",
|
||||
expected: &dynamic.Configuration{
|
||||
|
|
@ -1675,7 +1696,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
|
|||
DefaultRuleSyntax: test.defaultRuleSyntax,
|
||||
StrictPrefixMatching: test.strictPrefixMatching,
|
||||
}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)
|
||||
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
|
|
@ -1801,7 +1822,7 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
|
|||
|
||||
p := Provider{IngressClass: test.ingressClass}
|
||||
p.AllowExternalNameServices = test.allowExternalNameServices
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)
|
||||
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
|
|
@ -1851,7 +1872,7 @@ func TestLoadConfigurationFromIngressesWithNativeLB(t *testing.T) {
|
|||
clientMock := newClientMock(generateTestFilename(test.desc))
|
||||
|
||||
p := Provider{IngressClass: test.ingressClass}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)
|
||||
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
|
|
@ -1912,7 +1933,7 @@ func TestLoadConfigurationFromIngressesWithNodePortLB(t *testing.T) {
|
|||
clientMock := newClientMock(generateTestFilename(test.desc))
|
||||
|
||||
p := Provider{DisableClusterScopeResources: test.clusterScopeDisabled}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)
|
||||
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
|
|
@ -2084,7 +2105,7 @@ func TestGetCertificates(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
tlsConfigs := map[string]*tls.CertAndStores{}
|
||||
err := getCertificates(context.Background(), test.ingress, test.client, tlsConfigs)
|
||||
err := getCertificates(t.Context(), test.ingress, test.client, tlsConfigs)
|
||||
|
||||
if test.errResult != "" {
|
||||
assert.EqualError(t, err, test.errResult)
|
||||
|
|
@ -2170,7 +2191,7 @@ func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
|
|||
IngressClass: test.ingressClass,
|
||||
NativeLBByDefault: true,
|
||||
}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
|
||||
conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)
|
||||
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
|
|
@ -2270,9 +2291,9 @@ func TestIngressEndpointPublishedService(t *testing.T) {
|
|||
PublishedService: "default/published-service",
|
||||
},
|
||||
}
|
||||
p.loadConfigurationFromIngresses(context.Background(), client)
|
||||
p.loadConfigurationFromIngresses(t.Context(), client)
|
||||
|
||||
ingress, err := kubeClient.NetworkingV1().Ingresses(metav1.NamespaceDefault).Get(context.Background(), "foo", metav1.GetOptions{})
|
||||
ingress, err := kubeClient.NetworkingV1().Ingresses(metav1.NamespaceDefault).Get(t.Context(), "foo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, test.expected, ingress.Status.LoadBalancer.Ingress)
|
||||
|
|
@ -2380,9 +2401,11 @@ func TestStrictPrefixMatchingRule(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
muxer, err := traefikhttp.NewMuxer()
|
||||
parser, err := traefikhttp.NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
muxer := traefikhttp.NewMuxer(parser)
|
||||
|
||||
rule := buildStrictPrefixMatchingRule(tt.path)
|
||||
err = muxer.AddRoute(rule, "", 0, handler)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package kv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -298,7 +297,7 @@ func Test_buildConfiguration(t *testing.T) {
|
|||
"traefik/tls/certificates/1/stores/1": "foobar",
|
||||
}))
|
||||
|
||||
cfg, err := provider.buildConfiguration(context.Background())
|
||||
cfg, err := provider.buildConfiguration(t.Context())
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := &dynamic.Configuration{
|
||||
|
|
@ -958,7 +957,7 @@ func Test_buildConfiguration_KV_error(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
cfg, err := provider.buildConfiguration(context.Background())
|
||||
cfg, err := provider.buildConfiguration(t.Context())
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, cfg)
|
||||
}
|
||||
|
|
@ -977,7 +976,7 @@ func TestKvWatchTree(t *testing.T) {
|
|||
|
||||
configChan := make(chan dynamic.Message)
|
||||
go func() {
|
||||
err := provider.watchKv(context.Background(), configChan)
|
||||
err := provider.watchKv(t.Context(), configChan)
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package nomad
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -251,8 +250,7 @@ func Test_defaultRule(t *testing.T) {
|
|||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.TODO()
|
||||
config := p.buildConfig(ctx, test.items)
|
||||
config := p.buildConfig(t.Context(), test.items)
|
||||
require.Equal(t, test.expected, config)
|
||||
})
|
||||
}
|
||||
|
|
@ -3077,8 +3075,7 @@ func Test_buildConfig(t *testing.T) {
|
|||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.TODO()
|
||||
c := p.buildConfig(ctx, test.items)
|
||||
c := p.buildConfig(t.Context(), test.items)
|
||||
require.Equal(t, test.expected, c)
|
||||
})
|
||||
}
|
||||
|
|
@ -3246,8 +3243,7 @@ func Test_buildConfigAllowEmptyServicesTrue(t *testing.T) {
|
|||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.TODO()
|
||||
c := p.buildConfig(ctx, test.items)
|
||||
c := p.buildConfig(t.Context(), test.items)
|
||||
require.Equal(t, test.expected, c)
|
||||
})
|
||||
}
|
||||
|
|
@ -3379,8 +3375,7 @@ func Test_buildConfigAllowEmptyServicesFalseDefault(t *testing.T) {
|
|||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.TODO()
|
||||
c := p.buildConfig(ctx, test.items)
|
||||
c := p.buildConfig(t.Context(), test.items)
|
||||
require.Equal(t, test.expected, c)
|
||||
})
|
||||
}
|
||||
|
|
@ -3428,8 +3423,8 @@ func Test_keepItem(t *testing.T) {
|
|||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Constraints = test.constraints
|
||||
ctx := context.TODO()
|
||||
result := p.keepItem(ctx, test.i)
|
||||
|
||||
result := p.keepItem(t.Context(), test.i)
|
||||
require.Equal(t, test.exp, result)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package nomad
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -170,7 +169,7 @@ func Test_getNomadServiceDataWithEmptyServices_GroupService_Scaling1(t *testing.
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
|
@ -200,7 +199,7 @@ func Test_getNomadServiceDataWithEmptyServices_GroupService_Scaling0(t *testing.
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
|
@ -230,7 +229,7 @@ func Test_getNomadServiceDataWithEmptyServices_GroupService_ScalingDisabled(t *t
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
|
@ -260,7 +259,7 @@ func Test_getNomadServiceDataWithEmptyServices_GroupService_ScalingDisabled_Stop
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should not be listed as job is stopped
|
||||
|
|
@ -294,7 +293,7 @@ func Test_getNomadServiceDataWithEmptyServices_GroupTaskService_Scaling1(t *test
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
}
|
||||
|
|
@ -326,7 +325,7 @@ func Test_getNomadServiceDataWithEmptyServices_GroupTaskService_Scaling0(t *test
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
}
|
||||
|
|
@ -356,7 +355,7 @@ func Test_getNomadServiceDataWithEmptyServices_TCP(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
|
@ -386,7 +385,7 @@ func Test_getNomadServiceDataWithEmptyServices_UDP(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
|
@ -416,7 +415,7 @@ func Test_getNomadServiceDataWithEmptyServices_ScalingEnabled_Stopped(t *testing
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(t.Context())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should not be listed as job is stopped
|
||||
|
|
@ -465,7 +464,7 @@ func Test_getNomadServiceData(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceData(context.TODO())
|
||||
items, err := p.getNomadServiceData(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package tailscale
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -125,7 +124,7 @@ func TestProvider_findDomains(t *testing.T) {
|
|||
|
||||
p := Provider{ResolverName: "foo"}
|
||||
|
||||
got := p.findDomains(context.TODO(), test.config)
|
||||
got := p.findDomains(t.Context(), test.config)
|
||||
assert.Equal(t, test.want, got)
|
||||
})
|
||||
}
|
||||
|
|
@ -230,7 +229,7 @@ func Test_sanitizeDomains(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := sanitizeDomains(context.TODO(), test.domains)
|
||||
got := sanitizeDomains(t.Context(), test.domains)
|
||||
assert.Equal(t, test.want, got)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package traefik
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"os"
|
||||
|
|
@ -269,7 +268,7 @@ func Test_createConfiguration(t *testing.T) {
|
|||
|
||||
provider := Provider{staticCfg: test.staticCfg}
|
||||
|
||||
cfg := provider.createConfiguration(context.Background())
|
||||
cfg := provider.createConfiguration(t.Context())
|
||||
|
||||
filename := filepath.Join("fixtures", test.desc)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/testhelpers"
|
||||
"github.com/traefik/traefik/v3/pkg/tls/generate"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -125,9 +124,17 @@ func TestProxyFromEnvironment(t *testing.T) {
|
|||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
backendURL, backendCert := newBackendServer(t, test.tls, http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
_, _ = rw.Write([]byte("backend"))
|
||||
}))
|
||||
var backendServer *httptest.Server
|
||||
if test.tls {
|
||||
backendServer = httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
_, _ = rw.Write([]byte("backendTLS"))
|
||||
}))
|
||||
} else {
|
||||
backendServer = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
_, _ = rw.Write([]byte("backend"))
|
||||
}))
|
||||
}
|
||||
t.Cleanup(backendServer.Close)
|
||||
|
||||
var proxyCalled bool
|
||||
proxyHandler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
|
@ -155,8 +162,21 @@ func TestProxyFromEnvironment(t *testing.T) {
|
|||
connHj, _, err := hj.Hijack()
|
||||
require.NoError(t, err)
|
||||
|
||||
go func() { _, _ = io.Copy(connHj, conn) }()
|
||||
_, _ = io.Copy(conn, connHj)
|
||||
defer func() {
|
||||
_ = connHj.Close()
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err = io.Copy(connHj, conn)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, err = io.Copy(conn, connHj)
|
||||
errCh <- err
|
||||
}()
|
||||
<-errCh // Wait for one of the copy operations to finish
|
||||
})
|
||||
|
||||
var proxyURL string
|
||||
|
|
@ -198,7 +218,7 @@ func TestProxyFromEnvironment(t *testing.T) {
|
|||
proxyURL = proxyServer.URL
|
||||
|
||||
case proxyHTTPS:
|
||||
proxyServer := httptest.NewServer(proxyHandler)
|
||||
proxyServer := httptest.NewTLSServer(proxyHandler)
|
||||
t.Cleanup(proxyServer.Close)
|
||||
|
||||
proxyURL = proxyServer.URL
|
||||
|
|
@ -209,11 +229,8 @@ func TestProxyFromEnvironment(t *testing.T) {
|
|||
if proxyCert != nil {
|
||||
certPool.AddCert(proxyCert)
|
||||
}
|
||||
if backendCert != nil {
|
||||
cert, err := x509.ParseCertificate(backendCert.Certificate[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
certPool.AddCert(cert)
|
||||
if backendServer.Certificate() != nil {
|
||||
certPool.AddCert(backendServer.Certificate())
|
||||
}
|
||||
|
||||
builder := NewProxyBuilder(&transportManagerMock{tlsConfig: &tls.Config{RootCAs: certPool}}, static.FastProxyConfig{})
|
||||
|
|
@ -230,7 +247,7 @@ func TestProxyFromEnvironment(t *testing.T) {
|
|||
return u, nil
|
||||
}
|
||||
|
||||
reverseProxy, err := builder.Build("foo", testhelpers.MustParseURL(backendURL), false, false)
|
||||
reverseProxy, err := builder.Build("foo", testhelpers.MustParseURL(backendServer.URL), false, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
reverseProxyServer := httptest.NewServer(reverseProxy)
|
||||
|
|
@ -246,7 +263,11 @@ func TestProxyFromEnvironment(t *testing.T) {
|
|||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "backend", string(body))
|
||||
if test.tls {
|
||||
assert.Equal(t, "backendTLS", string(body))
|
||||
} else {
|
||||
assert.Equal(t, "backend", string(body))
|
||||
}
|
||||
assert.True(t, proxyCalled)
|
||||
})
|
||||
}
|
||||
|
|
@ -385,52 +406,6 @@ func TestTransferEncodingChunked(t *testing.T) {
|
|||
assert.Equal(t, "chunk 0\nchunk 1\nchunk 2\n", string(body))
|
||||
}
|
||||
|
||||
func newCertificate(t *testing.T, domain string) *tls.Certificate {
|
||||
t.Helper()
|
||||
|
||||
certPEM, keyPEM, err := generate.KeyPair(domain, time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
certificate, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &certificate
|
||||
}
|
||||
|
||||
func newBackendServer(t *testing.T, isTLS bool, handler http.Handler) (string, *tls.Certificate) {
|
||||
t.Helper()
|
||||
|
||||
var ln net.Listener
|
||||
var err error
|
||||
var cert *tls.Certificate
|
||||
|
||||
scheme := "http"
|
||||
domain := "backend.localhost"
|
||||
if isTLS {
|
||||
scheme = "https"
|
||||
|
||||
cert = newCertificate(t, domain)
|
||||
|
||||
ln, err = tls.Listen("tcp", ":0", &tls.Config{Certificates: []tls.Certificate{*cert}})
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
ln, err = net.Listen("tcp", ":0")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
srv := &http.Server{Handler: handler}
|
||||
go func() { _ = srv.Serve(ln) }()
|
||||
|
||||
t.Cleanup(func() { _ = srv.Close() })
|
||||
|
||||
_, port, err := net.SplitHostPort(ln.Addr().String())
|
||||
require.NoError(t, err)
|
||||
|
||||
backendURL := fmt.Sprintf("%s://%s:%s", scheme, domain, port)
|
||||
|
||||
return backendURL, cert
|
||||
}
|
||||
|
||||
type transportManagerMock struct {
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package httputil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
|
@ -69,7 +68,7 @@ func TestObservabilityRoundTripper_metrics(t *testing.T) {
|
|||
// force the meter provider with manual reader to collect metrics for the test.
|
||||
metrics.SetMeterProvider(meterProvider)
|
||||
|
||||
semConvMetricRegistry, err := metrics.NewSemConvMetricRegistry(context.Background(), &cfg)
|
||||
semConvMetricRegistry, err := metrics.NewSemConvMetricRegistry(t.Context(), &cfg)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, semConvMetricRegistry)
|
||||
|
||||
|
|
@ -83,7 +82,7 @@ func TestObservabilityRoundTripper_metrics(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
got := metricdata.ResourceMetrics{}
|
||||
err = rdr.Collect(context.Background(), &got)
|
||||
err = rdr.Collect(t.Context(), &got)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, got.ScopeMetrics, 1)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ func TestNewPoolContext(t *testing.T) {
|
|||
|
||||
testKey := testKeyType("test")
|
||||
|
||||
ctx := context.WithValue(context.Background(), testKey, "test")
|
||||
ctx := context.WithValue(t.Context(), testKey, "test")
|
||||
p := NewPool(ctx)
|
||||
|
||||
p.GoCtx(func(ctx context.Context) {
|
||||
|
|
@ -66,7 +66,7 @@ func TestPoolWithCtx(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
// These subtests cannot be run in parallel, since the testRoutine
|
||||
// is shared across the subtests.
|
||||
p := NewPool(context.Background())
|
||||
p := NewPool(t.Context())
|
||||
timer := time.NewTimer(500 * time.Millisecond)
|
||||
defer timer.Stop()
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ func TestPoolWithCtx(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPoolCleanupWithGoPanicking(t *testing.T) {
|
||||
p := NewPool(context.Background())
|
||||
p := NewPool(t.Context())
|
||||
|
||||
timer := time.NewTimer(500 * time.Millisecond)
|
||||
defer timer.Stop()
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func (p *mockProvider) Init() error {
|
|||
}
|
||||
|
||||
func TestNewConfigurationWatcher(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
t.Cleanup(routinesPool.Stop)
|
||||
|
||||
pvd := &mockProvider{
|
||||
|
|
@ -117,7 +117,7 @@ func TestNewConfigurationWatcher(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWaitForRequiredProvider(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
pvdAggregator := &mockProvider{
|
||||
wait: 5 * time.Millisecond,
|
||||
|
|
@ -165,7 +165,7 @@ func TestWaitForRequiredProvider(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIgnoreTransientConfiguration(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
config := &dynamic.Configuration{
|
||||
HTTP: th.BuildConfiguration(
|
||||
|
|
@ -305,7 +305,7 @@ func TestIgnoreTransientConfiguration(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersThrottleProviderConfigReload(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
pvd := &mockProvider{
|
||||
wait: 10 * time.Millisecond,
|
||||
|
|
@ -350,7 +350,7 @@ func TestListenProvidersThrottleProviderConfigReload(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersSkipsEmptyConfigs(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
pvd := &mockProvider{
|
||||
messages: []dynamic.Message{{ProviderName: "mock"}},
|
||||
|
|
@ -371,7 +371,7 @@ func TestListenProvidersSkipsEmptyConfigs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersSkipsSameConfigurationForProvider(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
message := dynamic.Message{
|
||||
ProviderName: "mock",
|
||||
|
|
@ -405,7 +405,7 @@ func TestListenProvidersSkipsSameConfigurationForProvider(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
configuration := &dynamic.Configuration{
|
||||
HTTP: th.BuildConfiguration(
|
||||
|
|
@ -475,7 +475,7 @@ func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersIgnoreSameConfig(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
configuration := &dynamic.Configuration{
|
||||
HTTP: th.BuildConfiguration(
|
||||
|
|
@ -568,7 +568,7 @@ func TestListenProvidersIgnoreSameConfig(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestApplyConfigUnderStress(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
watcher := NewConfigurationWatcher(routinesPool, &mockProvider{}, []string{}, "")
|
||||
|
||||
|
|
@ -611,7 +611,7 @@ func TestApplyConfigUnderStress(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersIgnoreIntermediateConfigs(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
configuration := &dynamic.Configuration{
|
||||
HTTP: th.BuildConfiguration(
|
||||
|
|
@ -704,7 +704,7 @@ func TestListenProvidersIgnoreIntermediateConfigs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
configuration := &dynamic.Configuration{
|
||||
HTTP: th.BuildConfiguration(
|
||||
|
|
@ -771,7 +771,7 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPublishConfigUpdatedByProvider(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
pvdConfiguration := dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
|
|
@ -817,7 +817,7 @@ func TestPublishConfigUpdatedByProvider(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPublishConfigUpdatedByConfigWatcherListener(t *testing.T) {
|
||||
routinesPool := safe.NewPool(context.Background())
|
||||
routinesPool := safe.NewPool(t.Context())
|
||||
|
||||
pvd := &mockProvider{
|
||||
wait: 10 * time.Millisecond,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -20,7 +19,7 @@ func TestBuilder_BuildChainNilConfig(t *testing.T) {
|
|||
}
|
||||
middlewaresBuilder := NewBuilder(testConfig, nil, nil)
|
||||
|
||||
chain := middlewaresBuilder.BuildChain(context.Background(), []string{"empty"})
|
||||
chain := middlewaresBuilder.BuildChain(t.Context(), []string{"empty"})
|
||||
_, err := chain.Then(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
|
@ -31,7 +30,7 @@ func TestBuilder_BuildChainNonExistentChain(t *testing.T) {
|
|||
}
|
||||
middlewaresBuilder := NewBuilder(testConfig, nil, nil)
|
||||
|
||||
chain := middlewaresBuilder.BuildChain(context.Background(), []string{"empty"})
|
||||
chain := middlewaresBuilder.BuildChain(t.Context(), []string{"empty"})
|
||||
_, err := chain.Then(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
|
@ -259,7 +258,7 @@ func TestBuilder_BuildChainWithContext(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
if len(test.contextProvider) > 0 {
|
||||
ctx = provider.AddInContext(ctx, "foobar@"+test.contextProvider)
|
||||
}
|
||||
|
|
@ -366,7 +365,7 @@ func TestBuilder_buildConstructor(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
constructor, err := middlewaresBuilder.buildConstructor(context.Background(), test.middlewareID)
|
||||
constructor, err := middlewaresBuilder.buildConstructor(t.Context(), test.middlewareID)
|
||||
require.NoError(t, err)
|
||||
|
||||
middleware, err2 := constructor(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}))
|
||||
|
|
|
|||
|
|
@ -16,31 +16,31 @@ func TestAddInContext(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
desc: "without provider information",
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
name: "test",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "provider name embedded in element name",
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
name: "test@foo",
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
desc: "provider name in context",
|
||||
ctx: context.WithValue(context.Background(), key, "foo"),
|
||||
ctx: context.WithValue(t.Context(), key, "foo"),
|
||||
name: "test",
|
||||
expected: "foo",
|
||||
},
|
||||
{
|
||||
desc: "provider name in context and different provider name embedded in element name",
|
||||
ctx: context.WithValue(context.Background(), key, "foo"),
|
||||
ctx: context.WithValue(t.Context(), key, "foo"),
|
||||
name: "test@fii",
|
||||
expected: "fii",
|
||||
},
|
||||
{
|
||||
desc: "provider name in context and same provider name embedded in element name",
|
||||
ctx: context.WithValue(context.Background(), key, "foo"),
|
||||
ctx: context.WithValue(t.Context(), key, "foo"),
|
||||
name: "test@foo",
|
||||
expected: "foo",
|
||||
},
|
||||
|
|
@ -71,31 +71,31 @@ func TestGetQualifiedName(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
desc: "empty name",
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
name: "",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "without provider",
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
name: "test",
|
||||
expected: "test",
|
||||
},
|
||||
{
|
||||
desc: "with explicit provider",
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
name: "test@foo",
|
||||
expected: "test@foo",
|
||||
},
|
||||
{
|
||||
desc: "with provider in context",
|
||||
ctx: context.WithValue(context.Background(), key, "foo"),
|
||||
ctx: context.WithValue(t.Context(), key, "foo"),
|
||||
name: "test",
|
||||
expected: "test@foo",
|
||||
},
|
||||
{
|
||||
desc: "with provider in context and explicit name",
|
||||
ctx: context.WithValue(context.Background(), key, "foo"),
|
||||
ctx: context.WithValue(t.Context(), key, "foo"),
|
||||
name: "test@fii",
|
||||
expected: "test@fii",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -42,10 +42,11 @@ type Manager struct {
|
|||
middlewaresBuilder middlewareBuilder
|
||||
conf *runtime.Configuration
|
||||
tlsManager *tls.Manager
|
||||
parser httpmuxer.SyntaxParser
|
||||
}
|
||||
|
||||
// NewManager creates a new Manager.
|
||||
func NewManager(conf *runtime.Configuration, serviceManager serviceManager, middlewaresBuilder middlewareBuilder, observabilityMgr *middleware.ObservabilityMgr, tlsManager *tls.Manager) *Manager {
|
||||
func NewManager(conf *runtime.Configuration, serviceManager serviceManager, middlewaresBuilder middlewareBuilder, observabilityMgr *middleware.ObservabilityMgr, tlsManager *tls.Manager, parser httpmuxer.SyntaxParser) *Manager {
|
||||
return &Manager{
|
||||
routerHandlers: make(map[string]http.Handler),
|
||||
serviceManager: serviceManager,
|
||||
|
|
@ -53,6 +54,7 @@ func NewManager(conf *runtime.Configuration, serviceManager serviceManager, midd
|
|||
middlewaresBuilder: middlewaresBuilder,
|
||||
conf: conf,
|
||||
tlsManager: tlsManager,
|
||||
parser: parser,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,10 +105,7 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string, t
|
|||
}
|
||||
|
||||
func (m *Manager) buildEntryPointHandler(ctx context.Context, entryPointName string, configs map[string]*runtime.RouterInfo) (http.Handler, error) {
|
||||
muxer, err := httpmuxer.NewMuxer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
muxer := httpmuxer.NewMuxer(m.parser)
|
||||
|
||||
defaultHandler, err := m.observabilityMgr.BuildEPChain(ctx, entryPointName, "", nil).Then(http.NotFoundHandler())
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"math"
|
||||
|
|
@ -13,10 +12,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
|
||||
httpmuxer "github.com/traefik/traefik/v3/pkg/muxer/http"
|
||||
"github.com/traefik/traefik/v3/pkg/server/middleware"
|
||||
"github.com/traefik/traefik/v3/pkg/server/service"
|
||||
"github.com/traefik/traefik/v3/pkg/testhelpers"
|
||||
|
|
@ -326,9 +327,12 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
tlsManager := traefiktls.NewManager()
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager)
|
||||
parser, err := httpmuxer.NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager, parser)
|
||||
|
||||
handlers := routerManager.BuildHandlers(t.Context(), test.entryPoints, false)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)
|
||||
|
|
@ -709,12 +713,15 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
serviceManager := service.NewManager(rtConf.Services, nil, nil, transportManager, proxyBuilderMock{})
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
tlsManager := traefiktls.NewManager()
|
||||
tlsManager.UpdateConfigs(context.Background(), nil, test.tlsOptions, nil)
|
||||
tlsManager.UpdateConfigs(t.Context(), nil, test.tlsOptions, nil)
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager)
|
||||
parser, err := httpmuxer.NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints, true)
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager, parser)
|
||||
|
||||
_ = routerManager.BuildHandlers(t.Context(), entryPoints, false)
|
||||
_ = routerManager.BuildHandlers(t.Context(), entryPoints, true)
|
||||
|
||||
// even though rtConf was passed by argument to the manager builders above,
|
||||
// it's ok to use it as the result we check, because everything worth checking
|
||||
|
|
@ -789,9 +796,12 @@ func TestProviderOnMiddlewares(t *testing.T) {
|
|||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
tlsManager := traefiktls.NewManager()
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager)
|
||||
parser, err := httpmuxer.NewSyntaxParser()
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager, parser)
|
||||
|
||||
_ = routerManager.BuildHandlers(t.Context(), entryPoints, false)
|
||||
|
||||
assert.Equal(t, []string{"chain@file", "m1@file"}, rtConf.Routers["router@file"].Middlewares)
|
||||
assert.Equal(t, []string{"m1@file", "m2@file", "m1@file"}, rtConf.Middlewares["chain@file"].Chain.Middlewares)
|
||||
|
|
@ -865,9 +875,12 @@ func BenchmarkRouterServe(b *testing.B) {
|
|||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
tlsManager := traefiktls.NewManager()
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager)
|
||||
parser, err := httpmuxer.NewSyntaxParser()
|
||||
require.NoError(b, err)
|
||||
|
||||
handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, nil, tlsManager, parser)
|
||||
|
||||
handlers := routerManager.BuildHandlers(b.Context(), entryPoints, false)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)
|
||||
|
|
@ -907,7 +920,7 @@ func BenchmarkService(b *testing.B) {
|
|||
w := httptest.NewRecorder()
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)
|
||||
|
||||
handler, _ := serviceManager.BuildHTTP(context.Background(), "foo-service")
|
||||
handler, _ := serviceManager.BuildHTTP(b.Context(), "foo-service")
|
||||
b.ReportAllocs()
|
||||
for range b.N {
|
||||
handler.ServeHTTP(w, req)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package tcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"math"
|
||||
"net/http"
|
||||
|
|
@ -350,7 +349,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
serviceManager := tcp.NewManager(conf, dialerManager)
|
||||
tlsManager := traefiktls.NewManager()
|
||||
tlsManager.UpdateConfigs(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
map[string]traefiktls.Store{},
|
||||
map[string]traefiktls.Options{
|
||||
"default": {
|
||||
|
|
@ -370,7 +369,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
routerManager := NewManager(conf, serviceManager, middlewaresBuilder,
|
||||
nil, nil, tlsManager)
|
||||
|
||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints)
|
||||
_ = routerManager.BuildHandlers(t.Context(), entryPoints)
|
||||
|
||||
// even though conf was passed by argument to the manager builders above,
|
||||
// it's ok to use it as the result we check, because everything worth checking
|
||||
|
|
@ -661,7 +660,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
serviceManager := tcp.NewManager(conf, tcp2.NewDialerManager(nil))
|
||||
|
||||
tlsManager := traefiktls.NewManager()
|
||||
tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, test.tlsOptions, []*traefiktls.CertAndStores{})
|
||||
tlsManager.UpdateConfigs(t.Context(), map[string]traefiktls.Store{}, test.tlsOptions, []*traefiktls.CertAndStores{})
|
||||
|
||||
httpsHandler := map[string]http.Handler{
|
||||
"web": http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}),
|
||||
|
|
@ -671,7 +670,7 @@ func TestDomainFronting(t *testing.T) {
|
|||
|
||||
routerManager := NewManager(conf, serviceManager, middlewaresBuilder, nil, httpsHandler, tlsManager)
|
||||
|
||||
routers := routerManager.BuildHandlers(context.Background(), entryPoints)
|
||||
routers := routerManager.BuildHandlers(t.Context(), entryPoints)
|
||||
|
||||
router, ok := routers["web"]
|
||||
require.True(t, ok)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package tcp
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -175,7 +174,7 @@ func Test_Routing(t *testing.T) {
|
|||
// Creates the tlsManager and defines the TLS 1.0 and 1.2 TLSOptions.
|
||||
tlsManager := traefiktls.NewManager()
|
||||
tlsManager.UpdateConfigs(
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
map[string]traefiktls.Store{
|
||||
tlsalpn01.ACMETLS1Protocol: {},
|
||||
},
|
||||
|
|
@ -606,7 +605,7 @@ func Test_Routing(t *testing.T) {
|
|||
router(dynConf)
|
||||
}
|
||||
|
||||
router, err := manager.buildEntryPointHandler(context.Background(), dynConf.TCPRouters, dynConf.Routers, nil, nil)
|
||||
router, err := manager.buildEntryPointHandler(t.Context(), dynConf.TCPRouters, dynConf.Routers, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
if test.allowACMETLSPassthrough {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package udp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -118,7 +117,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
serviceManager := udp.NewManager(conf)
|
||||
routerManager := NewManager(conf, serviceManager)
|
||||
|
||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints)
|
||||
_ = routerManager.BuildHandlers(t.Context(), entryPoints)
|
||||
|
||||
// even though conf was passed by argument to the manager builders above,
|
||||
// it's ok to use it as the result we check, because everything worth checking
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
httpmuxer "github.com/traefik/traefik/v3/pkg/muxer/http"
|
||||
"github.com/traefik/traefik/v3/pkg/server/middleware"
|
||||
tcpmiddleware "github.com/traefik/traefik/v3/pkg/server/middleware/tcp"
|
||||
"github.com/traefik/traefik/v3/pkg/server/router"
|
||||
|
|
@ -35,12 +37,14 @@ type RouterFactory struct {
|
|||
dialerManager *tcp.DialerManager
|
||||
|
||||
cancelPrevState func()
|
||||
|
||||
parser httpmuxer.SyntaxParser
|
||||
}
|
||||
|
||||
// NewRouterFactory creates a new RouterFactory.
|
||||
func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *service.ManagerFactory, tlsManager *tls.Manager,
|
||||
observabilityMgr *middleware.ObservabilityMgr, pluginBuilder middleware.PluginsBuilder, dialerManager *tcp.DialerManager,
|
||||
) *RouterFactory {
|
||||
) (*RouterFactory, error) {
|
||||
handlesTLSChallenge := false
|
||||
for _, resolver := range staticConfiguration.CertificatesResolvers {
|
||||
if resolver.ACME != nil && resolver.ACME.TLSChallenge != nil {
|
||||
|
|
@ -67,6 +71,11 @@ func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *
|
|||
}
|
||||
}
|
||||
|
||||
parser, err := httpmuxer.NewSyntaxParser()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating parser: %w", err)
|
||||
}
|
||||
|
||||
return &RouterFactory{
|
||||
entryPointsTCP: entryPointsTCP,
|
||||
entryPointsUDP: entryPointsUDP,
|
||||
|
|
@ -76,7 +85,8 @@ func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *
|
|||
pluginBuilder: pluginBuilder,
|
||||
dialerManager: dialerManager,
|
||||
allowACMEByPass: allowACMEByPass,
|
||||
}
|
||||
parser: parser,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateRouters creates new TCPRouters and UDPRouters.
|
||||
|
|
@ -93,7 +103,7 @@ func (f *RouterFactory) CreateRouters(rtConf *runtime.Configuration) (map[string
|
|||
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, f.pluginBuilder)
|
||||
|
||||
routerManager := router.NewManager(rtConf, serviceManager, middlewaresBuilder, f.observabilityMgr, f.tlsManager)
|
||||
routerManager := router.NewManager(rtConf, serviceManager, middlewaresBuilder, f.observabilityMgr, f.tlsManager, f.parser)
|
||||
|
||||
handlersNonTLS := routerManager.BuildHandlers(ctx, f.entryPointsTCP, false)
|
||||
handlersTLS := routerManager.BuildHandlers(ctx, f.entryPointsTCP, true)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/config/runtime"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
|
|
@ -58,7 +59,8 @@ func TestReuseService(t *testing.T) {
|
|||
|
||||
dialerManager := tcp.NewDialerManager(nil)
|
||||
dialerManager.Update(map[string]*dynamic.TCPServersTransport{"default@internal": {}})
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, nil, nil, dialerManager)
|
||||
factory, err := NewRouterFactory(staticConfig, managerFactory, tlsManager, nil, nil, dialerManager)
|
||||
require.NoError(t, err)
|
||||
|
||||
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
|
||||
|
||||
|
|
@ -196,7 +198,8 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
|||
dialerManager := tcp.NewDialerManager(nil)
|
||||
dialerManager.Update(map[string]*dynamic.TCPServersTransport{"default@internal": {}})
|
||||
observabiltyMgr := middleware.NewObservabilityMgr(staticConfig, nil, nil, nil, nil, nil)
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, observabiltyMgr, nil, dialerManager)
|
||||
factory, err := NewRouterFactory(staticConfig, managerFactory, tlsManager, observabiltyMgr, nil, dialerManager)
|
||||
require.NoError(t, err)
|
||||
|
||||
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: test.config(testServer.URL)}))
|
||||
|
||||
|
|
@ -240,7 +243,8 @@ func TestInternalServices(t *testing.T) {
|
|||
|
||||
dialerManager := tcp.NewDialerManager(nil)
|
||||
dialerManager.Update(map[string]*dynamic.TCPServersTransport{"default@internal": {}})
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, nil, nil, dialerManager)
|
||||
factory, err := NewRouterFactory(staticConfig, managerFactory, tlsManager, nil, nil, dialerManager)
|
||||
require.NoError(t, err)
|
||||
|
||||
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ func TestNewListenConfig(t *testing.T) {
|
|||
require.Nil(t, listenConfig.Control)
|
||||
require.Zero(t, listenConfig.KeepAlive)
|
||||
|
||||
l1, err := listenConfig.Listen(context.Background(), "tcp", ep.Address)
|
||||
l1, err := listenConfig.Listen(t.Context(), "tcp", ep.Address)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, l1)
|
||||
defer l1.Close()
|
||||
|
||||
l2, err := listenConfig.Listen(context.Background(), "tcp", l1.Addr().String())
|
||||
l2, err := listenConfig.Listen(t.Context(), "tcp", l1.Addr().String())
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "address already in use")
|
||||
require.Nil(t, l2)
|
||||
|
|
@ -31,12 +31,12 @@ func TestNewListenConfig(t *testing.T) {
|
|||
require.Nil(t, listenConfig.Control)
|
||||
require.Zero(t, listenConfig.KeepAlive)
|
||||
|
||||
l3, err := listenConfig.Listen(context.Background(), "tcp", ep.Address)
|
||||
l3, err := listenConfig.Listen(t.Context(), "tcp", ep.Address)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, l3)
|
||||
defer l3.Close()
|
||||
|
||||
l4, err := listenConfig.Listen(context.Background(), "tcp", l3.Addr().String())
|
||||
l4, err := listenConfig.Listen(t.Context(), "tcp", l3.Addr().String())
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "address already in use")
|
||||
require.Nil(t, l4)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
|
|
@ -17,12 +16,12 @@ func TestNewListenConfig(t *testing.T) {
|
|||
require.Nil(t, listenConfig.Control)
|
||||
require.Zero(t, listenConfig.KeepAlive)
|
||||
|
||||
l1, err := listenConfig.Listen(context.Background(), "tcp", ep.Address)
|
||||
l1, err := listenConfig.Listen(t.Context(), "tcp", ep.Address)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, l1)
|
||||
defer l1.Close()
|
||||
|
||||
l2, err := listenConfig.Listen(context.Background(), "tcp", l1.Addr().String())
|
||||
l2, err := listenConfig.Listen(t.Context(), "tcp", l1.Addr().String())
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "address already in use")
|
||||
require.Nil(t, l2)
|
||||
|
|
@ -32,24 +31,24 @@ func TestNewListenConfig(t *testing.T) {
|
|||
require.NotNil(t, listenConfig.Control)
|
||||
require.Zero(t, listenConfig.KeepAlive)
|
||||
|
||||
l3, err := listenConfig.Listen(context.Background(), "tcp", ep.Address)
|
||||
l3, err := listenConfig.Listen(t.Context(), "tcp", ep.Address)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, l3)
|
||||
defer l3.Close()
|
||||
|
||||
l4, err := listenConfig.Listen(context.Background(), "tcp", l3.Addr().String())
|
||||
l4, err := listenConfig.Listen(t.Context(), "tcp", l3.Addr().String())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, l4)
|
||||
defer l4.Close()
|
||||
|
||||
_, l3Port, err := net.SplitHostPort(l3.Addr().String())
|
||||
require.NoError(t, err)
|
||||
l5, err := listenConfig.Listen(context.Background(), "tcp", "127.0.0.1:"+l3Port)
|
||||
l5, err := listenConfig.Listen(t.Context(), "tcp", "127.0.0.1:"+l3Port)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, l5)
|
||||
defer l5.Close()
|
||||
|
||||
l6, err := listenConfig.Listen(context.Background(), "tcp", l1.Addr().String())
|
||||
l6, err := listenConfig.Listen(t.Context(), "tcp", l1.Addr().String())
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "address already in use")
|
||||
require.Nil(t, l6)
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/server/service"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
type key string
|
||||
|
|
@ -610,40 +608,47 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if configuration.HTTP.SanitizePath != nil && *configuration.HTTP.SanitizePath {
|
||||
// sanitizePath is used to clean the URL path by removing /../, /./ and duplicate slash sequences,
|
||||
// to make sure the path is interpreted by the backends as it is evaluated inside rule matchers.
|
||||
handler = sanitizePath(handler)
|
||||
debugConnection := os.Getenv(debugConnectionEnv) != ""
|
||||
if debugConnection || (configuration.Transport != nil && (configuration.Transport.KeepAliveMaxTime > 0 || configuration.Transport.KeepAliveMaxRequests > 0)) {
|
||||
handler = newKeepAliveMiddleware(handler, configuration.Transport.KeepAliveMaxRequests, configuration.Transport.KeepAliveMaxTime)
|
||||
}
|
||||
|
||||
var protocols http.Protocols
|
||||
protocols.SetHTTP1(true)
|
||||
protocols.SetHTTP2(true)
|
||||
|
||||
// With the addition of UnencryptedHTTP2 in http.Server#Protocols in go1.24 setting the h2c handler is not necessary anymore.
|
||||
protocols.SetUnencryptedHTTP2(withH2c)
|
||||
|
||||
handler = contenttype.DisableAutoDetection(handler)
|
||||
|
||||
if configuration.HTTP.EncodeQuerySemicolons {
|
||||
handler = encodeQuerySemicolons(handler)
|
||||
} else {
|
||||
handler = http.AllowQuerySemicolons(handler)
|
||||
}
|
||||
|
||||
handler = contenttype.DisableAutoDetection(handler)
|
||||
|
||||
debugConnection := os.Getenv(debugConnectionEnv) != ""
|
||||
if debugConnection || (configuration.Transport != nil && (configuration.Transport.KeepAliveMaxTime > 0 || configuration.Transport.KeepAliveMaxRequests > 0)) {
|
||||
handler = newKeepAliveMiddleware(handler, configuration.Transport.KeepAliveMaxRequests, configuration.Transport.KeepAliveMaxTime)
|
||||
// Note that the Path sanitization has to be done after the path normalization,
|
||||
// hence the wrapping has to be done before the normalize path wrapping.
|
||||
if configuration.HTTP.SanitizePath != nil && *configuration.HTTP.SanitizePath {
|
||||
handler = sanitizePath(handler)
|
||||
}
|
||||
|
||||
if withH2c {
|
||||
handler = h2c.NewHandler(handler, &http2.Server{
|
||||
MaxConcurrentStreams: uint32(configuration.HTTP2.MaxConcurrentStreams),
|
||||
})
|
||||
}
|
||||
handler = normalizePath(handler)
|
||||
|
||||
handler = denyFragment(handler)
|
||||
|
||||
serverHTTP := &http.Server{
|
||||
Protocols: &protocols,
|
||||
Handler: handler,
|
||||
ErrorLog: stdlog.New(logs.NoLevel(log.Logger, zerolog.DebugLevel), "", 0),
|
||||
ReadTimeout: time.Duration(configuration.Transport.RespondingTimeouts.ReadTimeout),
|
||||
WriteTimeout: time.Duration(configuration.Transport.RespondingTimeouts.WriteTimeout),
|
||||
IdleTimeout: time.Duration(configuration.Transport.RespondingTimeouts.IdleTimeout),
|
||||
MaxHeaderBytes: configuration.HTTP.MaxHeaderBytes,
|
||||
HTTP2: &http.HTTP2Config{
|
||||
MaxConcurrentStreams: int(configuration.HTTP2.MaxConcurrentStreams),
|
||||
},
|
||||
}
|
||||
if debugConnection || (configuration.Transport != nil && (configuration.Transport.KeepAliveMaxTime > 0 || configuration.Transport.KeepAliveMaxRequests > 0)) {
|
||||
serverHTTP.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
|
||||
|
|
@ -677,19 +682,6 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati
|
|||
return ctx
|
||||
}
|
||||
|
||||
// ConfigureServer configures HTTP/2 with the MaxConcurrentStreams option for the given server.
|
||||
// Also keeping behavior the same as
|
||||
// https://cs.opensource.google/go/go/+/refs/tags/go1.17.7:src/net/http/server.go;l=3262
|
||||
if !strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
|
||||
err = http2.ConfigureServer(serverHTTP, &http2.Server{
|
||||
MaxConcurrentStreams: uint32(configuration.HTTP2.MaxConcurrentStreams),
|
||||
NewWriteScheduler: func() http2.WriteScheduler { return http2.NewPriorityWriteScheduler(nil) },
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("configure HTTP/2 server: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
listener := newHTTPForwarder(ln)
|
||||
go func() {
|
||||
err := serverHTTP.Serve(listener)
|
||||
|
|
@ -763,7 +755,7 @@ func denyFragment(h http.Handler) http.Handler {
|
|||
})
|
||||
}
|
||||
|
||||
// sanitizePath removes the "..", "." and duplicate slash segments from the URL.
|
||||
// sanitizePath removes the "..", "." and duplicate slash segments from the URL according to https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.3.
|
||||
// It cleans the request URL Path and RawPath, and updates the request URI.
|
||||
func sanitizePath(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
|
@ -779,3 +771,85 @@ func sanitizePath(h http.Handler) http.Handler {
|
|||
h.ServeHTTP(rw, r2)
|
||||
})
|
||||
}
|
||||
|
||||
// unreservedCharacters contains the mapping of the percent-encoded form to the ASCII form
|
||||
// of the unreserved characters according to https://datatracker.ietf.org/doc/html/rfc3986#section-2.3.
|
||||
var unreservedCharacters = map[string]rune{
|
||||
"%41": 'A', "%42": 'B', "%43": 'C', "%44": 'D', "%45": 'E', "%46": 'F',
|
||||
"%47": 'G', "%48": 'H', "%49": 'I', "%4A": 'J', "%4B": 'K', "%4C": 'L',
|
||||
"%4D": 'M', "%4E": 'N', "%4F": 'O', "%50": 'P', "%51": 'Q', "%52": 'R',
|
||||
"%53": 'S', "%54": 'T', "%55": 'U', "%56": 'V', "%57": 'W', "%58": 'X',
|
||||
"%59": 'Y', "%5A": 'Z',
|
||||
|
||||
"%61": 'a', "%62": 'b', "%63": 'c', "%64": 'd', "%65": 'e', "%66": 'f',
|
||||
"%67": 'g', "%68": 'h', "%69": 'i', "%6A": 'j', "%6B": 'k', "%6C": 'l',
|
||||
"%6D": 'm', "%6E": 'n', "%6F": 'o', "%70": 'p', "%71": 'q', "%72": 'r',
|
||||
"%73": 's', "%74": 't', "%75": 'u', "%76": 'v', "%77": 'w', "%78": 'x',
|
||||
"%79": 'y', "%7A": 'z',
|
||||
|
||||
"%30": '0', "%31": '1', "%32": '2', "%33": '3', "%34": '4',
|
||||
"%35": '5', "%36": '6', "%37": '7', "%38": '8', "%39": '9',
|
||||
|
||||
"%2D": '-', "%2E": '.', "%5F": '_', "%7E": '~',
|
||||
}
|
||||
|
||||
// normalizePath removes from the RawPath unreserved percent-encoded characters as they are equivalent to their non-encoded
|
||||
// form according to https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 and capitalizes percent-encoded characters
|
||||
// according to https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1.
|
||||
func normalizePath(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rawPath := req.URL.RawPath
|
||||
|
||||
// When the RawPath is empty the encoded form of the Path is equivalent to the original request Path.
|
||||
// Thus, the normalization is not needed as no unreserved characters were encoded and the encoded version
|
||||
// of Path obtained with URL.EscapedPath contains only percent-encoded characters in upper case.
|
||||
if rawPath == "" {
|
||||
h.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
var normalizedRawPathBuilder strings.Builder
|
||||
for i := 0; i < len(rawPath); i++ {
|
||||
if rawPath[i] != '%' {
|
||||
normalizedRawPathBuilder.WriteString(string(rawPath[i]))
|
||||
continue
|
||||
}
|
||||
|
||||
// This should never happen as the standard library will reject requests containing invalid percent-encodings.
|
||||
// This discards URLs with a percent character at the end.
|
||||
if i+2 >= len(rawPath) {
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
encodedCharacter := strings.ToUpper(rawPath[i : i+3])
|
||||
if r, unreserved := unreservedCharacters[encodedCharacter]; unreserved {
|
||||
normalizedRawPathBuilder.WriteRune(r)
|
||||
} else {
|
||||
normalizedRawPathBuilder.WriteString(encodedCharacter)
|
||||
}
|
||||
|
||||
i += 2
|
||||
}
|
||||
|
||||
normalizedRawPath := normalizedRawPathBuilder.String()
|
||||
|
||||
// We do not have to alter the request URL as the original RawPath is already normalized.
|
||||
if normalizedRawPath == rawPath {
|
||||
h.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
r2 := new(http.Request)
|
||||
*r2 = *req
|
||||
|
||||
// Decoding unreserved characters only alter the RAW version of the URL,
|
||||
// as unreserved percent-encoded characters are equivalent to their non encoded form.
|
||||
r2.URL.RawPath = normalizedRawPath
|
||||
|
||||
// Because the reverse proxy director is building query params from RequestURI it needs to be updated as well.
|
||||
r2.RequestURI = r2.URL.RequestURI()
|
||||
|
||||
h.ServeHTTP(rw, r2)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package server
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net/http"
|
||||
|
|
@ -87,7 +86,7 @@ func TestHTTP3AdvertisedPort(t *testing.T) {
|
|||
epConfig := &static.EntryPointsTransport{}
|
||||
epConfig.SetDefaults()
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "foo", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "foo", &static.EntryPoint{
|
||||
Address: "127.0.0.1:0",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -108,7 +107,7 @@ func TestHTTP3AdvertisedPort(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}), nil)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
go entryPoint.Start(ctx)
|
||||
entryPoint.SwitchRouter(router)
|
||||
|
||||
|
|
@ -151,7 +150,7 @@ func TestHTTP30RTT(t *testing.T) {
|
|||
epConfig := &static.EntryPointsTransport{}
|
||||
epConfig.SetDefaults()
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "foo", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "foo", &static.EntryPoint{
|
||||
Address: "127.0.0.1:8090",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -170,7 +169,7 @@ func TestHTTP30RTT(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}), nil)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
go entryPoint.Start(ctx)
|
||||
entryPoint.SwitchRouter(router)
|
||||
|
||||
|
|
@ -193,7 +192,7 @@ func TestHTTP30RTT(t *testing.T) {
|
|||
tlsConf.ClientSessionCache = cache
|
||||
|
||||
// This first DialAddrEarly connection is here to populate the cache.
|
||||
earlyConnection, err := quic.DialAddrEarly(context.Background(), "127.0.0.1:8090", tlsConf, &quic.Config{})
|
||||
earlyConnection, err := quic.DialAddrEarly(t.Context(), "127.0.0.1:8090", tlsConf, &quic.Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
|
|
@ -207,7 +206,7 @@ func TestHTTP30RTT(t *testing.T) {
|
|||
// 0RTT is always false on the first connection.
|
||||
require.False(t, earlyConnection.ConnectionState().Used0RTT)
|
||||
|
||||
earlyConnection, err = quic.DialAddrEarly(context.Background(), "127.0.0.1:8090", tlsConf, &quic.Config{})
|
||||
earlyConnection, err = quic.DialAddrEarly(t.Context(), "127.0.0.1:8090", tlsConf, &quic.Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
<-earlyConnection.HandshakeComplete()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
ptypes "github.com/traefik/paerser/types"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
|
||||
tcprouter "github.com/traefik/traefik/v3/pkg/server/router/tcp"
|
||||
"github.com/traefik/traefik/v3/pkg/tcp"
|
||||
"golang.org/x/net/http2"
|
||||
|
|
@ -79,7 +80,7 @@ func testShutdown(t *testing.T, router *tcprouter.Router) {
|
|||
epConfig.RespondingTimeouts.ReadTimeout = ptypes.Duration(5 * time.Second)
|
||||
epConfig.RespondingTimeouts.WriteTimeout = ptypes.Duration(5 * time.Second)
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "", &static.EntryPoint{
|
||||
// We explicitly use an IPV4 address because on Alpine, with an IPV6 address
|
||||
// there seems to be shenanigans related to properly cleaning up file descriptors
|
||||
Address: "127.0.0.1:0",
|
||||
|
|
@ -89,7 +90,7 @@ func testShutdown(t *testing.T, router *tcprouter.Router) {
|
|||
}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn, err := startEntrypoint(entryPoint, router)
|
||||
conn, err := startEntrypoint(t, entryPoint, router)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { _ = conn.Close() })
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ func testShutdown(t *testing.T, router *tcprouter.Router) {
|
|||
_, err = reader.Peek(1)
|
||||
require.NoError(t, err)
|
||||
|
||||
go entryPoint.Shutdown(context.Background())
|
||||
go entryPoint.Shutdown(t.Context())
|
||||
|
||||
// Make sure that new connections are not permitted anymore.
|
||||
// Note that this should be true not only after Shutdown has returned,
|
||||
|
|
@ -143,8 +144,10 @@ func testShutdown(t *testing.T, router *tcprouter.Router) {
|
|||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
func startEntrypoint(entryPoint *TCPEntryPoint, router *tcprouter.Router) (net.Conn, error) {
|
||||
go entryPoint.Start(context.Background())
|
||||
func startEntrypoint(t *testing.T, entryPoint *TCPEntryPoint, router *tcprouter.Router) (net.Conn, error) {
|
||||
t.Helper()
|
||||
|
||||
go entryPoint.Start(t.Context())
|
||||
|
||||
entryPoint.SwitchRouter(router)
|
||||
|
||||
|
|
@ -166,7 +169,7 @@ func TestReadTimeoutWithoutFirstByte(t *testing.T) {
|
|||
epConfig.SetDefaults()
|
||||
epConfig.RespondingTimeouts.ReadTimeout = ptypes.Duration(2 * time.Second)
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "", &static.EntryPoint{
|
||||
Address: ":0",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -181,7 +184,7 @@ func TestReadTimeoutWithoutFirstByte(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
conn, err := startEntrypoint(entryPoint, router)
|
||||
conn, err := startEntrypoint(t, entryPoint, router)
|
||||
require.NoError(t, err)
|
||||
|
||||
errChan := make(chan error)
|
||||
|
|
@ -205,7 +208,7 @@ func TestReadTimeoutWithFirstByte(t *testing.T) {
|
|||
epConfig.SetDefaults()
|
||||
epConfig.RespondingTimeouts.ReadTimeout = ptypes.Duration(2 * time.Second)
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "", &static.EntryPoint{
|
||||
Address: ":0",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -220,7 +223,7 @@ func TestReadTimeoutWithFirstByte(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
conn, err := startEntrypoint(entryPoint, router)
|
||||
conn, err := startEntrypoint(t, entryPoint, router)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = conn.Write([]byte("GET /some HTTP/1.1\r\n"))
|
||||
|
|
@ -247,7 +250,7 @@ func TestKeepAliveMaxRequests(t *testing.T) {
|
|||
epConfig.SetDefaults()
|
||||
epConfig.KeepAliveMaxRequests = 3
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "", &static.EntryPoint{
|
||||
Address: ":0",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -262,7 +265,7 @@ func TestKeepAliveMaxRequests(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
conn, err := startEntrypoint(entryPoint, router)
|
||||
conn, err := startEntrypoint(t, entryPoint, router)
|
||||
require.NoError(t, err)
|
||||
|
||||
http.DefaultClient.Transport = &http.Transport{
|
||||
|
|
@ -295,7 +298,7 @@ func TestKeepAliveMaxTime(t *testing.T) {
|
|||
epConfig.SetDefaults()
|
||||
epConfig.KeepAliveMaxTime = ptypes.Duration(time.Millisecond)
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "", &static.EntryPoint{
|
||||
Address: ":0",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -310,7 +313,7 @@ func TestKeepAliveMaxTime(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
conn, err := startEntrypoint(entryPoint, router)
|
||||
conn, err := startEntrypoint(t, entryPoint, router)
|
||||
require.NoError(t, err)
|
||||
|
||||
http.DefaultClient.Transport = &http.Transport{
|
||||
|
|
@ -339,7 +342,7 @@ func TestKeepAliveH2c(t *testing.T) {
|
|||
epConfig.SetDefaults()
|
||||
epConfig.KeepAliveMaxRequests = 1
|
||||
|
||||
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
|
||||
entryPoint, err := NewTCPEntryPoint(t.Context(), "", &static.EntryPoint{
|
||||
Address: ":0",
|
||||
Transport: epConfig,
|
||||
ForwardedHeaders: &static.ForwardedHeaders{},
|
||||
|
|
@ -354,7 +357,7 @@ func TestKeepAliveH2c(t *testing.T) {
|
|||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
conn, err := startEntrypoint(entryPoint, router)
|
||||
conn, err := startEntrypoint(t, entryPoint, router)
|
||||
require.NoError(t, err)
|
||||
|
||||
http2Transport := &http2.Transport{
|
||||
|
|
@ -424,3 +427,224 @@ func TestSanitizePath(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePath(t *testing.T) {
|
||||
unreservedDecoded := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
|
||||
unreserved := []string{
|
||||
"%41", "%42", "%43", "%44", "%45", "%46", "%47", "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F", "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57", "%58", "%59", "%5A",
|
||||
"%61", "%62", "%63", "%64", "%65", "%66", "%67", "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F", "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77", "%78", "%79", "%7A",
|
||||
"%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37", "%38", "%39",
|
||||
"%2D", "%2E", "%5F", "%7E",
|
||||
}
|
||||
|
||||
reserved := []string{
|
||||
"%3A", "%2F", "%3F", "%23", "%5B", "%5D", "%40", "%21", "%24", "%26", "%27", "%28", "%29", "%2A", "%2B", "%2C", "%3B", "%3D", "%25",
|
||||
}
|
||||
reservedJoined := strings.Join(reserved, "")
|
||||
|
||||
unallowedCharacter := "%0a" // line feed
|
||||
unallowedCharacterUpperCased := "%0A" // line feed upper case
|
||||
|
||||
var callCount int
|
||||
handler := normalizePath(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
callCount++
|
||||
|
||||
wantRawPath := "/" + unreservedDecoded + reservedJoined + unallowedCharacterUpperCased
|
||||
assert.Equal(t, wantRawPath, r.URL.RawPath)
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://foo/"+strings.Join(unreserved, "")+reservedJoined+unallowedCharacter, http.NoBody)
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(res, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, res.Code)
|
||||
assert.Equal(t, 1, callCount)
|
||||
}
|
||||
|
||||
func TestNormalizePath_malformedPercentEncoding(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
path string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "well formed path",
|
||||
path: "/%20",
|
||||
},
|
||||
{
|
||||
desc: "percent sign at the end",
|
||||
path: "/%",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "incomplete percent encoding at the end",
|
||||
path: "/%f",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var callCount int
|
||||
handler := normalizePath(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
callCount++
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://foo", http.NoBody)
|
||||
req.URL.RawPath = test.path
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(res, req)
|
||||
|
||||
if test.wantErr {
|
||||
assert.Equal(t, http.StatusBadRequest, res.Code)
|
||||
assert.Equal(t, 0, callCount)
|
||||
} else {
|
||||
assert.Equal(t, http.StatusOK, res.Code)
|
||||
assert.Equal(t, 1, callCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPathOperations tests the whole behavior of normalizePath, and sanitizePath combined through the use of the createHTTPServer func.
|
||||
// It aims to guarantee the server entrypoint handler is secure regarding a large variety of cases that could lead to path traversal attacks.
|
||||
func TestPathOperations(t *testing.T) {
|
||||
// Create a listener for the server.
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = ln.Close()
|
||||
})
|
||||
|
||||
// Define the server configuration.
|
||||
configuration := &static.EntryPoint{}
|
||||
configuration.SetDefaults()
|
||||
|
||||
// Create the HTTP server using createHTTPServer.
|
||||
server, err := createHTTPServer(t.Context(), ln, configuration, false, requestdecorator.New(nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
server.Switcher.UpdateHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Path", r.URL.Path)
|
||||
w.Header().Set("RawPath", r.URL.EscapedPath())
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
go func() {
|
||||
// server is expected to return an error if the listener is closed.
|
||||
_ = server.Server.Serve(ln)
|
||||
}()
|
||||
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{
|
||||
ResponseHeaderTimeout: 1 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
desc string
|
||||
rawPath string
|
||||
expectedPath string
|
||||
expectedRaw string
|
||||
expectedStatus int
|
||||
}{
|
||||
{
|
||||
desc: "normalize and sanitize path",
|
||||
rawPath: "/a/../b/%41%42%43//%2f/",
|
||||
expectedPath: "/b/ABC///",
|
||||
expectedRaw: "/b/ABC/%2F/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with traversal attempt",
|
||||
rawPath: "/../../b/",
|
||||
expectedPath: "/b/",
|
||||
expectedRaw: "/b/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with multiple traversal attempts",
|
||||
rawPath: "/a/../../b/../c/",
|
||||
expectedPath: "/c/",
|
||||
expectedRaw: "/c/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with mixed traversal and valid segments",
|
||||
rawPath: "/a/../b/./c/../d/",
|
||||
expectedPath: "/b/d/",
|
||||
expectedRaw: "/b/d/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with trailing slash and traversal",
|
||||
rawPath: "/a/b/../",
|
||||
expectedPath: "/a/",
|
||||
expectedRaw: "/a/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with encoded traversal sequences",
|
||||
rawPath: "/a/%2E%2E/%2E%2E/b/",
|
||||
expectedPath: "/b/",
|
||||
expectedRaw: "/b/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with over-encoded traversal sequences",
|
||||
rawPath: "/a/%252E%252E/%252E%252E/b/",
|
||||
expectedPath: "/a/%2E%2E/%2E%2E/b/",
|
||||
expectedRaw: "/a/%252E%252E/%252E%252E/b/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "routing path with unallowed percent-encoded character",
|
||||
rawPath: "/foo%20bar",
|
||||
expectedPath: "/foo bar",
|
||||
expectedRaw: "/foo%20bar",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "routing path with reserved percent-encoded character",
|
||||
rawPath: "/foo%2Fbar",
|
||||
expectedPath: "/foo/bar",
|
||||
expectedRaw: "/foo%2Fbar",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "routing path with unallowed and reserved percent-encoded character",
|
||||
rawPath: "/foo%20%2Fbar",
|
||||
expectedPath: "/foo /bar",
|
||||
expectedRaw: "/foo%20%2Fbar",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "path with traversal and encoded slash",
|
||||
rawPath: "/a/..%2Fb/",
|
||||
expectedPath: "/a/../b/",
|
||||
expectedRaw: "/a/..%2Fb/",
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://"+ln.Addr().String()+test.rawPath, http.NoBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, test.expectedStatus, res.StatusCode)
|
||||
assert.Equal(t, test.expectedPath, res.Header.Get("Path"))
|
||||
assert.Equal(t, test.expectedRaw, res.Header.Get("RawPath"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
|
|
@ -27,7 +26,7 @@ func TestShutdownUDPConn(t *testing.T) {
|
|||
entryPoint, err := NewUDPEntryPoint(&ep, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
go entryPoint.Start(context.Background())
|
||||
go entryPoint.Start(t.Context())
|
||||
entryPoint.Switch(udp.HandlerFunc(func(conn *udp.Conn) {
|
||||
for {
|
||||
b := make([]byte, 1024*1024)
|
||||
|
|
@ -56,7 +55,7 @@ func TestShutdownUDPConn(t *testing.T) {
|
|||
|
||||
doneChan := make(chan struct{})
|
||||
go func() {
|
||||
entryPoint.Shutdown(context.Background())
|
||||
entryPoint.Shutdown(t.Context())
|
||||
close(doneChan)
|
||||
}()
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue