@@ -470,6 +470,9 @@ protected boolean mediate(Message message, boolean isFault) {
470470
471471 if (isOneway
472472 || !ContextUtils .isGenericAddress (maps .getReplyTo ())) {
473+ // Fail fast before the 202 partial response is sent when the
474+ // non-anonymous ReplyTo is blocked by the decoupled-destination guard.
475+ assertDecoupledReplyToAllowed (message , maps );
473476 InternalContextUtils .rebaseResponse (maps .getReplyTo (),
474477 maps ,
475478 message );
@@ -885,18 +888,7 @@ private void addRoleSpecific(AddressingProperties maps,
885888
886889 if (isFault
887890 && !ContextUtils .isGenericAddress (inMAPs .getFaultTo ())) {
888-
889- Message m = message .getExchange ().getInFaultMessage ();
890- if (m == null ) {
891- m = message ;
892- }
893- InternalContextUtils .rebaseResponse (inMAPs .getFaultTo (),
894- inMAPs ,
895- m );
896-
897- Destination destination = InternalContextUtils .createDecoupledDestination (m .getExchange (),
898- inMAPs .getFaultTo ());
899- m .getExchange ().setDestination (destination );
891+ rebaseOrFallbackFaultTo (message , maps , inMAPs );
900892 }
901893 }
902894 }
@@ -1224,6 +1216,105 @@ private void checkReplyTo(Message message, AddressingProperties maps) {
12241216 }
12251217 }
12261218
1219+ /**
1220+ * Throws a {@code wsa:DestinationUnreachable} SOAP fault when a non-anonymous
1221+ * {@code wsa:ReplyTo} is present but decoupled WS-Addressing is disabled.
1222+ * Must be called before {@link InternalContextUtils#rebaseResponse} so the fault
1223+ * is returned on the synchronous connection, not silently dropped after the 202.
1224+ */
1225+ private void assertDecoupledReplyToAllowed (Message message , AddressingProperties maps ) {
1226+ EndpointReferenceType replyTo = maps .getReplyTo ();
1227+ if (ContextUtils .isGenericAddress (replyTo )) {
1228+ return ;
1229+ }
1230+ final String uri = replyTo .getAddress ().getValue ();
1231+
1232+ boolean approved = Boolean .TRUE .equals (
1233+ message .getExchange ().get (ContextUtils .DECOUPLED_DESTINATION_APPROVED_PROPERTY ));
1234+ if (approved ) {
1235+ if (ContextUtils .isDecoupledDestinationSchemeAllowed (uri )) {
1236+ return ;
1237+ }
1238+ final String reason = "Decoupled WS-Addressing ReplyTo (" + uri
1239+ + ") is not permitted by this server: URI scheme is not allowed. "
1240+ + "Configure permitted schemes with system property "
1241+ + ContextUtils .ALLOWED_DECOUPLED_DEST_SCHEMES_PROPERTY ;
1242+ if (isSOAP12 (message )) {
1243+ SoapFault f = new SoapFault (reason , Soap12 .getInstance ().getSender ());
1244+ f .setSubCode (Names .DESTINATION_UNREACHABLE_QNAME );
1245+ throw f ;
1246+ }
1247+ throw new SoapFault (reason , Names .DESTINATION_UNREACHABLE_QNAME );
1248+ }
1249+
1250+ if (ContextUtils .isDecoupledDestinationAllowed (uri )) {
1251+ return ;
1252+ }
1253+ final String reason = "Decoupled WS-Addressing ReplyTo (" + uri
1254+ + ") is not permitted by this server. Enable with system property "
1255+ + ContextUtils .WS_ADDRESSING_DECOUPLED_ENABLED_PROPERTY + "=true" ;
1256+ if (isSOAP12 (message )) {
1257+ SoapFault f = new SoapFault (reason , Soap12 .getInstance ().getSender ());
1258+ f .setSubCode (Names .DESTINATION_UNREACHABLE_QNAME );
1259+ throw f ;
1260+ }
1261+ throw new SoapFault (reason , Names .DESTINATION_UNREACHABLE_QNAME );
1262+ }
1263+
1264+ /**
1265+ * Rebases the response to the non-anonymous {@code wsa:FaultTo} endpoint when
1266+ * decoupled WS-Addressing is permitted, or falls back to the synchronous
1267+ * {@code wsa:ReplyTo} with a warning when it is not.
1268+ */
1269+ private void rebaseOrFallbackFaultTo (Message message ,
1270+ AddressingProperties maps ,
1271+ AddressingProperties inMAPs ) {
1272+ final String faultToUri = inMAPs .getFaultTo ().getAddress ().getValue ();
1273+ boolean approved = Boolean .TRUE .equals (
1274+ message .getExchange ().get (ContextUtils .DECOUPLED_DESTINATION_APPROVED_PROPERTY ));
1275+ if (approved ) {
1276+ if (ContextUtils .isDecoupledDestinationSchemeAllowed (faultToUri )) {
1277+ Message m = message .getExchange ().getInFaultMessage ();
1278+ if (m == null ) {
1279+ m = message ;
1280+ }
1281+ InternalContextUtils .rebaseResponse (inMAPs .getFaultTo (), inMAPs , m );
1282+ Destination destination =
1283+ InternalContextUtils .createDecoupledDestination (m .getExchange (), inMAPs .getFaultTo ());
1284+ m .getExchange ().setDestination (destination );
1285+ return ;
1286+ }
1287+ LOG .log (Level .WARNING ,
1288+ "Decoupled pre-approved FaultTo ({0}) is not permitted: URI scheme is not allowed. "
1289+ + "Fault will be delivered to ReplyTo instead. Configure permitted schemes with {1}" ,
1290+ new Object []{faultToUri , ContextUtils .ALLOWED_DECOUPLED_DEST_SCHEMES_PROPERTY });
1291+ if (inMAPs .getReplyTo () != null ) {
1292+ maps .setTo (inMAPs .getReplyTo ());
1293+ }
1294+ return ;
1295+ }
1296+ if (!ContextUtils .isDecoupledDestinationAllowed (faultToUri )) {
1297+ LOG .log (Level .WARNING ,
1298+ "Decoupled WS-Addressing FaultTo ({0}) is not permitted; "
1299+ + "fault will be delivered to ReplyTo instead. "
1300+ + "Enable with system property {1}=true" ,
1301+ new Object []{faultToUri ,
1302+ ContextUtils .WS_ADDRESSING_DECOUPLED_ENABLED_PROPERTY });
1303+ if (inMAPs .getReplyTo () != null ) {
1304+ maps .setTo (inMAPs .getReplyTo ());
1305+ }
1306+ return ;
1307+ }
1308+ Message m = message .getExchange ().getInFaultMessage ();
1309+ if (m == null ) {
1310+ m = message ;
1311+ }
1312+ InternalContextUtils .rebaseResponse (inMAPs .getFaultTo (), inMAPs , m );
1313+ Destination destination =
1314+ InternalContextUtils .createDecoupledDestination (m .getExchange (), inMAPs .getFaultTo ());
1315+ m .getExchange ().setDestination (destination );
1316+ }
1317+
12271318 private boolean isSOAP12 (Message message ) {
12281319 if (message .getExchange ().getBinding () instanceof SoapBinding ) {
12291320 SoapBinding binding = (SoapBinding )message .getExchange ().getBinding ();
0 commit comments