Skip to content

Commit

Permalink
Merge pull request #130 from Nuvindu/error-handling
Browse files Browse the repository at this point in the history
Improve error handling in the SOAP Module
  • Loading branch information
Nuvindu authored Aug 2, 2024
2 parents f9c1fa6 + 30e4376 commit c9792e2
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 78 deletions.
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "soap"
version = "1.0.0"
version = "1.0.1"
authors = ["Ballerina"]
export=["soap", "soap.soap11", "soap.soap12"]
keywords = ["soap"]
Expand All @@ -19,8 +19,8 @@ graalvmCompatible = true
[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "soap-native"
version = "1.0.0"
path = "../native/build/libs/soap-native-1.0.0.jar"
version = "1.0.1"
path = "../native/build/libs/soap-native-1.0.1-SNAPSHOT.jar"

[[platform.java17.dependency]]
groupId = "org.apache.wss4j"
Expand Down
6 changes: 3 additions & 3 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "crypto"
version = "2.7.0"
version = "2.7.2"
dependencies = [
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "time"}
Expand All @@ -64,7 +64,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
version = "2.11.0"
version = "2.11.3"
dependencies = [
{org = "ballerina", name = "auth"},
{org = "ballerina", name = "cache"},
Expand Down Expand Up @@ -269,7 +269,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "soap"
version = "1.0.0"
version = "1.0.1"
dependencies = [
{org = "ballerina", name = "crypto"},
{org = "ballerina", name = "http"},
Expand Down
2 changes: 1 addition & 1 deletion ballerina/error.bal
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
# Defines the common error type for the module.
public type Error distinct error;

const SOAP_RESPONSE_ERROR = "Failed to create SOAP response.";
const SOAP_RESPONSE_ERROR = "Failed to create SOAP response";
const INVALID_PROTOCOL_ERROR = "Invalid protocol detected: Please use the `https` protocol instead of `http`.";
6 changes: 3 additions & 3 deletions ballerina/modules/soap11/error.bal
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Defines the common error type for the SOAP 1.1 module.
public type Error distinct error;

const SOAP_RESPONSE_ERROR = "Failed to create SOAP response.";
const SOAP_CLIENT_ERROR = "Failed to initialize SOAP 1.1 client.";
const SOAP_RESPONSE_ERROR = "Failed to create SOAP response";
const SOAP_CLIENT_ERROR = "Failed to initialize SOAP 1.1 client";
const SOAP_ERROR = "Error occurred while executing the API";
const INVALID_OUTBOUND_SECURITY_ERROR = "Outbound security configurations do not match with the SOAP response.";
const INVALID_OUTBOUND_SECURITY_ERROR = "Outbound security configurations do not match with the SOAP response";
12 changes: 6 additions & 6 deletions ballerina/modules/soap11/soap11.bal
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ public isolated client class Client {
check response[0].getXml().clone(), false);
}
}
} on fail var e {
return error Error(INVALID_OUTBOUND_SECURITY_ERROR, e.cause());
} on fail error soapError {
return error Error(INVALID_OUTBOUND_SECURITY_ERROR, soapError);
}
return response;
}
} on fail var e {
return error Error(SOAP_ERROR, e.cause());
} on fail error soapError {
return error Error(SOAP_ERROR, soapError);
}
}

Expand All @@ -122,8 +122,8 @@ public isolated client class Client {
securedBody = check soap:applySecurityPolicies(self.inboundSecurity.clone(), envelope.clone(), false);
}
return check soap:sendOnly(securedBody, self.soapClient, action, headers, path, false);
} on fail var e {
return error Error(SOAP_ERROR, e.cause());
} on fail error soapError {
return error Error(SOAP_ERROR, soapError);
}
}
}
34 changes: 18 additions & 16 deletions ballerina/modules/soap11/tests/http_soap_service.bal
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,22 @@ crypto:PublicKey serverPublicKey = check crypto:decodeRsaPublicKeyFromTrustStore

