diff --git a/ballerina-tests/http-advanced-tests/Ballerina.toml b/ballerina-tests/http-advanced-tests/Ballerina.toml
index 57a1af1f3f..7f1324ed29 100644
--- a/ballerina-tests/http-advanced-tests/Ballerina.toml
+++ b/ballerina-tests/http-advanced-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_advanced_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-advanced-tests/Dependencies.toml b/ballerina-tests/http-advanced-tests/Dependencies.toml
index b2f6524f89..4f61cfe022 100644
--- a/ballerina-tests/http-advanced-tests/Dependencies.toml
+++ b/ballerina-tests/http-advanced-tests/Dependencies.toml
@@ -72,7 +72,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -105,7 +105,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_advanced_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "crypto"},
{org = "ballerina", name = "file"},
@@ -125,7 +125,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-client-tests/Ballerina.toml b/ballerina-tests/http-client-tests/Ballerina.toml
index 90969bf5fd..964ffa836b 100644
--- a/ballerina-tests/http-client-tests/Ballerina.toml
+++ b/ballerina-tests/http-client-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_client_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-client-tests/Dependencies.toml b/ballerina-tests/http-client-tests/Dependencies.toml
index 76603e631d..f92e6e5b75 100644
--- a/ballerina-tests/http-client-tests/Dependencies.toml
+++ b/ballerina-tests/http-client-tests/Dependencies.toml
@@ -69,7 +69,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -102,7 +102,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_client_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "constraint"},
{org = "ballerina", name = "http"},
@@ -121,7 +121,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-dispatching-tests/Ballerina.toml b/ballerina-tests/http-dispatching-tests/Ballerina.toml
index bf47063437..896676e755 100644
--- a/ballerina-tests/http-dispatching-tests/Ballerina.toml
+++ b/ballerina-tests/http-dispatching-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_dispatching_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-dispatching-tests/Dependencies.toml b/ballerina-tests/http-dispatching-tests/Dependencies.toml
index 65149e9df4..80f445f8d4 100644
--- a/ballerina-tests/http-dispatching-tests/Dependencies.toml
+++ b/ballerina-tests/http-dispatching-tests/Dependencies.toml
@@ -69,7 +69,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -102,7 +102,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_dispatching_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "constraint"},
{org = "ballerina", name = "http"},
@@ -124,7 +124,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-interceptor-tests/Ballerina.toml b/ballerina-tests/http-interceptor-tests/Ballerina.toml
index f8d14b19eb..253b1b9e75 100644
--- a/ballerina-tests/http-interceptor-tests/Ballerina.toml
+++ b/ballerina-tests/http-interceptor-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_interceptor_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-interceptor-tests/Dependencies.toml b/ballerina-tests/http-interceptor-tests/Dependencies.toml
index 5ea506f318..3e9e0310d8 100644
--- a/ballerina-tests/http-interceptor-tests/Dependencies.toml
+++ b/ballerina-tests/http-interceptor-tests/Dependencies.toml
@@ -66,7 +66,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -99,7 +99,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_interceptor_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "http"},
{org = "ballerina", name = "http_test_common"},
@@ -115,7 +115,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-misc-tests/Ballerina.toml b/ballerina-tests/http-misc-tests/Ballerina.toml
index 8a126e960c..dc19ad36b9 100644
--- a/ballerina-tests/http-misc-tests/Ballerina.toml
+++ b/ballerina-tests/http-misc-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_misc_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-misc-tests/Dependencies.toml b/ballerina-tests/http-misc-tests/Dependencies.toml
index d179c7f73f..90dc8e9622 100644
--- a/ballerina-tests/http-misc-tests/Dependencies.toml
+++ b/ballerina-tests/http-misc-tests/Dependencies.toml
@@ -66,7 +66,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -99,7 +99,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_misc_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "http"},
{org = "ballerina", name = "http_test_common"},
@@ -118,7 +118,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-resiliency-tests/Ballerina.toml b/ballerina-tests/http-resiliency-tests/Ballerina.toml
index 1830863379..ff6a27b7a9 100644
--- a/ballerina-tests/http-resiliency-tests/Ballerina.toml
+++ b/ballerina-tests/http-resiliency-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_resiliency_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-resiliency-tests/Dependencies.toml b/ballerina-tests/http-resiliency-tests/Dependencies.toml
index 0aab6aec9a..c650f16263 100644
--- a/ballerina-tests/http-resiliency-tests/Dependencies.toml
+++ b/ballerina-tests/http-resiliency-tests/Dependencies.toml
@@ -66,7 +66,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -99,7 +99,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_resiliency_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "http"},
{org = "ballerina", name = "http_test_common"},
@@ -116,7 +116,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-resiliency-tests/tests/resiliency_passthrough_test.bal b/ballerina-tests/http-resiliency-tests/tests/resiliency_passthrough_test.bal
new file mode 100644
index 0000000000..189aa6272b
--- /dev/null
+++ b/ballerina-tests/http-resiliency-tests/tests/resiliency_passthrough_test.bal
@@ -0,0 +1,202 @@
+// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/test;
+
+public type Data record {|
+ string name;
+ int age;
+ string[] address;
+|};
+
+final http:Client passthroughRetryClient = check new (string`http://localhost:${passthroughTestPort1}`,
+ retryConfig = {
+ count: 3,
+ interval: 10
+ }
+);
+
+final http:LoadBalanceClient passthroughLoadBalancerClient = check new ({
+ targets: [
+ {url: string`http://localhost:${passthroughTestPort1}`}
+ ],
+ timeout: 5
+}
+);
+
+final http:FailoverClient passthroughFailoverClient = check new ({
+ timeout: 5,
+ failoverCodes: [501, 502, 503],
+ interval: 5,
+ targets: [
+ {url: "http://nonexistentEP"},
+ {url: string`http://localhost:${passthroughTestPort1}`}
+ ]
+});
+
+final http:Client passthroughRedirectClient = check new (string`http://localhost:${passthroughTestPort1}`,
+ followRedirects = {
+ enabled: true,
+ maxCount: 5
+ }
+);
+
+service on new http:Listener(passthroughTestPort2) {
+
+ resource function post passRetryWithReq(http:Request req) returns http:Response|error {
+ return passthroughRetryClient->/echo.post(req);
+ }
+
+ resource function post passRetryWithPayload(@http:Payload Data[]|xml|string payload) returns Data[]|xml|string|error {
+ return passthroughRetryClient->/echo.post(payload);
+ }
+
+ resource function post passLoadBalancerWithReq(http:Request req) returns http:Response|error {
+ return passthroughLoadBalancerClient->/echo.post(req);
+ }
+
+ resource function post passLoadBalancerWithPayload(@http:Payload Data[]|xml|string payload) returns Data[]|xml|string|error {
+ return passthroughLoadBalancerClient->/echo.post(payload);
+ }
+
+ resource function post passFailoverWithReq(http:Request req) returns http:Response|error {
+ return passthroughFailoverClient->/echo.post(req);
+ }
+
+ resource function post passFailoverWithPayload(@http:Payload Data[]|xml|string payload) returns Data[]|xml|string|error {
+ return passthroughFailoverClient->/echo.post(payload);
+ }
+
+ resource function post passRedirectWithReq(http:Request req) returns http:Response|error {
+ return passthroughRedirectClient->/echo.post(req);
+ }
+
+ resource function post passRedirectWithPayload(@http:Payload Data[]|xml|string payload) returns Data[]|xml|string|error {
+ return passthroughRedirectClient->/echo.post(payload);
+ }
+}
+
+service on new http:Listener(passthroughTestPort1) {
+
+ resource function post echo(@http:Payload Data[]|xml|string payload) returns Data[]|xml|string {
+ return payload;
+ }
+}
+
+@test:Config {}
+function testPassthroughRetryClientWithReq() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passRetryWithReq.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passRetryWithReq.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passRetryWithReq.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughRetryClientWithPayload() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passRetryWithPayload.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passRetryWithPayload.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passRetryWithPayload.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughLoadBalancerClientWithReq() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passLoadBalancerWithReq.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passLoadBalancerWithReq.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passLoadBalancerWithReq.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughLoadBalancerClientWithPayload() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passLoadBalancerWithPayload.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passLoadBalancerWithPayload.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passLoadBalancerWithPayload.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughFailoverClientWithReq() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passFailoverWithReq.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passFailoverWithReq.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passFailoverWithReq.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughFailoverClientWithPayload() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passFailoverWithPayload.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passFailoverWithPayload.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passFailoverWithPayload.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughRedirectClientWithReq() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passRedirectWithReq.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passRedirectWithReq.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passRedirectWithReq.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
+
+@test:Config {}
+function testPassthroughRedirectClientWithPayload() returns error? {
+ http:Client clientEP = check new(string`http://localhost:${passthroughTestPort2}`);
+ string stringResp = check clientEP->/passRedirectWithPayload.post("Hello World");
+ test:assertEquals(stringResp, "Hello World");
+
+ json jsonResp = check clientEP->/passRedirectWithPayload.post([{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+ test:assertEquals(jsonResp, [{name:"John", age:30, address:["Colombo", "Sri Lanka"]}]);
+
+ xml xmlResp = check clientEP->/passRedirectWithPayload.post(xml`Hello World`);
+ test:assertEquals(xmlResp, xml`Hello World`);
+}
diff --git a/ballerina-tests/http-resiliency-tests/tests/test_service_ports.bal b/ballerina-tests/http-resiliency-tests/tests/test_service_ports.bal
index 1938bc8f4f..a375f36d84 100644
--- a/ballerina-tests/http-resiliency-tests/tests/test_service_ports.bal
+++ b/ballerina-tests/http-resiliency-tests/tests/test_service_ports.bal
@@ -24,3 +24,6 @@ const int foClientWithoutStatusCodeTestPort1 = 9571;
const int foClientWithoutStatusCodeTestPort2 = 9572;
const int http2RetryFunctionTestPort = 9706;
+
+const int passthroughTestPort1 = 9543;
+const int passthroughTestPort2 = 9544;
diff --git a/ballerina-tests/http-security-tests/Ballerina.toml b/ballerina-tests/http-security-tests/Ballerina.toml
index f00ae61169..4470b01501 100644
--- a/ballerina-tests/http-security-tests/Ballerina.toml
+++ b/ballerina-tests/http-security-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_security_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-security-tests/Dependencies.toml b/ballerina-tests/http-security-tests/Dependencies.toml
index f06bdab1fd..d0f9105bc1 100644
--- a/ballerina-tests/http-security-tests/Dependencies.toml
+++ b/ballerina-tests/http-security-tests/Dependencies.toml
@@ -69,7 +69,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -102,7 +102,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_security_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "auth"},
{org = "ballerina", name = "http"},
@@ -120,7 +120,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-service-tests/Ballerina.toml b/ballerina-tests/http-service-tests/Ballerina.toml
index e8fe6bf394..3c91515e6f 100644
--- a/ballerina-tests/http-service-tests/Ballerina.toml
+++ b/ballerina-tests/http-service-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_service_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http-service-tests/Dependencies.toml b/ballerina-tests/http-service-tests/Dependencies.toml
index 145332254e..6999c125ad 100644
--- a/ballerina-tests/http-service-tests/Dependencies.toml
+++ b/ballerina-tests/http-service-tests/Dependencies.toml
@@ -69,7 +69,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -102,7 +102,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_service_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "file"},
{org = "ballerina", name = "http"},
@@ -121,7 +121,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina-tests/http-test-common/Ballerina.toml b/ballerina-tests/http-test-common/Ballerina.toml
index cb7d40d3d0..143f6d7ab9 100644
--- a/ballerina-tests/http-test-common/Ballerina.toml
+++ b/ballerina-tests/http-test-common/Ballerina.toml
@@ -1,4 +1,4 @@
[package]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
diff --git a/ballerina-tests/http-test-common/Dependencies.toml b/ballerina-tests/http-test-common/Dependencies.toml
index 9e265c2596..0c3f9b7dfb 100644
--- a/ballerina-tests/http-test-common/Dependencies.toml
+++ b/ballerina-tests/http-test-common/Dependencies.toml
@@ -10,7 +10,7 @@ distribution-version = "2201.7.0"
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "lang.string"},
{org = "ballerina", name = "mime"},
diff --git a/ballerina-tests/http2-tests/Ballerina.toml b/ballerina-tests/http2-tests/Ballerina.toml
index 8e4b4e8646..f4c0e69d95 100644
--- a/ballerina-tests/http2-tests/Ballerina.toml
+++ b/ballerina-tests/http2-tests/Ballerina.toml
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http2_tests"
-version = "2.9.3"
+version = "2.9.4"
[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
-version = "2.9.3"
+version = "2.9.4"
[platform.java11]
graalvmCompatible = true
[[platform.java11.dependency]]
scope = "testOnly"
-path = "../../test-utils/build/libs/http-test-utils-2.9.3.jar"
+path = "../../test-utils/build/libs/http-test-utils-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina-tests/http2-tests/Dependencies.toml b/ballerina-tests/http2-tests/Dependencies.toml
index c0f292c5dc..c43cedf7ab 100644
--- a/ballerina-tests/http2-tests/Dependencies.toml
+++ b/ballerina-tests/http2-tests/Dependencies.toml
@@ -69,7 +69,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
@@ -102,7 +102,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http2_tests"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "file"},
{org = "ballerina", name = "http"},
@@ -121,7 +121,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
-version = "2.9.3"
+version = "2.9.4"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml
index 46ee651397..d4e4af8921 100644
--- a/ballerina/Ballerina.toml
+++ b/ballerina/Ballerina.toml
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
authors = ["Ballerina"]
keywords = ["http", "network", "service", "listener", "client"]
repository = "https://github.com/ballerina-platform/module-ballerina-http"
@@ -16,8 +16,8 @@ graalvmCompatible = true
[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "http-native"
-version = "2.9.3"
-path = "../native/build/libs/http-native-2.9.3.jar"
+version = "2.9.4"
+path = "../native/build/libs/http-native-2.9.4-SNAPSHOT.jar"
[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml
index 13e8b01bda..e829778485 100644
--- a/ballerina/CompilerPlugin.toml
+++ b/ballerina/CompilerPlugin.toml
@@ -3,4 +3,4 @@ id = "http-compiler-plugin"
class = "io.ballerina.stdlib.http.compiler.HttpCompilerPlugin"
[[dependency]]
-path = "../compiler-plugin/build/libs/http-compiler-plugin-2.9.3.jar"
+path = "../compiler-plugin/build/libs/http-compiler-plugin-2.9.4-SNAPSHOT.jar"
diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml
index 51629790ca..66d982c33c 100644
--- a/ballerina/Dependencies.toml
+++ b/ballerina/Dependencies.toml
@@ -50,7 +50,7 @@ modules = [
[[package]]
org = "ballerina"
name = "crypto"
-version = "2.4.0"
+version = "2.4.1"
dependencies = [
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "time"}
@@ -62,7 +62,7 @@ modules = [
[[package]]
org = "ballerina"
name = "file"
-version = "1.8.0"
+version = "1.8.1"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
@@ -76,7 +76,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
-version = "2.9.3"
+version = "2.9.4"
dependencies = [
{org = "ballerina", name = "auth"},
{org = "ballerina", name = "cache"},
@@ -240,7 +240,7 @@ modules = [
[[package]]
org = "ballerina"
name = "log"
-version = "2.8.0"
+version = "2.8.1"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
diff --git a/ballerina/http_request.bal b/ballerina/http_request.bal
index 1c4f6f4fc0..38ad126bf2 100644
--- a/ballerina/http_request.bal
+++ b/ballerina/http_request.bal
@@ -587,6 +587,13 @@ public class Request {
return externCheckReqEntityBodyAvailability(self);
}
+ # Check whether the message data source is already built.
+ #
+ # + return - A boolean indicating the availability of the message data source
+ isolated function hasMsgDataSource() returns boolean {
+ return externHasMsgDataSource(self);
+ }
+
# Adds cookies to the request.
#
# + cookiesToAdd - Represents the cookies to be added
@@ -692,6 +699,12 @@ isolated function externCheckReqEntityBodyAvailability(Request request) returns
name: "checkEntityBodyAvailability"
} external;
+isolated function externHasMsgDataSource(Request request) returns boolean =
+@java:Method {
+ 'class: "io.ballerina.stdlib.http.api.nativeimpl.ExternRequest",
+ name: "hasMsgDataSource"
+} external;
+
# A record for providing mutual SSL handshake results.
#
# + status - Status of the handshake.
diff --git a/ballerina/redirect_http_client.bal b/ballerina/redirect_http_client.bal
index 661deb89f8..e892e9e977 100644
--- a/ballerina/redirect_http_client.bal
+++ b/ballerina/redirect_http_client.bal
@@ -316,9 +316,11 @@ client isolated class RedirectClient {
if !(httpOperation is safeHttpOperation) {
// When performing redirect operation for non-safe method, message needs to be built before sending out the
// to keep the request message to subsequent redirect.
- byte[]|error binaryPayload = check inRequest.getBinaryPayload();
- if binaryPayload is error {
- log:printDebug("Error building datasource for request redirect: " + binaryPayload.message());
+ if !inRequest.hasMsgDataSource() {
+ byte[]|error binaryPayload = inRequest.getBinaryPayload();
+ if binaryPayload is error {
+ log:printDebug("Error building datasource for request redirect: " + binaryPayload.message());
+ }
}
// Build message for for multipart requests
inRequest = check populateMultipartRequest(inRequest);
diff --git a/ballerina/resiliency_failover_client.bal b/ballerina/resiliency_failover_client.bal
index 5b732c953b..4fd71b8900 100644
--- a/ballerina/resiliency_failover_client.bal
+++ b/ballerina/resiliency_failover_client.bal
@@ -522,9 +522,11 @@ public client isolated class FailoverClient {
} else {
// When performing passthrough scenarios using Failover connector, message needs to be built before trying
// out the failover endpoints to keep the request message to failover the messages.
- byte[]|error binaryPayload = failoverRequest.getBinaryPayload();
- if binaryPayload is error {
- log:printDebug("Error building payload for request failover: " + binaryPayload.message());
+ if !failoverRequest.hasMsgDataSource() {
+ byte[]|error binaryPayload = failoverRequest.getBinaryPayload();
+ if binaryPayload is error {
+ log:printDebug("Error building payload for request failover: " + binaryPayload.message());
+ }
}
requestEntity = check failoverRequest.getEntity();
}
diff --git a/ballerina/resiliency_http_retry_client.bal b/ballerina/resiliency_http_retry_client.bal
index 8348936dee..fe1c19d6b6 100644
--- a/ballerina/resiliency_http_retry_client.bal
+++ b/ballerina/resiliency_http_retry_client.bal
@@ -304,9 +304,11 @@ isolated function performRetryAction(string path, Request request, HttpOperation
Request inRequest = request;
// When performing passthrough scenarios using retry client, message needs to be built before sending out the
// to keep the request message to retry.
- byte[]|error binaryPayload = check inRequest.getBinaryPayload();
- if binaryPayload is error {
- log:printDebug("Error building payload for request retry: " + binaryPayload.message());
+ if !inRequest.hasMsgDataSource() {
+ byte[]|error binaryPayload = inRequest.getBinaryPayload();
+ if binaryPayload is error {
+ log:printDebug("Error building payload for request retry: " + binaryPayload.message());
+ }
}
while (currentRetryCount < (retryCount + 1)) {
diff --git a/ballerina/resiliency_load_balance_client.bal b/ballerina/resiliency_load_balance_client.bal
index 29115d6477..f2742bf26e 100644
--- a/ballerina/resiliency_load_balance_client.bal
+++ b/ballerina/resiliency_load_balance_client.bal
@@ -423,9 +423,11 @@ public client isolated class LoadBalanceClient {
// When performing passthrough scenarios using Load Balance connector,
// message needs to be built before trying out the load balance endpoints to keep the request message
// to load balance the messages in case of failure.
- byte[]|error binaryPayload = loadBalancerInRequest.getBinaryPayload();
- if binaryPayload is error {
- log:printDebug("Error building payload for request load balance: " + binaryPayload.message());
+ if !loadBalancerInRequest.hasMsgDataSource() {
+ byte[]|error binaryPayload = loadBalancerInRequest.getBinaryPayload();
+ if binaryPayload is error {
+ log:printDebug("Error building payload for request load balance: " + binaryPayload.message());
+ }
}
requestEntity = check loadBalancerInRequest.getEntity();
}
diff --git a/changelog.md b/changelog.md
index d44f0b8420..c418c13c70 100644
--- a/changelog.md
+++ b/changelog.md
@@ -5,6 +5,18 @@ This file contains all the notable changes done to the Ballerina HTTP package th
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [Unreleased]
+
+### Fixed
+
+- [Fix resilient client failure in passthrough scenarios](https://github.com/ballerina-platform/ballerina-standard-library/issues/4824)
+
+## [2.9.3] - 2023-09-07
+
+### Fixed
+
+- [Address CVE-2023-33201 bouncy castle Vulnerability](https://github.com/ballerina-platform/ballerina-standard-library/issues/4776)
+
## [2.9.2] - 2023-08-10
### Fixed
diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequest.java b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequest.java
index 1c06fe794d..9f983561aa 100644
--- a/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequest.java
+++ b/native/src/main/java/io/ballerina/stdlib/http/api/nativeimpl/ExternRequest.java
@@ -32,6 +32,8 @@
import io.ballerina.stdlib.http.uri.URIUtil;
import io.ballerina.stdlib.mime.util.EntityBodyHandler;
+import java.util.Objects;
+
import static io.ballerina.stdlib.http.api.HttpConstants.QUERY_PARAM_MAP;
import static io.ballerina.stdlib.http.api.HttpConstants.TRANSPORT_MESSAGE;
import static io.ballerina.stdlib.http.api.HttpUtil.checkRequestBodySizeHeadersAvailability;
@@ -103,6 +105,11 @@ public static boolean checkEntityBodyAvailability(BObject requestObj) {
return lengthHeaderCheck(requestObj) || EntityBodyHandler.checkEntityBodyAvailability(entityObj);
}
+ public static boolean hasMsgDataSource(BObject requestObj) {
+ BObject entityObj = (BObject) requestObj.get(REQUEST_ENTITY_FIELD);
+ return Objects.nonNull(EntityBodyHandler.getMessageDataSource(entityObj));
+ }
+
private static boolean lengthHeaderCheck(BObject requestObj) {
Object outboundMsg = requestObj.getNativeData(TRANSPORT_MESSAGE);
if (outboundMsg == null) {