From 73df258774e3a839891e308ba39fc55ff51e414b Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Wed, 11 Dec 2019 17:34:55 -0800 Subject: [PATCH] Ensure meta and document field maps are never null in GetResult This commit ensures deseriable a GetResult from StreamInput does not leave metaFields and documentFields null. This could cause an NPE in situations where upsert response for a document that did not exist is passed back to a node that forwarded the upsert request. closes #48215 --- .../org/elasticsearch/index/get/GetResult.java | 17 +++++++---------- .../elasticsearch/index/get/GetResultTests.java | 13 +++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/get/GetResult.java b/server/src/main/java/org/elasticsearch/index/get/GetResult.java index f64aa03b9c487..949cc1969e7ae 100644 --- a/server/src/main/java/org/elasticsearch/index/get/GetResult.java +++ b/server/src/main/java/org/elasticsearch/index/get/GetResult.java @@ -65,8 +65,8 @@ public class GetResult implements Writeable, Iterable, ToXContent private long seqNo; private long primaryTerm; private boolean exists; - private Map documentFields; - private Map metaFields; + private final Map documentFields; + private final Map metaFields; private Map sourceAsMap; private BytesReference source; private byte[] sourceAsBytes; @@ -95,6 +95,9 @@ public GetResult(StreamInput in) throws IOException { metaFields = new HashMap<>(); splitFieldsByMetadata(fields, documentFields, metaFields); } + } else { + metaFields = Collections.emptyMap(); + documentFields = Collections.emptyMap(); } } @@ -111,14 +114,8 @@ public GetResult(String index, String id, long seqNo, long primaryTerm, long ver this.version = version; this.exists = exists; this.source = source; - this.documentFields = documentFields; - if (this.documentFields == null) { - this.documentFields = emptyMap(); - } - this.metaFields = metaFields; - if (this.metaFields == null) { - this.metaFields = emptyMap(); - } + this.documentFields = documentFields == null ? emptyMap() : documentFields; + this.metaFields = metaFields == null ? emptyMap() : metaFields; } /** diff --git a/server/src/test/java/org/elasticsearch/index/get/GetResultTests.java b/server/src/test/java/org/elasticsearch/index/get/GetResultTests.java index 92cf49ac6f487..4bca0952685ef 100644 --- a/server/src/test/java/org/elasticsearch/index/get/GetResultTests.java +++ b/server/src/test/java/org/elasticsearch/index/get/GetResultTests.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.document.DocumentField; +import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; @@ -138,6 +139,18 @@ public void testToXContentEmbeddedNotFound() throws IOException { assertEquals("{\"found\":false}", originalBytes.utf8ToString()); } + public void testSerializationNotFound() throws IOException { + // serializes and deserializes with streamable, then prints back to xcontent + GetResult getResult = new GetResult("index", "id", UNASSIGNED_SEQ_NO, 0, 1, false, null, null, null); + + BytesStreamOutput out = new BytesStreamOutput(); + getResult.writeTo(out); + getResult = new GetResult(out.bytes().streamInput()); + + BytesReference originalBytes = toXContentEmbedded(getResult, XContentType.JSON, false); + assertEquals("{\"found\":false}", originalBytes.utf8ToString()); + } + public void testGetSourceAsBytes() { XContentType xContentType = randomFrom(XContentType.values()); Tuple tuple = randomGetResult(xContentType);