users@jersey.java.net

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

From: Igor Minar <iiminar_at_gmail.com>
Date: Tue, 14 Jul 2009 16:02:46 -0700

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.

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.

> 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?

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.

thanks,
Igor


On Jul 13, 2009, at 12:11 AM, Paul Sandoz wrote:

> H Igor,
>
> Your filter is consuming the request entity, and unless you buffer
> the entity it can only be consumed once.
>
> For now you will have to get the entity stream read it into a byte
> array input stream, set that as the stream, read the entity in the
> filter, then, most importantly, reset the byte array input stream so
> the entity can be re-read.
>
> 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?
>
> Thanks,
> Paul.
>
> On Jul 12, 2009, at 3:09 AM, Igor Minar wrote:
>
>> Hi there,
>>
>> I have a application that needs to process a multipart-form
>> request. Everything works great, until I try to access my form
>> fields both in a jersey filter as well as in my resource.
>>
>> In my filter I have:
>>
>> private Credentials attemptBrowserBasedToken(HttpRequestContext
>> context) {
>> FormDataMultiPart form =
>> context.getEntity(FormDataMultiPart.class);
>> String key = form.getField("AccessKey").getValue(); //
>> TODO NPEs!!!
>> String signature =
>> Base64Coder.decode(form.getField("signature").getValue());
>> ...
>> }
>>
>> In my resource I have:
>>
>> @POST
>> @Consumes(MediaType.MULTIPART_FORM_DATA)
>> public Response processForm(@PathParam("bucketName") final String
>> bucketName,
>> @FormDataParam("policy") final
>> String policyEncoded,
>> @FormDataParam("key") String key,
>>
>> @FormDataParam("success_action_redirect") final String
>> successRedirect,
>> @FormDataParam("acl") final
>> String acl,
>> final FormDataMultiPart formData,
>> @Context final SecurityContext
>> securityContext,
>> @Context final HttpHeaders
>> headers) {
>> ...
>> }
>>
>> When I run a request against this resource method, I get the
>> exception below some time after the filter returns and before
>> processForm in the resource is called.
>>
>> It looks like when the filter reads the form, it doesn't cache the
>> result, but closes the request stream when it reads it. As a
>> result, when jersey tries to initialize resource method arguments,
>> it can't do it any more.
>>
>> If I remove all FromData* stuff from the resource method signature,
>> the exceptions is not thrown.
>>
>> Is this a known limitation or a result of a design decision?
>>
>> Do you know if there is some workaround for this? Maybe a way to
>> store the data retrieved in the filter somewhere in the request
>> context and then retrieve it somehow in the resource? I suppose I
>> could do this via a thread local hack, but I'd rather avoid that if
>> possible.
>>
>> thanks,
>> Igor
>>
>>
>>
>>
>> Jul 11, 2009 4:19:55 PM
>> com.sun.jersey.server.impl.application.WebApplicationImpl onException
>> SEVERE: Internal server error
>> javax.ws.rs.WebApplicationException:
>> org.jvnet.mimepull.MIMEParsingException: java.io.IOException:
>> Stream closed
>> at
>> com
>> .sun
>> .jersey
>> .multipart.impl.MultiPartReader.readFrom(MultiPartReader.java:203)
>> at
>> com
>> .sun
>> .jersey
>> .multipart.impl.MultiPartReader.readFrom(MultiPartReader.java:74)
>> at
>> com
>> .sun
>> .jersey
>> .spi.container.ContainerRequest.getEntity(ContainerRequest.java:393)
>> at
>> com
>> .sun
>> .jersey
>> .spi.container.ContainerRequest.getEntity(ContainerRequest.java:402)
>> at
>> com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider
>> $
>> FormDataInjectableValuesProvider
>> .getInjectableValues(FormDataMultiPartDispatchProvider.java:112)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl.model.method.dispatch.AbstractResourceMethodDispatchProvider
>> $
>> EntityParamInInvoker
>> .getParams(AbstractResourceMethodDispatchProvider.java:126)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl.model.method.dispatch.AbstractResourceMethodDispatchProvider
>> $
>> ResponseOutInvoker
>> ._dispatch(AbstractResourceMethodDispatchProvider.java:173)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .model
>> .method
>> .dispatch
>> .ResourceJavaMethodDispatcher
>> .dispatch(ResourceJavaMethodDispatcher.java:67)
>> at
>> com
>> .sun
>> .jersey
>> .server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:163)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:71)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .uri
>> .rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:
>> 63)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .application
>> .WebApplicationImpl._handleRequest(WebApplicationImpl.java:654)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .application
>> .WebApplicationImpl.handleRequest(WebApplicationImpl.java:612)
>> at
>> com
>> .sun
>> .jersey
>> .server
>> .impl
>> .application
>> .WebApplicationImpl.handleRequest(WebApplicationImpl.java:603)
>> at
>> com
>> .sun
>> .jersey
>> .spi.container.servlet.WebComponent.service(WebComponent.java:309)
>> at
>> com
>> .sun
>> .jersey
>> .spi
>> .container.servlet.ServletContainer.service(ServletContainer.java:
>> 425)
>> at
>> com
>> .sun
>> .jersey
>> .spi
>> .container.servlet.ServletContainer.service(ServletContainer.java:
>> 590)
>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
>> at
>> com
>> .google
>> .inject.servlet.ServletDefinition.doService(ServletDefinition.java:
>> 216)
>> at
>> com
>> .google
>> .inject.servlet.ServletDefinition.service(ServletDefinition.java:141)
>> at
>> com
>> .google
>> .inject
>> .servlet.ManagedServletPipeline.service(ManagedServletPipeline.java:
>> 93)
>> at
>> com
>> .google
>> .inject
>> .servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:
>> 63)
>> at
>> com
>> .google
>> .inject
>> .servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:
>> 122)
>> at
>> com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:110)
>> at
>> com
>> .sun
>> .grizzly.http.servlet.FilterChainImpl.doFilter(FilterChainImpl.java:
>> 172)
>> at
>> com
>> .sun
>> .grizzly
>> .http
>> .servlet.FilterChainImpl.invokeFilterChain(FilterChainImpl.java:137)
>> at
>> com
>> .sun
>> .grizzly.http.servlet.ServletAdapter.service(ServletAdapter.java:322)
>> at
>> com
>> .sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:
>> 165)
>> at
>> com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:
>> 746)
>> at
>> com
>> .igorminar
>> .grizzlysendfile.SendfileFilter.doFilter(SendfileFilter.java:128)
>> at
>> com
>> .sun
>> .grizzly
>> .arp.DefaultAsyncExecutor.invokeFilters(DefaultAsyncExecutor.java:
>> 147)
>> at
>> com
>> .sun
>> .grizzly
>> .arp.DefaultAsyncExecutor.interrupt(DefaultAsyncExecutor.java:126)
>> at
>> com
>> .sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:
>> 88)
>> at com.sun.grizzly.http.TaskBase.run(TaskBase.java:189)
>> at java.util.concurrent.ThreadPoolExecutor
>> $Worker.runTask(ThreadPoolExecutor.java:886)
>> at java.util.concurrent.ThreadPoolExecutor
>> $Worker.run(ThreadPoolExecutor.java:908)
>> at java.lang.Thread.run(Thread.java:637)
>> Caused by: org.jvnet.mimepull.MIMEParsingException:
>> java.io.IOException: Stream closed
>> at org.jvnet.mimepull.MIMEParser.fillBuf(MIMEParser.java:436)
>> at org.jvnet.mimepull.MIMEParser.skipPreamble(MIMEParser.java:
>> 302)
>> at org.jvnet.mimepull.MIMEParser.access$300(MIMEParser.java:62)
>> at org.jvnet.mimepull.MIMEParser
>> $MIMEEventIterator.next(MIMEParser.java:138)
>> at org.jvnet.mimepull.MIMEParser
>> $MIMEEventIterator.next(MIMEParser.java:123)
>> at
>> org.jvnet.mimepull.MIMEMessage.makeProgress(MIMEMessage.java:193)
>> at org.jvnet.mimepull.MIMEMessage.parseAll(MIMEMessage.java:
>> 176)
>> at
>> org.jvnet.mimepull.MIMEMessage.getAttachments(MIMEMessage.java:101)
>> at
>> com
>> .sun
>> .jersey
>> .multipart.impl.MultiPartReader.readFrom(MultiPartReader.java:166)
>> ... 37 more
>> Caused by: java.io.IOException: Stream closed
>> at
>> com
>> .sun
>> .grizzly.tcp.http11.GrizzlyInputBuffer.read(GrizzlyInputBuffer.java:
>> 343)
>> at
>> com
>> .sun
>> .grizzly.tcp.http11.GrizzlyInputStream.read(GrizzlyInputStream.java:
>> 234)
>> at
>> com
>> .sun
>> .grizzly
>> .http
>> .servlet.ServletInputStreamImpl.read(ServletInputStreamImpl.java:91)
>> at org.jvnet.mimepull.MIMEParser.fillBuf(MIMEParser.java:434)
>> ... 45 more
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>