private Optional<RequestConfig> addJerseyRequestConfig(ClientRequest clientRequest) { final Integer timeout = clientRequest.resolveProperty(ClientProperties.READ_TIMEOUT, Integer.class); final Integer connectTimeout = clientRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, Integer.class); final Boolean followRedirects = clientRequest.resolveProperty(ClientProperties.FOLLOW_REDIRECTS, Boolean.class); if (timeout != null || connectTimeout != null || followRedirects != null) { final RequestConfig.Builder requestConfig = RequestConfig.copy(defaultRequestConfig); if (timeout != null) { requestConfig.setSocketTimeout(timeout); } if (connectTimeout != null) { requestConfig.setConnectTimeout(connectTimeout); } if (followRedirects != null) { requestConfig.setRedirectsEnabled(followRedirects); } return Optional.of(requestConfig.build()); } return Optional.empty(); }
@Test public void multiple_headers_with_the_same_name_are_processed_successfully() throws Exception { final CloseableHttpClient client = mock(CloseableHttpClient.class); final DropwizardApacheConnector dropwizardApacheConnector = new DropwizardApacheConnector(client, null, false); final Header[] apacheHeaders = { new BasicHeader("Set-Cookie", "test1"), new BasicHeader("Set-Cookie", "test2") }; final CloseableHttpResponse apacheResponse = mock(CloseableHttpResponse.class); when(apacheResponse.getStatusLine()) .thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); when(apacheResponse.getAllHeaders()).thenReturn(apacheHeaders); when(client.execute(Matchers.any())).thenReturn(apacheResponse); final ClientRequest jerseyRequest = mock(ClientRequest.class); when(jerseyRequest.getUri()).thenReturn(URI.create("http://localhost")); when(jerseyRequest.getMethod()).thenReturn("GET"); when(jerseyRequest.getHeaders()).thenReturn(new MultivaluedHashMap<>()); final ClientResponse jerseyResponse = dropwizardApacheConnector.apply(jerseyRequest); assertThat(jerseyResponse.getStatus()) .isEqualTo(apacheResponse.getStatusLine().getStatusCode()); }
@Override public ClientResponse apply(final ClientRequest jerseyRequest) throws ProcessingException { final Request jettyRequest = translateRequest(jerseyRequest); final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(jerseyRequest.getHeaders(), jettyRequest); final ContentProvider entity = getBytesProvider(jerseyRequest); if (entity != null) { jettyRequest.content(entity); } try { final ContentResponse jettyResponse = jettyRequest.send(); HeaderUtils.checkHeaderChanges( clientHeadersSnapshot, jerseyRequest.getHeaders(), JettyConnector.this.getClass().getName()); final javax.ws.rs.core.Response.StatusType status = jettyResponse.getReason() == null ? Statuses.from(jettyResponse.getStatus()) : Statuses.from(jettyResponse.getStatus(), jettyResponse.getReason()); final ClientResponse jerseyResponse = new ClientResponse(status, jerseyRequest); processResponseHeaders(jettyResponse.getHeaders(), jerseyResponse); try { jerseyResponse.setEntityStream(new HttpClientResponseInputStream(jettyResponse)); } catch (final IOException e) { LOGGER.log(Level.SEVERE, null, e); } return jerseyResponse; } catch (final Exception e) { throw new ProcessingException(e); } }
private BufferedJerseyRequestHttpEntity(ClientRequest clientRequest) { final ByteArrayOutputStream stream = new ByteArrayOutputStream(BUFFER_INITIAL_SIZE); clientRequest.setStreamProvider(contentLength -> stream); try { clientRequest.writeEntity(); } catch (IOException e) { throw new ProcessingException(LocalizationMessages.ERROR_BUFFERING_ENTITY(), e); } buffer = stream.toByteArray(); setChunked(false); }
/** * Build a new Apache's {@link org.apache.http.client.methods.HttpUriRequest} from Jersey's {@link * org.glassfish.jersey.client.ClientRequest} * * <p>Convert a method, URI, body, headers and override a user-agent if necessary * * @param jerseyRequest representation of an HTTP request in Jersey * @return a new {@link org.apache.http.client.methods.HttpUriRequest} */ private HttpUriRequest buildApacheRequest(ClientRequest jerseyRequest) { final RequestBuilder builder = RequestBuilder.create(jerseyRequest.getMethod()) .setUri(jerseyRequest.getUri()) .setEntity(getHttpEntity(jerseyRequest)); for (String headerName : jerseyRequest.getHeaders().keySet()) { builder.addHeader(headerName, jerseyRequest.getHeaderString(headerName)); } final Optional<RequestConfig> requestConfig = addJerseyRequestConfig(jerseyRequest); requestConfig.ifPresent(builder::setConfig); return builder.build(); }
/** * Get an Apache's {@link org.apache.http.HttpEntity} from Jersey's {@link * org.glassfish.jersey.client.ClientRequest} * * <p>Create a custom HTTP entity, because Jersey doesn't provide a request stream or a byte * buffer. * * @param jerseyRequest representation of an HTTP request in Jersey * @return a correct {@link org.apache.http.HttpEntity} implementation */ private HttpEntity getHttpEntity(ClientRequest jerseyRequest) { if (jerseyRequest.getEntity() == null) { return null; } return chunkedEncodingEnabled ? new JerseyRequestHttpEntity(jerseyRequest) : new BufferedJerseyRequestHttpEntity(jerseyRequest); }
private Request translateRequest(final ClientRequest clientRequest) { final HttpMethod method = HttpMethod.fromString(clientRequest.getMethod()); if (method == null) { throw new ProcessingException( LocalizationMessages.METHOD_NOT_SUPPORTED(clientRequest.getMethod())); } final URI uri = clientRequest.getUri(); final Request request = client.newRequest(uri); request.method(method); request.followRedirects(clientRequest.resolveProperty(ClientProperties.FOLLOW_REDIRECTS, true)); final Object readTimeout = clientRequest.getConfiguration().getProperties().get(ClientProperties.READ_TIMEOUT); if (readTimeout != null && readTimeout instanceof Integer && (Integer) readTimeout > 0) { request.timeout((Integer) readTimeout, TimeUnit.MILLISECONDS); } return request; }
@Override public ClientResponse apply(ClientRequest requestContext) { final ClientResponse responseContext = new ClientResponse(Response.Status.OK, requestContext); final String headerValue = requestContext.getHeaderString(CsrfProtectionFilter.HEADER_NAME); if (headerValue != null) { responseContext.header(CsrfProtectionFilter.HEADER_NAME, headerValue); } return responseContext; }
private ContentProvider getStreamProvider(final ClientRequest clientRequest) { final Object entity = clientRequest.getEntity(); if (entity == null) { return null; } final OutputStreamContentProvider streamContentProvider = new OutputStreamContentProvider(); clientRequest.setStreamProvider( new OutboundMessageContext.StreamProvider() { @Override public OutputStream getOutputStream(final int contentLength) throws IOException { return streamContentProvider.getOutputStream(); } }); try { clientRequest.writeEntity(); } catch (final IOException e) { throw new ProcessingException("Failed to write request entity.", e); } return streamContentProvider; }
/** {@inheritDoc} */ @Override public void writeTo(final OutputStream outputStream) throws IOException { clientRequest.setStreamProvider(contentLength -> outputStream); clientRequest.writeEntity(); }
@Override public Future<?> apply(final ClientRequest jerseyRequest, final AsyncConnectorCallback callback) { final Request jettyRequest = translateRequest(jerseyRequest); final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(jerseyRequest.getHeaders(), jettyRequest); final ContentProvider entity = getStreamProvider(jerseyRequest); if (entity != null) { jettyRequest.content(entity); } final AtomicBoolean callbackInvoked = new AtomicBoolean(false); final Throwable failure; try { final SettableFuture<ClientResponse> responseFuture = SettableFuture.create(); Futures.addCallback( responseFuture, new FutureCallback<ClientResponse>() { @Override public void onSuccess(final ClientResponse result) {} @Override public void onFailure(final Throwable t) { if (t instanceof CancellationException) { // take care of future cancellation jettyRequest.abort(t); } } }); final AtomicReference<ClientResponse> jerseyResponse = new AtomicReference<ClientResponse>(); final ByteBufferInputStream entityStream = new ByteBufferInputStream(); jettyRequest.send( new Response.Listener.Adapter() { @Override public void onHeaders(final Response jettyResponse) { HeaderUtils.checkHeaderChanges( clientHeadersSnapshot, jerseyRequest.getHeaders(), JettyConnector.this.getClass().getName()); if (responseFuture.isDone()) if (!callbackInvoked.compareAndSet(false, true)) { return; } final ClientResponse response = translateResponse(jerseyRequest, jettyResponse, entityStream); jerseyResponse.set(response); callback.response(response); } @Override public void onContent(final Response jettyResponse, final ByteBuffer content) { try { entityStream.put(content); } catch (final InterruptedException ex) { final ProcessingException pe = new ProcessingException(ex); entityStream.closeQueue(pe); // try to complete the future with an exception responseFuture.setException(pe); Thread.currentThread().interrupt(); } } @Override public void onComplete(final Result result) { entityStream.closeQueue(); // try to complete the future with the response only once truly done responseFuture.set(jerseyResponse.get()); } @Override public void onFailure(final Response response, final Throwable t) { entityStream.closeQueue(t); // try to complete the future with an exception responseFuture.setException(t); if (callbackInvoked.compareAndSet(false, true)) { callback.failure(t); } } }); return responseFuture; } catch (final Throwable t) { failure = t; } if (callbackInvoked.compareAndSet(false, true)) { callback.failure(failure); } return Futures.immediateFailedFuture(failure); }