Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multipart config not working for dynamic added servlet in a curious condition

jsp:

<!DOCTYPE html>
<form action="/{insert your context here}/p/hello" method="post" enctype="multipart/form-data">
  <input type="file" name="data">
  <button>Go</button>
</form>

Servlet:

@WebServlet
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1;
    @Override
    protected void doPost( HttpServletRequest request, HttpServletResponse response )
    throws IOException, ServletException {
        if ( request.getPart( "data" ) != null ) {
            response.getWriter().print( "It worked\n\n" );
        } else {
            response.getWriter().print( "IT IS NOT WORKING!\n\n" );
        }
    }
}

Filter

@WebFilter( filterName = "hello" )
public class HelloFilter implements Filter {
    @Override
    public void init( FilterConfig config ) throws ServletException {}

    @Override
    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
    throws IOException, ServletException {
        request
            .getRequestDispatcher( "/hello" )
            .include( request, response );

        request
            .getRequestDispatcher( "/hello.jsp" )
            .include( request, response );
    }

    @Override
    public void destroy() {}
}

Listener

@WebListener
public class HelloListener implements ServletContextListener {
    @Override
    public void contextInitialized( ServletContextEvent event ) {
        ServletContext context = event.getServletContext();
        Dynamic hello = context.addServlet( "hello", HelloServlet.class );
        hello.addMapping( "/hello" );
        hello.setMultipartConfig( getMultiPartConfig() );
    }
    @Override
    public void contextDestroyed( ServletContextEvent event ) {}

    private MultipartConfigElement getMultiPartConfig() {
        String location = "";
        long maxFileSize = -1;
        long maxRequestSize = -1;
        int fileSizeThreshold = 0;
        return new MultipartConfigElement(
            location,
            maxFileSize,
            maxRequestSize,
            fileSizeThreshold
        );
    }
}

My web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>{insert the context here}</display-name>
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
  </jsp-config>
  <filter-mapping>
    <filter-name>hello</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

When I submit the form I receive the output "IT IS NOT WORKING!" in the first line of the response. If I change the requested path from /{insert your context here}/p/hello to /{insert your context here}/hello it works, why?

Using:
JBoss EAP 6.1

like image 843
Fagner Brack Avatar asked Oct 10 '13 13:10

Fagner Brack


1 Answers

I was able to reproduce the problem with Tomcat 7.0.30. The same problem was present whether I configured the "HelloServlet" dynamically or statically, using a @MultipartConfig annotation.

I also tested on Jetty version 8.1.13.v20130916, and it worked fine in both cases; /{context}/p/hello and /{context}/hello, without any modifications.

If you were to modify your HelloListener like this:

Dynamic hello = context.addServlet( "hello", HelloServlet.class );
hello.addMapping( "/hello" );
hello.addMapping( "/p/hello" );
hello.setMultipartConfig( getMultiPartConfig() );

it would work, but I suspect that defeats the purpose of what you are trying to do. Another option would be to modify your filter to add new mappings dynamically as required:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    // dynamically add mappings
    ServletContext context = request.getServletContext();
    ServletRegistration registration = context.getServletRegistration("hello");
    registration.addMapping("/<dynamic path>/hello");

    request.getRequestDispatcher("/hello").include(request, response);
    request.getRequestDispatcher("/hello.jsp").include(request, response);
}

It seems like tomcat/jboss is only enabling multipart support for the request based on whether or not the original request path matches one of the servlets configured for multipart support, whereas it should be enabling support based on the path of the request it is currently handling (which might have been "included" by the RequestDispatcher.

It does seem like a tomcat/jboss bug, but you'd have to carefully read the servlet spec to find out, otherwise you could use Jetty instead.

like image 55
Barry Pitman Avatar answered Nov 14 '22 22:11

Barry Pitman