users@jersey.java.net

Re: [Jersey] MIMEParsingException (IOException: Stream closed) when accessing a multipart form from a filter

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Thu, 16 Jul 2009 09:29:47 +0200

On Jul 15, 2009, at 11:10 PM, Igor Minar wrote:

>
> On Jul 15, 2009, at 12:59 AM, Paul Sandoz wrote:
>
>>
>> On Jul 15, 2009, at 1:02 AM, Igor Minar wrote:
>>
>>> Hi Paul,
>>>
>>> Thanks for the answer, but I'm afraid that due to the expected
>>> size of the requests handled in this way, I don't think that
>>> buffering things in the memory will be feasible.
>>>
>>> If I read the jersey multipart docs/emails on the list correctly
>>> then the multipart implementation buffers large requests on the
>>> disk, which is something that I'd like to take advantage of.
>>>
>>
>> That is the problem, the filter may not necessarily process the
>> same Java type as required by the resource method.
>
> Do you mean the case where filter would want to process the request
> as FormDataMultiPart and resource would instead be interested in for
> example the raw inputstream?

Yes.


> I can see that being a problem, but that's not what we are doing.
>

Right, but i am searching for generic solutions to the problem.


>>
>> Are you using a resource filter and specifically associating it
>> with the resource method or a container request filter that would
>> apply to all resource methods?
>
> Currently it's a container request filter. It applies to all
> resource methods, but we don't process the request in the filter if
> the request doesn't have multipart media type (which is most of the
> time).
>

You could make this a resource specific filter, based on an annotation
a resource method is annotated with (or say what the resource method
consumes, if you want to be more generic). This more closely ties the
entity processing functionality between the filter and the resource
method and also modularizes functionality.


> The filter is a generic authentication filter, which is capable
> extracting credentials via several different ways and one of them is
> an authentication mechanism which uses tokens and multipart form
> fields - similar to how S3 browser based uploads work.
>
>>
>>
>>> In the meantime I did implement a workaround where I pass the
>>> FormDataMultiPart instance from filter to my resource via a thread
>>> local class, but I still would like to see a nicer solution to
>>> this problem.
>>>
>>
>> Yes, this of course does not work for @FormDataParam though.
>
> FormDataMultiPart object contains all the FormDataParam objects, so
> if I pass it around, I can get access to the individual
> FormDataParam objects too. It's not ideal, but it works.
>

Right.


>>
>>
>>>> In general when using Jersey filters one should not assume that
>>>> the Java type the filter wants for an entity is the same as the
>>>> Java type for the resource method. But there is probably some way
>>>> i could optimize this, for the case of when it is. Could you log
>>>> an enhancement issue?
>>>
>>> You mean that you would cache the entity within the provider, so
>>> that when it is requested the second time provider just retrieves
>>> the entity from the cache? Or are you thinking of something else?
>>>
>>
>> Cache it within the ContainerRequest. But this will not work if one
>> requests a different Java type for the entity the second time.
>
> As I mentioned we extract the same java type from the request.
>

I know, but i have to cover the cases for developers where this may
not be the case. Hence i think the solution is to allow extension of
ContainerRequest to support your use-case.


>>
>> The right way to do this would i think be for the filter to extend
>> ContainerRequest with such functionality by overriding the
>> getEntity method. Then the filter can adapt the ContainerRequest
>> passed in and return the adapted instance. Unfortunately the
>> ContainerRequest class is currently set up to easily do this so we
>> need to modify this class so it can adapted (likewise for
>> ContainerResponse). Could you log an issue?
>
> done: https://jersey.dev.java.net/issues/show_bug.cgi?id=330
>

Thanks.


>>
>>
>>> As an alternative to thread local hack, I also looked for an api
>>> similar to servlet's request.setAttribute but I didn't find
>>> anything like that in jersey. Am I just not looking hard enough or
>>> there really isn't anything like that in Jersey.
>>>
>>
>> See:
>>
>> https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/api/core/HttpContext.html
>> #getProperties()
>> See:
>>
>> and you can inject HttpContext e.g. @Context HttpContext hc.
>>
>> Note that the same properties are accessible that ContainerRequest
>> as well:
>>
>> https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/spi/container/ContainerRequest.html
>> #getProperties()
>>
>> So in your filter you do not need to inject HttpContext.
>
> ahhh.. sweet! I was looking for setters and missed the properties
> getter which returns a mutable Properties object.
>
> thanks! I'll use this in the meantime to transport the extracted
> FormDataMultiPart object from our filter to the resource instead of
> the thread local hack we use now.
>

Great!

Paul.