Revision Content

XPCNativeWrapper is a way to wrap up an object so that it's safe to access from privileged code. It can be used in all Firefox versions, though the
behavior changed somewhat starting with Firefox 1.5 (or rather Gecko 1.8).

XPCNativeWrapper in Firefox versions prior to 1.5

In Firefox versions prior to 1.5, use of XPCNativeWrapper requires manually constructing an XPCNativeWrapper and passing it the object to be wrapped and the names of the methods/properties to be exposed as arguments. The resulting object exposes ONLY the methods/properties whose methods were passed as arguments. This is described in more detail in the the entry for XPCNativeWrapper at the MozillaZine KnowledgeBase.

XPCNativeWrapper in Firefox versions starting with 1.5

There are three different types of XPCNativeWrapper in Firefox 1.5. All three types wrap a possibly-unsafe object and provide safe access to all of its properties and methods (unlike XPCNativeWrapper in versions before 1.5, which only provided safe access to the properties and methods listed in its constructor). If unsafe access to a property is required for some reason, this can be accomplished via the wrappedJSObject property of the wrapper. For example, if docWrapper is a wrapper for doc, then

docWrapper.wrappedJSObject.prop

is the same as

doc.prop

The differences in behavior between the three types of XPCNativeWrapper are determined by two characteristics an XPCNativeWrapper wrapper can have. An XPCNativeWrapper can be explicit (or the opposite, implicit) and can be deep (or the opposite, shallow). The type of wrapper created is generally determined by the way it was created as follows:

Explicit vs. Implicit

The difference in behavior between explicit and implicit XPCNativeWrapper is that a property access on an implicit XPCNativeWrapper from code that does not have xpcnativewrappers=yes is NOT safe. The property access will be forwarded through to the wrappedJSObject of the XPCNativeWrapper.

This means the code that doesn't use xpcnativewrappers=yes doesn't need to worry about bugs arising because other code that does hands it an implicit XPCNativeWrapper. On the other hand, it does need to watch out for unsafe object access.

Property access on an explicit XPCNativeWrapper is safe no matter whether xpcnativewrappers=yes is being used.

Deep vs. Shallow

The difference in behavior between deep and shallow XPCNativeWrapper is that when a property is accessed or a function is called on a deep wrapper the return value will be wrapped in a XPCNativeWrapper of its own. The new XPCNativeWrapper will also be deep and it will be explicit if and only if the XPCNativeWrapper whose property is accessed was explicit. By contrast, when a property is accessed or a function is called on a shallow wrapper, the return value may be an unsafe object.

For example, say we are given three instances of XPCNativeWrapper for the same window object. Let us call them deepExplicitWindow, deepImplicitWindow and shallowWindow. Then we have:

var doc2 = deepImplicitWindow.document;
// If the caller has xpcnativewrappers=yes set, doc2 is now a deep
// implicit XPCNativeWrapper for the document object.
// Otherwise doc2 is now the unsafe document object, since the
// property access was simply passed along to the unsafe window object.

Creating XPCNativeWrapper objects

There are three different ways of creating an XPCNativeWrapper object; one way for each of the three types.

XPCNativeWrapper constructor call with string arguments

For example:

var contentWinWrapper = new XPCNativeWrapper(content,
"document");

This creates an explicitshallowXPCNativeWrapper. This syntax has been kept for compatibility with versions prior to Firefox 1.5. While all properties of the contentWinWrapper object can now be safely accessed, the return values of these properties are NOT safe to access (just like in versions prior to Firefox 1.5), since the XPCNativeWrapper is shallow. So to compare the content document title to the current content selection, one must do:

just like in versions before Firefox 1.5. Note that the "getSelection()" argument is not strictly needed here; if the code is not intended for use with Firefox versions before 1.5 it can be removed. A single string argument after the object being wrapped is all that is required for Firefox 1.5 to create this type of XPCNativeWrapper.

XPCNativeWrapper constructor call with no string arguments

For example:

var contentWinWrapper = new XPCNativeWrapper(content);

This creates an explicitdeepXPCNativeWrapper. Accessing properties of this XPCNativeWrapper is safe, and the return values will also be wrapped in
explicitdeepXPCNativeWrapper objects.

