Skip to content

Include response body to exception message #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/main/java/com/bettercloud/vault/api/Logical.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bettercloud.vault.api;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -61,11 +62,12 @@ public LogicalResponse read(final String path) throws VaultException {

// Validate response
if (restResponse.getStatus() != 200) {
throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus(), restResponse.getStatus());
throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus()
+ "\nResponse body: " + new String(restResponse.getBody(), "UTF-8"), restResponse.getStatus());
}

return new LogicalResponse(restResponse, retryCount);
} catch (RuntimeException | VaultException | RestException e) {
} catch (RuntimeException | VaultException | RestException | UnsupportedEncodingException e) {
// If there are retries to perform, then pause for the configured interval and then execute the loop again...
if (retryCount < config.getMaxRetries()) {
retryCount++;
Expand Down Expand Up @@ -150,7 +152,8 @@ public LogicalResponse write(final String path, final Map<String, Object> nameVa
if (restStatus == 200 || restStatus == 204) {
return new LogicalResponse(restResponse, retryCount);
} else {
throw new VaultException("Expecting HTTP status 204 or 200, but instead receiving " + restStatus, restStatus);
throw new VaultException("Expecting HTTP status 204 or 200, but instead receiving " + restStatus
+ "\nResponse body: " + new String(restResponse.getBody(), "UTF-8"), restStatus);
}
} catch (Exception e) {
// If there are retries to perform, then pause for the configured interval and then execute the loop again...
Expand Down Expand Up @@ -238,10 +241,11 @@ public LogicalResponse delete(final String path) throws VaultException {

// Validate response
if (restResponse.getStatus() != 204) {
throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus(), restResponse.getStatus());
throw new VaultException("Vault responded with HTTP status code: " + restResponse.getStatus()
+ "\nResponse body: " + new String(restResponse.getBody(), "UTF-8"), restResponse.getStatus());
}
return new LogicalResponse(restResponse, retryCount);
} catch (RuntimeException | VaultException | RestException e) {
} catch (RuntimeException | VaultException | RestException | UnsupportedEncodingException e) {
// If there are retries to perform, then pause for the configured interval and then execute the loop again...
if (retryCount < config.getMaxRetries()) {
retryCount++;
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/com/bettercloud/vault/rest/Rest.java
Original file line number Diff line number Diff line change
Expand Up @@ -512,10 +512,23 @@ private String parametersToQueryString() {
*
* @param connection An active HTTP(S) connection
* @return The body payload, downloaded from the HTTP connection response
* @throws RestException
*/
private byte[] responseBodyBytes(final URLConnection connection) {
private byte[] responseBodyBytes(final URLConnection connection) throws RestException {
try {
final InputStream inputStream = connection.getInputStream();
final InputStream inputStream;
final int responseCode = this.connectionStatus(connection);
if (200 <= responseCode && responseCode <= 299) {
inputStream = connection.getInputStream();
} else {
if (connection instanceof HttpsURLConnection) {
final HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;
inputStream = httpsURLConnection.getErrorStream();
} else {
final HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
inputStream = httpURLConnection.getErrorStream();
}
}
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int bytesRead;
final byte[] bytes = new byte[16384];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;

import com.bettercloud.vault.Vault;
import com.bettercloud.vault.VaultConfig;
import com.bettercloud.vault.VaultException;
import org.junit.rules.ExpectedException;

import static junit.framework.TestCase.*;

Expand Down Expand Up @@ -137,6 +139,84 @@ public void testDelete() throws VaultException {
assertFalse(vault.logical().list("secret").contains("hello"));
}

@Rule
public ExpectedException expectedEx = ExpectedException.none();

/**
* Tests that exception message includes errors returned by Vault
*
* @throws VaultException
*/
@Test
public void testReadExceptionMessageIncludesErrorsReturnedByVault() throws VaultException {
expectedEx.expect(VaultException.class);
expectedEx.expectMessage("permission denied");

final VaultConfig config = new VaultConfig(address, "invalid-token");
final Vault vault = new Vault(config);
vault.logical().read("secret/null");
}

/**
* Tests that exception message includes errors returned by Vault
*
* @throws VaultException
*/
@Test
public void testWriteExceptionMessageIncludesErrorsReturnedByVault() throws VaultException {
expectedEx.expect(VaultException.class);
expectedEx.expectMessage("permission denied");

final VaultConfig config = new VaultConfig(address, "invalid-token");
final Vault vault = new Vault(config);
vault.logical().write("secret/null", new HashMap<String, String>() {{ put("value", null); }});
}

/**
* Tests that exception message includes errors returned by Vault
*
* @throws VaultException
*/
@Test
public void testDeleteExceptionMessageIncludesErrorsReturnedByVault() throws VaultException {
expectedEx.expect(VaultException.class);
expectedEx.expectMessage("permission denied");

final VaultConfig config = new VaultConfig(address, "invalid-token");
final Vault vault = new Vault(config);
vault.logical().delete("secret/null");
}

/**
* Tests that exception message includes errors returned by Vault
*
* @throws VaultException
*/
@Test
public void testListExceptionMessageIncludesErrorsReturnedByVault() throws VaultException {
expectedEx.expect(VaultException.class);
expectedEx.expectMessage("permission denied");

final VaultConfig config = new VaultConfig(address, "invalid-token");
final Vault vault = new Vault(config);
vault.logical().list("secret/null");
}

/**
* Write a secret and verify that it can be read containing a null value.
*
* @throws VaultException
*/
@Test
public void testReadExceptionMessageIncludesErrorsReturnedByVaultOn404() throws VaultException {
expectedEx.expect(VaultException.class);
expectedEx.expectMessage("{\"errors\":[]}");

final VaultConfig config = new VaultConfig(address, token);
final Vault vault = new Vault(config);

vault.logical().read("secret/null");

@Test
public void testWriteAndRead_allDataTypes() throws VaultException {
final String path = "secret/hello";
Expand All @@ -155,5 +235,4 @@ public void testWriteAndRead_allDataTypes() throws VaultException {
System.out.println(entry.getKey() + " - " + entry.getValue());
}
}

}
19 changes: 19 additions & 0 deletions src/test/java/com/bettercloud/vault/rest/GetTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.io.UnsupportedEncodingException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
* Unit tests relating the REST client processing of GET requests.
Expand Down Expand Up @@ -131,4 +132,22 @@ public void testGet_WithHeaders() throws RestException, UnsupportedEncodingExcep
assertEquals("Note+that+headers+are+send+in+url-encoded+format", headers.getString("Two-Part", null));
}

/**
* <p>Verify that response body is retrieved when http status is error code</p>
*
* @throws RestException
* @throws UnsupportedEncodingException If there's a problem parsing the response JSON as UTF-8
*/
@Test
public void testGet_RetrievesResponseBodyWhenStatusIs418() throws RestException, UnsupportedEncodingException {
final RestResponse restResponse = new Rest()
.url("http://httpbin.org/status/418")
.get();
assertEquals(418, restResponse.getStatus());

final String responseBody = new String(restResponse.getBody(), "UTF-8");
assertTrue("Response body is empty", responseBody.length() > 0);
assertTrue("Response body doesn't contain word teapot", responseBody.contains("teapot"));
}

}