• Skip to main content
  • Select language
  • Skip to search
MDN Web Docs
  • Technologies
    • HTML
    • CSS
    • JavaScript
    • Graphics
    • HTTP
    • APIs / DOM
    • WebExtensions
    • MathML
  • References & Guides
    • Learn web development
    • Tutorials
    • References
    • Developer Guides
    • Accessibility
    • Game development
    • ...more docs
Add-ons
  1. MDN
  2. Mozilla
  3. Add-ons
  4. Overlay extensions
  5. XUL School Tutorial
  6. Connecting to Remote Content

Connecting to Remote Content

In This Article
  1. Using XMLHttpRequest
  2. JSON content
  3. XML content
    1. Using XPath
    2. Using XSLT
  4. HTTP debugging

Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

From Firefox 53 onwards, no new legacy add-ons will be accepted on addons.mozilla.org (AMO).

From Firefox 57 onwards, WebExtensions will be the only supported extension type, and Firefox will not load other types.

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to WebExtensions if they can. See the "Compatibility Milestones" document for more.

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.

« PreviousNext »

Using XMLHttpRequest

XMLHttpRequest is an API for transferring XML between a local script and a remote server via HTTP. It is an integral part of the modern web, and all major browsers support it. Besides XML, it can be used to retrieve data in other formats, for example JSON, HTML and plain text. In this section we'll look into the XML and JSON communication mechanisms.

let url = "http://www.example.com/";
let request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
              .createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onload = function(aEvent) {
  window.alert("Response Text: " + aEvent.target.responseText);
};
request.onerror = function(aEvent) {
   window.alert("Error Status: " + aEvent.target.status);
};
request.open("GET", url, true);
request.send(null);

In this example we demonstrate how to make a XMLHttpRequest call in asynchronous mode. You can see that an instance of the XMLHttpRequest class is created and it holds all functionality for making a request. We create this instance using XPCOM instead of the usual way (new XMLHttpRequest()) because this way works both in chrome and non-chrome code.

Following initialization, onload and onerror handlers are registered to a callback function to handle the response returned from the remote server. In both cases aEvent.target is an nsIXMLHttpRequest. In the onload callback function, the responseText parameter contains the server response as text.

If the response is an XML document, the responseXML property will hold an XMLDocument object that can be manipulated using DOM methods. Sometimes the server doesn't specify an XML Content-Type header, which is necessary for the XML parsing to happen automatically. You can use overrideMimeType to force the response to be parsed as XML.

request.overrideMimeType("text/xml"); // do this before sending the request!

The open method takes two required parameters: the HTTP request method and the URL to send the request. The HTTP request method can be "GET", "POST" or "PUT". Sending a POST request requires you to set the content type of the request and to pass the post data to the send() method as below.

request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send("data=hello&version=2");

The third parameter for the open method specifies whether the request should be handled asynchronously or not. In asynchronous mode code execution continues immediately after the send call. In synchronous mode the code and user interface are blocked while waiting for a response to come back.

Note: Requests can take a long time to process and you don't want users to be stuck waiting while a request is obtained and processed. Therefore, it is very important that XMLHttpRequest calls are always done asynchronously.

Now let's look at the most common types of content you can use to communicate with remote servers.

JSON content

JSON is a very lightweight and simple data representation format, similar to the object representation used in JavaScript. Unlike JavaScript, the JSON format doesn't allow any kind of code that can be run, only data.

JSON used to be risky in terms of security because the favored way of parsing it was to use the JavaScript eval function. Since eval executes any code contained in the string, workarounds had to be devised in order to close security holes. Luckily, Firefox now provides a few alternatives for extension developers. The JSON page explains in detail how to parse JSON data in different versions of Firefox and other applications.

Assume we need to parse the following data:

{"shops": [{"name": "Apple", "code": "A001"}, {"name": "Orange"}], "total": 100}

When the onload callback function is called, the response text is converted into a JS object using the parse method. You can then use this object like any other JavaScript objects in your code.

