title: CSP without unsafe-inline register onload handler for cross-origin iframe
body: <h3>our motivation</h3>
  
  <p>We're implementing CSP 2.0 with <code>script-src: 'self'</code> (especially no <code>'unsafe-inline'</code>). In some places we render iframes with cross-origin content and we need to know when they are loaded. Before CSP we would simply write</p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;iframe src="https://some.cross/origin/content" onload="this.complete = true"/&gt;
  &lt;script&gt;
    var iframe = document.querySelector('iframe');
    function loaded() { /* whatever happens when the iframe is loaded */ }
    if (iframe.complete) {
      loaded();
    } else {
      iframe.addEventListener('load', loaded);
    }
  &lt;/script&gt;
  </code></pre>
  
  <p>However, without <code>'unsafe-inline'</code> we can't use the <code>onload="this.complete = true"</code> any more. Simply attaching the event listener does not work if it did already fire:</p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;iframe src="https://some.cross/origin/content"/&gt;
  &lt;script&gt;
    var iframe = document.querySelector('iframe');
    function loaded() { /* ... */ }
    // if the load event does not fire because it fired before
    // loaded() will never be executed
    iframe.addEventListener('load', loaded);
  &lt;/script&gt;
  </code></pre>
  
  <h3>what we tried</h3>
  
  <p>Now, a solution would be to look inside the iframe contents <code>document.readystate</code>, but with cross-origin content we get security exceptions here.</p>
  
  <p>Nonces don't work on inline handlers (at least in CSP 2.0), so simply supplying a nonce for the inline handler is not an option.</p>
  
  <p>Our final idea would be to rewrite all onload iframes to javascript-inserted elements, because there we could attach the load handler before inserting the element, like</p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;!-- no iframe tag anymore --&gt;
  &lt;script&gt;
    var iframe = document.createElement('iframe');
    function loaded() { /* ... */ }
    iframe.addEventListener('load', loaded);
    document.body.appendChild(iframe);
  &lt;/script&gt;
  </code></pre>
  
  <p>But for this approach we fear the performance impact of creating iframes via JavaScript -- the html iframe would be rendered and loaded before the script would even start to execute.</p>
  
  <h3>our question</h3>
  
  <p>How do we figure out reliably if the content of a cross-origin iframe is loaded without an <code>onload="this.complete = true"</code> inline handler (that would need CSP 2.0's <code>script-src: ... 'unsafe-inline'</code>)?</p>