frauzufall
frauzufall

Reputation: 57

How to upload InputStream via HttpPut from Apache HttpClient 4.x

I'm trying to upload an InputStream via HttpPut using the Apache HttpClient 4.5.6:

InputStream inputStream = ..
CredentialsProvider provider = ..
HttpClient client = HttpClientBuilder.create()
                .setDefaultCredentialsProvider(provider)
                .build();

HttpPut method = new HttpPut("MY_REMOTE_URL");
InputStreamEntity entity = new InputStreamEntity(inputStream);
method.setEntity(entity);
client.execute(method);

Uploading requires authentication and in my case I don't know if the Server used digest or basic authentication, therefore the client automatically sends multiple requests to determine the authentication scheme. But InputStreamEntity is non repeatable , leading to the following errors:

org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.

Idea #1: Buffering the InputStream

I can wrap the entity with BufferedHttpEntity which makes it repeatable:

..
BufferedHttpEntity entity = new BufferedHttpEntity(new InputStreamEntity(inputStream));
method.setEntity(entity);
..

.. but then the stream first gets buffered and then sent in total, not chunked / streamed. This does not work for bigger files.


Idea #2: Preemptive Authentication

I can add a hardcoded header with the correct authentication to prevent the request from being repeated. But as I said, I don't know the authentication scheme.


Idea #3: Dummy FileEntity upload to get context (my current solution)

I upload an empty file first, harvest the context and add it to my InputStream PUT request:

HttpPut testMethod = new HttpPut("MY_REMOTE_DUMMY_URL");
FileEntity testEntity = new FileEntity(testFile);
testMethod.setEntity(testEntity);
HttpContext context = new BasicHttpContext();
client.execute(testMethod, context);

// .. delete the testEntity from server ..

HttpPut method = new HttpPut("MY_REMOTE_URL");
InputStreamEntity entity = new InputStreamEntity(inputStream);
method.setEntity(entity);
client.execute(method, context);

It works, but it seems like a hack. Should I do this? Are there alternatives?

Upvotes: 2

Views: 3305

Answers (1)

ok2c
ok2c

Reputation: 27583

Activate expect-continue handshake instead.

HttpClientContext context = HttpClientContext.create();
RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(true).build();
context.setRequestConfig(config);

Upvotes: 1

Related Questions