Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileUpload: Decoding FileUpload requires contentType "multipart/form-data" #11806

Closed
stolp opened this issue Apr 24, 2024 · 17 comments · Fixed by #11816, #11851 or #11852
Closed

FileUpload: Decoding FileUpload requires contentType "multipart/form-data" #11806

stolp opened this issue Apr 24, 2024 · 17 comments · Fixed by #11816, #11851 or #11852
Assignees
Labels
🐞 defect Bug...Something isn't working
Milestone

Comments

@stolp
Copy link
Contributor

stolp commented Apr 24, 2024

Describe the bug

In FileUploadRenderer I see the following method:

  public void decode(FacesContext context, UIComponent component) {
       FileUpload fileUpload = (FileUpload) component;
       if (!fileUpload.isDisabled()) {
           if (!context.getExternalContext().getRequestContentType().toLowerCase().startsWith("multipart/")) {
               LOGGER.severe(() -> "Decoding FileUpload requires contentType \"multipart/form-data\"." +
                       " Skipping clientId: " + component.getClientId(context));
               return;
           }

           PrimeApplicationContext applicationContext = PrimeApplicationContext.getCurrentInstance(context);

           FileUploadDecoder decoder = applicationContext.getFileUploadDecoder();
           decoder.decode(context, fileUpload);
       }
   }

On one of my pages, I get the above severe error message. I did set a breakpoint there and find that the request in question is indeed content-type = application/x-www-form-urlencoded; but it also is faces-request = partial/ajax.

This is just during rendering of the p:fileUpload. The upload itself is working perfectly fine.

Is the logging condition correct as it is, or shouldn't it exclude partial ajax requests here?

Reproducer

<h:head>
    <title>PrimeFaces Test</title>
    <h:outputScript name="test.js" />
    <h:outputStylesheet name="test.css" />
</h:head>
<h:body>

    <h:form id="frmTest">

      <p:fileUpload 
        auto="true" dragDropSupport="true" mode="advanced" skinSimple="false"
        update="@form" multiple="true" sequential="true" />

      <p:commandButton value="Refresh" partialSubmit="true" update="@form" />
    </h:form>

</h:body>

Expected behavior

The message should not be logged for partial updates.

PrimeFaces edition

None

PrimeFaces version

14.0.0-RC3

Theme

No response

JSF implementation

MyFaces

JSF version

2.3

Java version

21

Browser(s)

No response

@stolp stolp added ‼️ needs-triage Issue needs triaging 🐞 defect Bug...Something isn't working labels Apr 24, 2024
@melloware
Copy link
Member

It used to do this...

