[SERVLET_SPEC-57] Add getFileName() method to javax.servlet.http.Part Created: 18/Feb/13  Updated: 01/Mar/13  Resolved: 01/Mar/13

Status: Resolved
Project: servlet-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Nick Williams Assignee: Shing Wai Chan
Resolution: Fixed Votes: 3
Labels: None
Remaining Estimate: 2 hours
Time Spent: Not Specified
Original Estimate: 2 hours
Environment:

All


Tags: HttpServletRequest, Part, file_upload, filename

 Description   

The javax.servlet.http.Part interface lacks a method for retrieving the file name of a part. Most request parts have file names, typically provided by the client's browser as the name of the file on the client's file system when the file is uploaded through the form submission. Currently, consumers of Part must create their own method to extract the file name:

public static String getFileName(Part filePart)
{
    String header = filePart.getHeader("content-disposition");
    for(String headerPart : header.split(";"))
    {
        if(headerPart.trim().startsWith("filename"))
        {
            return headerPart.substring(headerPart.indexOf('=') + 1).trim()
                             .replace("\"", "");
        }
    }
    return null;
}

Tomcat, as an example, already has a method to extract the file name in its Part implementation, but since it is not exposed via the public Part interface developers cannot use it without limiting the portability of their applications. It's possible other containers already do something similar.

The suggested getFileName() method should:

  • Locate the Content-Disposition header from the Part. If no such header exists, return null.
  • Extract the filename attribute from the Content-Disposition header and return its value trimmed.
  • If no filename attribute exists or the filename attribute value is null, return null.
  • Not throw any exceptions.

Estimate 5 minutes to add the method to the interface and < 2 hours to add relevant documentation regarding the method to the spec.



 Comments   
Comment by Nick Williams [ 18/Feb/13 ]

Note that the sample code submitted does not follow the second part of rule 1, "If no such header exists, return null." A more stable implementation would be:

public static String getFileName(Part filePart)
{
    String header = filePart.getHeader("content-disposition");
    if(header == null)
        return null;
    for(String headerPart : header.split(";"))
    {
        if(headerPart.trim().startsWith("filename"))
        {
            return headerPart.substring(headerPart.indexOf('=') + 1).trim()
                             .replace("\"", "");
        }
    }
    return null;
}

Of course, this is merely a sample implementation, and container developers are free to implement the spec in their own way.

Comment by carojkov [ 18/Feb/13 ]

I'd like to propose a method name that clearly states that this is a file name specified by the client. e.g. getClientFileName(). getRequestedFileName() or getSubmittedFileName(). This should help avoid confusion if/when it's decided if adding another get*File() method to the Part is needed. i.e. getFile() returning File after a call to Part#write(String) method.

Comment by Nick Williams [ 18/Feb/13 ]

I agree. I prefer getSubmittedFileName(). Seems the most applicable, as that's exactly what it is: nothing more or less than the submitted file name.

Comment by markt_asf [ 18/Feb/13 ]

+1

Comment by Nick Williams [ 20/Feb/13 ]

By the way, Mark, if this gets accepted for 3.1 I'll implement it in Tomcat. Should just be a matter of adding the method to the interface and then implementing the method in ApplicationPart to wrap ApplicationPart#getFilename().

Comment by Shing Wai Chan [ 01/Mar/13 ]

Add a method Part#getSubmittedFileName

Sending src/main/java/javax/servlet/http/Part.java
Transmitting file data .
Committed revision 59926.





[JAVASERVERFACES_SPEC_PUBLIC-1206] required attribute is not enforced for inputFile Created: 08/Jul/13  Updated: 13/Aug/14

Status: Open
Project: javaserverfaces-spec-public
Component/s: Components/Renderers
Affects Version/s: 2.2
Fix Version/s: None

Type: Bug Priority: Major
Reporter: jasonzhang2002gmailcom Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

glassfish 4.0, Firefox


Issue Links:
Related
is related to JAVASERVERFACES-2923 required attribute is not enforced fo... Closed
Tags: file, file_upload, require

 Description   

When I select file at browser or not, I always have a part at server side. If no file is selected, the Part.size is zero.



 Comments   
Comment by Manfred Riem [ 08/Jul/13 ]

Can you please supply an example that reproduces the problem?

Comment by jasonzhang2002gmailcom [ 09/Jul/13 ]

This can be reproduced easily.


@RequestScoped
@Named
public class Test
{
	Part file;
	String str;
	public String getStr()
	{
		return str;
	}
	public void setStr(String str)
	{
		this.str = str;
	}
	public Part getFile()
	{
		return file;
	}
	public void setFile(Part file)
	{
		this.file = file;
	}
	public String save()
	{
		System.out.println("save is called");
		return null;
	}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:f="http://xmlns.jcp.org/jsf/core"
	xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
	
<h:body>
	<h:messages>
	</h:messages>
	<h:form enctype="multipart/form-data">
		<h:inputFile value="#{test.file}" id="file" required="true"></h:inputFile>
		<h:inputText value="#{test.str}" id="string" required="true"></h:inputText>
		<h:commandButton value="submit" action="#{test.save}">
		</h:commandButton>
	</h:form>
</h:body>
</html>
Comment by Ed Burns [ 09/Jul/13 ]

Manfred and I investigated this and determined that UIInput.isEmpty() doesn't correctly handle this case when there is a Part that is empty.

UIInput.isEmpty() was added in support of JAVASERVERFACES_SPEC_PUBLIC-426.

Comment by Ed Burns [ 01/Aug/14 ]

Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.





[JAVASERVERFACES-2923] required attribute is not enforced for inputFile Created: 09/Jul/13  Updated: 17/Jul/13  Resolved: 17/Jul/13

Status: Closed
Project: javaserverfaces
Component/s: None
Affects Version/s: 2.2.0, 2.2.1
Fix Version/s: 2.2.2

Type: Bug Priority: Major
Reporter: jasonzhang2002gmailcom Assignee: Manfred Riem
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

glassfish 4.0, Firefox


Attachments: Text File changebundle.txt     Text File changebundle.txt     Zip Archive newfiles.zip    
Issue Links:
Related
is related to JAVASERVERFACES_SPEC_PUBLIC-1206 required attribute is not enforced fo... Open
Tags: file, file_upload, require

 Description   

When I select file at browser or not, I always have a part at server side. If no file is selected, the Part.size is zero.



 Comments   
Comment by Manfred Riem [ 10/Jul/13 ]

Applied to 2.2 branch,

svn commit -m "Fixes https://java.net/jira/browse/JAVASERVERFACES-2923, r=rogerk, make sure the required attribute on h:inputFile works"
Sending jsf-ri\src\main\java\com\sun\faces\renderkit\html_basic\FileRenderer.java
Deleting test\agnostic\facelets\html\nb-configuration.xml
Sending test\agnostic\facelets\html\pom.xml
Adding test\agnostic\facelets\html\src\main\resources
Adding test\agnostic\facelets\html\src\main\webapp\inputFileRequired.xhtml
Adding test\agnostic\facelets\html\src\test\java\com\sun\faces\test\agnostic\facelets\html\Issue2923IT.java
Transmitting file data ....
Committed revision 12080.

Comment by Manfred Riem [ 15/Jul/13 ]

Investigate problem with Tomcat

Comment by Manfred Riem [ 17/Jul/13 ]

Applied to 2.2 branch,

svn commit -m "Fixes https://java.net/jira/browse/JAVASERVERFACES-2923, make sure the test does not rely on CDI"
Sending test\agnostic\facelets\html\src\main\java\com\sun\faces\test\agnostic\facelets\html\FileUploadBean.java
Deleting test\agnostic\facelets\html\src\main\webapp\WEB-INF\beans.xml
Sending test\agnostic\facelets\html\src\main\webapp\inputFileRequired.xhtml
Transmitting file data ..
Committed revision 12112.





[JAVASERVERFACES-2845] h:inputFile Ajax Fails. Request not recognized as multipart/form-data. Created: 13/Apr/13  Updated: 14/Jun/13  Resolved: 14/Jun/13

Status: Closed
Project: javaserverfaces
Component/s: ajax, expression language, facelets, managed bean, renderkit, validation
Affects Version/s: 2.2.0-m09, 2.2.0-m10, 2.2.0-m11, 2.2.0-m12, 2.2.0-m13
Fix Version/s: None

Type: Bug Priority: Major
Reporter: ericying Assignee: rogerk
Resolution: Cannot Reproduce Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

JDK 1.7.0_17, Mac OS 10.8.3, GlassFish 3.1.2.2, WebKit and Mozilla


Tags: ajax, file_upload, multipart