xpcnativewrappers=yes

Code that has xpcnativewrappers=yes and accesses a content object will get back an implicitdeepXPCNativeWrapper. Accessing properties of this XPCNativeWrapper is safe from code that uses xpcnativewrappers=yes, and the return values will also be wrapped in implicitdeepXPCNativeWrapper objects.

A wrapper created in this way will stick around as long as the object being wrapped does and accessing an object twice in a row will give the same XPCNativeWrapper.

bz: except for {{template.Bug(295937)}} -- sort that out before trying to explain the exact behavior here.

Setting "expando" properties on XPCNativeWrapper

It is possible to set "expando" properties (properties with names that don't correspond to IDL-defined properties) on XPCNativeWrapper objects. If this is done, then chrome will be able to see these expando properties, but content will not be able to. There is no safe way to set an expando property from chrome and have it be readable from content.

XPCNativeWrapper lifetime

Explicit XPCNativeWrapper objects exist while they are referenced. Creating a new explicit XPCNativeWrapper for the same possibly-unsafe object will create a new wrapper object; something to watch out for when <a href="Setting_.22expando.22_properties_on_XPCNativeWrapper">setting "expando" properties</a>.

Implicit XPCNativeWrapper objects have the same lifetime as the object they're wrapping.

Limitations of XPCNativeWrapper

There are some commonly used properties that cannot be used with XPCNativeWrapper. Specifically:

Assigning to the location property of a wrapped document or window will not work. Code that wishes to set the location should assign to the href property of the location object (after wrapping the location object itself, as needed).

document.open() (with no arguments) will not work. Code that wishes to do this should call document.open("text/html",false) instead.

Assigning to an on* property on an XPCNativeWrapper of a DOM node or Window object will not actually add an event handler for that event.

Passing false for the fourth argument of addEventListener does not work.

document.all does not work on an XPCNativeWrapper for a document.

Access to forms by name does not work on an XPCNativeWrapper for an HTML document. For example, if you have a <form name="foo"> and docWrapper is a wrapper for the HTML document doc then doc.foo is an HTMLFormElement while docWrapper.foo is undefined. Code that wishes to do this could use docWrapper.forms.namedItem("formname").elements.namedItem("foo").

Access to nodes by id doesn't work on an XPCNativeWrapper for an HTML document. getElementById should be used instead.

Access to inputs by name doesn't work on an XPCNativeWrapper for an HTML form. Code that wishes to do this should use form.elements.namedItem("somename").

Access to named items by name doesn't work on an XPCNativeWrapper for any node list (for example, document.forms.formName would not work if |document| is a deep wrapper for an HTML document). Code that wishes to do this should use the namedItem() method.

Access to numeric properties of an XPCNativeWrapper for an HTML form doesn't work. Code that wishes to access the form's inputs by their number in the form should use formWrapper.elements{{mediawiki.external('n')}} instead of formWrapper{{mediawiki.external('n')}}.

scrollIntoView cannot be called on an XPCNativeWrapper for an HTML element.

Calling methods implemented by NPAPI plugins though the XPCNativeWrapper for the corresponding node does not work.

Getting or setting properties implemented by NPAPI plugins though the XPCNativeWrapper for the corresponding node does not work.

Calling the add() method on an XPCNativeWrapper for an options collection of an HTML <select> does not work.

Setting a numeric property on an XPCNativeWrapper for a <select> or for its .options does not work.

Access to frames by window name (e.g. window.frameName) does not work on an XPCNativeWrapper

Revision Source

<p><code>XPCNativeWrapper</code> is a way to wrap up an object so that it's safe to access from privileged code. It can be used in all Firefox versions, though the
behavior changed somewhat starting with Firefox 1.5 (or rather Gecko 1.8).
</p>
<h3 name="XPCNativeWrapper_in_Firefox_versions_prior_to_1.5"> <code>XPCNativeWrapper</code> in Firefox versions prior to 1.5 </h3>
<p>In Firefox versions prior to 1.5, use of <code>XPCNativeWrapper</code> requires manually constructing an <code>XPCNativeWrapper</code> and passing it the object to be wrapped and the names of the methods/properties to be exposed as arguments. The resulting object exposes ONLY the methods/properties whose methods were passed as arguments. This is described in more detail in the <a class="external" href="http://kb.mozillazine.org/XPCNativeWrapper">the entry for <code>XPCNativeWrapper</code> at the MozillaZine KnowledgeBase</a>.
</p>
<h3 name="XPCNativeWrapper_in_Firefox_versions_starting_with_1.5"> <code>XPCNativeWrapper</code> in Firefox versions starting with 1.5 </h3>
<p>There are three different types of <code>XPCNativeWrapper</code> in Firefox 1.5. All three types wrap a possibly-unsafe object and provide safe access to all of its properties and methods (unlike <code>XPCNativeWrapper</code> in versions before 1.5, which only provided safe access to the properties and methods listed in its constructor). If unsafe access to a property is required for some reason, this can be accomplished via the <code>wrappedJSObject</code> property of the wrapper. For example, if <code>docWrapper</code> is a wrapper for <code>doc</code>, then
</p>
<pre class="eval">docWrapper.wrappedJSObject.prop
</pre>
<p>is the same as
</p>
<pre class="eval">doc.prop
</pre>
<p>The differences in behavior between the three types of <code>XPCNativeWrapper</code> are determined by two characteristics an <code>XPCNativeWrapper</code> wrapper can have. An <code>XPCNativeWrapper</code> can be <a href="#Explicit_vs._Implicit"><i>explicit</i></a> (or the opposite, <i>implicit</i>) and can be <a href="#Deep_vs._Shallow"><i>deep</i></a> (or the opposite, <i>shallow</i>). The type of wrapper created is generally determined by the way it was created as follows:
</p>
<table border="1">
<tbody><tr>
<th> Created by
</th><th> Explicit/Implicit
</th><th> Deep/Shallow
</th></tr>
<tr>
<th> <a href="#xpcnativewrappers.3Dyes"><code>xpcnativewrappers=yes</code></a> in the <a href="en/Chrome_Registration">chrome manifest</a>
</th><td> Implicit
</td><td> Deep
</td></tr>
<tr>
<th> <a href="#XPCNativeWrapper_constructor_call_with_string_arguments">Constructor called with string arguments</a>
</th><td> Explicit
</td><td> Shallow
</td></tr>
<tr>
<th> <a href="#XPCNativeWrapper_constructor_call_with_no_string_arguments">Constructor called with no string arguments</a>
</th><td> Explicit
</td><td> Deep
</td></tr></tbody></table>
<h4 name="Explicit_vs._Implicit"> Explicit vs. Implicit </h4>
<p>The difference in behavior between explicit and implicit <code>XPCNativeWrapper</code> is that a property access on an implicit <code>XPCNativeWrapper</code> from code that does not have <code>xpcnativewrappers=yes</code> is NOT safe. The property access will be forwarded through to the <code>wrappedJSObject</code> of the <code>XPCNativeWrapper</code>.
</p><p>This means the code that doesn't use <code>xpcnativewrappers=yes</code> doesn't need to worry about bugs arising because other code that does hands it an implicit <code>XPCNativeWrapper</code>. On the other hand, it does need to watch out for unsafe object access.
</p><p>Property access on an explicit <code>XPCNativeWrapper</code> is safe no matter whether <code>xpcnativewrappers=yes</code> is being used.
</p>
<h4 name="Deep_vs._Shallow"> Deep vs. Shallow </h4>
<p>The difference in behavior between deep and shallow <code>XPCNativeWrapper</code> is that when a property is accessed or a function is called on a deep wrapper the return value will be wrapped in a <code>XPCNativeWrapper</code> of its own. The new <code>XPCNativeWrapper</code> will also be deep and it will be <a href="#Explicit_vs._Implicit">explicit</a> if and only if the <code>XPCNativeWrapper</code> whose property is accessed was explicit. By contrast, when a property is accessed or a function is called on a shallow wrapper, the return value may be an unsafe object.
</p><p>For example, say we are given three instances of <code>XPCNativeWrapper</code> for the same window object. Let us call them <code>deepExplicitWindow</code>, <code>deepImplicitWindow</code> and <code>shallowWindow</code>. Then we have:
</p>
<pre class="eval">var doc1 = deepExplicitWindow.document;
// doc1 is now a deep explicit <code>XPCNativeWrapper</code> for
// the document object. Accessing doc1.open(), say, is safe.
</pre>
<pre class="eval">var doc2 = deepImplicitWindow.document;
// If the caller has xpcnativewrappers=yes set, doc2 is now a deep
// implicit <code>XPCNativeWrapper</code> for the document object.
// Otherwise doc2 is now the unsafe document object, since the
// property access was simply passed along to the unsafe window object.
</pre>
<pre class="eval">var doc3 = shallowWindow.document;
// doc3 is now the unsafe document object.
</pre>
<h4 name="Creating_XPCNativeWrapper_objects"> Creating <code>XPCNativeWrapper</code> objects </h4>
<p>There are three different ways of creating an <code>XPCNativeWrapper</code> object; one way for each of the three types.
</p>
<h5 name="XPCNativeWrapper_constructor_call_with_string_arguments"> <code>XPCNativeWrapper</code> constructor call with string arguments </h5>
<p>For example:
</p>
<pre class="eval">var contentWinWrapper = new XPCNativeWrapper(content,
"document");
</pre>
<p>This creates an <a href="#Explicit_vs._Implicit">explicit</a> <a href="#Deep_vs._Shallow">shallow</a> <code>XPCNativeWrapper</code>. This syntax has been kept for compatibility with versions prior to Firefox 1.5. While all properties of the <code>contentWinWrapper</code> object can now be safely accessed, the return values of these properties are NOT safe to access (just like in versions prior to Firefox 1.5), since the <code>XPCNativeWrapper</code> is <a href="#Deep_vs._Shallow">shallow</a>. So to compare the content document title to the current content selection, one must do:
</p>
<pre class="eval">var winWrapper = new XPCNativeWrapper(content, "document",
"getSelection()");
var docWrapper = new XPCNativeWrapper(winWrapper.document,
"title");
return docWrapper.title == winWrapper.getSelection();
</pre>
<p>just like in versions before Firefox 1.5. Note that the <code>"getSelection()"</code> argument is not strictly needed here; if the code is not intended for use with Firefox versions before 1.5 it can be removed. A single string argument after the object being wrapped is all that is required for Firefox 1.5 to create this type of <code>XPCNativeWrapper</code>.
</p>
<h5 name="XPCNativeWrapper_constructor_call_with_no_string_arguments"> <code>XPCNativeWrapper</code> constructor call with no string arguments </h5>
<p>For example:
</p>
<pre class="eval">var contentWinWrapper = new XPCNativeWrapper(content);
</pre>
<p>This creates an <a href="#Explicit_vs._Implicit">explicit</a> <a href="#Deep_vs._Shallow">deep</a> <code>XPCNativeWrapper</code>. Accessing properties of this <code>XPCNativeWrapper</code> is safe, and the return values will also be wrapped in
<a href="#Explicit_vs._Implicit">explicit</a> <a href="#Deep_vs._Shallow">deep</a> <code>XPCNativeWrapper</code> objects.
</p>
<h5 name="xpcnativewrappers.3Dyes"> <code>xpcnativewrappers=yes</code> </h5>
<p>Code that has <code>xpcnativewrappers=yes</code> and accesses a content object will get back an <a href="#Explicit_vs._Implicit">implicit</a> <a href="#Deep_vs._Shallow">deep</a> <code>XPCNativeWrapper</code>. Accessing properties of this <code>XPCNativeWrapper</code> is safe from code that uses <code>xpcnativewrappers=yes</code>, and the return values will also be wrapped in <a href="#Explicit_vs._Implicit">implicit</a> <a href="#Deep_vs._Shallow">deep</a> <code>XPCNativeWrapper</code> objects.
</p><p>A wrapper created in this way will stick around as long as the object being wrapped does and accessing an object twice in a row will give the same <code>XPCNativeWrapper</code>.
</p><p><i>bz: except for {{template.Bug(295937)}} -- sort that out before trying to explain the exact behavior here.</i>
</p>
<h4 name="Setting_.22expando.22_properties_on_XPCNativeWrapper"> Setting "expando" properties on <code>XPCNativeWrapper</code> </h4>
<p>It is possible to set "expando" properties (properties with names that don't correspond to IDL-defined properties) on <code>XPCNativeWrapper</code> objects. If this is done, then chrome will be able to see these expando properties, but content will not be able to. <b>There is no safe way to set an expando property from chrome and have it be readable from content.</b>
</p>
<h4 name="XPCNativeWrapper_lifetime"> <code>XPCNativeWrapper</code> lifetime </h4>
<p>Explicit <code>XPCNativeWrapper</code> objects exist while they are referenced. Creating a new explicit <code>XPCNativeWrapper</code> for the same possibly-unsafe object will create a new wrapper object; something to watch out for when &lt;a href="Setting_.22expando.22_properties_on_XPCNativeWrapper"&gt;setting "expando" properties&lt;/a&gt;.
</p><p>Implicit <code>XPCNativeWrapper</code> objects have the same lifetime as the object they're wrapping.
</p>
<h4 name="Limitations_of_XPCNativeWrapper"> Limitations of <code>XPCNativeWrapper</code> </h4>
<p>There are some commonly used properties that cannot be used with <code>XPCNativeWrapper</code>. Specifically:
</p>
<ol><li> Assigning to a numeric property (e.g. <code>foo{{mediawiki.external(1)}} = "val"</code>) will throw.
</li><li> Assigning to the <code>location</code> property of a wrapped document or window will not work. Code that wishes to set the location should assign to the <code>href</code> property of the location object (after wrapping the location object itself, as needed).
</li><li> <code>document.open()</code> (with no arguments) will not work. Code that wishes to do this should call <code>document.open("text/html",false)</code> instead.
</li><li> Assigning to an <code>on*</code> property on an <code>XPCNativeWrapper</code> of a DOM node or Window object will not actually add an event handler for that event.
</li><li> Passing <code>false</code> for the fourth argument of addEventListener does not work.
</li><li> <code>document.all</code> does not work on an <code>XPCNativeWrapper</code> for a document.
</li><li> Access to forms by name does not work on an <code>XPCNativeWrapper</code> for an HTML document. For example, if you have a <code>&lt;form name="foo"&gt;</code> and <code>docWrapper</code> is a wrapper for the HTML document <code>doc</code> then <code>doc.foo</code> is an <code>HTMLFormElement</code> while <code>docWrapper.foo</code> is <code>undefined</code>. Code that wishes to do this could use docWrapper.forms.namedItem("formname").elements.namedItem("foo").
</li><li> Access to nodes by id doesn't work on an <code>XPCNativeWrapper</code> for an HTML document. <code>getElementById</code> should be used instead.
</li><li> Access to inputs by name doesn't work on an <code>XPCNativeWrapper</code> for an HTML form. Code that wishes to do this should use form.elements.namedItem("somename").
</li><li> Access to named items by name doesn't work on an <code>XPCNativeWrapper</code> for any node list (for example, <code>document.forms.formName</code> would not work if |document| is a deep wrapper for an HTML document). Code that wishes to do this should use the namedItem() method.
</li><li> Access to numeric properties of an <code>XPCNativeWrapper</code> for an HTML form doesn't work. Code that wishes to access the form's inputs by their number in the form should use <code>formWrapper.elements{{mediawiki.external('n')}}</code> instead of <code>formWrapper{{mediawiki.external('n')}}</code>.
</li><li> <code>scrollIntoView</code> cannot be called on an <code>XPCNativeWrapper</code> for an HTML element.
</li><li> Calling methods implemented by NPAPI plugins though the <code>XPCNativeWrapper</code> for the corresponding node does not work.
</li><li> Getting or setting properties implemented by NPAPI plugins though the <code>XPCNativeWrapper</code> for the corresponding node does not work.
</li><li> Calling the <code>add()</code> method on an <code>XPCNativeWrapper</code> for an options collection of an HTML <code>&lt;select&gt;</code> does not work.
</li><li> Setting a numeric property on an <code>XPCNativeWrapper</code> for a <code>&lt;select&gt;</code> or for its <code>.options</code> does not work.
</li><li> Access to frames by window name (e.g. <code>window.frameName</code>) does not work on an <code>XPCNativeWrapper</code>
</li></ol>