-2

I've already looked at this one and the related tickets to no avail.

I have, what looks like the, simplest example possible

<h:form enctype="multipart/form-data"  prependId="false">
<h:outputText value="File: "></h:outputText>
<h:inputFile value="#{configUploadController.uploadedFile}"  />
<h:commandButton value="Save" type="submit" action="#{configUploadController.uploadFile}" style="color: red;"></h:commandButton>
</h:form>

I put a breakpoint in my uploadFile method but it never gits hit. when I remove the enctype from the form it does try to submit but then I get the obvious error...

javax.servlet.ServletException: Content-Type != multipart/form-data

And just for completeness, I remove the <h:inputFile> and enctype and can see my breakpoint being hit. When I set enctype to text/plain it DOESNT hit the breakpoint. However, when I set enctype to gibberish it DOES hit the breakpoint :(

Am I missing a dependency or config somewhere?

And in case it matters, my web.xml...

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">

    <!-- File(s) appended to a request for a URL that is not mapped to a web 
        component -->
    <welcome-file-list>
        <welcome-file>status.xhtml</welcome-file>
    </welcome-file-list>

    <context-param>
        <param-name>com.sun.faces.expressionFactory</param-name>
        <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
    </context-param>

    <listener>
        <description>Initializes Oracle JSF</description>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>

    <!-- Define the JSF servlet (manages the request processing life cycle for 
        JavaServer Faces) -->
    <servlet>
        <servlet-name>faces-servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <!-- Map following files to the JSF servlet -->
    <servlet-mapping>
        <servlet-name>faces-servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>


</web-app>
  • jsf-api-2.2.15
  • jsf-impl-2.2.15
  • el-api-2.2
  • el-impl-2.2
  • jetty 9.4.18
  • javax.servlet-api-3.1.0
Kukeltje
  • 12,223
  • 4
  • 24
  • 47
TedTrippin
  • 3,525
  • 5
  • 28
  • 46
  • If you look at the browser's inspection / networking panel, what is the `Content-Type` request header for that failed Request? – Joakim Erdfelt Dec 06 '19 at 13:48
  • Slightly newer answer on this topic then the one you linked - https://stackoverflow.com/questions/28715559/multipart-form-data-enctype-ignored – Joakim Erdfelt Dec 06 '19 at 13:52
  • when i set enctype="gibberish" the request Content-Type is application/x-www-form-urlencoded – TedTrippin Dec 06 '19 at 13:54
  • lol @JoakimErdfelt its only 2 months newer and I'm not using jsf 2.1 or primefaces – TedTrippin Dec 06 '19 at 13:55
  • 1
    Here is a collection of possible reasons for action method not invoked: [commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated](https://stackoverflow.com/questions/2118656/commandbutton-commandlink-ajax-action-listener-method-not-invoked-or-input-value) – Selaron Dec 06 '19 at 14:00
  • Looks like I'm missing @MultipartConfig. But how can I add it since the servlets aren't my own? – TedTrippin Dec 06 '19 at 14:10
  • @TedTrippin: where did you find the information to come to the conclusion you miss the ` @MutlipartConfig` ? Oh and **always** post full stacktraces or at least the top and bottom part (the relevant parts) – Kukeltje Dec 06 '19 at 14:22
  • Off-topic (at least I assume it is), see https://stackoverflow.com/questions/7415230/uiform-with-prependid-false-breaks-fajax-render – Kukeltje Dec 06 '19 at 14:29
  • @BalusC you're a knowledgeable chap, got any good links to jetty/jsf/fileUpload? I've tried as many different examples as I can google but I always get stuck one way or another. – TedTrippin Dec 10 '19 at 11:04

2 Answers2

0

Instead of working around with a servlet (as per other answer) the actual problem was Jetty needs the multipart config setting up per multipart request.

Simple way to do this would be to add a filter that adds it as necessary, eg.

public class LoginFilter implements Filter {

  private static final String MULTIPART_FORM_DATA = "multipart/form-data";
  private static final MultipartConfigElement MULTI_PART_CONFIG =
        new MultipartConfigElement(System.getProperty("java.io.tmpdir"));

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

    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;

    String contentType = request.getContentType();
    if (contentType != null && contentType.startsWith(MULTIPART_FORM_DATA))
        request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);

    filterChain.doFilter(request, response);
  }
}

See also:

TedTrippin
  • 3,525
  • 5
  • 28
  • 46
-1

So, I haven't spent the time to track down why but jetty doesn't appear to like multipart forms. I got round it by using a servlet. Solution looks like this...

I've gone with ajax approach and a HTML form so I can specify my action, that matches the servlets pattern...

<form action="upload/config" enctype="multipart/form-data" method="post">
    <h:inputFile id="file" />
    <br />
    <h:commandButton type="submit" value="Upload">
        <f:ajax execute="file" render="@all"/>
    </h:commandButton>
</form>

And the servlet...

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

import javax.servlet.MultipartConfigElement;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import org.eclipse.jetty.server.Request;

@WebServlet("upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse resp) {

        try {
            // This needed to get access to the parts
            MultipartConfigElement multipartConfigElement = new MultipartConfigElement((String)null);
            request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, multipartConfigElement);

            Part filePart = request.getPart("file");

            try ( InputStream inputStream = filePart.getInputStream(); ) {
                // Do what you want with your part

            } catch (Exception e) {
                resp.setStatus(500);
            }


        } catch (Exception e) {
            resp.setStatus(500);
        }
    }
}
TedTrippin
  • 3,525
  • 5
  • 28
  • 46
  • It's not Jetty not liking multipart forms, it's that the HTTP Client isn't submitting a POST with a request header `Content-Type: multipart/form-data`, the exception is telling you that it got some other value for `Content-Type` (which is unsupported) – Joakim Erdfelt Dec 06 '19 at 19:22
  • I went ahead and updated that exception message to be more clear - [eclipse/jetty.project@53eda032](https://github.com/eclipse/jetty.project/commit/53eda03203706e5f29ba3a4881262a7cd63f7ebb) – Joakim Erdfelt Dec 06 '19 at 19:25
  • @JoakimErdfelt: I don't think OP stated that Jetty does not like multipart forms. OP stated that with this `enctype="multipart/form-data"` the method is not called and without it, the aforementioned error occurs. Which makes sense since `multipart/form-data' was expected and not sent (since it was not set). – Kukeltje Dec 06 '19 at 20:07