request.onload = function(aEvent) {
  let text = aEvent.target.responseText;
  let jsObject = JSON.parse(text);
  window.alert(jsObject.shops[1].name); // => "Orange"
  window.alert(jsObject.total);         // => 2;
};

The JavaScript object can also be serialized back with the stringify method.

let string = JSON.stringify(jsObject);

XML content

XML is possibly the most popular data interchange format. Let's assume that the XML returned from remote server is this:

<?xml version="1.0"?>
<data>
  <shops>
    <shop>
      <name>Apple</name>
      <code>A001</code>
    </shop>
    <shop>
      <name>Orange</name>
    </shop>
  </shops>
  <total>2</total>
</data>

When a valid XML response comes back from the remote server, the XML document object can be manipulated using different DOM methods, to display the data in the UI or store it into a local datasource.

request.onload = function(aEvent) {
  let responseXML = aEvent.target.responseXML;
  let rootElement = responseXML.documentElement;
  if (rootElement && "parseerror" != rootElement.tagName) {
    let shopElements = rootElement.getElementsByTagName("shop");
    let totalElement = rootElement.getElementsByTagName("total")[0];
    window.alert(shopElements[1].getElementsByTagName("name")[0].firstChild.nodeValue); // => Orange
    window.alert(totalElement.firstChild.nodeValue);                                     // => 2
  }
};

Using DOM functions is good for simple XML documents, but DOM manipulation code can become too complicated if the documents are more complex. There are a couple of tools you can use to process these documents more efficiently:

Using XPath

XPath stands for XML Path Language, it uses a non-XML syntax that provides a flexible way of addressing (pointing to) different parts of an XML document.

Taken from the XPath page.

You can use XPath to quickly access specific nodes in an XML or HTML document with a simple query mechanism. XPath can also be used to extract information from web pages once they load, along with the page load interception techniques discussed previously.

XPath is very useful for cases when you're receiving large and complex XML files, and you only need some of the data contained in them. Using XPath to parse a complete XML document is probably not a good idea performance-wise.

Using XSLT

XSLT (eXtensible Stylesheet Language Transformations) is another tool used to manipulate XML documents and transform them into other forms of text output, such as HTML, XUL, and so on.

We can not cover all transformations to various output formats, so we'll just look into converting an XML document to XUL.

First you need to create an XSLT stylesheet that acts as a template. This template will transform the XML you receive (in our case, the example XML document above) and convert it into XUL. The XSLT tutorial contains details for building these templates.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <xsl:template match="/data">
    <xul:vbox>
      <xsl:for-each select="shops/name">
        <xul:hbox>
          <xul:label value="Name:" />
          <xul:label>
            <xsl:value-of select="." />
          </xul:label>
        </xul:hbox>
      </xsl:for-each>
      <xul:hbox>
        <xul:label value="Total:" />
        <xul:label>
          <xsl:value-of select="total" />
        </xul:label>
      </xul:hbox>
    </xul:vbox>
  </xsl:template>
</xsl:stylesheet>

Next you need to read the XSLT stylesheet as a file stream and parse it into a document object. After that, the XSLT stylesheet can be imported into an XSLT processor as shown below. Now, the processor is ready to perform the transformation.

let domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
                .createInstance(Components.interfaces.nsIDOMParser);
let fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                .createInstance(Components.interfaces.nsIFileInputStream);
let xsltProcessor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"]
                .createInstance(Components.interfaces.nsIXSLTProcessor);
let xslDocument;
fileStream.init(someXSLFile, -1, 0x01, 0444); // read only
// parse from the XSLT stylesheet file stream
xslDocument = domParser.parseFromStream(
    fileStream, null, fileStream.available(), "text/xml");
// import the XSLT stylesheet to the XSLT processor
xsltProcessor.importStylesheet(xslDocument);

Finally, you can either use nsIXSLTProcessor.transformToDocument() or nsIXSLTProcessor.transformToFragment() methods to transform the XML document. The nsIXSLTProcessor.transformToDocument() method returns a DOM Document with the results of the transformation, whereas, the nsIXSLTProcessor.transformToFragment() method returns a DOM DocumentFragment node. In this example code, the first child of the XUL document is appended to a XUL element after the transformation.

request.onload = function(aEvent) {
  let responseXML = aEvent.target.responseXML;
  let xulNode;
  // transform the XML document to a XUL document
  xulDocument = xsltProcessor.transformToDocument(responseXML);
  // append the XUL node to a XUL element
  xulNode = document.adoptNode(xulDocument.firstChild);
  document.getElementById("foo").appendChild(xulNode);
};

We effectively transformed the XML file into XUL and integrated it into the UI.

Note: Security should be your number one priority when handling remote content. Do not allow event handlers or any other kinds of code to be passed through your parsers. If you need your generated XUL to have JS code in it, all of it should be added locally, never from the remote source.

Here are a couple of practical situations were you may want to use XSLT:

  1. Convert a large XML document directly into XUL.
  2. Filter a complex XML file and generate a simpler XML document with only the data you need, so then you can use regular DOM functions to read it.
  3. Convert XML into SQL statements. You could use this to generate a script to run on your local database. You would of course need to be very careful about escaping characters and protecting yourself against SQL injection attacks.
  4. Convert XML into RDF. This was more useful when RDF was the default storage format. You can still use RDF as an intermediate format, though, and then use templates to generate XUL and display the data.

HTTP debugging

When you start debugging HTTP requests, you may find it hard to know exactly what data was sent, especially with POST data. We recommend you to use extensions like Tamper Data. They help you to track HTTP/HTTPS requests and responses occurring in Firefox.

After installation, you can find a Tamper Data menu item in the menu bar:

  • Tools > Tamper Data or
  • View > Sidebar > Tamper Data

Once you open the Tamper Data view, all requests and responses will begin to appear in it. You can discover some interesting things about Firefox like this, such as the automatic update URLs for extensions, and the behavior of web applications such as Gmail.

If you click on the "Start Tamper" button, for every request made you will get a popup dialog for tampering with it before it is sent. You can use it to view or even modify the data in a request, and then inspect the result. This can be a lot of work because there is a lot of web activity in a normal Firefox window, so use it sparingly.

A tutorial on Tamper Data can be found here.

Note: You should always test your connection code to cover edge cases, like when there is no Internet connection, or the computer is connected to a local network with no Internet access (like at an airport or hotel room). Make sure you're not telling users everything is OK, or worse, bombarding them with error messages.

« PreviousNext »

This tutorial was kindly donated to Mozilla by Appcoast.

Document Tags and Contributors

 Contributors to this page: wbamberg, teoli, trevorh, JamesWatts, jpgtama, Jorge.villalobos, shimil
 Last updated by: wbamberg, Jul 4, 2016, 1:45:42 PM
See also
  1. WebExtensions
  2. Getting started
    1. What are WebExtensions?
    2. Your first WebExtension
    3. Your second WebExtension
    4. Anatomy of a WebExtension
    5. Example WebExtensions
  3. How to
    1. Intercept HTTP requests
    2. Modify a web page
    3. Add a button to the toolbar
    4. Implement a settings page
  4. Concepts
    1. Using the JavaScript APIs
    2. User interface components
    3. Content scripts
    4. Match patterns
    5. Internationalization
    6. Content Security Policy
    7. Native messaging
  5. Porting
    1. Porting a Google Chrome extension
    2. Porting a legacy Firefox add-on
    3. Embedded WebExtensions
    4. Comparison with the Add-on SDK
    5. Comparison with XUL/XPCOM extensions
    6. Chrome incompatibilities
  6. Firefox workflow
    1. Temporary Installation in Firefox
    2. Debugging
    3. Getting started with web-ext
    4. web-ext command reference
    5. WebExtensions and the Add-on ID
    6. Publishing your WebExtension
  7. JavaScript APIs
    1. Browser support for JavaScript APIs
    2. alarms
    3. bookmarks
    4. browserAction
    5. browsingData
    6. commands
    7. contextMenus
    8. contextualIdentities
    9. cookies
    10. downloads
    11. events
    12. extension
    13. extensionTypes
    14. history
    15. i18n
    16. identity
    17. idle
    18. management
    19. notifications
    20. omnibox
    21. pageAction
    22. runtime
    23. sessions
    24. sidebarAction
    25. storage
    26. tabs
    27. topSites
    28. webNavigation
    29. webRequest
    30. windows
  8. Manifest keys
    1. applications
    2. author
    3. background
    4. browser_action
    5. chrome_url_overrides
    6. commands
    7. content_scripts
    8. content_security_policy
    9. default_locale
    10. description
    11. developer
    12. homepage_url
    13. icons
    14. manifest_version
    15. name
    16. omnibox
    17. options_ui
    18. page_action
    19. permissions
    20. short_name
    21. sidebar_action
    22. version
    23. web_accessible_resources
  9. Add-on SDK
  10. Getting started
    1. Installation
    2. Getting started
    3. Troubleshooting
  11. High-Level APIs
    1. addon-page
    2. base64
    3. clipboard
    4. context-menu
    5. hotkeys
    6. indexed-db
    7. l10n
    8. notifications
    9. page-mod
    10. page-worker
    11. panel
    12. passwords
    13. private-browsing
    14. querystring
    15. request
    16. selection
    17. self
    18. simple-prefs
    19. simple-storage
    20. system
    21. tabs
    22. timers
    23. ui
    24. url
    25. webextension
    26. widget
    27. windows
  12. Low-Level APIs
    1. /loader
    2. chrome
    3. console/plain-text
    4. console/traceback
    5. content/content
    6. content/loader
    7. content/mod
    8. content/symbiont
    9. content/worker
    10. core/heritage
    11. core/namespace
    12. core/promise
    13. dev/panel
    14. event/core
    15. event/target
    16. frame/hidden-frame
    17. frame/utils
    18. fs/path
    19. io/byte-streams
    20. io/file
    21. io/text-streams
    22. lang/functional
    23. lang/type
    24. loader/cuddlefish
    25. loader/sandbox
    26. net/url
    27. net/xhr
    28. places/bookmarks
    29. places/favicon
    30. places/history
    31. platform/xpcom
    32. preferences/event-target
    33. preferences/service
    34. remote/child
    35. remote/parent
    36. stylesheet/style
    37. stylesheet/utils
    38. system/child_process
    39. system/environment
    40. system/events
    41. system/runtime
    42. system/unload
    43. system/xul-app
    44. tabs/utils
    45. test/assert
    46. test/harness
    47. test/httpd
    48. test/runner
    49. test/utils
    50. ui/button/action
    51. ui/button/toggle
    52. ui/frame
    53. ui/id
    54. ui/sidebar
    55. ui/toolbar
    56. util/array
    57. util/collection
    58. util/deprecate
    59. util/list
    60. util/match-pattern
    61. util/object
    62. util/uuid
    63. window/utils
  13. Firefox for Android
  14. Getting started
    1. Walkthrough
    2. Debugging
    3. Code snippets
  15. APIs
    1. Accounts.jsm
    2. BrowserApp
    3. HelperApps.jsm
    4. Home.jsm
    5. HomeProvider.jsm
    6. JavaAddonManager.jsm
    7. NativeWindow
    8. Notifications.jsm
    9. PageActions.jsm
    10. Prompt.jsm
    11. RuntimePermissions.jsm
    12. Snackbars.jsm
    13. Sound.jsm
    14. Tab
  16. Legacy
  17. Restartless extensions
    1. Overview
  18. Overlay extensions
    1. Overview
  19. Themes
  20. Lightweight themes
    1. Overview
  21. Complete themes
    1. Overview
  22. Publishing add-ons
  23. Guides
    1. Signing and distribution overview
    2. Submit an add-on
    3. Review policies
    4. Developer agreement
    5. Featured add-ons
    6. Contact addons.mozilla.org
  24. Community and support
  25. Channels
    1. Add-ons blog
    2. Add-on forums
    3. Stack Overflow
    4. Development newsgroup
    5. IRC Channel