SQL: Improve error message for huge error responses (elastic/x-pack-elasticsearch#3049)
If the user has a funky proxy or something that throws back a massive error message to the CLI or JDBC then return a sensible error message. Original commit: elastic/x-pack-elasticsearch@94219969ea
This commit is contained in:
parent
fce5b494be
commit
87a3e93fae
|
@ -27,9 +27,14 @@ import static java.util.Collections.emptyMap;
|
||||||
public class RemoteFailure {
|
public class RemoteFailure {
|
||||||
/**
|
/**
|
||||||
* The maximum number of bytes before we no longer include the raw response if
|
* The maximum number of bytes before we no longer include the raw response if
|
||||||
* there is a catastrophic error parsing the remote failure.
|
* there is a catastrophic error parsing the remote failure. The actual value
|
||||||
|
* was chosen because it is ten times larger then a "normal" elasticsearch
|
||||||
|
* failure but not so big that we'll consume a ton of memory on huge errors.
|
||||||
|
* It <strong>will</strong> produce huge error messages but the user might
|
||||||
|
* want all that because it is <strong>probably</strong> being thrown by
|
||||||
|
* their proxy.
|
||||||
*/
|
*/
|
||||||
private static final int MAX_RAW_RESPONSE = 50*1024;
|
static final int MAX_RAW_RESPONSE = 512 * 1024;
|
||||||
|
|
||||||
private static final JsonFactory JSON_FACTORY = new JsonFactory();
|
private static final JsonFactory JSON_FACTORY = new JsonFactory();
|
||||||
static {
|
static {
|
||||||
|
@ -247,7 +252,12 @@ public class RemoteFailure {
|
||||||
private static String parseErrorMessage(String message, InputStream stream, JsonParser parser) {
|
private static String parseErrorMessage(String message, InputStream stream, JsonParser parser) {
|
||||||
String responseMessage;
|
String responseMessage;
|
||||||
try {
|
try {
|
||||||
stream.reset();
|
try {
|
||||||
|
stream.reset();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// So far as I know, this is always caused by the response being too large
|
||||||
|
throw new IOException("Response too large", e);
|
||||||
|
}
|
||||||
try (Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
try (Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append("Response:\n");
|
builder.append("Response:\n");
|
||||||
|
@ -259,7 +269,6 @@ public class RemoteFailure {
|
||||||
responseMessage = builder.toString();
|
responseMessage = builder.toString();
|
||||||
}
|
}
|
||||||
} catch (IOException replayException) {
|
} catch (IOException replayException) {
|
||||||
// TODO check for failed reset and return different error
|
|
||||||
responseMessage = "Attempted to include response but failed because [" + replayException.getMessage() + "].";
|
responseMessage = "Attempted to include response but failed because [" + replayException.getMessage() + "].";
|
||||||
}
|
}
|
||||||
String parserLocation = "";
|
String parserLocation = "";
|
||||||
|
|
|
@ -7,7 +7,9 @@ package org.elasticsearch.xpack.sql.client.shared;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.StringBuilder;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
@ -118,6 +120,29 @@ public class RemoteFailureTests extends ESTestCase {
|
||||||
+ "was expecting ('true', 'false' or 'null')] at [line 1 col 1]. Response:\n"));
|
+ "was expecting ('true', 'false' or 'null')] at [line 1 col 1]. Response:\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testTooBig() throws IOException {
|
||||||
|
StringBuilder tooBig = new StringBuilder(RemoteFailure.MAX_RAW_RESPONSE);
|
||||||
|
tooBig.append("{\n");
|
||||||
|
tooBig.append("\"error\" : {\n");
|
||||||
|
tooBig.append(" \"type\" : \"illegal_argument_exception\",\n");
|
||||||
|
tooBig.append(" \"reason\" : \"something\",\n");
|
||||||
|
tooBig.append(" \"header\" : {\n");
|
||||||
|
int i = 0;
|
||||||
|
while (tooBig.length() < RemoteFailure.MAX_RAW_RESPONSE) {
|
||||||
|
tooBig.append(" \"").append(String.format(Locale.ROOT, "%04d", i++))
|
||||||
|
.append("\" : \"lots and lots and lots and lots and lots of words\",\n");
|
||||||
|
}
|
||||||
|
tooBig.append(" \"end\" : \"lots and lots and lots and lots and lots of words\"\n");
|
||||||
|
tooBig.append(" }\n");
|
||||||
|
tooBig.append("}\n");
|
||||||
|
IOException e = expectThrows(IOException.class, () ->
|
||||||
|
RemoteFailure.parseFromResponse(new BytesArray(tooBig.toString()).streamInput()));
|
||||||
|
assertEquals(
|
||||||
|
"Can't parse error from Elasticearch [expected [stack_trace] cannot but didn't see it] "
|
||||||
|
+ "at [line 7951 col 1]. Attempted to include response but failed because [Response too large].",
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
private RemoteFailure parse(String fileName) throws IOException {
|
private RemoteFailure parse(String fileName) throws IOException {
|
||||||
try (InputStream in = Files.newInputStream(getDataPath("/remote_failure/" + fileName))) {
|
try (InputStream in = Files.newInputStream(getDataPath("/remote_failure/" + fileName))) {
|
||||||
return RemoteFailure.parseFromResponse(in);
|
return RemoteFailure.parseFromResponse(in);
|
||||||
|
|
Loading…
Reference in New Issue