Skip to content

Commit 927d280

Browse files
committed
DefaultEntityResolver: allow subclasses to register new internal filenames.
1 parent 920ff07 commit 927d280

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

junit/io/sf/carte/doc/xml/dtd/DefaultEntityResolverTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,30 @@ public void resolveNonexistent() {
198198
assertNull(isrc);
199199
}
200200

201+
@Test
202+
public void testRegisterInvalidPathFromSubclass() throws SAXException, IOException {
203+
try {
204+
resolver.registerSystemIdFilename("http://www.example.com/bad.dtd", null);
205+
fail("Must throw an exception.");
206+
} catch (NullPointerException e) {
207+
}
208+
try {
209+
resolver.registerSystemIdFilename(null, "/some/path");
210+
fail("Must throw an exception.");
211+
} catch (NullPointerException e) {
212+
}
213+
try {
214+
resolver.registerSystemIdFilename("http://www.example.com/bad.dtd", "");
215+
fail("Must throw an exception.");
216+
} catch (IllegalArgumentException e) {
217+
}
218+
try {
219+
resolver.registerSystemIdFilename("http://www.example.com/bad.dtd", "/path/to/confidential/stuff");
220+
fail("Must throw an exception.");
221+
} catch (IllegalArgumentException e) {
222+
}
223+
}
224+
201225
@Test
202226
public void testIsInvalidPath() throws SAXException, IOException {
203227
assertTrue(resolver.isInvalidPath(new URL("http://dtd.example.com/etc/passwd").getPath()));

src/io/sf/carte/doc/xml/dtd/DefaultEntityResolver.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.net.URL;
2020
import java.net.URLConnection;
2121
import java.nio.charset.StandardCharsets;
22-
import java.security.AccessControlException;
2322
import java.security.PrivilegedActionException;
2423
import java.util.HashMap;
2524
import java.util.HashSet;
@@ -218,6 +217,46 @@ public InputSource getExternalSubset(String name, String baseURI) throws SAXExce
218217
return null;
219218
}
220219

220+
/**
221+
* Register an internal classpath filename to retrieve a DTD {@code SystemId}.
222+
*
223+
* @param systemId the {@code SystemId}.
224+
* @param filename the internal filename.
225+
* @return {@code true} if the new {@code SystemId} was successfully registered,
226+
* {@code false} if it was already registered.
227+
* @throws IllegalArgumentException if the {@code filename} is considered
228+
* invalid by
229+
* {@link #isInvalidInternalPath(String)}.
230+
*/
231+
protected boolean registerSystemIdFilename(String systemId, String filename) {
232+
if (filename == null || systemId == null) {
233+
throw new NullPointerException("Null SystemId or filename.");
234+
}
235+
if (isInvalidInternalPath(filename)) {
236+
throw new IllegalArgumentException("Bad DTD filename.");
237+
}
238+
String ret;
239+
synchronized (systemIdToFilename) {
240+
ret = systemIdToFilename.putIfAbsent(systemId, filename);
241+
}
242+
return ret == null;
243+
}
244+
245+
/**
246+
* Determine if the given pathname is an invalid internal path.
247+
* <p>
248+
* The pathname must contain {@code /dtd/} and be a valid path according to
249+
* {@link #isInvalidPath(String)}.
250+
* </p>
251+
*
252+
* @param pathname the classpath pathname to check. It is assumed to be
253+
* non-{@code null}.
254+
* @return {@code true} if the pathname is invalid.
255+
*/
256+
protected boolean isInvalidInternalPath(String pathname) {
257+
return isInvalidPath(pathname) || !pathname.contains("/dtd/");
258+
}
259+
221260
@Override
222261
public final InputSource resolveEntity(String name, String publicId, String baseURI, String systemId)
223262
throws SAXException, IOException {
@@ -296,6 +335,15 @@ private String getSystemIdFromPublicId(String publicId) {
296335
return null;
297336
}
298337

338+
/**
339+
* Determine if the given path is considered invalid for a DTD.
340+
* <p>
341+
* To be valid, must end with {@code .dtd}, {@code .ent} or {@code .mod}.
342+
* </p>
343+
*
344+
* @param path the path to check.
345+
* @return {@code true} if the path is invalid for a DTD, {@code false} otherwise.
346+
*/
299347
protected boolean isInvalidPath(String path) {
300348
int len = path.length();
301349
String ext;
@@ -314,6 +362,9 @@ protected boolean isWhitelistEnabled() {
314362

315363
/**
316364
* Is the given protocol not supported by this resolver ?
365+
* <p>
366+
* Only {@code http} and {@code https} are valid.
367+
* </p>
317368
*
318369
* @param protocol
319370
* the protocol.
@@ -411,8 +462,7 @@ private Reader loadDTDfromClasspath(final String dtdFilename) {
411462
buf.append('/').append(pkgPath).append('/').append(dtdFilename);
412463
resPath = buf.toString();
413464
} else {
414-
// All filenames must be relative
415-
throw new AccessControlException("Attempt to read " + dtdFilename);
465+
resPath = dtdFilename;
416466
}
417467
InputStream is = java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<InputStream>() {
418468
@Override

0 commit comments

Comments
 (0)