service / on new http:Listener(9090) {

resource function post .() returns xml|error {
return xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><AddResponse xmlns="http://tempuri.org/"><AddResult>5</AddResult></AddResponse></soap:Body></soap:Envelope>`;
resource function post .(http:Request request) returns xml|error {
string action = check request.getHeader("SOAPAction");
if action == "http://tempuri.org/Add" {
return xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><AddResponse xmlns="http://tempuri.org/"><AddResult>5</AddResult></AddResponse></soap:Body></soap:Envelope>`;
} else {
return xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://tempuri.org/invalid_action.
at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean&amp; abortProcessing)</faultstring><detail/></soap:Fault></soap:Body></soap:Envelope>`;
}
}

resource function post getPayload(http:Request request) returns http:Response|error {
http:Response response = new;
response.setPayload(check (check request.getBodyParts())[0].getXml());
return response;
resource function post getPayload(http:Request request) returns xml|error {
return check (check request.getBodyParts())[0].getXml();
}

resource function post getMimePayload(http:Request request) returns http:Response|error {
Expand All @@ -51,11 +59,8 @@ service / on new http:Listener(9090) {
return response;
}

resource function post getSamePayload(http:Request request) returns http:Response|error {
xml payload = check request.getXmlPayload();
http:Response response = new;
response.setPayload(payload);
return response;
resource function post getSamePayload(http:Request request) returns xml|error {
return check request.getXmlPayload();
}

resource function post getSecuredMimePayload(http:Request request) returns http:Response|error {
Expand Down Expand Up @@ -92,7 +97,7 @@ service / on new http:Listener(9090) {
return response;
}

resource function post getSecuredPayload(http:Request request) returns http:Response|error {
resource function post getSecuredPayload(http:Request request) returns xml|error {
xml payload = check request.getXmlPayload();
xml applyOutboundConfig = check soap:applyOutboundConfig(
{
Expand All @@ -104,7 +109,7 @@ service / on new http:Listener(9090) {
payload,
false
);
xml securedEnv = check soap:applySecurityPolicies(
return check soap:applySecurityPolicies(
{
signatureAlgorithm: soap:RSA_SHA256,
encryptionAlgorithm: soap:RSA_ECB,
Expand All @@ -114,8 +119,5 @@ service / on new http:Listener(9090) {
applyOutboundConfig,
false
);
http:Response response = new;
response.setPayload(securedEnv);
return response;
}
}
33 changes: 32 additions & 1 deletion ballerina/modules/soap11/tests/soap11_client_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,37 @@ function testSendReceive() returns error? {
test:assertEquals(response, expected);
}

@test:Config {
groups: ["soap11", "send_receive"]
}
function testSendReceiveWithInvalidAction() returns error? {
Client soapClient = check new ("http://localhost:9090",
{
inboundSecurity: NO_POLICY,
outboundSecurity: {}
}
);

xml body = xml `<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body>
<quer:Add xmlns:quer="http://tempuri.org/">
<quer:intA>2</quer:intA>
<quer:intB>3</quer:intB>
</quer:Add>
</soap:Body>
</soap:Envelope>`;
xml response = check soapClient->sendReceive(body, "http://tempuri.org/invalid_action");
xml expected = xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://tempuri.org/invalid_action.
at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean&amp; abortProcessing)</faultstring><detail/></soap:Fault></soap:Body></soap:Envelope>`;
test:assertEquals(response, expected);
}

@test:Config {
groups: ["soap11", "send_receive"]
}
Expand Down Expand Up @@ -627,5 +658,5 @@ function testInvalidOutboundConfigWithMime() returns error? {
mtomMessage.push(bytesPart);
xml|Error response = soapClient->sendReceive(mtomMessage, "http://tempuri.org/Add", path = "/getSecuredMimePayload");
test:assertTrue(response is Error);
test:assertEquals((<Error>response).message(), "Outbound security configurations do not match with the SOAP response.");
test:assertEquals((<Error>response).message(), "Outbound security configurations do not match with the SOAP response");
}
6 changes: 3 additions & 3 deletions ballerina/modules/soap12/error.bal
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Defines the common error type for the SOAP 1.2 module.
public type Error distinct error;

const SOAP_RESPONSE_ERROR = "Failed to create SOAP response.";
const SOAP_CLIENT_ERROR = "Failed to initialize SOAP 1.2 client.";
const SOAP_RESPONSE_ERROR = "Failed to create SOAP response";
const SOAP_CLIENT_ERROR = "Failed to initialize SOAP 1.2 client";
const SOAP_ERROR = "Failed to generate a response";
const INVALID_OUTBOUND_SECURITY_ERROR = "Outbound security configurations do not match with the SOAP response.";
const INVALID_OUTBOUND_SECURITY_ERROR = "Outbound security configurations do not match with the SOAP response";
12 changes: 6 additions & 6 deletions ballerina/modules/soap12/soap12.bal
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ public isolated client class Client {
check response[0].getXml().clone());
}
}
} on fail var e {
return error Error(INVALID_OUTBOUND_SECURITY_ERROR, e.cause());
} on fail error soapError {
return error Error(INVALID_OUTBOUND_SECURITY_ERROR, soapError);
}
return response;
}
} on fail var e {
return error Error(SOAP_ERROR, e.cause());
} on fail error soapError {
return error Error(SOAP_ERROR, soapError);
}
}

Expand All @@ -122,8 +122,8 @@ public isolated client class Client {
securedBody = check soap:applySecurityPolicies(self.inboundSecurity.clone(), envelope.clone());
}
return check soap:sendOnly(securedBody, self.soapClient, action, headers, path);
} on fail var e {
return error Error(SOAP_ERROR, e.cause());
} on fail error soapError {
return error Error(SOAP_ERROR, soapError);
}
}
}
40 changes: 20 additions & 20 deletions ballerina/modules/soap12/tests/http_soap_service.bal
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ service / on new http:Listener(9090) {
return xml `<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><AddResponse xmlns="http://tempuri.org/"><AddResult>5</AddResult></AddResponse></soap:Body></soap:Envelope>`;
}

