8

Is there a way to load a page, hidden from the user?

I can't use an iframe in a background page, because the page has frame-busting techniques.

I can't use an XHR, because the page has AJAX - I need its (dynamically generated) DOM.

Chris Broadfoot
  • 5,082
  • 1
  • 29
  • 37
  • What would that loaded page contain? HTML, JS, XML? – gaborsch Jun 25 '13 at 14:03
  • Is the DOM dynamically generated using JavaScript, or present in advance? – Rob W Jun 25 '13 at 14:03
  • The page contains HTML/JS - it's a page on the internet. The DOM is dynamically generated after a series of AJAX calls. – Chris Broadfoot Jun 25 '13 at 14:04
  • Can't you use an ` – gaborsch Jun 25 '13 at 14:05
  • No, can't use an ` – Chris Broadfoot Jun 25 '13 at 14:05
  • There used to be an API called [`offscreenTabs`](http://www.chromium.org/developers/design-documents/extensions/proposed-changes/apis-under-development/offscreen-tabs) which would suit well for this purpose. Unfortunately, it has been plugged out from Chromium's code base because it was not maintained any more. Can't you just do the AJAX calls yourself and construct the DOM based on that response? Otherwise you don't have any nice solutions left (creating a tab then closing it is not nice in my opinion). – Rob W Jun 25 '13 at 14:09
  • `offscreenTabs` looks perfect, Rob. Unfortunately the AJAX calls are constructed by GWT, so not straight forward to parse, and pretty much guaranteed to change in the future. – Chris Broadfoot Jun 25 '13 at 14:12
  • Actually - if it does not disturb your users - you can open a `popUnder` window (same like popup, just opens the window in the background). When you're finished, you can even close it. – gaborsch Jun 25 '13 at 14:19
  • @ChrisBroadfoot As I said, [offscreenTabs has been removed](https://code.google.com/p/chromium/issues/detail?id=164121). How is the frame buster implemented? – Rob W Jun 25 '13 at 14:26
  • I meant to say that they *looked* perfect ;-) The frame buster is here: https://gist.github.com/broady/28d572afa644b94df322 – Chris Broadfoot Jun 25 '13 at 15:02

2 Answers2

14

I'm afraid that you don't have any other option than inserting the iframe anyway. To bust the iframe buster, you can employ the following techniques:

  • If the iframe is blocked by the X-Frames-Option: DENY, just remove the header using the webRequest API - see Getting around X-Frame-Options DENY in a Chrome extension?.
  • If the frame buster uses something like

    if (top !== self) {
        top.location.href = location.href;
    }
    

    Then block the scripted navigation by set the sandbox attribute on the iframe:

    var frame = document.createElement('iframe');
    frame.sandbox = 'allow-scripts';
    frame.src = 'data:text/html,<script>' +
        'if (top !== self) { top.location.href = location.href;}' +
        'alert(" (runs the rest of the code) ");' + 
        '</script>';
    document.body.appendChild(frame);
    

    Navigation will be blocked without throwing any errors. The following message is logged to the console though:

    Unsafe JavaScript attempt to initiate navigation for frame with URL '(...URL of top page...)' from frame with URL '(....URL of frame..)'. The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.

These methods will always work, unless:

  • The page contains <meta http-equiv="X-Frame-Options" content="deny">.
  • The frame busting script is implemented as if (top === self) { /* run code*/ }

In these cases, you have no other option than opening a new tab, read its content, then close it. See chrome.tabs.create and chrome.tabs.remove.

Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • I'm going to use `onBeforeRequest` to modify the response, by redirecting to a blob URL version with the frame busting code stripped out. – Chris Broadfoot Jun 25 '13 at 15:32
  • @ChrisBroadfoot There's no need to use the webRequest API for that. Just read the original source code, strip out the frame buster, then load a frame with the data-URL: `frame.src = 'data:text/html;charset=utf8,' + encodeURIComponent(html);`. – Rob W Jun 25 '13 at 15:34
  • Looks like I can't display an iframe pointing to a blob: url anyway. – Chris Broadfoot Jun 25 '13 at 16:17
  • @ChrisBroadfoot The iframe busting method in answer should work for your case (https://gist.github.com/broady/28d572afa644b94df322). You can load a content script to disable the alert, if you want to, by injecting a script tag which sets `alert` to a no-op function). – Rob W Jun 25 '13 at 16:21
  • It seems that getting around the `X-Frame-Options` header doesn't work any more (Chrome 46) – cprcrack Nov 10 '15 at 17:10
2

You can use popUnder s to load data:

var win2;
function loadPopUnder(){
win2 = window.open("about:blank","",
    width=150,height=150,scrollbars=0,resizable=0,toolbar=0,location=0,menubar=0,status=0,directories=0");
    win2.blur();
    window.focus()
}

win2.document.location.href='http://www.exampe.com/url';

Actually they may open in a new tab in certain circumstances - you have to check the actual behavior.

Also it is an advantage that this one is a browser independent solution.

gaborsch
  • 15,408
  • 6
  • 37
  • 48
  • 1
    Pop-unders are an awful UX. What would you do with an extension which spawns pop-unders all over the place? The Chrome API allows one to create inactive tabs. This is still bad, but not as bad as a popunder. – Rob W Jun 25 '13 at 14:59
  • @RobW I agree it's ugly, I just wanted to get recorded that there is such option. If there are no other ways, you can still fallback to this (and since offScreenTabs are not 100%, it seemed a real possibility). Meanwhile I noticed that you elaborated a better solution, so it may be a bit out-of-date anyway. +1 for your solution anyway. – gaborsch Jun 25 '13 at 15:21