1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
package nokogiri.internals;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import nokogiri.internals.ParserContext.Options;
import org.jruby.Ruby;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.EntityResolver2;
/**
* An entity resolver aware of the fact that the Ruby runtime can
* change directory but the JVM cannot. Thus any file based
* entity resolution that uses relative paths must be translated
* to be relative to the current directory of the Ruby runtime.
*/
public class NokogiriEntityResolver implements EntityResolver2
{
protected final Ruby runtime;
private final NokogiriErrorHandler handler;
private final Options options;
public
NokogiriEntityResolver(Ruby runtime, NokogiriErrorHandler handler, Options options)
{
super();
this.runtime = runtime;
this.handler = handler;
this.options = options;
}
@Override
public InputSource
getExternalSubset(String name, String baseURI)
throws SAXException, IOException
{
return null;
}
@Override
public InputSource
resolveEntity(String publicId, String systemId)
throws SAXException, IOException
{
return resolveEntity(runtime, null, publicId, null, systemId);
}
@Override
public InputSource
resolveEntity(String name,
String publicId,
String baseURI,
String systemId)
throws SAXException, IOException
{
return resolveEntity(runtime, name, publicId, baseURI, systemId);
}
private static File
join(String parent, String child)
{
if (new File(parent).isFile()) {
parent = new File(parent).getParent();
}
return new File(parent, child);
}
private static InputSource
emptyInputSource(InputSource source)
{
source.setByteStream(new ByteArrayInputStream(new byte[0]));
return source;
}
private boolean
shouldLoadDtd()
{
return options.dtdLoad || options.dtdValid;
}
private void
addError(String errorMessage)
{
if (handler != null) { handler.addError(new Exception(errorMessage)); }
}
/**
* Create a file base input source taking into account the current
* directory of <code>runtime</code>.
* @throws SAXException
*/
protected InputSource
resolveEntity(Ruby runtime, String name, String publicId, String baseURI, String systemId)
throws IOException, SAXException
{
InputSource s = new InputSource();
if (name.equals("[dtd]") && !shouldLoadDtd()) {
return emptyInputSource(s);
} else if (!name.equals("[dtd]") && !options.noEnt) {
return emptyInputSource(s);
}
String adjustedSystemId;
URI uri = URI.create(systemId);
if (options.noNet && uri.getHost() != null) {
addError("Attempt to load network entity " + systemId);
return emptyInputSource(s);
}
// if this is a url or absolute file name then use it
if (uri.isAbsolute() && !uri.isOpaque()) {
adjustedSystemId = uri.toURL().toString();
} else if (new File(uri.getPath()).isAbsolute()) {
adjustedSystemId = uri.getPath();
} else if (baseURI != null) {
URI baseuri = URI.create(baseURI);
if (options.noNet && baseuri.getHost() != null) {
addError("Attempt to load network entity " + systemId);
return emptyInputSource(s);
}
if (baseuri.getHost() == null) {
// this is a local file
adjustedSystemId = join(baseuri.getPath(), uri.getPath()).getCanonicalPath();
} else {
// this is a url, then resolve uri using baseuri
adjustedSystemId = baseuri.resolve(systemId).toURL().toString();
}
} else {
// baseURI is null we have to use the current working directory to resolve the entity
String pwd = runtime.getCurrentDirectory();
adjustedSystemId = join(pwd, uri.getPath()).getCanonicalPath();
}
s.setSystemId(adjustedSystemId);
s.setPublicId(publicId);
return s;
}
}
|