Identify requests coming from PageWorker - javascript

Is it possible, from within the "http-on-modify-request" event, to identify which requests are coming from a PageWorker object, as opposed to those coming from visible tabs/windows?
Note: Because of redirects and subresources, the URL here is NOT the same URL as the pageWorkers contentURL property.
require("sdk/system/events").on("http-on-modify-request", function(e) {
var httpChannel = e.subject.QueryInterface(Ci.nsIHttpChannel),
url = httpChannel.URI.spec,
origUrl = httpChannel.originalURI.spec;
...
});

I don't know of any way to actually distinguish page-worker requests from "regular" ones.
Current, page workers are implemented like this:
The SDK essentially creates an <iframe> in the hiddenWindow (technically, in sdk/addon/window, which creates a hidden window in the hiddenWindow). The hiddenWindow in mozilla applications is more or less an always-present top-level XUL or HTML window that is simply hidden.
The worker page is loaded into that iframe.
The page-worker will then operate on the DOM on that iframe.
It is possible to identify requests originating from the hidden window and the document within the hidden window.
But identifying if the request or associated document belongs to a page-worker, let alone which page-worker instance, doesn't seem possible, judging from the code. The SDK itself could map the document associated with a request back to a page-worker, as it keeps some WeakMaps around to do so, but that is internal stuff you cannot access.
You only can say that a request is not coming from a page-worker when it is not coming from the hiddenWindow.
Also, keep in mind that there are tons of requests originating neither from a tab nor page-worker: Other (XUL) windows, add-ons, js modules and components, etc...
If it a page-worker created by your add-on that you're interested in: The contentURL property should reflect the final URI once the page is loaded.

Related

Javascript postMessage

How does a browser like chrome exchange data between a window and its IFrame (window being on 1 domain name and IFrame loads content from another domain name)?
My question is, how the browser can send a JS object to an IFrame? Is it done with HTTP request or some other network protocol?
I can't see it in Chrome's network tab, that's why I was wondering
TLDR; because the parent window can directly get the iframe's Window, the browser can use an offline, event-based communication protocol to communicate.
A network protocol is not needed in this case as the parent window can directly reference the embedded iframe's Window object (using HTMLIFrameElement.contentWindow, which can then be used to listen to MessageEvents).
When the parent window calls otherWindow.postMessage(...), that message is serialized internally and passed to the otherWindow, which automatically deserializes the object so long as the iframe's Window is listening for MessageEvents by having registered an event listener for message like so:
window.addEventListener("message", function(event) {
// passed offline using serialization algorithm specified in spec (2.9.1)
console.log(event.data); // contains deserialized object
});
You cant pass a JavaScript object to an iFrame, but you can still access elements from iFrame like below:
$('#iframeId').contents().find('iframe').contents().find('#element');
It will access the element (suppose a hidden field) and set the value which you need to pass and use it in your iFrame content.
should be able to read the globals.
<script>var masterOfTheUniverse = "He-Man";</script>
should be visible from anywhere in and out the iFrame.
Or, you can use the browser storage
// Store
localStorage.setItem("masterOfTheUniverse", "He-Man");
// Retrieve
localStorage.getItem("masterOfTheUniverse");

Check if a request is a subresource integrity in a Chrome extension

Is it possible to check if a script/stylesheet is integrity protected via subresource-integrity (SRI) from a Chrome extension?
I want to know this before the request is initiated, so this should be done with chrome.webRequest.onBeforeRequest. But it gives no hints about the request as SRI is browser side. Everything happens after the request has finished.
From my point of view the only way to get this information is to access the DOM directly. This would mean I have to stall all requests until the HTML is completely parsed, which doesn't seem the way to go.
Maybe SRI is just too new to be accessible to extensions, as I didn't find it anywhere in the Chrome extension docs.
Yes, you can determine if a resource is protected by subresource-integrity, prior to the request for the resource being made, by checking for the appropriate attribute(s) (i.e. integrity) on the element specifying the resource as the element is added to the DOM. You can have a content script that is executed at document_start (either specified in manifest.json (run_at), or injected using tabs.executeScript()1 (runAt)). That script could then set up a MutationObserver to watch elements being placed in the DOM. Each appropriate element type (i.e. <script> and <link>) would then need to be checked for using subresource-integrity. This check/determination will occur prior to the webRequest.onBeforeRequest event.
Doing this does not stall all requests until the HTML is fully parsed. It performs the check as each element specifying a resource is entered into the DOM. On the other hand, obviously, any additional processing you introduce through the use of the MutationObserver does add some additional time to parsing the HTML, creating the DOM and loading all resources.
Getting the timing correct to have a script executed at document_start using tabs.executeScript() is non-trivial. How to do so would be a separate question.

Dynamics 2013 Accessing Page entities is hard to access with iframe based views

I am building an angular application which is running as a web resource on Dynamics 2013.
The application runs using a button which is added to the commandContainer using Ribbon workbench which then that button calls a Xrm.Internal.openDialog
All this works fine until I want to start using the Entities exposed by Xrm.Page.Data
Basically my button runs in the context of the main page of dynamics however the Entities are inside an iframe which based on the page I am in has a different Id and name.
So using a simple selector I can not get its contentWindow and start using the Entities.
The #crmContentPanel always has few iframes in it starting from #contentIFrame0 to #contentIFrame(n) and I can never know which iframe is the one with Entities in it.
What is the best practice, associated work flow with developing applications in this environment? How can I easily and reliably access the correct frame which holds the main page entities and work with them.
Perhaps the script is in the wrong location and needs to injected into the main content area so it has direct access to the correct Xrm? How can I achieve that?
Furthermore once I eventually manage to access this data, how can I easily pass this data to my angular application which runs in the dialog as from the documentation I read that the dialog is only allowed 1 query string param and it has to be called data. That would not be enough for my application to start using $routeParams. And I don't think using local or session storage is nice practice. What is the correct approach in this situation.
Sample code of my button script:
function runSendSender() {
// Content Iframe Entity data:
var contentFrameXrm = $('#crmContentPanel')
.find("iframe#contentIFrame0...n")[0]
.contentWindow['Xrm'];
// even if above selector was consistent across pages
// I need to send over much more than this one Id :(
var data = contentFrameXrm.Page.data.entity.getId();
var src = "/WebResources/concep_/ConcepDynamicsApp/ConcepDynamicsApp.html?data=" + data;
var DialogOptions = new Xrm.DialogOptions();
DialogOptions.width = 800;
DialogOptions.height = 500;
Xrm.Internal.openDialog(src, DialogOptions, null, null, CallbackFunction);
function CallbackFunction(returnValue) { }
}
Little more detail
When I type the following in the console I can sometimes (randomly) read the title of the form:
$('#crmContentPanel').find("iframe#contentIFrame0")[0].contentWindow['Xrm'].Page.ui.get_formTitle();
But the same code from the associated web resource function can not access the iframe and errors:
Can not Cannot read property 'contentWindow' of undefined.
Why is the iframe not accessible via the resource script and how can I access the correct context and form title/id.
I'm usually including following JavaScript file to the header of the custom WebResource that need to have an access to the CRM specific actions / information:
<script src="ClientGlobalContext.js.aspx" type="text/javascript"></script>
This gives access to some none-entity specific information, such as Xrm.Page.context.getServerUrl() or Xrm.Page.context.getUserId() for example.
But if you added layer with your own iFrame on top of the standard entity page, you definitely can access to information underneath your current context by using following construction:
window.parent.Xrm.Page.data.entity.attributes.get("name").getValue();
Note the window.parent prefix.
The record Id can be sent to runSendSender as parameter by the ribbon itself. Just add the appropriate CrmParameter (MSDN) to the function call.
In your case, the parameter value would be FirstPrimaryItemId ("Provides one GUID identifier as a string for the record being viewed.")
After that, you'll have your function changed like this
function runSendSender(recordId) { ... }
Also, stay out from internals: to open a web resource in a dialog, you should use the supported way (link provides info about passing parameters other than data to the resource).
Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)

var myvalue = window.opener.document.getElementById(“parentId1”) is not working

I was trying to get the value from my child.jsp to my parent.jsp using
var myvalue = window.opener.document.getElementById(“parentId1”)
Even though there were no errors found in the console the value is not getting in the parent page.
The child popup window has the url starting like, https://host.example.com:7001/..... and the parent page url is different starts with http://anotherhost:8080/webapp.... is there any issue in communicating with a child window and a parent page which is on another server?
If so how can I solve this issue?
...is there any issue in communicating with a child window and a parent page which is on another server?
Yes, this is prevented by the browser's implementation of the Same Origin Policy.
If you control both servers, look at using Cross Origin Resource Sharing.
Alternately, if you control the JavaScript code on the pages but not the servers (or just if you prefer this mechanism), you can use postMessage to send messages from one window to another. You can't directly access the other window's elements as in your code snippet, but the two pages can cooperate to deliver the relevant value from one page to another, even cross-origin. More on postMessage: MDN | Spec
Unless you can use CORS or postMessage, I don't think you can do it client-side; you'll need a proxy.

HTML5 - Cross Browser Iframe postmessage - parent to child communication

I wrote a content script that injects an iframe to any website (therefore different domain).
I need the parent website to send some information to the child iframe, however I couldn't find a way to do it.
The code
var targetFrame = $('#myIframe')[0];
targetFrame.contentWindow.postMessage('the message', '*');
Doesn't work somehow and i get a Cannot call method 'postMessage' of undefined error.
But then when I tried the same code directly in Chrome's console, it worked.
I had no trouble sending a postMessage from the child to the parent though but just need a way for the parent to send messages to the child iframe.
I recently wrote code that did postMessage to an iframe and I encountered quite a similar issue where it said contentWindow is undefined.
In my case, my iframe was not yet part of the DOM tree, it was a variable created by document.createElement('iframe').
Once I put it hidden (width and height 0px, visibility hidden) into the body of the page, contentWindow was no longer undefined and everything worked as expected.
I found the Mozilla Developer Network page for postMessage extremely useful when I was working on my project.
I've had success using the following library:
http://easyxdm.net/wp/
It doesn't require any flash/silverlight, only javascript. And it is compatible as far back as as IE6.
It took a little doing to get it up and running, but once it was things ran very smoothly.
Keep in mind that if the iFrame you're opening on the other domain uses a different protocol (HTTP vs. HTTPS) the browser will kick out a warning which prevents your script from running (unless the user says they will accept the risk). If you have access to both protocols it may be wise to host the contents of the iFrame on both HTTP and HTTPS and load the appropriate script accordingly.
Good luck!
You don't need to target contentWindow. Try this:
var targetFrame = $('#myIframe')[0];
targetFrame.postMessage('the message', '*');

Categories

Resources