Improve error handling when decoding async execution ids (#56285)

When decoding async execution ids, exceptions thrown from the decode method itself were not caught, leading to cryptic errors like "Input byte array has incorrect ending byte at 68" being returned. With this commit we return "invalid id: [abcdef]".

Added tests coverage for a couple of these scenarios and also added tests for equals/hashcode methods.
This commit is contained in:
Luca Cavanna 2020-05-13 12:18:56 +02:00
parent 4394235c63
commit 30e9a1b8c7
2 changed files with 55 additions and 11 deletions

View File

@ -92,14 +92,20 @@ public final class AsyncExecutionId {
* to retrieve the response of an async execution.
*/
public static AsyncExecutionId decode(String id) {
final ByteBuffer byteBuffer;
try {
byteBuffer = ByteBuffer.wrap(Base64.getUrlDecoder().decode(id));
} catch (Exception e) {
throw new IllegalArgumentException("invalid id: [" + id + "]", e);
}
final AsyncExecutionId searchId;
try (StreamInput in = new ByteBufferStreamInput(ByteBuffer.wrap(Base64.getUrlDecoder().decode(id)))) {
try (StreamInput in = new ByteBufferStreamInput(byteBuffer)) {
searchId = new AsyncExecutionId(in.readString(), new TaskId(in.readString()));
if (in.available() > 0) {
throw new IllegalArgumentException("invalid id: [" + id + "]");
}
} catch (IOException e) {
throw new IllegalArgumentException("invalid id:[" + id + "]");
throw new IllegalArgumentException("invalid id: [" + id + "]", e);
}
return searchId;
}

View File

@ -7,25 +7,32 @@
package org.elasticsearch.xpack.core.async;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import java.io.IOException;
import java.util.Base64;
import static org.hamcrest.CoreMatchers.instanceOf;
public class AsyncExecutionIdTests extends ESTestCase {
public void testEncode() {
public void testEncodeAndDecode() {
for (int i = 0; i < 10; i++) {
AsyncExecutionId instance = new AsyncExecutionId(UUIDs.randomBase64UUID(),
new TaskId(randomAlphaOfLengthBetween(5, 20), randomNonNegativeLong()));
AsyncExecutionId instance = randomAsyncId();
String encoded = AsyncExecutionId.encode(instance.getDocId(), instance.getTaskId());
AsyncExecutionId same = AsyncExecutionId.decode(encoded);
assertEquals(same, instance);
AsyncExecutionId mutate = mutate(instance);
assertNotEquals(mutate, instance);
assertNotEquals(mutate, same);
}
}
private AsyncExecutionId mutate(AsyncExecutionId id) {
private static AsyncExecutionId randomAsyncId() {
return new AsyncExecutionId(UUIDs.randomBase64UUID(), new TaskId(randomAlphaOfLengthBetween(5, 20), randomNonNegativeLong()));
}
private static AsyncExecutionId mutate(AsyncExecutionId id) {
int rand = randomIntBetween(0, 1);
switch (rand) {
case 0:
@ -39,4 +46,35 @@ public class AsyncExecutionIdTests extends ESTestCase {
throw new AssertionError();
}
}
public void testEqualsAndHashcode() {
EqualsHashCodeTestUtils.checkEqualsAndHashCode(randomAsyncId(),
instance -> new AsyncExecutionId(instance.getDocId(), instance.getTaskId()),
AsyncExecutionIdTests::mutate);
}
public void testDecodeInvalidId() throws IOException {
{
IllegalArgumentException exc = expectThrows(IllegalArgumentException.class, () -> AsyncExecutionId.decode("wrong"));
assertEquals("invalid id: [wrong]", exc.getMessage());
assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class));
}
{
IllegalArgumentException exc = expectThrows(IllegalArgumentException.class,
() -> AsyncExecutionId.decode("FmhEOGQtRWVpVGplSXRtOVZudXZCOVEaYjFVZjZNWndRa3V0VmJvNV8tQmRpZzoxMzM=?pretty"));
assertEquals("invalid id: [FmhEOGQtRWVpVGplSXRtOVZudXZCOVEaYjFVZjZNWndRa3V0VmJvNV8tQmRpZzoxMzM=?pretty]", exc.getMessage());
assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class));
}
{
try (BytesStreamOutput out = new BytesStreamOutput()) {
out.writeString(randomAlphaOfLengthBetween(5, 10));
out.writeString(new TaskId(randomAlphaOfLengthBetween(5, 10), randomLong()).toString());
out.writeString("wrong");
String encoded = Base64.getUrlEncoder().encodeToString(BytesReference.toBytes(out.bytes()));
IllegalArgumentException exc = expectThrows(IllegalArgumentException.class, () -> AsyncExecutionId.decode(encoded));
assertEquals("invalid id: [" + encoded + "]", exc.getMessage());
assertNull(exc.getCause());
}
}
}
}