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.
As promised ;)
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>
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 ;)
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) ;)
Created attachment 14517 [details] a patch to allow Jasper to resolve external entities located in WEBAPP
if (systemId.startsWith("file:///WEB-INF/")) return new InputSource(ctxt.getResourceAsStream(systemId.substring(7))); -> -1 No surprise here ...
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.
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.
Well if it works, I'm happy with this patch. Will try it Monday. Thanks William
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 :)
Created attachment 14546 [details] Allow jasper to resolve external entities
After Bill and Jan review, a new patch to close this BZ
*** Bug 36284 has been marked as a duplicate of this bug. ***