private HttpURLConnection createAndConfigureConnection(HttpExecuteRequest request) { HttpURLConnection connection = connectionFactory.createConnection(request.httpRequest().getUri()); request.httpRequest() .headers() .forEach((key, values) -> values.forEach(value -> connection.setRequestProperty(key, value))); invokeSafely(() -> connection.setRequestMethod(request.httpRequest().method().name())); if (request.contentStreamProvider().isPresent()) { connection.setDoOutput(true); } // Disable following redirects since it breaks SDK error handling and matches Apache. // See: https://github.com/aws/aws-sdk-java-v2/issues/975 connection.setInstanceFollowRedirects(false); return connection; }
private HttpRequestBase wrapEntity(HttpExecuteRequest request, HttpEntityEnclosingRequestBase entityEnclosingRequest) { /* * We should never reuse the entity of the previous request, since * reading from the buffered entity will bypass reading from the * original request content. And if the content contains InputStream * wrappers that were added for validation-purpose (e.g. * Md5DigestCalculationInputStream), these wrappers would never be * read and updated again after AmazonHttpClient resets it in * preparation for the retry. Eventually, these wrappers would * return incorrect validation result. */ if (request.contentStreamProvider().isPresent()) { HttpEntity entity = new RepeatableInputStreamRequestEntity(request); if (request.httpRequest().headers().get(HttpHeaders.CONTENT_LENGTH) == null) { entity = ApacheUtils.newBufferedHttpEntity(entity); } entityEnclosingRequest.setEntity(entity); } return entityEnclosingRequest; }
@Override public HttpExecuteResponse call() throws IOException { connection.connect(); request.contentStreamProvider().ifPresent(provider -> invokeSafely(() -> IoUtils.copy(provider.newStream(), connection.getOutputStream()))); int responseCode = connection.getResponseCode(); boolean isErrorResponse = HttpStatusFamily.of(responseCode).isOneOf(CLIENT_ERROR, SERVER_ERROR); InputStream content = !isErrorResponse ? connection.getInputStream() : connection.getErrorStream(); AbortableInputStream responseBody = content != null ? AbortableInputStream.create(content) : null; return HttpExecuteResponse.builder() .response(SdkHttpResponse.builder() .statusCode(responseCode) .statusText(connection.getResponseMessage()) // TODO: Don't ignore abort? .headers(extractHeaders(connection)) .build()) .responseBody(responseBody) .build(); }
/** * Creates a new RepeatableInputStreamRequestEntity using the information * from the specified request. If the input stream containing the request's * contents is repeatable, then this RequestEntity will report as being * repeatable. * * @param request The details of the request being written out (content type, * content length, and content). */ public RepeatableInputStreamRequestEntity(final HttpExecuteRequest request) { setChunked(false); /* * If we don't specify a content length when we instantiate our * InputStreamRequestEntity, then HttpClient will attempt to * buffer the entire stream contents into memory to determine * the content length. */ long contentLength = request.httpRequest().firstMatchingHeader("Content-Length") .map(this::parseContentLength) .orElse(-1L); content = getContent(request.contentStreamProvider()); // TODO v2 MetricInputStreamEntity inputStreamRequestEntity = new InputStreamEntity(content, contentLength); setContent(content); setContentLength(contentLength); request.httpRequest().firstMatchingHeader("Content-Type").ifPresent(contentType -> { inputStreamRequestEntity.setContentType(contentType); setContentType(contentType); }); }