use of io.datarouter.httpclient.response.DatarouterHttpResponse in project datarouter by hotpads.
the class HttpTestHandler method httpTest.
@Handler(defaultHandler = true)
public Mav httpTest(OptionalString url, OptionalString method, OptionalString requestBody, OptionalString headers, OptionalString contentType, OptionalString useProxy, OptionalString followRedirects) {
Mav mav = new Mav(files.jsp.http.httpTesterJsp);
mav.put("path", paths.datarouter.http.tester.toSlashedString());
if (url.isEmpty() || method.isEmpty()) {
return mav;
}
mav.put("url", url.get());
HttpRequestMethod requestMethod = "POST".equals(method.get()) ? HttpRequestMethod.POST : HttpRequestMethod.GET;
mav.put("method", requestMethod.name());
DatarouterHttpRequest request = new DatarouterHttpRequest(requestMethod, url.get()).setRetrySafe(true);
if (headers.isPresent()) {
Map<String, String> headersMap = GsonTool.GSON.fromJson(headers.get(), new TypeToken<Map<String, String>>() {
}.getType());
request.addHeaders(headersMap);
mav.put("headersMap", GsonTool.GSON.toJson(headersMap));
}
if (requestBody.isPresent()) {
ContentType cont = contentType.isPresent() ? ContentType.getByMimeType(contentType.get()) : ContentType.APPLICATION_JSON;
request.setEntity(requestBody.get(), cont);
mav.put("requestBody", requestBody.get());
mav.put("contentType", cont.getMimeType());
}
if (useProxy.isPresent()) {
mav.put("useProxy", true);
proxySetter.setProxyOnRequest(request);
}
Long start = System.currentTimeMillis();
Conditional<DatarouterHttpResponse> response;
if (followRedirects.isPresent()) {
mav.put("followRedirects", true);
response = httpTesterClient.tryExecute(request);
} else {
response = httpTesterWithoutRedirectClient.tryExecute(request);
}
Long elapsedMs = System.currentTimeMillis() - start;
if (response.isFailure() && response.getException() instanceof DatarouterHttpResponseException) {
DatarouterHttpResponseException responseException = (DatarouterHttpResponseException) response.getException();
addResponseToMavModel(mav, url.get(), elapsedMs, Optional.of(responseException.getResponse()));
} else if (response.isFailure()) {
mav.put("stackTrace", ExceptionTool.getStackTraceAsString(response.getException()));
addResponseToMavModel(mav, url.get(), elapsedMs, Optional.empty());
}
response.ifSuccess(httpResponse -> addResponseToMavModel(mav, url.get(), elapsedMs, Optional.of(httpResponse)));
return mav;
}
use of io.datarouter.httpclient.response.DatarouterHttpResponse in project datarouter by hotpads.
the class DatarouterHttpClientIntegrationTests method testServiceUnavailableFailure.
@Test(expectedExceptions = DatarouterHttpResponseException.class)
public void testServiceUnavailableFailure() throws DatarouterHttpException {
try {
int status = HttpStatus.SC_SERVICE_UNAVAILABLE;
String expectedResponse = UUID.randomUUID().toString();
server.setResponse(status, expectedResponse);
DatarouterHttpClient client = new DatarouterHttpClientBuilder().build();
DatarouterHttpRequest request = new DatarouterHttpRequest(HttpRequestMethod.GET, URL).setRetrySafe(false);
client.executeChecked(request);
} catch (DatarouterHttpResponseException e) {
Assert.assertTrue(e.isServerError());
DatarouterHttpResponse response = e.getResponse();
Assert.assertNotNull(response);
Assert.assertEquals(response.getStatusCode(), HttpStatus.SC_SERVICE_UNAVAILABLE);
throw e;
}
}
use of io.datarouter.httpclient.response.DatarouterHttpResponse in project datarouter by hotpads.
the class DatarouterHttpClientIntegrationTests method testSecurityComponentsWithRefreshableSuppliers.
@Test
public void testSecurityComponentsWithRefreshableSuppliers() {
DatarouterHttpClient client;
DatarouterHttpRequest request;
DatarouterHttpResponse response;
Map<String, String> postParams;
String salt = "some super secure salty salt " + UUID.randomUUID().toString();
String cipherKey = "kirg king kind " + UUID.randomUUID().toString();
String apiKey = "apiKey advanced placement incremental key " + UUID.randomUUID().toString();
DefaultSignatureGenerator signatureGenerator = new RefreshableDefaultSignatureGenerator(() -> salt);
DefaultCsrfGenerator csrfGenerator = new RefreshableDefaultCsrfGenerator(() -> cipherKey);
Supplier<String> apiKeySupplier = new RefreshableStringSupplier(() -> apiKey);
client = new DatarouterHttpClientBuilder().setSignatureGenerator(signatureGenerator).setCsrfGenerator(csrfGenerator).setApiKeySupplier(apiKeySupplier).build();
Map<String, String> params = new HashMap<>();
params.put("1", UUID.randomUUID().toString());
params.put("2", Integer.toString(RANDOM.nextInt()));
params.put("3", "Everything is awesome! Everything is cool when you're part of a team!");
String expectedResponse = Arrays.toString(params.entrySet().toArray());
server.setResponse(HttpStatus.SC_ACCEPTED, expectedResponse);
// GET request cannot be signed
request = new DatarouterHttpRequest(HttpRequestMethod.GET, URL).setRetrySafe(false).addPostParams(params);
response = client.execute(request);
postParams = request.getFirstPostParams();
Assert.assertEquals(response.getEntity(), expectedResponse);
Assert.assertEquals(postParams.size(), params.size());
Assert.assertNull(postParams.get(SecurityParameters.CSRF_IV));
Assert.assertNull(postParams.get(SecurityParameters.CSRF_TOKEN));
Assert.assertNull(postParams.get(SecurityParameters.API_KEY));
Assert.assertNull(postParams.get(SecurityParameters.SIGNATURE));
client = new DatarouterHttpClientBuilder().setSignatureGenerator(signatureGenerator).setCsrfGenerator(csrfGenerator).setApiKeySupplier(apiKeySupplier).build();
// entity enclosing request with no entity or params cannot be signed
request = new DatarouterHttpRequest(HttpRequestMethod.POST, URL);
response = client.execute(request);
postParams = request.getFirstPostParams();
Assert.assertEquals(response.getEntity(), expectedResponse);
Assert.assertEquals(request.getPostParams().size(), 4);
Assert.assertNotNull(postParams.get(SecurityParameters.CSRF_IV));
Assert.assertNotNull(postParams.get(SecurityParameters.CSRF_TOKEN));
Assert.assertNotNull(postParams.get(SecurityParameters.API_KEY));
Assert.assertNotNull(postParams.get(SecurityParameters.SIGNATURE));
client = new DatarouterHttpClientBuilder().setSignatureGenerator(signatureGenerator).setCsrfGenerator(csrfGenerator).setApiKeySupplier(apiKeySupplier).build();
// entity enclosing request already with an entity cannot be signed, even with params
request = new DatarouterHttpRequest(HttpRequestMethod.PATCH, URL).setRetrySafe(false).setEntity(params).addPostParams(params);
response = client.execute(request);
postParams = request.getFirstPostParams();
Assert.assertEquals(response.getEntity(), expectedResponse);
Assert.assertEquals(postParams.size(), 3);
Assert.assertNull(postParams.get(SecurityParameters.CSRF_IV));
Assert.assertNull(postParams.get(SecurityParameters.CSRF_TOKEN));
Assert.assertNull(postParams.get(SecurityParameters.API_KEY));
Assert.assertNull(postParams.get(SecurityParameters.SIGNATURE));
client = new DatarouterHttpClientBuilder().setSignatureGenerator(signatureGenerator).setCsrfGenerator(csrfGenerator).setApiKeySupplier(apiKeySupplier).build();
// entity enclosing request is signed with entity from post params
request = new DatarouterHttpRequest(HttpRequestMethod.POST, URL).addPostParams(params);
response = client.execute(request);
postParams = request.getFirstPostParams();
Assert.assertEquals(response.getEntity(), expectedResponse);
Assert.assertEquals(postParams.size(), params.size() + 4);
Assert.assertNotNull(postParams.get(SecurityParameters.CSRF_IV));
Assert.assertNotNull(postParams.get(SecurityParameters.CSRF_TOKEN));
Assert.assertNotNull(postParams.get(SecurityParameters.API_KEY));
Assert.assertNotNull(postParams.get(SecurityParameters.SIGNATURE));
// test equivalence classes
client = new DatarouterHttpClientBuilder().setCsrfGenerator(csrfGenerator).build();
request = new DatarouterHttpRequest(HttpRequestMethod.PUT, URL).setRetrySafe(false).addPostParams(params);
response = client.execute(request);
postParams = request.getFirstPostParams();
Assert.assertEquals(response.getEntity(), expectedResponse);
Assert.assertEquals(postParams.size(), params.size() + 2);
Assert.assertNotNull(postParams.get(SecurityParameters.CSRF_IV));
Assert.assertNotNull(postParams.get(SecurityParameters.CSRF_TOKEN));
Assert.assertNull(postParams.get(SecurityParameters.API_KEY));
Assert.assertNull(postParams.get(SecurityParameters.SIGNATURE));
client = new DatarouterHttpClientBuilder().setApiKeySupplier(apiKeySupplier).build();
request = new DatarouterHttpRequest(HttpRequestMethod.PATCH, URL).setRetrySafe(false).addPostParams(params);
response = client.execute(request);
postParams = request.getFirstPostParams();
Assert.assertEquals(response.getEntity(), expectedResponse);
Assert.assertEquals(postParams.size(), params.size() + 1);
Assert.assertNull(postParams.get(SecurityParameters.CSRF_IV));
Assert.assertNull(postParams.get(SecurityParameters.CSRF_TOKEN));
Assert.assertNotNull(postParams.get(SecurityParameters.API_KEY));
Assert.assertNull(postParams.get(SecurityParameters.SIGNATURE));
}
use of io.datarouter.httpclient.response.DatarouterHttpResponse in project datarouter by hotpads.
the class DatarouterHttpClientIoExceptionCircuitBreaker method call.
public DatarouterHttpResponse call(CloseableHttpClient httpClient, DatarouterHttpRequest request, Consumer<HttpEntity> httpEntityConsumer, HttpClientContext context, Supplier<Boolean> enableBreakers, Supplier<Boolean> traceInQueryString, Supplier<Boolean> debugLog) throws DatarouterHttpException {
CircuitBreakerState state = getState();
if (state == CircuitBreakerState.OPEN && enableBreakers.get()) {
incrementCounterOnStateChange("open");
throw new DatarouterHttpCircuitBreakerException(name, callResultQueue.getOriginalException());
}
DatarouterHttpException ex;
TracerTool.startSpan("http call " + request.getPath(), TraceSpanGroupType.HTTP);
Tracer tracer = TracerThreadLocal.get();
W3TraceContext traceContext;
if (tracer != null && tracer.getTraceContext().isPresent()) {
traceContext = tracer.getTraceContext().get().copy();
traceContext.updateParentIdAndAddTracestateMember();
} else {
count("traceContext null");
traceContext = new W3TraceContext(Trace2Dto.getCurrentTimeInNs());
}
String traceparent = traceContext.getTraceparent().toString();
if (traceInQueryString.get()) {
request.addGetParam(TRACEPARENT, traceparent);
}
HttpRequestBase internalHttpRequest = request.getRequest();
count("request");
logger.debug("traceparent={} passing to request={}", traceparent, request.getPath());
internalHttpRequest.addHeader(TRACEPARENT, traceparent);
internalHttpRequest.addHeader(TRACESTATE, traceContext.getTracestate().toString());
context.setAttribute(TRACEPARENT, traceContext.getTraceparent().toString());
if (debugLog.get()) {
logger.warn("sending http request method={} url={}", internalHttpRequest.getMethod(), internalHttpRequest.getURI());
}
long requestStartTimeNs = Trace2Dto.getCurrentTimeInNs();
try {
HttpResponse httpResponse = httpClient.execute(internalHttpRequest, context);
Duration duration = Duration.ofNanos(Trace2Dto.getCurrentTimeInNs() - requestStartTimeNs);
String entity = null;
int statusCode = httpResponse.getStatusLine().getStatusCode();
count("response " + statusCode);
boolean isBadStatusCode = statusCode >= HttpStatus.SC_BAD_REQUEST;
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
// skip the httpEntityConsumer in case of error because we are going to close the input stream
if (httpEntityConsumer != null && !isBadStatusCode) {
httpEntityConsumer.accept(httpEntity);
} else {
entity = EntityUtils.toString(httpEntity);
}
}
Optional<Traceparent> remoteTraceparent = Optional.ofNullable(httpResponse.getFirstHeader(TRACEPARENT)).map(Header::getValue).map(Traceparent::parse).filter(Optional::isPresent).map(Optional::get);
remoteTraceparent.ifPresent(tp -> TracerTool.appendToSpanInfo("remote parentId", tp.parentId));
if (remoteTraceparent.isPresent() && remoteTraceparent.get().shouldSample()) {
// if remote server has forced sample for trace, we also force sample the client's trace
TracerTool.setForceSample();
}
if (duration.compareTo(LOG_SLOW_REQUEST_THRESHOLD) > 0) {
logger.warn("Slow request target={} durationS={} remoteTraceparent={}", request.getPath(), duration.getSeconds(), remoteTraceparent.orElse(null));
}
DatarouterHttpResponse response = new DatarouterHttpResponse(httpResponse, context, statusCode, entity);
if (isBadStatusCode) {
TracerTool.appendToSpanInfo("bad status code", statusCode);
ex = new DatarouterHttpResponseException(response, duration, traceparent, request.getPath());
callResultQueue.insertFalseResultWithException(ex);
// no need to abort the connection, we received a response line, the connection is probably still good
response.tryClose();
throw ex;
}
if (state == CircuitBreakerState.HALF_OPEN) {
callResultQueue.reset();
incrementCounterOnStateChange("closing");
logger.error("Half opened circuit now closing. CircuitName={}", name);
}
callResultQueue.insertTrueResult();
return response;
} catch (IOException e) {
count("IOException");
TracerTool.appendToSpanInfo("exception", e.getMessage());
ex = new DatarouterHttpConnectionAbortedException(e, TimeUnit.NANOSECONDS.toMillis(requestStartTimeNs), traceparent, request.getPath());
callResultQueue.insertFalseResultWithException(ex);
} catch (CancellationException e) {
count("CancellationException");
TracerTool.appendToSpanInfo("exception", e.getMessage());
ex = new DatarouterHttpRequestInterruptedException(e, TimeUnit.NANOSECONDS.toMillis(requestStartTimeNs), traceparent, request.getPath());
callResultQueue.insertFalseResultWithException(ex);
} finally {
TracerTool.finishSpan();
}
// connection might have gone bad, destroying it
if (internalHttpRequest != null) {
forceAbortRequestUnchecked(internalHttpRequest);
}
throw ex;
}
use of io.datarouter.httpclient.response.DatarouterHttpResponse in project datarouter by hotpads.
the class ExampleMakeRequest method example.
public void example() {
// reuse this client
DatarouterHttpClient client = new DatarouterHttpClientBuilder().build();
DatarouterHttpRequest request = new DatarouterHttpRequest(HttpRequestMethod.GET, "https://example.com/api").addGetParam("id", // Passing a GET parameter
"1");
DatarouterHttpResponse response = client.execute(request);
String stringResult = response.getEntity();
}
Aggregations