diff options
author | Jon Bratseth <bratseth@gmail.com> | 2022-12-09 13:27:59 +0100 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2022-12-09 13:27:59 +0100 |
commit | 2e63be2d4d856cd59345190dd63c9b257eb1872d (patch) | |
tree | 366b5938c6a6685d67f940365711f709f6181255 | |
parent | 3f4e538fe2bcad11e45eb2ea558c0e4fa811770a (diff) |
Render completely when the response is malformed
2 files changed, 53 insertions, 4 deletions
diff --git a/container-core/src/main/java/com/yahoo/processing/rendering/AsynchronousSectionedRenderer.java b/container-core/src/main/java/com/yahoo/processing/rendering/AsynchronousSectionedRenderer.java index aa753beb6a7..2749b73272d 100644 --- a/container-core/src/main/java/com/yahoo/processing/rendering/AsynchronousSectionedRenderer.java +++ b/container-core/src/main/java/com/yahoo/processing/rendering/AsynchronousSectionedRenderer.java @@ -404,11 +404,15 @@ public abstract class AsynchronousSectionedRenderer<RESPONSE extends Response> e } } - /** - * Renders a list - */ + /** Renders a list. */ private void renderDataList(DataList list) throws IOException { final boolean ordered = isOrdered(list); + if (list.asList() == null) { + logger.log(Level.WARNING, "DataList.asList() returned null, indicating it is closed. " + + "This is likely caused by adding the same list multiple " + + "times in the response."); + return; + } while (currentIndex < list.asList().size()) { Data data = list.get(currentIndex++); if (data instanceof DataList) { diff --git a/container-core/src/test/java/com/yahoo/processing/rendering/AsynchronousSectionedRendererTest.java b/container-core/src/test/java/com/yahoo/processing/rendering/AsynchronousSectionedRendererTest.java index fb8aca95d9a..a4d5649a7f3 100644 --- a/container-core/src/test/java/com/yahoo/processing/rendering/AsynchronousSectionedRendererTest.java +++ b/container-core/src/test/java/com/yahoo/processing/rendering/AsynchronousSectionedRendererTest.java @@ -189,6 +189,18 @@ public class AsynchronousSectionedRendererTest { render(dataList)); } + /** Validate we get a full response with a malformed response structure. */ + @Test + void testRenderingOfListsAddedTwice() throws Exception { + StringDataList dataList = createDataListWithReusedSublist(); + + TestRenderer renderer = new TestRenderer(); + renderer.init(); + + assertEquals(" beginResponse beginList[[[]], []] beginList[[]] beginList[] endList[] endList[[]] beginList[] endList[] endList[[[]], []] endResponse", + render(renderer, dataList)); + } + public StringDataList createDataList() { Request request = new Request(); StringDataList dataList = new StringDataList(request); @@ -200,6 +212,20 @@ public class AsynchronousSectionedRendererTest { return dataList; } + public StringDataList createDataListWithReusedSublist() { + Request request = new Request(); + StringDataList dataList = new StringDataList(request); + + StringDataList group1 = new StringDataList(request); + dataList.add(group1); + + StringDataList group2 = new StringDataList(request); + group1.add(group2); + + dataList.add(group2); // Bug: This should not be added twice + return dataList; + } + public StringDataList createDataListWithStrangeStrings() { Request request = new Request(); StringDataList dataList = new StringDataList(request); @@ -325,6 +351,7 @@ public class AsynchronousSectionedRendererTest { } private static abstract class StringData extends ListenableFreezableClass implements Data { + private final Request request; private StringData(Request request) { @@ -342,6 +369,7 @@ public class AsynchronousSectionedRendererTest { public String toString() { return getString(); } + } private class StringDataItem extends StringData { @@ -361,7 +389,8 @@ public class AsynchronousSectionedRendererTest { private class StringDataList extends StringData implements DataList<StringData> { - private final ArrayList<StringData> list = new ArrayList<>(); + private ArrayList<StringData> list = new ArrayList<>(); + private String stringValue = null; // set on close private final IncomingData incomingData; @@ -404,8 +433,24 @@ public class AsynchronousSectionedRendererTest { @Override public String getString() { + if (stringValue != null) return stringValue; return list.toString(); } + + @Override + public void close() { + if (list == null) return; // Already closed + stringValue = list.toString(); + list = null; + } + + @Override + public StringDataList clone() { + var clone = new StringDataList(request()); + clone.list = new ArrayList<>(list); + return clone; + } + } private static class NoopProcessor extends Processor { |