Watcher: Throw exception when empty URL is handed in http requests
This ensures that invalid watches are not even added and rejected on index time. Closes elastic/elasticsearch#1510 Original commit: elastic/x-pack-elasticsearch@d18e0c8ef6
This commit is contained in:
parent
b97fea44d7
commit
47f1c2daa5
|
@ -242,6 +242,10 @@ public class HttpRequest implements ToXContent {
|
|||
return new Builder(host, port);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Parser {
|
||||
|
||||
private final HttpAuthRegistry httpAuthRegistry;
|
||||
|
@ -443,8 +447,15 @@ public class HttpRequest implements ToXContent {
|
|||
}
|
||||
|
||||
public Builder fromUrl(String supposedUrl) {
|
||||
if (Strings.hasLength(supposedUrl) == false) {
|
||||
throw new ElasticsearchParseException("Configured URL is empty, please configure a valid URL");
|
||||
}
|
||||
|
||||
try {
|
||||
URI uri = new URI(supposedUrl);
|
||||
if (Strings.hasLength(uri.getScheme()) == false) {
|
||||
throw new ElasticsearchParseException("URL [{}] does not contain a scheme", uri);
|
||||
}
|
||||
scheme = Scheme.parse(uri.getScheme());
|
||||
port = uri.getPort() > 0 ? uri.getPort() : scheme.defaultPort();
|
||||
host = uri.getHost();
|
||||
|
|
|
@ -248,6 +248,10 @@ public class HttpRequestTemplate implements ToXContent {
|
|||
return new Builder(host, port);
|
||||
}
|
||||
|
||||
static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Parser {
|
||||
|
||||
private final HttpAuthRegistry httpAuthRegistry;
|
||||
|
@ -477,8 +481,15 @@ public class HttpRequestTemplate implements ToXContent {
|
|||
}
|
||||
|
||||
public Builder fromUrl(String supposedUrl) {
|
||||
if (Strings.hasLength(supposedUrl) == false) {
|
||||
throw new ElasticsearchParseException("Configured URL is empty, please configure a valid URL");
|
||||
}
|
||||
|
||||
try {
|
||||
URI uri = new URI(supposedUrl);
|
||||
if (Strings.hasLength(uri.getScheme()) == false) {
|
||||
throw new ElasticsearchParseException("URL [{}] does not contain a scheme", uri);
|
||||
}
|
||||
scheme = Scheme.parse(uri.getScheme());
|
||||
port = uri.getPort() > 0 ? uri.getPort() : scheme.defaultPort();
|
||||
host = uri.getHost();
|
||||
|
@ -495,7 +506,7 @@ public class HttpRequestTemplate implements ToXContent {
|
|||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ElasticsearchParseException("Malformed URI [{}]", supposedUrl);
|
||||
throw new ElasticsearchParseException("Malformed URL [{}]", supposedUrl);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.watcher.support.http;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -25,6 +26,7 @@ import java.util.Collections;
|
|||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
@ -168,6 +170,33 @@ public class HttpRequestTemplateTests extends ESTestCase {
|
|||
assertThatManualBuilderEqualsParsingFromUrl("http://www.example.org?foo=%20white%20space", builder);
|
||||
}
|
||||
|
||||
public void testParsingEmptyUrl() throws Exception {
|
||||
try {
|
||||
HttpRequestTemplate.builder().fromUrl("");
|
||||
fail("Expected exception due to empty URL");
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertThat(e.getMessage(), containsString("Configured URL is empty, please configure a valid URL"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidUrlsWithMissingScheme() throws Exception {
|
||||
try {
|
||||
HttpRequestTemplate.builder().fromUrl("www.test.de");
|
||||
fail("Expected exception due to missing scheme");
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertThat(e.getMessage(), containsString("URL [www.test.de] does not contain a scheme"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidUrlsWithHost() throws Exception {
|
||||
try {
|
||||
HttpRequestTemplate.builder().fromUrl("https://");
|
||||
fail("Expected exception due to missing host");
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertThat(e.getMessage(), containsString("Malformed URL [https://]"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertThatManualBuilderEqualsParsingFromUrl(String url, HttpRequestTemplate.Builder builder) throws Exception {
|
||||
XContentBuilder urlContentBuilder = jsonBuilder().startObject().field("url", url).endObject();
|
||||
XContentParser urlContentParser = JsonXContent.jsonXContent.createParser(urlContentBuilder.bytes());
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.watcher.support.http;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class HttpRequestTests extends ESTestCase {
|
||||
|
||||
public void testParsingFromUrl() throws Exception {
|
||||
HttpRequest.Builder builder = HttpRequest.builder("www.example.org", 1234);
|
||||
builder.path("/foo/bar/org");
|
||||
builder.setParam("param", "test");
|
||||
builder.scheme(Scheme.HTTPS);
|
||||
assertThatManualBuilderEqualsParsingFromUrl("https://www.example.org:1234/foo/bar/org?param=test", builder);
|
||||
|
||||
// test without specifying port
|
||||
builder = HttpRequest.builder("www.example.org", 80);
|
||||
assertThatManualBuilderEqualsParsingFromUrl("http://www.example.org", builder);
|
||||
|
||||
// encoded values
|
||||
builder = HttpRequest.builder("www.example.org", 80).setParam("foo", " white space");
|
||||
assertThatManualBuilderEqualsParsingFromUrl("http://www.example.org?foo=%20white%20space", builder);
|
||||
}
|
||||
|
||||
public void testParsingEmptyUrl() throws Exception {
|
||||
try {
|
||||
HttpRequest.builder().fromUrl("");
|
||||
fail("Expected exception due to empty URL");
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertThat(e.getMessage(), containsString("Configured URL is empty, please configure a valid URL"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidUrlsWithMissingScheme() throws Exception {
|
||||
try {
|
||||
HttpRequest.builder().fromUrl("www.test.de");
|
||||
fail("Expected exception due to missing scheme");
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertThat(e.getMessage(), containsString("URL [www.test.de] does not contain a scheme"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidUrlsWithHost() throws Exception {
|
||||
try {
|
||||
HttpRequest.builder().fromUrl("https://");
|
||||
fail("Expected exception due to missing host");
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertThat(e.getMessage(), containsString("Malformed URL [https://]"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertThatManualBuilderEqualsParsingFromUrl(String url, HttpRequest.Builder builder) throws Exception {
|
||||
XContentBuilder urlContentBuilder = jsonBuilder().startObject().field("url", url).endObject();
|
||||
XContentParser urlContentParser = JsonXContent.jsonXContent.createParser(urlContentBuilder.bytes());
|
||||
urlContentParser.nextToken();
|
||||
|
||||
HttpRequest.Parser parser = new HttpRequest.Parser(mock(HttpAuthRegistry.class));
|
||||
HttpRequest urlParsedRequest = parser.parse(urlContentParser);
|
||||
|
||||
XContentBuilder xContentBuilder = builder.build().toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS);
|
||||
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(xContentBuilder.bytes());
|
||||
xContentParser.nextToken();
|
||||
HttpRequest parsedRequest = parser.parse(xContentParser);
|
||||
|
||||
assertThat(parsedRequest, is(urlParsedRequest));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
"Test invalid urls in email attachments reject put watch":
|
||||
- do:
|
||||
cluster.health:
|
||||
wait_for_status: yellow
|
||||
|
||||
- do:
|
||||
catch: /Configured URL is empty/
|
||||
watcher.put_watch:
|
||||
id: "my_watch"
|
||||
master_timeout: "40s"
|
||||
body: >
|
||||
{
|
||||
"trigger": {
|
||||
"schedule": {
|
||||
"hourly": {
|
||||
"minute": [ 0, 5 ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"input": {
|
||||
"simple": {
|
||||
"payload": {}
|
||||
}
|
||||
},
|
||||
"condition": {
|
||||
"always": {}
|
||||
},
|
||||
"actions": {
|
||||
"send_email": {
|
||||
"email": {
|
||||
"to": "test.account@elastic.co",
|
||||
"subject": "Cluster Status Warning",
|
||||
"body": "hello",
|
||||
"attachments": {
|
||||
"my_id": {
|
||||
"http": {
|
||||
"request": { "url": "" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- do:
|
||||
catch: /Malformed URL/
|
||||
watcher.put_watch:
|
||||
id: "my_watch"
|
||||
master_timeout: "40s"
|
||||
body: >
|
||||
{
|
||||
"trigger": {
|
||||
"schedule": {
|
||||
"hourly": {
|
||||
"minute": [ 0, 5 ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"input": {
|
||||
"simple": {
|
||||
"payload": {}
|
||||
}
|
||||
},
|
||||
"condition": {
|
||||
"always": {}
|
||||
},
|
||||
"actions": {
|
||||
"send_email": {
|
||||
"email": {
|
||||
"to": "test.account@elastic.co",
|
||||
"subject": "Cluster Status Warning",
|
||||
"body": "hello",
|
||||
"attachments": {
|
||||
"my_id": {
|
||||
"http": {
|
||||
"request": { "url": "https://" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue