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 } ]

Reply via email to