Bug 34034

Summary: Jasper didn't respect external entities
Product: Tomcat 5 Reporter: Henri Gomez <hgomez>
Component: JasperAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal CC: paul4christ79
Priority: P2    
Version: Nightly Build   
Target Milestone: ---   
Hardware: Other   
OS: other   
Attachments: a patch to allow Jasper to resolve external entities located in WEBAPP
Allow jasper to resolve external entities

Description Henri Gomez 2005-03-16 14:57:01 UTC
While converting my apps from Tomcat 3.3.x to Tomcat 5.5.x, I discovered a
serious bug in Jasper.

My web.xml is :

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" [ 
    
<!ENTITY base      SYSTEM "base.xml">

]>

<web-app>

...
&base.xml;

</web-app>


Tomcat 5.0.30 and 5.5.8 have no problem in loading web.xml at startup, they
resolve since the base.xml external entity file is local to the WAR.

But jasper when it tried to compile it's first JSP fail with message :


Etat HTTP 500 -

type Rapport d'exception

message

description Le serveur a rencontré une erreur interne () qui l'a
empêché de satisfaire la requête.

exception

org.apache.jasper.JasperException: Erreur d'évaluation XML sur le
fichier /WEB-INF/web.xml
      
org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:113)
       org.apache.jasper.compiler.JspConfig.processWebDotXml(JspConfig.java:70)
       org.apache.jasper.compiler.JspConfig.init(JspConfig.java:188)
       org.apache.jasper.compiler.JspConfig.findJspProperty(JspConfig.java:240)
       org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:103)
       org.apache.jasper.compiler.Compiler.compile(Compiler.java:286)
       org.apache.jasper.compiler.Compiler.compile(Compiler.java:267)
       org.apache.jasper.compiler.Compiler.compile(Compiler.java:255)
      
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:556)
      
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:296)
       org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:291)
       org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
       javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

cause mère

java.io.FileNotFoundException: C:\eclipse3\base.xml (Le fichier
spécifié est introuvable)
       java.io.FileInputStream.open(Native Method)
       java.io.FileInputStream.<init>(FileInputStream.java:106)
       java.io.FileInputStream.<init>(FileInputStream.java:66)
      
sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:69)
      
sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:156)
       org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
       org.apache.xerces.impl.XMLEntityManager.startEntity(Unknown Source)
       org.apache.xerces.impl.XMLEntityManager.startEntity(Unknown Source)
      
org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEntityReference(Unknown
Source)
      
org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
Source)
       org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
Source)
       org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
       org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
       org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
       org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
       org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
       javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
       org.apache.jasper.xmlparser.ParserUtils.parseXMLDocument(ParserUtils.java:98)
       org.apache.jasper.compiler.JspConfig.processWebDotXml(JspConfig.java:70)
       org.apache.jasper.compiler.JspConfig.init(JspConfig.java:188)
       org.apache.jasper.compiler.JspConfig.findJspProperty(JspConfig.java:240)
       org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:103)
       org.apache.jasper.compiler.Compiler.compile(Compiler.java:286)
       org.apache.jasper.compiler.Compiler.compile(Compiler.java:267)
       org.apache.jasper.compiler.Compiler.compile(Compiler.java:255)
      
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:556)
      
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:296)
       org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:291)
       org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
       javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

note La trace complète de la cause mère de cette erreur est disponible
dans les fichiers journaux de Apache Tomcat/5.5.8.

It seems that Jasper didn't use the WEBAPP path but start from my environnement
path, in my case eclipse3, c:\eclipse3, which is bad.
Comment 1 Remy Maucherat 2005-03-16 15:00:15 UTC
As promised ;)
Comment 2 Henri Gomez 2005-03-16 15:02:33 UTC
Reread xml spec, nothing prevent us to use external entities like this.
Also external entities are invalid when outside webapp, it's not the case here.

You should read :

My web.xml is :

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" [ 
    
<!ENTITY base      SYSTEM "base.xml">

]>

<web-app>

...
&base;

</web-app>

