Skip to content

Commit 147940e

Browse files
Add try-catch around sheet.cssRules access (#433)
Some browsers do not allow script access to cross-origin sheets. Details: MatthewHerbst/react-to-print#429
1 parent b1ab040 commit 147940e

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

src/index.tsx

+19-9
Original file line numberDiff line numberDiff line change
@@ -363,29 +363,36 @@ export default class ReactToPrint extends React.Component<IReactToPrintProps> {
363363

364364
if (copyStyles) {
365365
const headEls = document.querySelectorAll("style, link[rel='stylesheet']");
366-
367366
for (let i = 0, headElsLen = headEls.length; i < headElsLen; ++i) {
368367
const node = headEls[i];
369-
if (node.tagName === "STYLE") {
368+
if (node.tagName === "STYLE") { // <style> nodes
370369
const newHeadEl = domDoc.createElement(node.tagName);
371370
const sheet = (node as HTMLStyleElement).sheet as CSSStyleSheet;
372-
373371
if (sheet) {
374372
let styleCSS = "";
375373
// NOTE: for-of is not supported by IE
376-
for (let j = 0, cssLen = sheet.cssRules.length; j < cssLen; ++j) {
377-
if (typeof sheet.cssRules[j].cssText === "string") {
378-
styleCSS += `${sheet.cssRules[j].cssText}\r\n`;
374+
try {
375+
// Accessing `sheet.cssRules` on cross-origin sheets can throw
376+
// security exceptions in some browsers, notably Firefox
377+
// https://github.com/gregnb/react-to-print/issues/429
378+
const cssLength = sheet.cssRules.length;
379+
for (let j = 0; j < cssLength; ++j) {
380+
if (typeof sheet.cssRules[j].cssText === "string") {
381+
styleCSS += `${sheet.cssRules[j].cssText}\r\n`;
382+
}
379383
}
384+
} catch (error) {
385+
this.logMessages([`A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/gregnb/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross \`crossorigin\` attribute, and setting the \`Access-Control-Allow-Origin\` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.`, node], 'warning');
380386
}
387+
381388
newHeadEl.setAttribute("id", `react-to-print-${i}`);
382389
if (nonce) {
383390
newHeadEl.setAttribute("nonce", nonce);
384391
}
385392
newHeadEl.appendChild(domDoc.createTextNode(styleCSS));
386393
domDoc.head.appendChild(newHeadEl);
387394
}
388-
} else {
395+
} else { // <link> nodes, and any others
389396
// Many browsers will do all sorts of weird things if they encounter an
390397
// empty `href` tag (which is invalid HTML). Some will attempt to load
391398
// the current page. Some will attempt to load the page"s parent
@@ -395,8 +402,11 @@ export default class ReactToPrint extends React.Component<IReactToPrintProps> {
395402
if (node.getAttribute("href")) {
396403
const newHeadEl = domDoc.createElement(node.tagName);
397404

398-
// node.attributes has NamedNodeMap type that is not an Array and
399-
// can be iterated only via direct [i] access
405+
// Manually re-create the node
406+
// TODO: document why cloning the node won't work? I don't recall
407+
// the reasoning behind why we do it this way
408+
// NOTE: node.attributes has NamedNodeMap type that is not an Array
409+
// and can be iterated only via direct [i] access
400410
for (let j = 0, attrLen = node.attributes.length; j < attrLen; ++j) { // eslint-disable-line max-len
401411
const attr = node.attributes[j];
402412
if (attr) {

0 commit comments

Comments
 (0)