 Description   

Ajax file upload with h:inputFile fails with pop-up warning (in development mode).

serverError: class javax.servlet.ServletException The request content-type is not a multipart/form-data

Console logs and exception:
javax.faces.FacesException: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at com.sun.faces.renderkit.html_basic.FileRenderer.decode(FileRenderer.java:97)
at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:842)
at javax.faces.component.UIInput.decode(UIInput.java:771)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1234)
at javax.faces.component.UIInput.processDecodes(UIInput.java:676)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:535)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1680)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1691)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1691)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1691)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:395)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:259)
at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:927)
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:181)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:645)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at org.apache.catalina.fileupload.Multipart.getParts(Multipart.java:176)
at org.apache.catalina.connector.Request.getParts(Request.java:4085)
at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1116)
at com.sun.faces.renderkit.html_basic.FileRenderer.decode(FileRenderer.java:87)
... 42 more

WARNING: javax.faces.FacesException: javax.servlet.ServletException: The request content-type is not a multipart/form-data
javax.faces.FacesException: javax.faces.FacesException: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:927)
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:181)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:645)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.faces.FacesException: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at com.sun.faces.renderkit.html_basic.FileRenderer.decode(FileRenderer.java:97)
at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:842)
at javax.faces.component.UIInput.decode(UIInput.java:771)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1234)
at javax.faces.component.UIInput.processDecodes(UIInput.java:676)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:535)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1680)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1691)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1691)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1691)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:395)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:259)
... 29 more
Caused by: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at org.apache.catalina.fileupload.Multipart.getParts(Multipart.java:176)
at org.apache.catalina.connector.Request.getParts(Request.java:4085)
at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1116)
at com.sun.faces.renderkit.html_basic.FileRenderer.decode(FileRenderer.java:87)
... 42 more



 Comments   
Comment by ericying [ 13/Apr/13 ]

Simple facelet and backing bean to reproduce:

<!-- index.xhtml -->
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Ajax Multi-Part Test</title>
</h:head>
<h:body>
<h:form enctype="multipart/form-data">
Ajax-updated Integer
<h:inputText value="#

{testBean.someInteger}" id="integerId">
<f:ajax render="@form" />
</h:inputText>
<h:message for="integerId"/><br/>
Current Value #{testBean.someInteger}

<p/>

Ajax-updated String
<h:inputText value="#

{testBean.someString}" id="stringId">
<f:ajax render="@form" />
</h:inputText>
<h:message for="stringId"/><br/>
Current Value #{testBean.someString}

<p/>

<h:inputFile value="#

{testBean.someImage}

" id="imageId">
<f:ajax execute="imageId" render="@form" />
</h:inputFile>
</h:form>
</h:body>
</html>

          • Backing Bean ******

package ajaxtest;

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import javax.servlet.http.Part;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@ManagedBean
@SessionScoped
public class TestBean implements Serializable {
private static final long serialVersionUID = 1L;

@NotNull
@Min(5)
private Integer someInteger;

@NotNull
@Size(min = 5, max = 10)
private String someString;

private Part someImage;

public Integer getSomeInteger()

{ return someInteger; }

public void setSomeInteger(Integer someInteger)

{ this.someInteger = someInteger; }

public String getSomeString()

{ return someString; }

public void setSomeString(String someString)

{ this.someString = someString; }

public void setSomeImage(Part someImage)

{ this.someImage = someImage; }

public Part getSomeImage()

{ return someImage; }

}

Comment by rogerk [ 17/May/13 ]

I am unable to reproduce the error you are seeing working off the code you included in the issue.
Can you send a war (with exact sources) to iassues@javaserverfaces list?

Comment by rogerk [ 14/Jun/13 ]

I am unable to reproduce this issue. If you still experience problems please file a new issue.
Thanks.





Generated at Wed Feb 22 07:49:31 UTC 2017 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.