8

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

Fagner Brack
  • 2,365
  • 4
  • 33
  • 69
  • Please add your `url-pattern` mappings. – Sotirios Delimanolis Oct 10 '13 at 13:45
  • I can't reproduce with the code you've shown. Are you sure everything is as you have it? – Sotirios Delimanolis Oct 10 '13 at 14:35
  • I have updated to show the full web.xml file. Are you sure you are using JBoss EAP 6.1? The full project is here if you are interested (Eclipse Kepler + JBOss Tools): http://bit.ly/GHYq0f – Fagner Brack Oct 10 '13 at 14:51
  • That is a reproducible piece of a system to dinamically include parts of a jsp into a given set of urls according to the servlets and jsp locations (without needing to manually define the paths, it is like a convention) – Fagner Brack Oct 10 '13 at 14:52
  • like `org.company.pages.foo.bar == "/foo/bar/"` and `org.company.pages.foo.bar.PageAction.java == "/foo/bar/page-action"`, it may not be the best design, but is what I could come up with giving my java knowledge. – Fagner Brack Oct 10 '13 at 14:55
  • I would suggest do to some debugging to find out when the filter is called and when the servlet is called, and probably add some logging in the filter to check if `data` is available there. – Uooo Oct 15 '13 at 12:49
  • @FagnerBrack Jboss AS 6.1 != JBoss EAP 6.1. JBoss EAP 6.1 is closer to JBoss AS 7. – eis Oct 16 '13 at 21:09
  • @eis Huge mistake, I meant EAP 6.1 but had AS in my mind. Damn it! Very sorry. – Fagner Brack Oct 18 '13 at 15:34

2 Answers2

2

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.

Barry Pitman
  • 3,087
  • 1
  • 24
  • 32
  • Do you have the sentences on the servlet spec that may state that it should be working? I took a look before posting this issue (ctrl + f) and did not find anything expliciting such behavior, I hope this is not considered an implementation detail. I will probably create an issue for JBoss regarding this. – Fagner Brack Oct 18 '13 at 15:48
0

I randomly came across this and what may be the answer to your dilemma at the same time. Given the annotations supplied, the page would be accessed with {insert your context here}/hello and not {insert your context here}/p/hello. Take a look at Multiple folders in Java EE 6 web pages. It is very similar and BalusC provides some great information. Hope that helps.

Community
  • 1
  • 1
John
  • 376
  • 1
  • 7
  • What I mean by this is that "
    – John Oct 18 '13 at 20:40
  • You misread the problem, `/{context}/p/hello` is being dispatched at runtime through `request.getRequestDispatcher( "/hello" ).include( request, response );`. Actually, every path is being dispatched to that by the given filter. Unfortunately the upload is not working under this condition and that is the actual problem. By my comment above "That is a reproducible piece of a system to dinamically include parts of a jsp into a given set of urls according to the servlets and jsp locations" – Fagner Brack Oct 18 '13 at 21:26
  • You may argue that this is not the correct way to do it, I would like to know a better way then. The framework have this feature, it is expected to work under such condition. – Fagner Brack Oct 18 '13 at 21:29
  • Again, it's the path of your mapping. In the answer you accepted, "hello.addMapping( "/hello" ); hello.addMapping( "/p/hello" );" worked. Why? Because you were trying to get /p/hello and you only had /hello mapped. Exactly as my answer stated. What you were trying to access was not relative to the mapping you had. – John Oct 22 '13 at 14:03
  • This behavior does not make sense, I suppose the mapping should not be considered for this case, but the path I am currently accessing. I created an issue in the JBoss EAP bug tracker, I will see how that works out. – Fagner Brack Oct 22 '13 at 16:11
  • From the specs, it sounds like the path being mapped has to be representative of the physical path of the action in order for the action to be found. I'm curious as to what comes of it, as I ran into a somewhat similar issue mapping Struts2 actions myself, where the namespaces were being ignored for the physical location of the actions. If you get a chance to read the other SO I linked in my original answer, the answer from BalusC might help. He suggested a domain relative URL so that you wouldn't have to specify every single folder in your mappings. – John Oct 22 '13 at 17:12
  • Yes I read that response but still I don't see how that would help without defeating my purpose. My original context path will always be "/" since I am changing it by the Filter (no, RequestDispatcher will not update that, I am not sure about other containers). Always using the context would imply putting all my mapping in the root, and that is not what I want to do. I want to make it work disregard the level of the browser path. – Fagner Brack Oct 22 '13 at 18:57
  • Yeah, the only things I can think of to get it working are to add the mapping for the url from the root you want, ie, "/p/hello", but as you're really looking for /hello, if the jboss crew doesn't have an answer, maybe take a look at something like pretty faces where you can do URL rewriting? http://ocpsoft.org/prettyfaces/ If that doesn't handle what you need exactly, there may be a way to extend it out to do so, or other similar plugins.. – John Oct 23 '13 at 18:18