How to create a repeatable POST request that contains multipart-form-data?
Asked Answered
S

2

7

I am trying to create a POST request that contains multipart-form-data that requires NT Credentials. The authentication request causes the POST to be resent and I get a unrepeatable entity exception.

I tried wrapping the MultipartContent entity that is produced with a BufferedHttpEntity but it throws NullPointerExceptions?

final GenericUrl sau = new GenericUrl(baseURI.resolve("Record"));
final MultipartContent c = new MultipartContent().setMediaType(MULTIPART_FORM_DATA).setBoundary("__END_OF_PART__");
final MultipartContent.Part p0 = new MultipartContent.Part(new HttpHeaders().set("Content-Disposition", format("form-data; name=\"%s\"", "RecordRecordType")), ByteArrayContent.fromString(null, "C_APP_BOX"));
final MultipartContent.Part p1 = new MultipartContent.Part(new HttpHeaders().set("Content-Disposition", format("form-data; name=\"%s\"", "RecordTitle")), ByteArrayContent.fromString(null, "JAVA_TEST"));
c.addPart(p0);
c.addPart(p1);

The documentation for ByteArrayContent says

Concrete implementation of AbstractInputStreamContent that generates repeatable input streams based on the contents of byte array.

Making all the parts repeatable does not solve the problem. Because this code System.out.println("c.retrySupported() = " + c.retrySupported()); outputs c.retrySupported() = true.

I found the following documentation:

1.1.4.1. Repeatable entities An entity can be repeatable, meaning its content can be read more than once. This is only possible with self contained entities (like ByteArrayEntity or StringEntity)

I have now converted my MultipartContent to a ByteArrayContent with a multi/part-form media type by extracting the string contents and still get the same error!

But I still get the following exception when I try and call request.execute().

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

So how do I go about convincing the ApacheHttpTransport to create a repeatable Entity?

Strong answered 26/11, 2015 at 4:34 Comment(0)
S
5

I had to modify all the classes that inherited from HttpContent so that they would report back correctly with .retrySupported() so that the when the ApacheHttpTransport code was entered it would create repeatable content correctly.

The changes were made against version 1.20.0 because that is what I was using. I am submitting a pull request against dev branch HEAD so hopefully, this or some version of this will make it into the next release.

Here are the modifications that need to be merged in.

Strong answered 3/12, 2015 at 18:35 Comment(0)
V
0

If content length of all parts in multipart entity is known (returned as a non negative value) the entity will be treated as repeatable. The easiest way to make multipart entity repeatable is to make all its parts repeatable.

Veats answered 26/11, 2015 at 9:24 Comment(4)
1.1.4.1. Repeatable entities An entity can be repeatable, meaning its content can be read more than once. This is only possible with self contained entities (like ByteArrayEntity or StringEntity)Strong
Sigh I know what this paragraph says because I wrote it. See for your self:hc.apache.org/httpcomponents-client-4.5.x/httpmime/xref/org/… hc.apache.org/httpcomponents-client-4.5.x/httpmime/xref/org/…Veats
Your answer does not work, I was already supplying repeatable parts. After I found that caveat I changed serialized the MultipartContent to a ByteArrayContent with the MulitpartContent mediatype. Still get the same error. I have updated the question with all these details about what I have tried and why/how it is still failing.Strong
If the library that sits on top of Apache HttpClient does not use its native MIME framework and simply passes a non-repeatable entity to it there is nothing HttpClient can do.Veats

© 2022 - 2024 — McMap. All rights reserved.