From e82f3a2d8455a3d02b6f4d39de8206cbde1bedea Mon Sep 17 00:00:00 2001 From: reiern70 Date: Tue, 19 Sep 2023 11:30:07 -0500 Subject: [PATCH] [WICKET-7074] write AJAX responses to a temporary buffer so that is AJAX fails in rendering phase response is not polluted with an invalid XML --- .../wicket/ajax/AjaxRequestHandler.java | 8 +- .../wicket/ajax/AjaxRequestHandlerTest.java | 94 +++++++++++++++++++ 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java index 5e52cfa6787..2f69f22b60c 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxRequestHandler.java @@ -273,14 +273,16 @@ public final void respond(final IRequestCycle requestCycle) final List filters = Application.get() .getRequestCycleSettings() .getResponseFilters(); + // KP-7074 we need to write to a temporary buffer, otherwise, if an exception is produced, + // and a redirect is done we will end up with a malformed XML + final StringResponse bodyResponse = new StringResponse(); + update.writeTo(bodyResponse, encoding); if (filters == null || filters.isEmpty()) { - update.writeTo(response, encoding); + response.write(bodyResponse.getBuffer()); } else { - final StringResponse bodyResponse = new StringResponse(); - update.writeTo(bodyResponse, encoding); CharSequence filteredResponse = invokeResponseFilters(bodyResponse, filters); response.write(filteredResponse); } diff --git a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java index f2c12362e93..61542ef1021 100644 --- a/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/ajax/AjaxRequestHandlerTest.java @@ -34,11 +34,15 @@ import org.apache.wicket.MarkupContainer; import org.apache.wicket.MockPageWithLink; import org.apache.wicket.MockPageWithLinkAndComponent; +import org.apache.wicket.Page; +import org.apache.wicket.RuntimeConfigurationType; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.IMarkupResourceStreamProvider; import org.apache.wicket.markup.html.WebComponent; import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.mock.MockApplication; import org.apache.wicket.request.IRequestHandler; import org.apache.wicket.request.cycle.IRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycle; @@ -47,7 +51,9 @@ import org.apache.wicket.util.resource.StringResourceStream; import org.apache.wicket.util.tester.DiffUtil; import org.apache.wicket.util.tester.WicketTestCase; +import org.apache.wicket.util.tester.WicketTester; import org.apache.wicket.util.time.Instants; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -306,6 +312,94 @@ void ajaxRedirectSetsNoCachingHeaders() assertEquals("no-cache, no-store", tester.getLastResponse().getHeader("Cache-Control")); } + private static class Wicket7074Application extends MockApplication + { + + @Override + public Class getHomePage() + { + return Wicket7074.class; + } + + + @Override + public RuntimeConfigurationType getConfigurationType() { + // this ise needed so that no filters are added + return RuntimeConfigurationType.DEPLOYMENT; + } + } + + private static class WeirdException extends IllegalStateException { + + } + + private static class Wicket7074 extends WebPage implements IMarkupResourceStreamProvider + { + private static final long serialVersionUID = 1L; + + private boolean generateError = false; + + private final Component label; + /** + * Construct. + */ + private Wicket7074() + { + setOutputMarkupId(true); + + add(new AjaxLink("action") + { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) + { + // we simulate producing an exception in rendering phase + generateError = true; + target.add(label); + } + }); + + add(label = new Label("label", "error") + { + private static final long serialVersionUID = 1L; + + @Override + protected void onBeforeRender() + { + super.onBeforeRender(); + // we simulate producing an exception in rendering phase + if (generateError) + { + throw new WeirdException(); + } + } + }.setOutputMarkupId(true)); + } + + @Override + public IResourceStream getMarkupResourceStream(MarkupContainer container, + Class containerClass) + { + return new StringResourceStream( + "link1


Link2"); + } + } + + @Test + void ajaxResposeIsEmptyIfExceptionIsProducedDuringRenderingAndNoFiltersAreSet() { + Wicket7074Application application = new Wicket7074Application(); + WicketTester tester = newWicketTester(application); + // page renders normally first time + tester.startPage(new Wicket7074()); + // click on action to produce render phase error + assertThrows(WeirdException.class, () -> { + tester.clickLink("action"); + }); + // AJAX response is written now into a buffer => response should empty + assertTrue(tester.getLastResponseAsString().isEmpty()); + } + /** * https://issues.apache.org/jira/browse/WICKET-6808 */