Skip to content

Commit 1622281

Browse files
committed
Put relative raster images from SVGs thru the resolver.
Also change tests so that they do not call out on network. Only way I could achieve it was to register a bridge extension.
1 parent fdac18f commit 1622281

File tree

4 files changed

+136
-11
lines changed

4 files changed

+136
-11
lines changed

openhtmltopdf-examples/src/main/resources/visualtest/html/malicious-svg-insecure-mode.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
<!-- The flying saucer raster image should render, since external resources are allowed. -->
2929
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
30-
<image xlink:href="https://openhtmltopdf.com/flyingsaucer.png" height="200" width="200"/>
30+
<image xlink:href="../../demos/images/flyingsaucer.png" height="200" width="200"/>
3131
</svg>
3232

3333
</body>

openhtmltopdf-examples/src/main/resources/visualtest/html/malicious-svg-secure-mode.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
<!-- The flying saucer raster image shouldn't render. -->
2929
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
30-
<image xlink:href="https://openhtmltopdf.com/flyingsaucer.png" height="200" width="200"/>
30+
<image xlink:href="../../demos/images/flyingsaucer.png" height="200" width="200"/>
3131
</svg>
3232

3333
</body>

openhtmltopdf-svg-support/src/main/java/com/openhtmltopdf/svgsupport/PDFTranscoder.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
import com.openhtmltopdf.simple.extend.ReplacedElementScaleHelper;
1717
import com.openhtmltopdf.util.LogMessageId;
1818
import com.openhtmltopdf.util.XRLog;
19+
1920
import org.apache.batik.bridge.BridgeContext;
2021
import org.apache.batik.bridge.FontFace;
2122
import org.apache.batik.bridge.FontFamilyResolver;
22-
import org.apache.batik.bridge.svg12.SVG12BridgeContext;
2323
import org.apache.batik.gvt.font.GVTFontFamily;
2424
import org.apache.batik.transcoder.ErrorHandler;
2525
import org.apache.batik.transcoder.SVGAbstractTranscoder;
@@ -264,14 +264,10 @@ public void setSecurityOptions(boolean allowScripts, boolean allowExternalResour
264264
this.allowedProtocols = allowedProtocols;
265265
}
266266

267-
@Override
268-
protected BridgeContext createBridgeContext(String svgVersion) {
269-
if ("1.2".equals(svgVersion)) {
270-
return new SVG12BridgeContext(userAgent, new OpenHtmlDocumentLoader(userAgent, userAgentCallback));
271-
} else {
272-
return new BridgeContext(userAgent, new OpenHtmlDocumentLoader(userAgent, userAgentCallback));
273-
}
274-
}
267+
@Override
268+
protected BridgeContext createBridgeContext(String svgVersion) {
269+
return SVGImageExtension.newBridge(svgVersion, userAgent, userAgentCallback);
270+
}
275271

