users@jersey.java.net

Re: [Jersey] Multipart Post

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 05 Jan 2010 18:48:04 +0100

On Jan 5, 2010, at 6:30 PM, Alexander Birmingham wrote:

> Paul -
>
> Thanks for the quick response! I'm referencing the following
> libraries:
> jersey-client-1.1.4.1.jar
> jersey-core-1.1.4.1.jar
> jsr311-api-1.1.jar
> activation-1.1.jar
> jersey-multipart-1.1.4.1.jar
> mail-1.4.jar
> mimepull-1.3.jar
>
> Additionally, it may help to know that the Jersey client prints the
> following blurb when created:
> Jan 5, 2010 9:16:32 AM com.sun.jersey.api.client.Client <init>
> INFO: Adding the following classes declared in META-INF/services/
> jersey-client-components to the client configuration:
> class com.sun.jersey.multipart.impl.MultiPartConfigProvider
> class com.sun.jersey.multipart.impl.MultiPartReader
> class com.sun.jersey.multipart.impl.MultiPartWriter
>

The above is OK.


> The server side processor is an internal tool to my company written
> in perl. Frankly I don't know a lot about it, but it is verified as
> functional according to the curl request. Additionally, Jersey has
> worked fine so far for my plain-jane getting/posting needs, so long
> as the request is composed entirely of ordinary query parameters. I
> should mention also that my client setup is fairly minimalistic:
> CLIENT = Client.create();. That's it :)
>
> Finally, I have revised the following line of code to use
> FormDataMultiPart as per your recommendation:
> MultiPart multiPart = new FormDataMultiPart().bodyPart(new
> FileDataBodyPart("file", file,
> MediaType.APPLICATION_OCTET_STREAM_TYPE));
>
> Other than above... I'm not sure what to think. Your code looks
> identical to mine, as far as I can tell, except that your request
> doesn't include query parameters in addition to the MultiPart. Could
> that be where I'm stumbling?
>

I suspect the server side is not capable of correctly processing
multipart/form-data representations, and specifically it has problems
with the Content-Dispostion header.

You could try this:

   MultiPart multiPart = new FormDataMultiPart().field("file", file,
MediaType.APPLICATION_OCTET_STREAM_TYPE);

which will send a Content-Dispostion header as follows:

   Content-Disposition: form-data;name="file"

You might want to try:

         FormDataBodyPart f = new FormDataBodyPart(
                  
FormDataContentDisposition
.name("file").fileName(file.getName()).build(),
                 file, MediaType.APPLICATION_OCTET_STREAM_TYPE);
         MultiPart multiPart = new FormDataMultiPart().bodyPart(f);

which will send a Content-Dispostion header as follows:

   Content-Disposition: form-data;filename="a.patch";name="file"

Failing that you might have to add you own Content-Disposition header
such that it is compatible with your server. For example,

         FormDataBodyPart f = new FormDataBodyPart(
                  
FormDataContentDisposition
.name("file").fileName(file.getName()).build(),
                 file, MediaType.APPLICATION_OCTET_STREAM_TYPE);
         f.getHeaders().putSingle("Content-Disposition", "form-
data;name=\"file\";filename=\"a.patch\"");
         MultiPart multiPart = new FormDataMultiPart().bodyPart(f);

Paul.

