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 {
|
||||
/**
|
||||
* 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 = "";
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue