XPCNativeWrapper

  • Revision slug: XPCNativeWrapper
  • Revision title: XPCNativeWrapper
  • Revision id: 93012
  • Created:
  • Creator: Bzbarsky
  • Is current revision? No
  • Comment /* <code>XPCNativeWrapper</code> in Firefox versions starting with 1.1 */

Revision Content

bz: Note that this is a work in progress. Some rewriting may need to happen pending the outcome of . Please let me know if you plan to make any major changes to this document before doing so. --Bzbarsky 15:19, 31 May 2005 (PDT)

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.1.

XPCNativeWrapper in Firefox versions prior to 1.1

In Firefox versions prior to 1.1, 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.1

bz: Three types, or two, or four? Still sorting this out. See https://bugzilla.mozilla.org/show_bug.cgi?id=295782

There are three slightly different types of XPCNativeWrapper in Firefox 1.1. 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.1, 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:

Created by Explicit/Implicit Deep/Shallow
xpcnativewrappers=yes in the chrome manifest Implicit Deep
Constructor called with string arguments Explicit Shallow
Constructor called with no string arguments Explicit Deep

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.

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.

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 doc1 = deepExplicitWindow.document;
// doc1 is now a deep explicit XPCNativeWrapper for
// the document object.  Accessing doc1.open(), say, is safe.
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 not the unsafe document object, since the
// property access was simply passed along to the unsafe window object.
var doc3 = shallowWindow.document;
// doc3 is now the unsafe document object.

Explicit XPCNativeWrapper with string arguments

For example:

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

This syntax has been kept for compatibility with versions prior to Firefox 1.1. 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.1). So to compare the content document title to the current content selection, one must do:

var winWrapper = new XPCNativeWrapper(content, "document",
                                      "getSelection()");
var docWrapper = new XPCNativeWrapper(winWrapper.document,
                                      "title");
return docWrapper.title == winWrapper.getSelection();

Note that the "getSelection()" argument is not strictly needed here; if the code is not intended for use with Firefox versions before 1.1 it can be removed. A single string argument after the object being wrapped is all that is required for Firefox 1.1.

Explicit XPCNativeWrapper with no string arguments

For example:

var contentWinWrapper = new XPCNativeWrapper(content);

The resulting object behaves just like an implicit wrapper (most importantly, it will be deep), except that properties set on it will not be visible on either other explicit wrappers or implicit wrappers. Note that this means that for code not using xpcnativewrappers=yes this type of XPCNativeWrapper is useless at the moment.

bz: Again, see https://bugzilla.mozilla.org/show_bug.cgi?id=295782 -- that might introduce more differences between this type of wrapper and implicit wrappers.

Implicit XPCNativeWrapper

This type of wrapper can be created in one of two ways: either by accessing a content object from code that has xpcnativewrappers=yes set or by accessing a property of a deep wrapper.

bz: The latter may not always be true pending outcome of https://bugzilla.mozilla.org/show_bug.cgi?id=295782

The wrapper created in this way is always a deep wrapper. Furthermore, a wrapper created in this way will stick around as long as the object being wrapped does.

bz: except for https://bugzilla.mozilla.org/show_bug.cgi?id=295937 -- sort that out before trying to explain the exact behavior here.

Deep Wrappers

If a wrapper is deep, that means that the return value of any property access or method call on the wrapper will be implicitly wrapped.

If a deep wrapper is accessed from code that doesn't use xpcnativewrappers=yes, it will NOT provide safe access to properties. Instead, it will automatically forward all accesses to the underlying wrappedJSObject.

bz: This may not be the case for all deep wrappers pending https://bugzilla.mozilla.org/show_bug.cgi?id=295782

Limitations of XPCNativeWrapper

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

  1. 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).
  2. document.open() (with no arguments) will not work. Code that wishes to do this should call document.open("text/html",false) instead.

Revision Source

