You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@axis.apache.org by ro...@apache.org on 2026/02/14 18:22:07 UTC
(axis-axis2-java-core) branch master updated (df8b1186fd -> 90764ed878)
This is an automated email from the ASF dual-hosted git repository.
robertlazarski pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
from df8b1186fd Add fuzz testing module with Jazzer-based fuzz targets for OSS-Fuzz
new 921c4581fb Fix AXIS2-3879 + AXIS2-4146: Respect user-set HTTP status codes on responses
new 90764ed878 Document custom HTTP response status codes in http-transport guide
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../apache/axis2/util/MessageContextBuilder.java | 3 +
.../http/AbstractHTTPTransportSender.java | 45 +++++++++++++-
.../apache/axis2/transport/http/AxisServlet.java | 7 ++-
.../transport/http/HTTPTransportSenderTest.java | 62 ++++++++++++++++++++
.../http/mock/MockHttpServletResponse.java | 8 ++-
src/site/xdoc/docs/http-transport.xml | 68 +++++++++++++++++++++-
6 files changed, 184 insertions(+), 9 deletions(-)
(axis-axis2-java-core) 01/02: Fix AXIS2-3879 + AXIS2-4146: Respect user-set HTTP status codes on responses
Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit 921c4581fb05b8dc4fb2b921cd818c296a11c919
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Sat Feb 14 08:10:09 2026 -1000
Fix AXIS2-3879 + AXIS2-4146: Respect user-set HTTP status codes on responses
The transport sender unconditionally set HTTP 500 for all fault responses,
overwriting any user-specified status code (e.g., 503, 400). This change
checks Constants.HTTP_RESPONSE_STATE on the message context before falling
back to the default, and propagates the property through fault contexts.
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
.../apache/axis2/util/MessageContextBuilder.java | 3 ++
.../http/AbstractHTTPTransportSender.java | 45 +++++++++++++++-
.../apache/axis2/transport/http/AxisServlet.java | 7 ++-
.../transport/http/HTTPTransportSenderTest.java | 62 ++++++++++++++++++++++
.../http/mock/MockHttpServletResponse.java | 8 +--
5 files changed, 119 insertions(+), 6 deletions(-)
diff --git a/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java b/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java
index ccc4d9b612..9bf82f965c 100644
--- a/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java
+++ b/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java
@@ -114,6 +114,9 @@ public class MessageContextBuilder {
newmsgCtx.setProperty(Constants.OUT_TRANSPORT_INFO,
inMessageContext.getProperty(Constants.OUT_TRANSPORT_INFO));
+ newmsgCtx.setProperty(Constants.HTTP_RESPONSE_STATE,
+ inMessageContext.getProperty(Constants.HTTP_RESPONSE_STATE));
+
handleCorrelationID(inMessageContext,newmsgCtx);
return newmsgCtx;
}
diff --git a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AbstractHTTPTransportSender.java b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AbstractHTTPTransportSender.java
index 06c9bcc094..8d89e9d6dc 100644
--- a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AbstractHTTPTransportSender.java
+++ b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AbstractHTTPTransportSender.java
@@ -271,9 +271,11 @@ public abstract class AbstractHTTPTransportSender extends AbstractHandler implem
servletBasedOutTransportInfo =
(ServletBasedOutTransportInfo) transportInfo;
- // if sending a fault, set HTTP status code to 500
+ // if sending a fault, set HTTP status code (respecting user-set status codes)
if (msgContext.isFault()) {
- servletBasedOutTransportInfo.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ int faultStatus = resolveHttpStatusCode(msgContext,
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ servletBasedOutTransportInfo.setStatus(faultStatus);
}
Object customHeaders = msgContext.getProperty(HTTPConstants.HTTP_HEADERS);
@@ -299,6 +301,12 @@ public abstract class AbstractHTTPTransportSender extends AbstractHandler implem
}
}
} else if (transportInfo instanceof AxisHttpResponse) {
+ if (msgContext.isFault()) {
+ int faultStatus = resolveHttpStatusCode(msgContext,
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ ((AxisHttpResponse) transportInfo).setStatus(faultStatus);
+ }
+
Object customHeaders = msgContext.getProperty(HTTPConstants.HTTP_HEADERS);
if (customHeaders != null) {
if (customHeaders instanceof List) {
@@ -360,6 +368,39 @@ public abstract class AbstractHTTPTransportSender extends AbstractHandler implem
}
}
+ /**
+ * Resolves the HTTP status code to use for a response. Checks the message context
+ * (and the inbound message context as a fallback) for a user-specified status code
+ * via {@link Constants#HTTP_RESPONSE_STATE}. If none is found, returns the default.
+ *
+ * @param msgContext the current (outbound) message context
+ * @param defaultStatus the default HTTP status code to use if no user override is found
+ * @return the resolved HTTP status code
+ */
+ private static int resolveHttpStatusCode(MessageContext msgContext, int defaultStatus) {
+ // Check the outbound message context first
+ String statusStr = (String) msgContext.getProperty(Constants.HTTP_RESPONSE_STATE);
+
+ // Fall back to the inbound message context (createFaultMessageContext may not
+ // have copied this property in older code paths)
+ if (statusStr == null) {
+ MessageContext inMsgCtx =
+ (MessageContext) msgContext.getProperty(MessageContext.IN_MESSAGE_CONTEXT);
+ if (inMsgCtx != null) {
+ statusStr = (String) inMsgCtx.getProperty(Constants.HTTP_RESPONSE_STATE);
+ }
+ }
+
+ if (statusStr != null) {
+ try {
+ return Integer.parseInt(statusStr);
+ } catch (NumberFormatException e) {
+ log.error("Invalid HTTP status code value: " + statusStr, e);
+ }
+ }
+ return defaultStatus;
+ }
+
private void writeMessageWithCommons(MessageContext messageContext,
EndpointReference toEPR, OMOutputFormat format)
throws AxisFault {
diff --git a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AxisServlet.java b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AxisServlet.java
index 96f99098f5..8fc6ebef78 100644
--- a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AxisServlet.java
+++ b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/AxisServlet.java
@@ -512,7 +512,12 @@ public class AxisServlet extends HttpServlet {
if (valueElement != null) {
if (SOAP12Constants.FAULT_CODE_SENDER.equals(valueElement.getTextAsQName().getLocalPart())
&& !msgContext.isDoingREST()) {
- response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ // Only set SOAP 1.2 Sender → 400 if the user hasn't already set a custom status
+ if (msgContext.getProperty(Constants.HTTP_RESPONSE_STATE) == null) {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ faultContext.setProperty(Constants.HTTP_RESPONSE_STATE,
+ String.valueOf(HttpServletResponse.SC_BAD_REQUEST));
+ }
}
}
}
diff --git a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/HTTPTransportSenderTest.java b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/HTTPTransportSenderTest.java
index a3353da4e8..173b1541e5 100644
--- a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/HTTPTransportSenderTest.java
+++ b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/HTTPTransportSenderTest.java
@@ -149,6 +149,68 @@ public abstract class HTTPTransportSenderTest extends TestCase {
}
+ /**
+ * AXIS2-3879: Fault with a user-specified custom status code should use that code,
+ * not the default 500.
+ */
+ public void testFaultWithCustomStatusCode() throws Exception {
+ MockHttpServletResponse httpResponse = new MockHttpServletResponse();
+ ServletBasedOutTransportInfo info = new ServletBasedOutTransportInfo(httpResponse);
+ configAndRunFault(httpResponse, info, "503", getTransportSender());
+ assertEquals("Custom status code should be respected", 503, httpResponse.getStatus());
+ }
+
+ /**
+ * AXIS2-3879: Fault without a custom status code should default to 500.
+ */
+ public void testFaultDefaultsTo500() throws Exception {
+ MockHttpServletResponse httpResponse = new MockHttpServletResponse();
+ ServletBasedOutTransportInfo info = new ServletBasedOutTransportInfo(httpResponse);
+ configAndRunFault(httpResponse, info, null, getTransportSender());
+ assertEquals("Default fault status should be 500", 500, httpResponse.getStatus());
+ }
+
+ /**
+ * AXIS2-4146: User-set status code 400 should not be overwritten to 500.
+ */
+ public void testFaultWithStatus400NotOverwritten() throws Exception {
+ MockHttpServletResponse httpResponse = new MockHttpServletResponse();
+ ServletBasedOutTransportInfo info = new ServletBasedOutTransportInfo(httpResponse);
+ configAndRunFault(httpResponse, info, "400", getTransportSender());
+ assertEquals("Status 400 should not be overwritten to 500", 400, httpResponse.getStatus());
+ }
+
+ private static void configAndRunFault(MockHttpServletResponse outResponse,
+ OutTransportInfo outTransportInfo, String customStatus,
+ TransportSender sender) throws Exception {
+ ConfigurationContext confContext = ConfigurationContextFactory
+ .createEmptyConfigurationContext();
+ TransportOutDescription transportOut = new TransportOutDescription("http");
+ Parameter param = new Parameter(HTTPConstants.OMIT_SOAP_12_ACTION, false);
+ SOAPEnvelope envelope = getFaultEnvelope();
+ MessageContext msgContext = new MessageContext();
+
+ transportOut.addParameter(param);
+ msgContext.setEnvelope(envelope);
+ msgContext.setProperty(MessageContext.TRANSPORT_OUT,
+ outResponse.getByteArrayOutputStream());
+ msgContext.setProperty(Constants.OUT_TRANSPORT_INFO, outTransportInfo);
+ msgContext.setTransportOut(transportOut);
+ msgContext.setConfigurationContext(confContext);
+ if (customStatus != null) {
+ msgContext.setProperty(Constants.HTTP_RESPONSE_STATE, customStatus);
+ }
+ sender.init(confContext, transportOut);
+ sender.invoke(msgContext);
+ }
+
+ static SOAPEnvelope getFaultEnvelope() {
+ SOAPFactory soapFac = OMAbstractFactory.getSOAP11Factory();
+ SOAPEnvelope envelope = soapFac.getDefaultFaultEnvelope();
+ envelope.getBody().getFault().getReason().setText("test fault");
+ return envelope;
+ }
+
static SOAPEnvelope getEnvelope() throws IOException {
SOAPFactory soapFac = OMAbstractFactory.getSOAP11Factory();
OMFactory omFac = OMAbstractFactory.getOMFactory();
diff --git a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/mock/MockHttpServletResponse.java b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/mock/MockHttpServletResponse.java
index a3c1e75375..cc5473ba2b 100644
--- a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/mock/MockHttpServletResponse.java
+++ b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/mock/MockHttpServletResponse.java
@@ -49,8 +49,9 @@ public class MockHttpServletResponse implements HttpServletResponse, OutTranspor
private OutputStream outStream;
private boolean committed;
private HeaderGroup headerGroup;
- private ByteArrayOutputStream byteArrayOutputStream;
-
+ private ByteArrayOutputStream byteArrayOutputStream;
+ private int status = 200;
+
public MockHttpServletResponse() {
headerGroup = new HeaderGroup();
byteArrayOutputStream = new ByteArrayOutputStream();
@@ -203,6 +204,7 @@ public class MockHttpServletResponse implements HttpServletResponse, OutTranspor
@Override
public void setStatus(int sc) {
+ this.status = sc;
}
@Override
@@ -222,7 +224,7 @@ public class MockHttpServletResponse implements HttpServletResponse, OutTranspor
@Override
public int getStatus() {
- throw new UnsupportedOperationException();
+ return status;
}
@Override
(axis-axis2-java-core) 02/02: Document custom HTTP response status codes in http-transport guide
Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit 90764ed8787f8e4aa5220e86738669aeea2af833
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Sat Feb 14 08:18:23 2026 -1000
Document custom HTTP response status codes in http-transport guide
Add a new section to the HTTP transport documentation explaining how
users can override HTTP status codes on responses via the
Constants.HTTP_RESPONSE_STATE MessageContext property, with code
examples and precedence rules. References AXIS2-3879 and AXIS2-4146.
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
src/site/xdoc/docs/http-transport.xml | 68 +++++++++++++++++++++++++++++++++--
1 file changed, 65 insertions(+), 3 deletions(-)
diff --git a/src/site/xdoc/docs/http-transport.xml b/src/site/xdoc/docs/http-transport.xml
index 1d09d080b4..fe5e6afde8 100644
--- a/src/site/xdoc/docs/http-transport.xml
+++ b/src/site/xdoc/docs/http-transport.xml
@@ -47,6 +47,7 @@ as the transport mechanism.</p>
<li><a href="#preemptive_auth">Basic, Digest and NTLM Authentication</a></li>
<li><a href="#reusing_httpclient_object">Reusing the httpclient object</a></li>
<li><a href="#setting_cached_httpclient_object">Setting the cached httpclient object</a></li>
+ <li><a href="#custom_http_status_codes">Custom HTTP Response Status Codes</a></li>
</ul>
<a name="HTTPClient5TransportSender"></a>
@@ -400,8 +401,69 @@ HttpState myHttpState = new HttpState();
options.setProperty(WSClientConstants.CACHED_HTTP_STATE, myHttpState);
</pre>
-Doing so the HttpState is attached to the client. Respectively this is automatically propagated to all MessageContext objects used by the client.
-Underneath this just instructs Axis2 that the CACHED_HTTP_STATE set should be passed as a parameter when HttpClient#executeMethod is invoked.
-
+Doing so the HttpState is attached to the client. Respectively this is automatically propagated to all MessageContext objects used by the client.
+Underneath this just instructs Axis2 that the CACHED_HTTP_STATE set should be passed as a parameter when HttpClient#executeMethod is invoked.
+
+<a name="custom_http_status_codes"></a>
+<h2>Custom HTTP Response Status Codes</h2>
+
+<p>By default, Axis2 sends HTTP 200 for successful responses and HTTP 500 for
+fault responses. For SOAP 1.2 messages where the fault code is
+<code>Sender</code>, Axis2 automatically uses HTTP 400 instead of 500.</p>
+
+<p>You can override the HTTP status code on any response by setting the
+<code>Constants.HTTP_RESPONSE_STATE</code> property
+(<code>"axis2.http.response.state"</code>) on the MessageContext. The value
+must be a String representation of the desired HTTP status code. This works
+for both fault and non-fault responses.</p>
+
+<h3>Server-side: Custom fault status code</h3>
+
+<p>In a service implementation or handler, set the property on the inbound
+MessageContext before throwing the fault. The status code will be propagated
+to the fault response context automatically.</p>
+<pre>
+public void myServiceMethod(MessageContext msgContext) throws AxisFault {
+ if (isServiceUnavailable()) {
+ // Return 503 Service Unavailable instead of the default 500
+ msgContext.setProperty("axis2.http.response.state", "503");
+ throw new AxisFault("Service temporarily unavailable");
+ }
+}
+</pre>
+
+<h3>Server-side: Custom status in a handler</h3>
+
+<p>Axis2 handlers in the inbound flow can set the status code before the
+message reaches the service. The transport sender will respect this value
+when writing the response.</p>
+<pre>
+public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
+ // Example: return 429 Too Many Requests for rate limiting
+ if (isRateLimited(msgContext)) {
+ msgContext.setProperty("axis2.http.response.state", "429");
+ throw new AxisFault("Rate limit exceeded");
+ }
+ return InvocationResponse.CONTINUE;
+}
+</pre>
+
+<h3>Precedence rules</h3>
+
+<p>When determining the HTTP status code for a response, the following
+precedence applies (highest to lowest):</p>
+<ol>
+ <li>User-specified value in <code>Constants.HTTP_RESPONSE_STATE</code> on
+ the MessageContext</li>
+ <li>SOAP 1.2 Sender fault code mapping to HTTP 400 (only applied if no
+ user-specified value exists)</li>
+ <li>WSDL binding <code>whttp:code</code> attribute</li>
+ <li>Default: HTTP 500 for faults, HTTP 200 for success</li>
+</ol>
+
+<p>This feature was introduced to address
+<a href="https://issues.apache.org/jira/browse/AXIS2-3879">AXIS2-3879</a> and
+<a href="https://issues.apache.org/jira/browse/AXIS2-4146">AXIS2-4146</a>.</p>
+
</body>
</html>