> Best Regards,
> Alexander
>
> On Tue, Jan 5, 2010 at 1:44 AM, Paul Sandoz <Paul.Sandoz_at_sun.com>
> wrote:
> Hi Alexander,
>
> You client code looks fine. Although strictly speaking you should
> use an instance of FormDataMultiPart.
>
> What version of Jersey are you using?
>
> What is the server side that consumes the request?
>
> Attached is a very simple client and server using Jersey which works
> fine. And the server-side also works fine when i use curl to do send
> an equivalent request.
>
> If you run this example (suitably modifying the file to send) you
> will notice that Jersey will log the request received from the client:
>
> Jan 5, 2010 10:29:44 AM
> com.sun.jersey.api.container.filter.LoggingFilter filter
> INFO: 3 * Server in-bound request
> 3 > POST http://localhost:8080/mavenproject9/webresources/myresource
> 3 > content-type: multipart/form-
> data;boundary=Boundary_1_2384204_1262683784353
> 3 > mime-version: 1.0
> 3 > user-agent: Java/1.5.0_20
> 3 > host: localhost:8080
> 3 > accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
> 3 > connection: keep-alive
> 3 > content-length: 1210
> 3 >
>
> --Boundary_1_2384204_1262683784353
> Content-Type: application/octet-stream
> Content-Disposition: form-data;filename="a.patch";modification-
> date="Mon, 07 Dec 2009 09:48:27 GMT";size=968;name="file"
>
> # This patch file was generated by NetBeans IDE
> # Following Index: paths are relative to: /Users/paulsandoz/Projects/
> atmosphere/trunk/atmosphere/modules/jersey/src/main/java/org/
> atmosphere/jersey
> # This patch can be applied using context Tools: Patch action on
> respective folder.
> # It uses platform neutral UTF-8 encoding and \n newlines.
> # Above lines and this line are ignored by the patching process.
> Index: AtmosphereFilter.java
> --- AtmosphereFilter.java Base (BASE)
> +++ AtmosphereFilter.java Locally Modified (Based On LOCAL)
> @@ -156,6 +156,9 @@
> * @return the {_at_link ContainerResponse}
> */
> public ContainerResponse filter(ContainerRequest request,
> ContainerResponse response) {
> + if (response.getMappedThrowable() != null)
> + return response;
> +
> AtmosphereResource r = (AtmosphereResource) servletReq
> .getAttribute
> (ReflectorServletProcessor.ATMOSPHERE_RESOURCE);
>
>
> --Boundary_1_2384204_1262683784353--
>
>
> Jan 5, 2010 10:29:44 AM
> com.sun.jersey.api.container.filter.LoggingFilter$Adapter finish
> INFO: 3 * Server out-bound response
> 3 < 204
> 3 <
>
>
> Notice the Content-Disposition header:
>
> Content-Disposition: form-data;filename="a.patch";modification-
> date="Mon, 07 Dec 2009 09:48:27 GMT";size=968;name="file"
>
> That contains the property "name" of the value "file".
>
> Note that you can also log from the client side as well by doing:
>
> Client c = ...
> c.addFilter(new LoggingFilter());
>
> to also verify the Content-Disposition header.
>
> Paul.
>
>
>
> On Jan 5, 2010, at 1:31 AM, Alexander Birmingham wrote:
>
>> Hi Everyone:
>>
>> I've been trying to do a multipart post using the Jersey Client,
>> and it's just about near driving me crazy. The examples I've found
>> have been helpful in modelling my code, but haven't taken me quite
>> to the end.
>>
>> I am looking to duplicate the following curl command:
>>
>> curl -F "file=_at_test.zip;type=application/octet-stream" -F "e=alexx1523_at_gmail.com
>> " -F "l=iQdad" -F "t=5Cp" -F "client_id=1000076" http://my.url.here.com/home/upload
>>
>> This is my java code:
>>
>> MultivaluedMap<String, String> queryParams;
>> File file = new File("/tmp/test.zip");
>>
>> addArgument(SessionUser.getCURRENTUSER()); // This adds the
>> parameters you see above to queryParams
>>
>> MultiPart multiPart = new MultiPart().bodyPart(new
>> FileDataBodyPart("file", file,
>> MediaType.APPLICATION_OCTET_STREAM_TYPE));
>>
>>
>> webResource
>> .queryParams
>> (queryParams
>> ).type
>> (MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class,
>> multiPart);
>>
>> The response indicates that the post is missing field "file". I am
>> unable to determine if this is because the binary is not being
>> attached correctly, or if the attachment is not being sent with the
>> correct name. The name has to be "file", as occurs in the above
>> curl, or it will not be recognized.
>>
>> Please help!
>>
>> Best Regards,
>> Alexander Birmingham
>
>
>