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:
Nik Everett 2017-11-17 12:29:07 -05:00 committed by GitHub
parent fce5b494be
commit 87a3e93fae
2 changed files with 38 additions and 4 deletions

View File

@ -27,9 +27,14 @@ import static java.util.Collections.emptyMap;
public class RemoteFailure {
/**
* 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();
static {
@ -247,7 +252,12 @@ public class RemoteFailure {
private static String parseErrorMessage(String message, InputStream stream, JsonParser parser) {
String responseMessage;
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)) {
StringBuilder builder = new StringBuilder();
builder.append("Response:\n");
@ -259,7 +269,6 @@ public class RemoteFailure {
responseMessage = builder.toString();
}
} catch (IOException replayException) {
// TODO check for failed reset and return different error
responseMessage = "Attempted to include response but failed because [" + replayException.getMessage() + "].";
}
String parserLocation = "";

View File

@ -7,7 +7,9 @@ package org.elasticsearch.xpack.sql.client.shared;
import java.io.IOException;
import java.io.InputStream;
import java.lang.StringBuilder;
import java.nio.file.Files;
import java.util.Locale;
import org.elasticsearch.common.bytes.BytesArray;
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"));
}
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 {
try (InputStream in = Files.newInputStream(getDataPath("/remote_failure/" + fileName))) {
return RemoteFailure.parseFromResponse(in);