You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@wink.apache.org by Mike Rheinheimer <ro...@apache.org> on 2010/09/11 06:07:40 UTC

proposed support for multipart/form-data to @FormParam

Currently, in Wink, multipart/form-data parts will not be passed to a
resource method in the @FormParam annotated method params.  In other
words, if you send data from an html form that has declared
enctype="multipart/form-data" (which is what you would use if you wish
to send a file via the file input tag), you have to declare
@Consumes("multipart/form-data") and take as input a
BufferedInMultiPart in your resource method, from which you can
iterate over the InPart(s) and do with the data as you wish.

The bad news is that it means you might have to introduce
Wink-specific objects to your resource class, iterate over the parts,
convert them yourself, etc.  This annoys me.  :)  So I propose we
support the pattern where we go ahead and convert the parts of the
multipart/form-data (or multipart/* -- but I haven't looked into that
yet) into the @FormParam objects requested by the resource method
receiving the inbound request.

The good news is that I've already worked up a patch that supports
something like:

<form enctype="multipart/form-data" action="POST" action="someurl">
<input type="text" name="firstname" />
<input type="file" name="file" /> <!-- browsers will inspect the file
and make a best effort to send appropriate Content-Type header for
this part -->
<input type="submit" /> <!-- browser will not send this data due to
missing the "name" attribute -->
</form>

@POST
@Consumes("multipart/form-data")
public Response postFromForm(@FormParam("firstname") String firstname,
@FormParam("file") File file) {
    // good data!
}

The other good news is that when Wink retrieves the parts and attempts
to convert them to the type specified by the @FormParam annotated
method, it will use the existing providers list.  So in the above
example, it will simply use the FileProvider.  The really good news, I
think, is that this means a application can write a provider that can
convert the inbound file into arbitrary application objects.  Let's
say you want a resource method like so:

@POST
@Consumes("multipart/form-data")
public Response postFromForm(@FormParam("file") MyObject myObject) {
    // good data, if you have a provider that can do this
}

The client sends a file via a multipart/form-data Content-Type message
in whatever format can be understood by the provider, which could be
(should be?):

@Provider
@Consumes("*/*")  // NOT multipart/form-data
class MyProvider implements MessageBodyReader<MyObject> {
    public boolean isReadable(...) {
        // can do some safety checking here.  The MediaType passed in
will be from the Content-Type header on the part, not on the message
        // So if the user sent a jpeg from Firefox via a form, you'll
see image/jpeg.  It defaults to plain/text.  Remember to check that
the genericType
        // param is compatible with MyObject!
    }
    public MyObject readFrom(...) {
        // do your magic; marshal the entityStream into MyObject
    }
}

I should be able to work up some unittests around this.  Anyone see
any issues or problems supporting this?

Besides the above, how about supporting postFiles(@FormParam("file")
List<File> files)  ?  I don't think this will be difficult to support.
 If the resource needed some assurance that the list of files were all
jpeg image files, for example, you could use the provider approach
from above to inspect the content-type header and/or the actual
serialized payload in the message, or the resource method itself would
have to check that.  Just a thought.  Any thoughts on this?

FYI, the html form for sending such data (two files in two parts of
one message, in this case) looks like this:

<form enctype="multipart/form-data" method="POST" action="someuri">
<input type="file" name="file[]" />
<input type="file" name="file[]" />
<input type="submit" />
</form>

Thanks..
mike

Re: proposed support for multipart/form-data to @FormParam

Posted by Mike Rheinheimer <ro...@apache.org>.
Ok, so I had PHP's global $_FILES variable in mind when I typed up
that last html form snippet; it's the way to simplify processing of
multiple values for a given name in PHP.  However, the technique could
be easily adapted for Wink.  We certainly could advise people to use
this construct, and support it in such a way that it would pass a
List<File> or File[] as the method param when we see
@FormParam("file") List<File> files.

<input type="file" name="file[]" />
<input type="file" name="file[]" />

Opinions?
mike


On Fri, Sep 10, 2010 at 11:07 PM, Mike Rheinheimer <ro...@apache.org> wrote:
> Currently, in Wink, multipart/form-data parts will not be passed to a
> resource method in the @FormParam annotated method params.  In other
> words, if you send data from an html form that has declared
> enctype="multipart/form-data" (which is what you would use if you wish
> to send a file via the file input tag), you have to declare
> @Consumes("multipart/form-data") and take as input a
> BufferedInMultiPart in your resource method, from which you can
> iterate over the InPart(s) and do with the data as you wish.
>
> The bad news is that it means you might have to introduce
> Wink-specific objects to your resource class, iterate over the parts,
> convert them yourself, etc.  This annoys me.  :)  So I propose we
> support the pattern where we go ahead and convert the parts of the
> multipart/form-data (or multipart/* -- but I haven't looked into that
> yet) into the @FormParam objects requested by the resource method
> receiving the inbound request.
>
> The good news is that I've already worked up a patch that supports
> something like:
>
> <form enctype="multipart/form-data" action="POST" action="someurl">
> <input type="text" name="firstname" />
> <input type="file" name="file" /> <!-- browsers will inspect the file
> and make a best effort to send appropriate Content-Type header for
> this part -->
> <input type="submit" /> <!-- browser will not send this data due to
> missing the "name" attribute -->
> </form>
>
> @POST
> @Consumes("multipart/form-data")
> public Response postFromForm(@FormParam("firstname") String firstname,
> @FormParam("file") File file) {
>    // good data!
> }
>
> The other good news is that when Wink retrieves the parts and attempts
> to convert them to the type specified by the @FormParam annotated
> method, it will use the existing providers list.  So in the above
> example, it will simply use the FileProvider.  The really good news, I
> think, is that this means a application can write a provider that can
> convert the inbound file into arbitrary application objects.  Let's
> say you want a resource method like so:
>
> @POST
> @Consumes("multipart/form-data")
> public Response postFromForm(@FormParam("file") MyObject myObject) {
>    // good data, if you have a provider that can do this
> }
>
> The client sends a file via a multipart/form-data Content-Type message
> in whatever format can be understood by the provider, which could be
> (should be?):
>
> @Provider
> @Consumes("*/*")  // NOT multipart/form-data
> class MyProvider implements MessageBodyReader<MyObject> {
>    public boolean isReadable(...) {
>        // can do some safety checking here.  The MediaType passed in
> will be from the Content-Type header on the part, not on the message
>        // So if the user sent a jpeg from Firefox via a form, you'll
> see image/jpeg.  It defaults to plain/text.  Remember to check that
> the genericType
>        // param is compatible with MyObject!
>    }
>    public MyObject readFrom(...) {
>        // do your magic; marshal the entityStream into MyObject
>    }
> }
>
> I should be able to work up some unittests around this.  Anyone see
> any issues or problems supporting this?
>
> Besides the above, how about supporting postFiles(@FormParam("file")
> List<File> files)  ?  I don't think this will be difficult to support.
>  If the resource needed some assurance that the list of files were all
> jpeg image files, for example, you could use the provider approach
> from above to inspect the content-type header and/or the actual
> serialized payload in the message, or the resource method itself would
> have to check that.  Just a thought.  Any thoughts on this?
>
> FYI, the html form for sending such data (two files in two parts of
> one message, in this case) looks like this:
>
> <form enctype="multipart/form-data" method="POST" action="someuri">
> <input type="file" name="file[]" />
> <input type="file" name="file[]" />
> <input type="submit" />
> </form>
>
> Thanks..
> mike
>