This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 93b0e225d6 multiplexer: support request bodies from non-POST/PUT
(#11772)
93b0e225d6 is described below
commit 93b0e225d6ddc6121adfcb00aa59d547876f0204
Author: Brian Neradt <[email protected]>
AuthorDate: Mon Oct 7 15:24:41 2024 -0500
multiplexer: support request bodies from non-POST/PUT (#11772)
This updates the multiplexer plugin to support request bodies from
non-POST and PUT methods. As long as they are Content-Length requests.
---
doc/admin-guide/plugins/multiplexer.en.rst | 56 ++--------------------
plugins/multiplexer/ats-multiplexer.cc | 2 +-
.../pluginTest/multiplexer/multiplexer.test.py | 20 ++++++++
.../replays/multiplexer_copy.replay.yaml | 29 +++++++++++
.../replays/multiplexer_copy_skip_post.replay.yaml | 29 +++++++++++
.../replays/multiplexer_original.replay.yaml | 33 +++++++++++++
.../multiplexer_original_skip_post.replay.yaml | 33 +++++++++++++
7 files changed, 148 insertions(+), 54 deletions(-)
diff --git a/doc/admin-guide/plugins/multiplexer.en.rst
b/doc/admin-guide/plugins/multiplexer.en.rst
index aab6fc99ee..12ec019df8 100644
--- a/doc/admin-guide/plugins/multiplexer.en.rst
+++ b/doc/admin-guide/plugins/multiplexer.en.rst
@@ -24,8 +24,9 @@
|Name| is a remap plug-in that allows requests to certain origins to be
multiplexed (i.e.,
duplicated and dispatched in parallel) to one or more other hosts. The
headers are copied into the
-new requests as well as POST bodies. Optionally POST and PUT requests can be
skipped via
-``pparam=proxy.config.multiplexer.skip_post_put=1``.
+new requests as well as request bodies specified via Content-Length. Chunk
encoded request bodies
+are not supported for multiplexing, but they will pass through to the
non-multiplexed origin.
+Optionally POST and PUT requests can be skipped via
``pparam=proxy.config.multiplexer.skip_post_put=1``.
Description
===========
@@ -90,54 +91,3 @@ Here are some example :file:`remap.config` configuration
lines::
#. The fourth entry will multiplex requests sent to ``http://www.example.com``
with a path of ``/d``
to both ``host1.example.com`` and ``host2.example.com``, but POST and PUT
requests will
not be multiplexed.
-
-Implementation
-==============
-
-Parsing Chunk Encoded Data
---------------------------
-
-|Name| parses chunked data with its own home brew parser. In the parser
:code:`size_` is the size of
-a chunk to be consumed. The local variable / parameter :code:`size` is raw
input size as read from an
-:code:`TSIOBufferBlock`. The "size states" are marked blue.
-
-.. uml::
- :align: center
-
- @startuml
-
- skinparam state {
- backgroundColor<<SIZE_STATE>> SkyBlue
- }
-
- state kSize <<SIZE_STATE>>
- kSize : Accumulate size_\nfrom hex input.
- [*] --> kSize
- kSize --> kSize : hex digit
- kSize --> kDataN : CR,size_ > 0
- kSize --> kEndN : CR, size_ == 0
- kSize --> kInvalid : *
-
- state kDataN <<SIZE_STATE>>
- kDataN --> kData : LF
- kDataN --> kInvalid : *
- kDataN : ASSERT(size_ > 0)
-
- state kEndN <<SIZE_STATE>>
- kEndN --> kEnd : LF
- kEndN --> kInvalid : *
-
- kData : Consume size_\nbytes of input.
- kData --> kSizeR : Input consumed
-
- state kSizeR <<SIZE_STATE>>
- kSizeR --> kSizeN : CR
- kSizeR --> kInvalid : *
-
- state kSizeN <<SIZE_STATE>>
- kSizeN --> kSize : LF
- kSizeN --> kInvalid : *
-
- kInvalid --> [*]
- kEnd --> [*]
- @enduml
diff --git a/plugins/multiplexer/ats-multiplexer.cc
b/plugins/multiplexer/ats-multiplexer.cc
index ba92706e5b..a6e9773351 100644
--- a/plugins/multiplexer/ats-multiplexer.cc
+++ b/plugins/multiplexer/ats-multiplexer.cc
@@ -158,7 +158,7 @@ DoRemap(const Instance &i, TSHttpTxn t)
generateRequests(i.origins, buffer, location, requests);
assert(requests.size() == i.origins.size());
- if (is_post_or_put) {
+ if (is_post_or_put || content_length > 0) {
const TSVConn vconnection = TSTransformCreate(handlePost, t);
assert(vconnection != nullptr);
PostState *state = new PostState(requests, content_length);
diff --git a/tests/gold_tests/pluginTest/multiplexer/multiplexer.test.py
b/tests/gold_tests/pluginTest/multiplexer/multiplexer.test.py
index 5e52c3fae7..c4ffe1d479 100644
--- a/tests/gold_tests/pluginTest/multiplexer/multiplexer.test.py
+++ b/tests/gold_tests/pluginTest/multiplexer/multiplexer.test.py
@@ -99,6 +99,18 @@ class MultiplexerTestBase:
self.server_https.Streams.All += Testers.ExcludesExpression(
'uuid: CHUNKED_POST', 'We do not expect a multiplexed chunked
POST.')
+ # Verify that the CUSTOM_METHOD is sent to all servers.
+ self.server_origin.Streams.All += Testers.ContainsExpression(
+ 'uuid: MYCUSTOMMETHOD', "Verify the client's original target
received the MYCUSTOMMETHOD transaction.")
+ self.server_http.Streams.All += Testers.ContainsExpression(
+ 'uuid: MYCUSTOMMETHOD', "Verify the HTTP server received the
MYCUSTOMMETHOD request.")
+ self.server_http.Streams.All += Testers.ContainsExpression(
+ 'x-response: fifth', "Verify the HTTP server sent the
MYCUSTOMMETHOD response.")
+ self.server_https.Streams.All += Testers.ContainsExpression(
+ 'uuid: MYCUSTOMMETHOD', "Verify the HTTPS server received the
MYCUSTOMMETHOD request.")
+ self.server_https.Streams.All += Testers.ContainsExpression(
+ 'x-response: fifth', "Verify the HTTPS server sent the
MYCUSTOMMETHOD response.")
+
# Verify that the HTTPS server receives a TLS connection.
self.server_https.Streams.All += Testers.ContainsExpression(
'Finished accept using TLSSession', "Verify the HTTPS was indeed
used by the HTTPS server.")
@@ -172,12 +184,20 @@ class MultiplexerTest(MultiplexerTestBase):
'x-response: second', "Verify the HTTP server sent the POST
response.")
self.server_https.Streams.All += Testers.ContainsExpression(
'x-response: second', "Verify the HTTPS server sent the POST
response.")
+ self.server_https.Streams.All += Testers.ContainsExpression(
+ 'x-response: fifth', "Verify the HTTPS server sent the custom
method response.")
# Same with PUT
self.server_http.Streams.All += Testers.ContainsExpression('uuid:
PUT', "Verify the HTTP server received the PUT request.")
self.server_https.Streams.All += Testers.ContainsExpression(
'uuid: PUT', "Verify the HTTPS server received the PUT request.")
+ # Same with MYCUSTOMMETHOD
+ self.server_http.Streams.All += Testers.ContainsExpression(
+ 'uuid: MYCUSTOMMETHOD', "Verify the HTTP server received the
custom method request.")
+ self.server_https.Streams.All += Testers.ContainsExpression(
+ 'uuid: MYCUSTOMMETHOD', "Verify the HTTPS server received the
custom method request.")
+
class MultiplexerSkipPostTest(MultiplexerTestBase):
"""
diff --git
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy.replay.yaml
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy.replay.yaml
index ddc0403a20..aaadd0d3c4 100644
---
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy.replay.yaml
+++
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy.replay.yaml
@@ -111,3 +111,32 @@ sessions:
# There is no client since this response terminates at ATS, so no need for
# proxy-response.
+
+ - client-request:
+ method: "MYCUSTOMMETHOD"
+ version: "1.1"
+ url: /path/mycustommethod
+ headers:
+ fields:
+ - [ Host, origin.server.com ]
+ - [ Content-Length, 8 ]
+ - [ X-Request, second ]
+ - [ uuid, MYCUSTOMMETHOD ]
+
+ proxy-request:
+ method: "MYCUSTOMMETHOD"
+ headers:
+ fields:
+ - [ X-Request, { value: fifth, as: equal } ]
+ - [ X-Multiplexer, { value: copy, as: equal } ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 320000 ]
+ - [ X-Response, fifth ]
+
+ # There is no client since this response terminates at ATS, so no need for
+ # proxy-response.
diff --git
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy_skip_post.replay.yaml
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy_skip_post.replay.yaml
index d655d488e9..243160b93d 100644
---
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy_skip_post.replay.yaml
+++
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_copy_skip_post.replay.yaml
@@ -53,3 +53,32 @@ sessions:
# Since POST and POST requests are skipped, the multiplexed hosts should
# not receive them.
+
+ - client-request:
+ method: "MYCUSTOMMETHOD"
+ version: "1.1"
+ url: /path/mycustommethod
+ headers:
+ fields:
+ - [ Host, origin.server.com ]
+ - [ Content-Length, 8 ]
+ - [ X-Request, second ]
+ - [ uuid, MYCUSTOMMETHOD ]
+
+ proxy-request:
+ method: "MYCUSTOMMETHOD"
+ headers:
+ fields:
+ - [ X-Request, { value: fifth, as: equal } ]
+ - [ X-Multiplexer, { value: copy, as: equal } ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 320000 ]
+ - [ X-Response, fifth ]
+
+ # There is no client since this response terminates at ATS, so no need for
+ # proxy-response.
diff --git
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original.replay.yaml
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original.replay.yaml
index daeead023e..a3b26e27da 100644
---
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original.replay.yaml
+++
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original.replay.yaml
@@ -156,3 +156,36 @@ sessions:
headers:
fields:
- [ X-Response, { value: fourth, as: equal } ]
+
+ # Custom method with body.
+ - client-request:
+ method: "MYCUSTOMMETHOD"
+ version: "1.1"
+ url: /path/mycustommethod
+ headers:
+ fields:
+ - [ Host, origin.server.com ]
+ - [ Content-Length, 320000 ]
+ - [ X-Request, fifth ]
+ - [ uuid, MYCUSTOMMETHOD ]
+
+ proxy-request:
+ method: "MYCUSTOMMETHOD"
+ headers:
+ fields:
+ - [ X-Request, { value: fifth, as: equal } ]
+ - [ X-Multiplexer, { value: original, as: equal } ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 320000 ]
+ - [ X-Response, fifth ]
+
+ proxy-response:
+ status: 200
+ headers:
+ fields:
+ - [ X-Response, { value: fifth, as: equal } ]
diff --git
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original_skip_post.replay.yaml
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original_skip_post.replay.yaml
index 86f2f14224..5639227aa0 100644
---
a/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original_skip_post.replay.yaml
+++
b/tests/gold_tests/pluginTest/multiplexer/replays/multiplexer_original_skip_post.replay.yaml
@@ -156,3 +156,36 @@ sessions:
headers:
fields:
- [ X-Response, { value: fourth, as: equal } ]
+
+ # Custom method with body. Should not be skipped because it is neither a PUT
or POST.
+ - client-request:
+ method: "MYCUSTOMMETHOD"
+ version: "1.1"
+ url: /path/mycustommethod
+ headers:
+ fields:
+ - [ Host, origin.server.com ]
+ - [ Content-Length, 320000 ]
+ - [ X-Request, fifth ]
+ - [ uuid, MYCUSTOMMETHOD ]
+
+ proxy-request:
+ method: "MYCUSTOMMETHOD"
+ headers:
+ fields:
+ - [ X-Request, { value: fifth, as: equal } ]
+ - [ X-Multiplexer, { value: original, as: equal } ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 320000 ]
+ - [ X-Response, fifth ]
+
+ proxy-response:
+ status: 200
+ headers:
+ fields:
+ - [ X-Response, { value: fifth, as: equal } ]