-
Notifications
You must be signed in to change notification settings - Fork 24.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensures watch definitions are valid json #30692
Changes from 3 commits
36d0c12
6da9e8b
7252b00
9a4db9f
dcd9b86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
*/ | ||
package org.elasticsearch.xpack.watcher.watch; | ||
|
||
import com.fasterxml.jackson.core.JsonParseException; | ||
import org.elasticsearch.ElasticsearchParseException; | ||
import org.elasticsearch.common.Nullable; | ||
import org.elasticsearch.common.bytes.BytesReference; | ||
|
@@ -174,6 +175,13 @@ public Watch parse(String id, boolean includeStatus, WatcherXContentParser parse | |
throw new ElasticsearchParseException("could not parse watch [{}]. unexpected field [{}]", id, currentFieldName); | ||
} | ||
} | ||
/* Make sure we are at the end of the available input data -- certain types of JSON errors will not manifest | ||
until we try to consume additional tokens. | ||
*/ | ||
if (parser.nextToken() != null) { | ||
throw new ElasticsearchParseException("could not parse watch [{}]. unexpected data beyond [line: {}, column: {}]", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor nit: maybe we can come up with a more explaining error message here, as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @spinscale Actually it is this code that enables the JsonParseException for the original test case. Ryan asked that the code for the test case be changed, which resulted in a different error path. However, the key factor is that we now attempt to grab the next token beyond what we believe to be the last token of the watch definition. A previous revision of this code made that fact clear, at the expense of some more complex code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea I think what @spinscale is saying is that he would like the error message changed. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hub-cap I was trying to respond to @spinscale's comment above in the LGTM -- I'll rework the error message |
||
id, parser.getTokenLocation().lineNumber, parser.getTokenLocation().columnNumber); | ||
} | ||
if (trigger == null) { | ||
throw new ElasticsearchParseException("could not parse watch [{}]. missing required field [{}]", id, | ||
WatchField.TRIGGER.getPreferredName()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,14 +11,18 @@ | |
import org.elasticsearch.action.support.WriteRequest; | ||
import org.elasticsearch.client.Client; | ||
import org.elasticsearch.common.ParseField; | ||
import org.elasticsearch.common.bytes.BytesArray; | ||
import org.elasticsearch.common.bytes.BytesReference; | ||
import org.elasticsearch.common.logging.Loggers; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.common.unit.TimeValue; | ||
import org.elasticsearch.common.xcontent.DeprecationHandler; | ||
import org.elasticsearch.common.xcontent.NamedXContentRegistry; | ||
import org.elasticsearch.common.xcontent.XContentBuilder; | ||
import org.elasticsearch.common.xcontent.XContentParser; | ||
import org.elasticsearch.common.xcontent.XContentType; | ||
import org.elasticsearch.common.xcontent.json.JsonXContent; | ||
import org.elasticsearch.common.xcontent.json.JsonXContentParser; | ||
import org.elasticsearch.index.query.MatchAllQueryBuilder; | ||
import org.elasticsearch.index.query.QueryBuilder; | ||
import org.elasticsearch.index.query.ScriptQueryBuilder; | ||
|
@@ -121,6 +125,7 @@ | |
import org.junit.Before; | ||
|
||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.time.Clock; | ||
import java.time.Instant; | ||
import java.time.ZoneOffset; | ||
|
@@ -143,6 +148,8 @@ | |
import static org.elasticsearch.xpack.watcher.input.InputBuilders.searchInput; | ||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.templateRequest; | ||
import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule; | ||
|
||
import static org.hamcrest.Matchers.containsString; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.hasSize; | ||
import static org.hamcrest.Matchers.instanceOf; | ||
|
@@ -296,6 +303,31 @@ public void testParserBadActions() throws Exception { | |
} | ||
} | ||
|
||
public void testParserConsumesEntireDefinition() throws Exception { | ||
WatchParser wp = createWatchparser(); | ||
XContentBuilder jsonBuilder = jsonBuilder() | ||
.startObject() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason you did not opt for the syntax (yea i know, its a builder, lets chain it!!!) used in other spots in this class? Imho its harder to read the nested thing than blocks of code with spaces that define start/endings. This is also how we do it in most of our toXContent functions as well.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We prefer using braces like this: diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java
index 1ff59034831..dcb48fbd3c1 100644
--- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java
+++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java
@@ -305,27 +305,44 @@ public class WatchTests extends ESTestCase {
public void testParserConsumesEntireDefinition() throws Exception {
WatchParser wp = createWatchparser();
- XContentBuilder jsonBuilder = jsonBuilder()
- .startObject()
- .startObject("trigger")
- .startObject("schedule")
- .field("interval", "10s")
- .endObject()
- .endObject()
- .startObject("input")
- .startObject("simple")
- .endObject()
- .endObject()
- .startObject("condition")
- .startObject("script")
- .field("source", "return false")
- .endObject()
- .endObject()
- .endObject();
- jsonBuilder.generator().writeBinary(",".getBytes(StandardCharsets.UTF_8));
- ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () ->
- wp.parseWithSecrets("failure", false, BytesReference.bytes(jsonBuilder), new DateTime(), XContentType.JSON, true));
+ try (XContentBuilder builder = jsonBuilder()) {
+ builder.startObject();
+ {
+ builder.startObject("trigger");
+ {
+ builder.startObject("schedule");
+ {
+ builder.field("interval", "10s");
+ }
+ builder.endObject();
+ }
+ builder.endObject();
+ builder.startObject("input");
+ {
+ builder.startObject("simple");
+ {
+ }
+ builder.endObject();
+ }
+ builder.endObject();
+ builder.startObject("condition");
+ {
+ builder.startObject("script");
+ {
+ builder.field("source", "return false");
+ }
+ builder.endObject();
+ }
+ builder.endObject();
+ }
+ builder.endObject();
+ builder.generator().writeBinary(",".getBytes(StandardCharsets.UTF_8));
+ ElasticsearchParseException e = expectThrows(
+ ElasticsearchParseException.class,
+ () -> wp.parseWithSecrets("failure", false, BytesReference.bytes(builder), new DateTime(), XContentType.JSON, true));
assertThat(e.getMessage(), containsString("unexpected data beyond"));
+ }
+
}
public void testParserDefaults() throws Exception { Also note that the builder should be wrapped in a try-with-resources; it's good hygiene. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, ive not see this before but i like it. I almost removed a Also, WRT the try-with-resources and hygiene, this is specifically for tests? or should we be doing this in the XContent methods as well? I assumed the caller was responsible for it in our request/response objects. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we own the lifecycle of the builder so we are responsible for closing it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hub-cap The way the class does it is mixed, when i started this PR i based style on testParserBadActions(), as that seemed to be the closest example to what I wanted to do. I am happy to conform to whatever is preferred. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's the old style before we introduced using braces for this. |
||
.startObject("trigger") | ||
.startObject("schedule") | ||
.field("interval", "10s") | ||
.endObject() | ||
.endObject() | ||
.startObject("input") | ||
.startObject("simple") | ||
.endObject() | ||
.endObject() | ||
.startObject("condition") | ||
.startObject("script") | ||
.field("source", "return false") | ||
.endObject() | ||
.endObject() | ||
.endObject(); | ||
jsonBuilder.generator().writeBinary(",".getBytes(StandardCharsets.UTF_8)); | ||
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> | ||
wp.parseWithSecrets("failure", false, BytesReference.bytes(jsonBuilder), new DateTime(), XContentType.JSON, true)); | ||
assertThat(e.getMessage(), containsString("unexpected data beyond")); | ||
} | ||
|
||
public void testParserDefaults() throws Exception { | ||
Schedule schedule = randomSchedule(); | ||
ScheduleRegistry scheduleRegistry = registry(schedule); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit: can you use a
//
comment like the other comments in the methods as well and add new lines before and after?