276272
@Override
277273
protected void transcode(Document svg, String uri, TranscoderOutput out) throws TranscoderException {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.openhtmltopdf.svgsupport;
2+
3+
import java.net.URI;
4+
import java.net.URISyntaxException;
5+
import java.util.List;
6+
import java.util.logging.Level;
7+
8+
import org.apache.batik.bridge.BridgeContext;
9+
import org.apache.batik.bridge.SVGBridgeExtension;
10+
import org.apache.batik.bridge.SVGImageElementBridge;
11+
import org.apache.batik.bridge.UserAgent;
12+
import org.apache.batik.bridge.svg12.SVG12BridgeContext;
13+
import org.apache.batik.bridge.svg12.SVG12BridgeExtension;
14+
import org.apache.batik.util.ParsedURL;
15+
import org.w3c.dom.Document;
16+
17+
import com.openhtmltopdf.extend.UserAgentCallback;
18+
import com.openhtmltopdf.util.LogMessageId;
19+
import com.openhtmltopdf.util.XRLog;
20+
21+
public class SVGImageExtension {
22+
public static BridgeContext newBridge(String svgVersion, UserAgent userAgent, UserAgentCallback uac) {
23+
if ("1.2".equals(svgVersion)) {
24+
return new Bridge12Ctx(userAgent, uac);
25+
} else {
26+
return new BridgeCtx(userAgent, uac);
27+
}
28+
}
29+
30+
public static String resolveUri(String uri, UserAgentCallback userAgentCallback) {
31+
try {
32+
// special handling of relative uri in case of file protocol, we receive something like "file:file.svg"
33+
// ie. Batik adds file: to the start of relative uris for some reason.
34+
URI parsedURI = new URI(uri);
35+
36+
if ("file".equals(parsedURI.getScheme())) {
37+
return new URI(parsedURI.getSchemeSpecificPart()).isAbsolute() ?
38+
userAgentCallback.resolveURI(parsedURI.toString()) :
39+
userAgentCallback.resolveURI(parsedURI.getSchemeSpecificPart());
40+
} else {
41+
return userAgentCallback.resolveURI(uri);
42+
}
43+
} catch (URISyntaxException uriSyntaxException) {
44+
XRLog.log(Level.WARNING, LogMessageId.LogMessageId1Param.EXCEPTION_URI_SYNTAX_WHILE_LOADING_EXTERNAL_SVG_RESOURCE, uri, uriSyntaxException);
45+
return null;
46+
}
47+
}
48+
49+
private static class BridgeCtx extends BridgeContext {
50+
UserAgentCallback uac;
51+
52+
public BridgeCtx(UserAgent userAgent, UserAgentCallback userAgentCallback) {
53+
super(userAgent, new OpenHtmlDocumentLoader(userAgent, userAgentCallback));
54+
this.uac = userAgentCallback;
55+
}
56+
57+
@SuppressWarnings({ "rawtypes", "unchecked" })
58+
@Override
59+
public List getBridgeExtensions(Document doc) {
60+
List existing = super.getBridgeExtensions(doc);
61+
existing.add(new Ext(uac));
62+
return existing;
63+
}
64+
}
65+
66+
private static class Bridge12Ctx extends SVG12BridgeContext {
67+
UserAgentCallback uac;
68+
69+
public Bridge12Ctx(UserAgent userAgent, UserAgentCallback userAgentCallback) {
70+
super(userAgent, new OpenHtmlDocumentLoader(userAgent, userAgentCallback));
71+
this.uac = userAgentCallback;
72+
}
73+
74+
@SuppressWarnings({ "rawtypes", "unchecked" })
75+
@Override
76+
public List getBridgeExtensions(Document doc) {
77+
List existing = super.getBridgeExtensions(doc);
78+
existing.add(new Ext12(uac));
79+
return existing;
80+
}
81+
}
82+
83+
private static class Ext extends SVGBridgeExtension {
84+
final UserAgentCallback uac;
85+
86+
public Ext(UserAgentCallback uac) {
87+
this.uac = uac;
88+
}
89+
90+
@Override
91+
public void registerTags(BridgeContext ctx) {
92+
super.registerTags(ctx);
93+
ctx.putBridge(new ImageBridge(uac));
94+
}
95+
}
96+
97+
private static class Ext12 extends SVG12BridgeExtension {
98+
final UserAgentCallback uac;
99+
100+
public Ext12(UserAgentCallback uac) {
101+
this.uac = uac;
102+
}
103+
104+
@Override
105+
public void registerTags(BridgeContext ctx) {
106+
super.registerTags(ctx);
107+
ctx.putBridge(new ImageBridge(uac));
108+
}
109+
}
110+
111+
private static class ImageBridge extends SVGImageElementBridge {
112+
final UserAgentCallback uac;
113+
114+
public ImageBridge(UserAgentCallback uac) {
115+
this.uac = uac;
116+
}
117+
118+
@Override
119+
public org.apache.batik.bridge.Bridge getInstance() {
120+
return new ImageBridge(uac);
121+
}
122+
123+
@Override
124+
protected org.apache.batik.gvt.GraphicsNode createImageGraphicsNode(BridgeContext ctx, org.w3c.dom.Element e, org.apache.batik.util.ParsedURL purl) {
125+
String uri = resolveUri(purl.toString(), uac);
126+
return super.createImageGraphicsNode(ctx, e, new ParsedURL(uri));
127+
};
128+
}
129+
}

0 commit comments

Comments
 (0)