resource function post getPayload(http:Request request) returns http:Response|error {
http:Response response = new;
response.setPayload(check (check request.getBodyParts())[0].getXml());
return response;
resource function post getPayload(http:Request request) returns xml|error {
return check (check request.getBodyParts())[0].getXml();
}

resource function post getMimePayload(http:Request request) returns http:Response|error {
Expand All @@ -52,28 +50,33 @@ service / on new http:Listener(9090) {
return response;
}

resource function post getActionPayload(http:Request request) returns http:Response|error {
resource function post getActionPayload(http:Request request) returns xml|error {
string[] headers = check request.getHeaders(mime:CONTENT_TYPE);
mime:MediaType mediaHeader = check mime:getMediaType(headers[0]);
map<string> actionMap = mediaHeader.parameters;
string action = actionMap.get("action");
if action == "http://tempuri.org/Add" {
xml payload = check request.getXmlPayload();
http:Response response = new;
response.setPayload(payload);
return response;
return check request.getXmlPayload();
}
return error("Invalid action is found");
return xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://tempuri.org/invalid_action.
at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean&amp; abortProcessing)</faultstring><detail/></soap:Fault></soap:Body></soap:Envelope>`;
}

resource function post getSamePayload(http:Request request) returns http:Response|error {
xml payload = check request.getXmlPayload();
http:Response response = new;
response.setPayload(payload);
return response;
resource function post getErrorPayload(http:Request request) returns xml|http:InternalServerError {
return {
body: "Error occurred in the server"
};
}

resource function post getSecuredPayload(http:Request request) returns http:Response|error {
resource function post getSamePayload(http:Request request) returns xml|error {
return check request.getXmlPayload();
}

resource function post getSecuredPayload(http:Request request) returns xml|error {
xml payload = check request.getXmlPayload();
xml applyOutboundConfig = check soap:applyOutboundConfig(
{
Expand All @@ -84,7 +87,7 @@ service / on new http:Listener(9090) {
},
payload
);
xml securedEnv = check soap:applySecurityPolicies(
return check soap:applySecurityPolicies(
{
signatureAlgorithm: soap:RSA_SHA256,
encryptionAlgorithm: soap:RSA_ECB,
Expand All @@ -93,9 +96,6 @@ service / on new http:Listener(9090) {
},
applyOutboundConfig
);
http:Response response = new;
response.setPayload(securedEnv);
return response;
}

resource function post getSecuredMimePayload(http:Request request) returns http:Response|error {
Expand Down
41 changes: 39 additions & 2 deletions ballerina/modules/soap12/tests/soap12_client_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,43 @@ function testSendReceive12WithAction() returns error? {
test:assertEquals(response, expected);
}

@test:Config {
groups: ["soap12", "send_receive"]
}
function testSendReceive12WithServerError() returns error? {
Client soapClient = check new ("http://localhost:9090");
xml body = xml `<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding/"><soap:Body><quer:Add xmlns:quer="http://tempuri.org/"><quer:intA>2</quer:intA><quer:intB>3</quer:intB></quer:Add></soap:Body></soap:Envelope>`;

xml|Error response = soapClient->sendReceive(body, path = "/getErrorPayload");
test:assertTrue(response is Error);
test:assertEquals((<error>(<error>(<error>response).cause()).cause()).message(), "Internal Server Error");
}

@test:Config {
groups: ["soap12", "send_receive"]
}
function testSendReceive12WithInvalidSoapAction() returns error? {
Client soapClient = check new ("http://localhost:9090");
xml body = xml `<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<soap:Body>
<quer:Add xmlns:quer="http://tempuri.org/">
<quer:intA>2</quer:intA>
<quer:intB>3</quer:intB>
</quer:Add>
</soap:Body>
</soap:Envelope>`;
xml response = check soapClient->sendReceive(body, "http://tempuri.org/invalid_action", path = "/getActionPayload");
xml expected = xml `<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://tempuri.org/invalid_action.
at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean&amp; abortProcessing)</faultstring><detail/></soap:Fault></soap:Body></soap:Envelope>`;
test:assertEquals(response, expected);
}

@test:Config {
groups: ["soap12", "send_receive"]
}
Expand Down Expand Up @@ -199,7 +236,7 @@ function testSendReceive12WithMime2() returns error? {
}

@test:Config {
groups: ["soap12", "send_receive", "mime", "h"]
groups: ["soap12", "send_receive", "mime"]
}
function testSendReceive12MimeWithoutAction() returns error? {
Client soapClient = check new ("http://localhost:9090");
Expand Down Expand Up @@ -608,5 +645,5 @@ function testInvalidOutboundConfigWithMime12() returns error? {

mime:Entity[]|Error response = soapClient->sendReceive(mtomMessage, "http://tempuri.org/Add", path = "/getSecuredMimePayload");
test:assertTrue(response is Error);
test:assertEquals((<Error>response).message(), "Outbound security configurations do not match with the SOAP response.");
test:assertEquals((<Error>response).message(), "Outbound security configurations do not match with the SOAP response");
}
Loading

0 comments on commit c9792e2

Please sign in to comment.