if (!context.isProjectStage(ProjectStage.Production)) {
                LOGGER.fine

Now it does SEVERE and doesn't check the ProjectStage for some reason.

                LOGGER.severe

@melloware
Copy link
Member

melloware commented Apr 24, 2024

@stolp am I wrong that these are two different content types application/x-www-form-urlencoded; and multipart/form-data ?

here is what PF showcase has in the browser when submitting:
image

application/x-www-form-urlencoded; is a different content type?

Even on AJAX uploads it is multipart/form-data; boundary=----WebKitFormBoundarymEFqYry5LXCMK7zN so i think something else if going on with your setup?

@tandraschko
Copy link
Member

short: we need a reproducer

@melloware melloware added Status: Needs Reproducer Needs a reproducer showing the issue and removed 🐞 defect Bug...Something isn't working ‼️ needs-triage Issue needs triaging labels Apr 24, 2024
Copy link

Please provide an executable example using the PrimeFaces Test project. This issue will be closed if no activities in 20 days.

@stolp
Copy link
Contributor Author

stolp commented Apr 25, 2024

There is definitely something different on this single page where the error logging occurs. I have virtual identical code on other pages where it works without a hitch.

I see, if I can isolate a difference for a reproducer.

@stolp
Copy link
Contributor Author

stolp commented Apr 25, 2024

I added a reproducer. As debugged, a simple partial submit is enough to trigger this. My other pages hid the p:fileUpload in a dialog, hence there was no triggering for page interactions.

@tandraschko
Copy link
Member

it works wirth partialSubmit=false?

@stolp
Copy link
Contributor Author

stolp commented Apr 25, 2024

Same result with partialSubmit=false.

@tandraschko
Copy link
Member

tandraschko commented Apr 25, 2024

are you sure that its during rendering? #decode is only called for posts

anyway, i think the "problem" is that if you press your commandButton, the error is logged, which is actually right as you process the fileupload
however the upload works as advanced fileupload deosnt use the h:form here, it creates new formdata etc.

solutions:

  1. dont process the fileupload
  2. reduce logging level and only when Stage = Production, just see it as hint
  3. check for != advanced mode in the IF statement

i would stick for this now, which would give you a hint in dev stage (without return;) but it makes sense actually. You should just not process it.

  public void decode(FacesContext context, UIComponent component) {
       FileUpload fileUpload = (FileUpload) component;
       if (!fileUpload.isDisabled()) {
           if (context.isProjectStage(ProjectStage.Development) && !context.getExternalContext().getRequestContentType().toLowerCase().startsWith("multipart/")) {
               LOGGER.warn(() -> "Decoding FileUpload requires contentType \"multipart/form-data\"." +
                       " ClientId: " + component.getClientId(context));
           }

           PrimeApplicationContext applicationContext = PrimeApplicationContext.getCurrentInstance(context);

           FileUploadDecoder decoder = applicationContext.getFileUploadDecoder();
           decoder.decode(context, fileUpload);
       }
   }

@melloware melloware added enhancement Additional functionality to current component and removed Status: Needs Reproducer Needs a reproducer showing the issue labels Apr 25, 2024
@melloware melloware self-assigned this Apr 25, 2024
@melloware melloware added this to the 14.0.0 milestone Apr 25, 2024
melloware added a commit to melloware/primefaces that referenced this issue Apr 25, 2024
@melloware
Copy link
Member

PR submitted

melloware added a commit to melloware/primefaces that referenced this issue Apr 25, 2024
@stolp
Copy link
Contributor Author

stolp commented Apr 26, 2024

are you sure that its during rendering? #decode is only called for posts

I stand corrected, this is indeed occurring during the execute phase. Got distracted by the class name.

melloware added a commit to melloware/primefaces that referenced this issue Apr 26, 2024
@melloware melloware reopened this May 2, 2024
@melloware melloware added Status: Needs Reproducer Needs a reproducer showing the issue and removed enhancement Additional functionality to current component labels May 2, 2024
Copy link

github-actions bot commented May 2, 2024

Please provide an executable example using the PrimeFaces Test project. This issue will be closed if no activities in 20 days.

@melloware melloware modified the milestones: 14.0.0, 14.0.1 May 2, 2024
@stolp
Copy link
Contributor Author

stolp commented May 2, 2024

This is the stacktrace from the reproducer:

WARNUNG: javax.servlet.ServletException: Unsupported Content-Type [application/x-www-form-urlencoded; charset=UTF-8], expected [multipart/form-data]
javax.faces.FacesException: javax.servlet.ServletException: Unsupported Content-Type [application/x-www-form-urlencoded; charset=UTF-8], expected [multipart/form-data]
	at org.primefaces.component.fileupload.AbstractFileUploadDecoder.decode(AbstractFileUploadDecoder.java:58)
	at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.java:58)
	at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:514)
	at javax.faces.component.UIInput.decode(UIInput.java:798)
	at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:891)
	at javax.faces.component.UIInput.processDecodes(UIInput.java:692)
	at javax.faces.component.UIForm.processDecodes(UIForm.java:197)
	at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:886)
	at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:886)
	at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:1010)
	at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:55)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:177)
	at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:707)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
	at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1450)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656)
	at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:292)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:191)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:516)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:137)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: javax.servlet.ServletException: Unsupported Content-Type [application/x-www-form-urlencoded; charset=UTF-8], expected [multipart/form-data]
	at org.eclipse.jetty.server.Request.getParts(Request.java:2419)
	at org.eclipse.jetty.server.Request.getPart(Request.java:2410)
	at org.primefaces.component.fileupload.NativeFileUploadDecoder.createUploadedFile(NativeFileUploadDecoder.java:64)
	at org.primefaces.component.fileupload.AbstractFileUploadDecoder.decodeAdvanced(AbstractFileUploadDecoder.java:86)
	at org.primefaces.component.fileupload.AbstractFileUploadDecoder.decode(AbstractFileUploadDecoder.java:54)
	... 52 more

Mai 02, 2024 2:57:41 PM com.sun.faces.context.AjaxExceptionHandlerImpl handlePartialResponseError
SCHWERWIEGEND: javax.servlet.ServletException: Unsupported Content-Type [application/x-www-form-urlencoded; charset=UTF-8], expected [multipart/form-data]
	at org.eclipse.jetty.server.Request.getParts(Request.java:2419)
	at org.eclipse.jetty.server.Request.getPart(Request.java:2410)
	at org.primefaces.component.fileupload.NativeFileUploadDecoder.createUploadedFile(NativeFileUploadDecoder.java:64)
	at org.primefaces.component.fileupload.AbstractFileUploadDecoder.decodeAdvanced(AbstractFileUploadDecoder.java:86)
	at org.primefaces.component.fileupload.AbstractFileUploadDecoder.decode(AbstractFileUploadDecoder.java:54)
	at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.java:58)
	at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:514)
	at javax.faces.component.UIInput.decode(UIInput.java:798)
	at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:891)
	at javax.faces.component.UIInput.processDecodes(UIInput.java:692)
	at javax.faces.component.UIForm.processDecodes(UIForm.java:197)
	at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:886)
	at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:886)
	at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:1010)
	at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:55)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:177)
	at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:707)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
	at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1450)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656)
	at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:292)
	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:191)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
	at org.eclipse.jetty.server.Server.handle(Server.java:516)
	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
	at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:137)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
	at java.base/java.lang.Thread.run(Thread.java:1583)

@tandraschko
Copy link
Member

yeah, then we have to put the "return" back

@melloware
Copy link
Member

OK i will put the return back!

@stolp
Copy link
Contributor Author

stolp commented May 2, 2024

Sorry for not testing this earlier.

@melloware
Copy link
Member

It will be in 14.0.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment