Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Downloading a file from spring controllers throws IllegalStateException

I am using the following (which looks like a lot to this) code to download a file:

@RequestMapping(value = "/tunes/{file_name}", method = RequestMethod.GET)
public void downloadTune(@PathVariable(value = "file_name") String tuneId,
        HttpServletResponse response) {
    perfomanceLogger.trace("=== Start retrieving tune with id: " + tuneId);
    try {
        String location = "";
        // try {
        location = resourceManagementService.getArtifcatByIdAndType(tuneId,
                ControllerConstants.TYPE_MP3);
        String pathSeparator = File.separator;

        if (location == null || location.equals("")) {// load the default
                                                        // tune
            location = System.getProperties().get("jboss.server.base.dir")
                    + pathSeparator + ServicesConstants.FILE_LOCATION
                    + pathSeparator + "ringtone_1.mp3";
            if (!new File(location).exists()) {
                location = "";
            }
        }

        if (!location.equals("")) {
            Path musicFile = Paths.get(location);
            response.setContentType("audio/wav");
            response.setContentLength((int) Files.size(musicFile));
            try (OutputStream out = response.getOutputStream()) {
                Files.copy(musicFile, out);
                response.flushBuffer();
            } catch (Exception e) {
                log.info("Could not stream tune with id: " + tuneId + " "
                        + e.getCause() + " " + e.getMessage());
            }
        }
    } catch (IOException | InvalidPathException | IllegalStateException e) {
        log.info("Could not stream tune with id: " + tuneId + " "
                + e.getMessage());

    }
    perfomanceLogger.trace("=== Finished retrieving tune with id: "
            + tuneId);
}

I am using Spring 3.2.2 and Spring Security 3.2.0.M1 and JBoss 7.1.1.Final. The problem is that some times I get an IllegalStateException. Here is the stacktrace:

2014-01-21 12:23:34,969 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/MyWebApplication].[appServlet]] (http--0.0.0.0-80-2) Servlet.service() for servlet appServlet threw exception: java.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:2636) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.Request.getSession(Request.java:2375) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:841) [jbossweb-7.0.13.Final.jar:]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:255) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:255) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at org.springframework.web.context.request.ServletRequestAttributes.getSession(ServletRequestAttributes.java:79) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.context.request.ServletRequestAttributes.setAttribute(ServletRequestAttributes.java:129) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.bind.support.DefaultSessionAttributeStore.storeAttribute(DefaultSessionAttributeStore.java:54) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.method.annotation.SessionAttributesHandler.storeAttributes(SessionAttributesHandler.java:123) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.method.annotation.ModelFactory.updateModel(ModelFactory.java:202) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.getModelAndView(RequestMappingHandlerAdapter.java:842) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:751) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) [spring-webmvc-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:150) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.2.0.M1.jar:3.2.0.M1]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:567) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_21]

Is there something wrong with the session from time to time?

like image 992
ampofila Avatar asked Nov 02 '22 06:11

ampofila


1 Answers

Get rid of

response.flushBuffer();

which commits the response.

The Servlet container will take care of committing the response and flushing the OutputStream when it needs to.

If your file is too big, you'll want to create the session yourself before starting the download.


To answer comment:

It seems you never created an HttpSession during your request handling.

The container's implementation of HttpServletResponse commits the response (headers) and starts flushing the OutputStream when you've written X amount of bytes (configurable and depends on container). You cannot force the container to create an HttpSession after that's happened.

Obviously you weren't creating the HttpSession yourself, but Spring uses it to manage its model attributes, so it had to create it. It does that in

at org.springframework.web.method.annotation.ModelFactory.updateModel(ModelFactory.java:202) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]

The simple solution is to get a reference to the HttpServletRequest and call its getSession(boolean) method, passing true so that it forces the creation of the HttpSession. Do this anywhere before you start pushing the file.

like image 198
Sotirios Delimanolis Avatar answered Jan 04 '23 13:01

Sotirios Delimanolis