<p><i>bz: Note that this is a work in progress. Some rewriting may need to happen pending the outcome of <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=295937">. Please let me know if you plan to make any major changes to this document before doing so.	 </a></i><a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=295937">
--</a><a href="User:Bzbarsky">Bzbarsky</a> 15:19, 31 May 2005 (PDT)
</p><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.1.
</p>
<h3 name="XPCNativeWrapper_in_Firefox_versions_prior_to_1.1"> <code>XPCNativeWrapper</code> in Firefox versions prior to 1.1 </h3>
<p>In Firefox versions prior to 1.1, 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.1"> <code>XPCNativeWrapper</code> in Firefox versions starting with 1.1 </h3>
<p><i>bz: Three types, or two, or four?  Still sorting this out.  See https://bugzilla.mozilla.org/show_bug.cgi?id=295782</i>
</p><p>There are three slightly different types of <code>XPCNativeWrapper</code> in Firefox 1.1.  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.1, 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> <code>xpcnativewrappers=yes</code> in the <a href="en/Chrome_Registration">chrome manifest</a>
</th><td> Implicit
</td><td> Deep
</td></tr>
<tr>
<th> Constructor called with string arguments
</th><td> Explicit
</td><td> Shallow
</td></tr>
<tr>
<th> Constructor called with no string arguments
</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>.
</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 explicit if and only if the <code>XPCNativeWrapper</code> whose property is accessed was explicit.
</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 not 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="Explicit_XPCNativeWrapper_with_string_arguments"> Explicit <code>XPCNativeWrapper</code> with string arguments </h4>
<p>For example:
</p>
<pre class="eval">var contentWinWrapper = new XPCNativeWrapper(content,
                                             "document");
</pre>
<p>This syntax has been kept for compatibility with versions prior to Firefox 1.1.  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.1).  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>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.1 it can be removed.  A single string argument after the object being wrapped is all that is required for Firefox 1.1.
</p>
<h4 name="Explicit_XPCNativeWrapper_with_no_string_arguments"> Explicit <code>XPCNativeWrapper</code> with no string arguments </h4>
<p>For example:
</p>
<pre class="eval">var contentWinWrapper = new XPCNativeWrapper(content);
</pre>
<p>The resulting object behaves just like an implicit wrapper (most importantly, it will be <a href="#Deep_Wrappers">deep</a>), except that properties set on it will not be visible on either other explicit wrappers or implicit wrappers.  Note that this means that for code not using <code>xpcnativewrappers=yes</code> this type of <code>XPCNativeWrapper</code> is useless at the moment.
</p><p><i>bz: Again, see https://bugzilla.mozilla.org/show_bug.cgi?id=295782 -- that might introduce more differences between this type of wrapper and implicit wrappers.</i>
</p>
<h4 name="Implicit_XPCNativeWrapper"> Implicit <code>XPCNativeWrapper</code> </h4>
<p>This type of wrapper can be created in one of two ways: either by accessing a content object from code that has <code>xpcnativewrappers=yes</code> set or by accessing a property of a <a href="#Deep_Wrappers">deep</a> wrapper.
</p><p><i>bz: The latter may not always be true pending outcome of https://bugzilla.mozilla.org/show_bug.cgi?id=295782</i>
</p><p>The wrapper created in this way is always a <a href="#Deep_Wrappers">deep</a> wrapper.  Furthermore, a wrapper created in this way will stick around as long as the object being wrapped does.
</p><p><i>bz: except for https://bugzilla.mozilla.org/show_bug.cgi?id=295937 -- sort that out before trying to explain the exact behavior here.</i>
</p>
<h5 name="Deep_Wrappers"> Deep Wrappers </h5>
<p>If a wrapper is deep, that means that the return value of any property access or method call on the wrapper will be <a href="#Implicit_XPCNativeWrapper">implicitly wrapped</a>.
</p><p>If a deep wrapper is accessed from code that doesn't use <code>xpcnativewrappers=yes</code>, it will NOT provide safe access to properties.  Instead, it will automatically forward all accesses to the underlying wrappedJSObject.
</p><p><i>bz: This may not be the case for all deep wrappers pending https://bugzilla.mozilla.org/show_bug.cgi?id=295782</i>
</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 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></ol>
Revert to this revision