Comment 3 Remy Maucherat 2005-03-16 15:04:26 UTC
Webapps are not necessarily filesystem based. As a result, that kind of little
tricks are not portable, and cannot be supported. As you know, I am very
efficient at marking reports invalid ;)
Comment 4 Remy Maucherat 2005-03-16 15:16:32 UTC
Actually, I just saw it maybe can work even when not filesystem based:
                if (altDDName != null) {
                    url = new File(altDDName).toURL();
                } else {
                    url = servletContext.getResource(
                                                Constants.ApplicationWebXml);
                }
                if( url!=null ) {
                    InputSource is = new InputSource(url.toExternalForm());
                    is.setByteStream(stream);

I still really don't care about the issue, but my big issue with this might go away.

This might teach people that it's not a good idea to bug me about something I
don't care about all morning long (some people you might not know about may have
gotten the same idea at the same time) ;)
Comment 5 Henri Gomez 2005-03-18 14:47:36 UTC
Created attachment 14517 [details]
a patch to allow Jasper to resolve external entities located in WEBAPP
Comment 6 Remy Maucherat 2005-03-18 16:05:36 UTC
if (systemId.startsWith("file:///WEB-INF/"))
  return new InputSource(ctxt.getResourceAsStream(systemId.substring(7)));

-> -1
No surprise here ...
Comment 7 Henri Gomez 2005-03-18 16:15:27 UTC
It's a trick :

if (systemId.startsWith("file:///WEB-INF/"))
  return new InputSource(ctxt.getResourceAsStream(systemId.substring(7)));

XML parser have a pseudo root origine set to /WEB-INF/ and as such you get the
systemId filed with 'file:///WEB-INF/whatever.xml' when you have defined a
<ENTITY what SYSTEM "whatever.xml">

With the substring 7 we remove the "file:////" and as such get
"/WEB-INF/whatever.xml" from ServletContext via getResourceAsStream.

So it should works EVEN if the webapp is not file based.

I do that to respect WHAT YOU REQUIRED, ie no InputSource from a File, just from
a resource.

Comment 8 william.barker 2005-03-18 20:17:32 UTC
It should be enough to do (in JspConfig):
  URL uri = ctcx.getResource(WEB_XML);
  InputSource ip = new InputSource(uri.openStream());
  ip.setSystemId(uri.toExternalForm());

and leave the EntityResolver alone.  Between Xerces and o.a.naming they can 
work out the relative Entity references.



Comment 9 Henri Gomez 2005-03-19 10:36:22 UTC
Well if it works, I'm happy with this patch.

Will try it Monday.

Thanks William
Comment 10 Henri Gomez 2005-03-19 11:09:49 UTC
Couldn't wait monday.

Ok it seems to works.

Resolver get a systemId : jndi:/localhost/webappname/WEB-INF/app.xml

And it works.

Only got in System.out :

19 mars 2005 11:06:49 org.apache.jasper.xmlparser.MyEntityResolver resolveEntity
GRAVE: PUBLIC ID invalide: null
19 mars 2005 11:06:57 org.apache.jasper.xmlparser.MyEntityResolver resolveEntity
GRAVE: PUBLIC ID invalide: null
19 mars 2005 11:06:59 org.apache.jasper.xmlparser.MyEntityResolver resolveEntity
GRAVE: PUBLIC ID invalide: null
19 mars 2005 11:07:00 org.apache.jasper.xmlparser.MyEntityResolver resolveEntity
GRAVE: PUBLIC ID invalide: null
19 mars 2005 11:07:02 org.apache.jasper.xmlparser.MyEntityResolver resolveEntity
GRAVE: PUBLIC ID invalide: null


So a simpler patch could be commited :)
Comment 11 Henri Gomez 2005-03-23 15:36:00 UTC
Created attachment 14546 [details]
Allow jasper to resolve external entities
Comment 12 Henri Gomez 2005-03-23 15:36:55 UTC
After Bill and Jan review, a new patch to close this BZ
Comment 13 william.barker 2005-08-20 21:31:37 UTC
*** Bug 36284 has been marked as a duplicate of this bug. ***