I am developing a Chrome extension with a manifest that, for now, enables access to all hosts. The background script injects content scripts into all frames. After the DOM is loaded, the content script in the top page/frame begins to walk the DOM tree. When the walker encounters an iframe, it needs to message the specific content script associated with that iframe's window (possibly cross-origin) to begin it's work and includes some serialized data with this message. The parent window suspends execution and waits for the child to complete it's walk and send a message back that it is done along with serialized data. The parent then continues its work. I have tried two approaches to this problem:
frameElement.contentWindow.postMessage
: this works most of the time, but not always. Sometimes the message is never received by the content script message event listener associated with the iframe window. I have not been able to confirm the cause but I think it is listeners attached before my listener callingevent.stopImmediatePropagation()
. For example, on the yahoo home page (https://www.yahoo.com), when posting a message to my content script associated with iframe source https://s.yimg.com/rq/darla/2-9-9/html/r-sf.html, the message is never received. This is an ad-related iframe. Maybe the blocking of messages is intentional. There is no error when the message is posted and I use a targetOrigin of "*".chrome.runtime.sendMessage
: I can send a message to the background page but cannot figure out how to tell the background page to which frame to relay the message. The parent window content script does not know the chrome extension frameId associated with the child frame element it encountered in the DOM walk. So it cannot tell the background page how to direct the message.
For point 2, I have tried two techniques that I found here on stackoverflow:
- Using concept described in this question: In parent window, determine iframe's position in the
window.frames
array and post a message to the background page with this index. The background page posts a message to all frames with the desired index in the message data. Only the iframe that finds it's window object position in the window.parent.frames array matches the index received from the message proceeds with it's walk. This works OK but is vulnerable to changes in thewindow.frames
array during the asynchronous messaging process (if an iframe is deleted after message is sent, the index value may no longer match the desired frame). - Instead of the index value from point 1, use
frameElement.name
in the parent window. With same messaging technique, send name to child iframe for comparison to itswindow.name
value. I believewindow.name
gets it's value from theframeElement.name
at the time of the iframe element creation. However, since I don't control the frame element creation, the name attribute is often an empty string and can't be relied on to uniquely match iframe elements to their windows.
Is there a way for me to reliably send a message to a content script associated with an iframe element found in walking a DOM tree?
window.frames
makes this initial connection possible, but can fail due to asynchronous messaging. – Crap