Add mirrorBody option to HTTP mirroring

This commit is contained in:
Matteo Paier 2024-09-02 16:36:06 +02:00 committed by GitHub
parent 51f7f610c9
commit eb99c8c785
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 165 additions and 22 deletions

View file

@ -2506,6 +2506,11 @@ spec:
Default value is -1, which means unlimited size.
format: int64
type: integer
mirrorBody:
description: |-
MirrorBody defines whether the body of the request should be mirrored.
Default value is true.
type: boolean
mirrors:
description: Mirrors defines the list of mirrors where Traefik
will duplicate the traffic.

View file

@ -28,6 +28,10 @@
service = "mirrorWithMaxBody"
rule = "Path(`/whoamiWithMaxBody`)"
[http.routers.router3]
service = "mirrorWithoutBody"
rule = "Path(`/whoamiWithoutBody`)"
[http.services]
[http.services.mirror.mirroring]
@ -49,6 +53,16 @@
name = "mirror2"
percent = 50
[http.services.mirrorWithoutBody.mirroring]
service = "service1"
mirrorBody = false
[[http.services.mirrorWithoutBody.mirroring.mirrors]]
name = "mirror1"
percent = 10
[[http.services.mirrorWithoutBody.mirroring.mirrors]]
name = "mirror2"
percent = 50
[http.services.service1.loadBalancer]
[[http.services.service1.loadBalancer.servers]]

View file

@ -1004,8 +1004,13 @@ func (s *SimpleSuite) TestMirrorWithBody() {
_, err = rand.Read(body5)
require.NoError(s.T(), err)
verifyBody := func(req *http.Request) {
// forceOkResponse is used to avoid errors when Content-Length is set but no body is received
verifyBody := func(req *http.Request, canBodyBeEmpty bool) (forceOkResponse bool) {
b, _ := io.ReadAll(req.Body)
if canBodyBeEmpty && req.Header.Get("NoBody") == "true" {
require.Empty(s.T(), b)
return true
}
switch req.Header.Get("Size") {
case "20":
require.Equal(s.T(), body20, b)
@ -1014,20 +1019,25 @@ func (s *SimpleSuite) TestMirrorWithBody() {
default:
s.T().Fatal("Size header not present")
}
return false
}
main := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
verifyBody(req)
verifyBody(req, false)
atomic.AddInt32(&count, 1)
}))
mirror1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
verifyBody(req)
if verifyBody(req, true) {
rw.WriteHeader(http.StatusOK)
}
atomic.AddInt32(&countMirror1, 1)
}))
mirror2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
verifyBody(req)
if verifyBody(req, true) {
rw.WriteHeader(http.StatusOK)
}
atomic.AddInt32(&countMirror2, 1)
}))
@ -1104,6 +1114,28 @@ func (s *SimpleSuite) TestMirrorWithBody() {
assert.Equal(s.T(), int32(10), countTotal)
assert.Equal(s.T(), int32(0), val1)
assert.Equal(s.T(), int32(0), val2)
atomic.StoreInt32(&count, 0)
atomic.StoreInt32(&countMirror1, 0)
atomic.StoreInt32(&countMirror2, 0)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoamiWithoutBody", bytes.NewBuffer(body20))
require.NoError(s.T(), err)
req.Header.Set("Size", "20")
req.Header.Set("NoBody", "true")
for range 10 {
response, err := http.DefaultClient.Do(req)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
}
countTotal = atomic.LoadInt32(&count)
val1 = atomic.LoadInt32(&countMirror1)
val2 = atomic.LoadInt32(&countMirror2)
assert.Equal(s.T(), int32(10), countTotal)
assert.Equal(s.T(), int32(1), val1)
assert.Equal(s.T(), int32(5), val2)
}
func (s *SimpleSuite) TestMirrorCanceled() {