Bug in DTD catalog resolution

Hi folks,

As it stands, the "in-JAR" DTD catalog works fine when the checker is 
run from the command-line, but the checker fails to resolve well-known 
DTDs when the JAR is imported in a JSP page (at least using Jigsaw, it 
may work with other Web servers)

The problem lies in the ExtendedCatalogResolver class and in particular 
in the resolveEntity method. The call to "delegate.resolveEntity" fails 
because for some reason the mapping to an "in-JAR" file doesn't work in 
that case. It fails to resolve something like "[file path to mobileOK 
jar]/dtd/whatever", which should fetch the file in the JAR. I don't know 
why, I'm just seeing it doesn't work...

The subsequent lines of codes in the resolveEntity method seem to be 
willing to handle a similar case (where the systemId would already be a 
local file), but does not cover this one, because the only way to enter 
the loop is to have a systemId that already starts with "file://". It 
could easily be adapted to handle this more generic case.

My proposed patch for ExtendedCatalogResolver.resolveEntity:

public InputSource resolveEntity(final String publicId, String systemId) 
throws IOException {
  InputSource source = delegate.resolveEntity(publicId, systemId);
  if (source == null) {
   if (!systemId.startsWith("file://")) {
    systemId = delegate.getCatalog().resolveSystem(systemId);
   }
   if (systemId != null) {
    if (!systemId.startsWith("file:///")) {
     systemId = "file:///" + systemId.substring(7);
    }
    try {
     source = new InputSource(new URL(systemId).openStream());
    } catch (FileNotFoundException fnfe) {
     final String resourceName = getResourceFromAbsoluteFilename(systemId);
     final InputStream is = getClass().getResourceAsStream("/" + 
resourceName);
     source = new InputSource(is);
    }
    source.setSystemId(systemId);
    source.setPublicId(publicId);
   }
  }
  return source;
}


The only changed lines are at the beginning of the inner loop:
  if (source == null) {
   if (!systemId.startsWith("file://")) {
    systemId = delegate.getCatalog().resolveSystem(systemId);
   }

instead of:
  if (source == null && systemId.startsWith("file://")) {

Note that I'm not crazy about this patch as the case is handled by the 
"catch" line, so that means using exceptions as regular code flow... not 
really a good practice. Anything better?

Also note that's not related to the failures that occur when the checker 
doesn't have a DTD in its catalog, it's really about being able to read 
an existing file in the catalog when the JAR is imported in a JSP page.

François.

Received on Wednesday, 19 March 2008 16:44:18 UTC