Skip to content

Commit

Permalink
fix: resolve relative URIs against their base
Browse files Browse the repository at this point in the history
- re-implement the `PathUtil` class to fix various URI resolution issues
- remove the 3-arg `resolveRelativeReference` method
- systematically resolve URI references in Content Documents against the
  base URI
- the base URI is initially set to the document path, and overriden with
  `xml:base` attributes or HTML’s `base` element
- add more exhaustive tests for URI normalization/resolution logic

What this PR doesn’t do:

- cleanup the many uses of paths strings, where we should really use URIs.
  The `PathUtil` code is mostly a hack, when we should rely on more robust
  URI normalization/resolution logic from URIs.
- implement proper base resolution logic (`xml:base` should be deprecated,
  and only the first `base` element should be taken into account).
  See also w3c/epub-specs#1217.

Fixes #527
  • Loading branch information
rdeltour committed Jan 22, 2019
1 parent 0ed1ce3 commit a84e08c
Show file tree
Hide file tree
Showing 27 changed files with 704 additions and 175 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/adobe/epubcheck/css/CSSHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ else if (propertyName.equals("src"))
if (construct.getType() == CssConstruct.Type.URI)
{
fontUri = ((CssURI) construct).toUriString();
fontUri = PathUtil.resolveRelativeReference(path, fontUri, null);
fontUri = PathUtil.resolveRelativeReference(path, fontUri);
//check font mimetypes
String fontMimeType = xrefChecker.getMimeType(fontUri);
if (fontMimeType != null)
Expand Down Expand Up @@ -307,7 +307,7 @@ private void resolveAndRegister(String relativeRef, int line, int col, String co
{
if (relativeRef != null && relativeRef.trim().length() > 0)
{
String resolved = PathUtil.resolveRelativeReference(path, relativeRef, null);
String resolved = PathUtil.resolveRelativeReference(path, relativeRef);
xrefChecker.registerReference(path, line + startingLineNumber, col, resolved, XRefChecker.Type.GENERIC);
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/adobe/epubcheck/ctc/EpubCSSCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ static String getEntryFileName(ManifestItem itemEntry, EpubPackage epack)
String fileToParse;
if (epack.getPackageMainPath() != null && epack.getPackageMainPath().length() > 0)
{
fileToParse = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), itemEntry.getHref(), null);
fileToParse = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), itemEntry.getHref());
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public boolean validate()
continue;
}

imageFile = PathUtil.resolveRelativeReference(fileToParse, imageFile, null);
imageFile = PathUtil.resolveRelativeReference(fileToParse, imageFile);
int index = imageFile.lastIndexOf("#");
if (index > 0)
{
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/adobe/epubcheck/ctc/EpubNCXCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private void checkNcxDoc(String navDocEntry)
}
try
{
path = PathUtil.resolveRelativeReference(navDocEntry, path, null);
path = PathUtil.resolveRelativeReference(navDocEntry, path);
}
catch (IllegalArgumentException ex)
{
Expand Down Expand Up @@ -176,7 +176,7 @@ private void checkNcxDoc(String navDocEntry)
if (mi != null)
{
String path = mi.getHref();
path = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), path, null);
path = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), path);

if (path != null && !path.equals(tocFileName) && !path.equals(navDocEntry) && !tocLinkSet.contains(path))
{
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/adobe/epubcheck/ctc/EpubNavCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public boolean validate()
String fileToParse;
if (epack.getPackageMainPath() != null && epack.getPackageMainPath().length() > 0)
{
fileToParse = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), navDoc, null);
fileToParse = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), navDoc);
}
else
{
Expand Down Expand Up @@ -155,7 +155,7 @@ private boolean checkNavDoc(String navDocEntry)
{
path = href.substring(0, hash);
}
path = PathUtil.resolveRelativeReference(navDocEntry, path, null);
path = PathUtil.resolveRelativeReference(navDocEntry, path);

if (!path.equals("") && !tocLinkSet.contains(path))
{
Expand Down Expand Up @@ -194,7 +194,7 @@ else if (type.equals("landmarks"))
if (mi != null)
{
String path = mi.getHref();
path = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), path, null);
path = PathUtil.resolveRelativeReference(epack.getPackageMainFile(), path);

if (path != null && !path.equals(tocFileName) && !path.equals(navDocEntry) && !tocLinkSet.contains(path))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public String getManifestItemFileName(String entryName)

if (this.getPackageMainPath() != null && this.getPackageMainPath().length() > 0)
{
fileToParse = PathUtil.resolveRelativeReference(this.getPackageMainFile(), entryName, null);
fileToParse = PathUtil.resolveRelativeReference(this.getPackageMainFile(), entryName);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private void processRef(String ref)
{
if (ref != null && context.xrefChecker.isPresent())
{
ref = PathUtil.resolveRelativeReference(path, ref, null);
ref = PathUtil.resolveRelativeReference(path, ref);
context.xrefChecker.get().registerReference(path, parser.getLineNumber(),
parser.getColumnNumber(), ref, Type.SEARCH_KEY);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ else if (name.equals("img"))
if (href != null)
{
// TODO check if dtbook uses xml:base of so set third param
href = PathUtil.resolveRelativeReference(path, href, null);
href = PathUtil.resolveRelativeReference(path, href);
xrefChecker.registerReference(path, parser.getLineNumber(), parser.getColumnNumber(), href,
name.equals("img") ? XRefChecker.Type.IMAGE : XRefChecker.Type.HYPERLINK);
URI uri = checkURI(href);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/adobe/epubcheck/ncx/NCXHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void startElement()
String href = e.getAttribute("src");
if (href != null)
{
href = PathUtil.resolveRelativeReference(path, href, null);
href = PathUtil.resolveRelativeReference(path, href);
if (href.startsWith("http:"))
{
parser.getReport().info(path, FeatureEnum.REFERENCE, href);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/adobe/epubcheck/opf/OPFHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ else if (name.equals("item"))
{
try
{
href = PathUtil.resolveRelativeReference(path, href, null);
href = PathUtil.resolveRelativeReference(path, href);
} catch (IllegalArgumentException ex)
{
report
Expand Down Expand Up @@ -333,7 +333,7 @@ else if (name.equals("reference"))
{
try
{
href = PathUtil.resolveRelativeReference(path, href, null);
href = PathUtil.resolveRelativeReference(path, href);
context.xrefChecker.get().registerReference(path, parser.getLineNumber(),
parser.getColumnNumber(), href, XRefChecker.Type.GENERIC);
} catch (IllegalArgumentException ex)
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ private void processLink(XMLElement e)
{
try
{
href = PathUtil.resolveRelativeReference(path, href, null);
href = PathUtil.resolveRelativeReference(path, href);
} catch (IllegalArgumentException ex)
{
report.message(MessageId.OPF_010,
Expand Down
30 changes: 16 additions & 14 deletions src/main/java/com/adobe/epubcheck/ops/OPSHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,8 @@ int getColumnNumber()
}
}

/**
* null unless head/base or xml:base is given
*/
protected URI base;

protected String base;
protected String baseScheme;
protected final ValidationContext context;
protected final XMLParser parser;
protected final String path;
Expand All @@ -100,6 +97,7 @@ public OPSHandler(ValidationContext context, XMLParser parser)
{
this.context = context;
this.path = context.path;
this.base = path;
this.xrefChecker = context.xrefChecker;
this.report = context.report;
this.parser = parser;
Expand All @@ -111,7 +109,7 @@ protected void checkPaint(XMLElement e, String attr)
if (xrefChecker.isPresent() && paint != null && paint.startsWith("url(") && paint.endsWith(")"))
{
String href = paint.substring(4, paint.length() - 1);
href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString());
href = PathUtil.resolveRelativeReference(base, href);
xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(),
href, XRefChecker.Type.SVG_PAINT);
}
Expand All @@ -122,7 +120,7 @@ protected void checkImage(XMLElement e, String attrNS, String attr)
String href = e.getAttributeNS(attrNS, attr);
if (xrefChecker.isPresent() && href != null)
{
href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString());
href = PathUtil.resolveRelativeReference(base, href);
xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(),
href, XRefChecker.Type.IMAGE);
}
Expand All @@ -133,7 +131,7 @@ protected void checkObject(XMLElement e, String attrNS, String attr)
String href = e.getAttributeNS(attrNS, attr);
if (xrefChecker.isPresent() && href != null)
{
href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString());
href = PathUtil.resolveRelativeReference(base, href);
xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(),
href, XRefChecker.Type.OBJECT);
}
Expand All @@ -146,7 +144,7 @@ protected void checkLink(XMLElement e, String attrNS, String attr)
if (xrefChecker.isPresent() && href != null && rel != null
&& rel.toLowerCase(Locale.ROOT).contains("stylesheet"))
{
href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString());
href = PathUtil.resolveRelativeReference(base, href);
xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(),
href, XRefChecker.Type.STYLESHEET);

Expand Down Expand Up @@ -189,7 +187,7 @@ protected void checkSymbol(XMLElement e, String attrNS, String attr)
String href = e.getAttributeNS(attrNS, attr);
if (xrefChecker.isPresent() && href != null)
{
href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString());
href = PathUtil.resolveRelativeReference(base, href);
xrefChecker.get().registerReference(path, parser.getLineNumber(), parser.getColumnNumber(),
href, XRefChecker.Type.SVG_SYMBOL);
}
Expand Down Expand Up @@ -245,7 +243,7 @@ else if (".".equals(href))
* solution to issue 155
*/
if (URISchemes.contains(uri.getScheme())
|| (null != base && URISchemes.contains(base.getScheme())))
|| (null != base && URISchemes.contains(baseScheme)))
{
return;
}
Expand All @@ -260,7 +258,7 @@ else if (uri.getScheme() != null)

try
{
href = PathUtil.resolveRelativeReference(path, href, base == null ? null : base.toString());
href = PathUtil.resolveRelativeReference(base, href);
} catch (IllegalArgumentException err)
{
report.message(MessageId.OPF_010,
Expand Down Expand Up @@ -299,7 +297,9 @@ public void startElement()
String baseTest = e.getAttributeNS(XMLConstants.XML_NS_URI, "base");
if (baseTest != null)
{
base = checkURI(baseTest);
URI baseURI = checkURI(baseTest);
baseScheme = baseURI.getScheme();
base = PathUtil.resolveRelativeReference(path, baseURI.toString());
}

if (!epubTypeInUse)
Expand Down Expand Up @@ -366,7 +366,9 @@ else if (name.equals("link"))
}
else if (name.equals("base"))
{
base = checkURI(e.getAttribute("href"));
URI baseURI = checkURI(e.getAttribute("href"));
baseScheme = baseURI.getScheme();
base = PathUtil.resolveRelativeReference(path, baseURI.toString());
}
else if (name.equals("style"))
{
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ protected void processVideo(XMLElement e)
String posterMimeType = null;
if (xrefChecker.isPresent() && posterSrc != null)
{
posterMimeType = xrefChecker.get().getMimeType(PathUtil.resolveRelativeReference(path,
posterSrc, base == null ? null : base.toString()));
posterMimeType = xrefChecker.get().getMimeType(PathUtil.resolveRelativeReference(base,
posterSrc));
}

if (posterMimeType != null && !OPFChecker.isBlessedImageType(posterMimeType))
Expand Down Expand Up @@ -446,7 +446,7 @@ protected void processSrc(String name, String src)
}
else
{
src = PathUtil.resolveRelativeReference(path, src, base == null ? null : base.toString());
src = PathUtil.resolveRelativeReference(base, src);
}

XRefChecker.Type refType;
Expand Down Expand Up @@ -499,7 +499,7 @@ protected void processObject(XMLElement e)
if (data != null)
{
processSrc(e.getName(), data);
data = PathUtil.resolveRelativeReference(path, data, base == null ? null : base.toString());
data = PathUtil.resolveRelativeReference(base, data);
}

if (type != null && data != null && xrefChecker.isPresent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private void processRef(String ref, XRefChecker.Type type)
{
if (ref != null && context.xrefChecker.isPresent())
{
ref = PathUtil.resolveRelativeReference(path, ref, null);
ref = PathUtil.resolveRelativeReference(path, ref);
if (type == XRefChecker.Type.AUDIO)
{
String mimeType = context.xrefChecker.get().getMimeType(ref);
Expand Down
Loading

0 comments on commit a84e08c

Please sign in to comment.