Team LiB
Previous Section Next Section

Hack 66. Work with Mozilla XML-RPC Services

Want web service scripting, but don't need SOAP's complexity? Use XML-RPC.

XML-RPC is a way for you to run methods on a server from a remote client. All commands and responses are formatted as XML. It's similar to SOAP [Hack #65], and both are intended to solve the same sorts of problems. However, XML-RPC is a much simpler protocol.

XML-RPC was developed by UserLand Software. The specification is at http://www.xmlrpc.com/spec.


There are two major differences between XML-RPC and SOAP. First, XML-RPC has only eight data types: int, boolean, string, double, dateTime.iso8601, base64, array, and struct, whereas SOAP has many more data types and more can be added via XML Schema. Second, XML-RPC has no standardized discovery mechanisms, such as SOAP's WSDL or UDDI.

You might find that XML-RPC's "limitations" make it easier to learn than SOAP. With fewer requirements, it's easier to make your code work, and there are fewer things that can go wrong.

XML-RPC is widely deployed on web services across the Internet. Most weblog publishing software, for example, includes support for at least one of the major external editor protocols: Blogger API, MetaWeblog API, or Movable Type (mt) API.

6.10.1. Locate XML-RPC in Firefox

Firefox supports XML-RPC in the chrome. Your extensions can use XML-RPC to pass commands and data back and forth between Firefox and any web service with a published XML-RPC specification.

6.10.1.1 Review security arrangements

XML-RPC used in the chrome has no security restrictions. Scripts can talk to any server. At the time of writing, Firefox's native XML-RPC service is not yet available to ordinary web pages.

This limitation is bound to change eventually, because of XML-RPC's similarity to SOAP, which is available to scripts in web pages. If you need to use XML-RPC in a web page, there are some free, cross-platform XML-RPC libraries on the Web, written in JavaScript. One oft-used example is Scott Andrew's XML-RPC JavaScript Message Builder, available at http://www.scottandrew.com/xml-rpc/.

6.10.1.2 Start out on the right foot

The XML-RPC component that comes with Firefox is slightly imperfect. It's easy to fix, but until the official component has been fixed, its bug will have implications for any chrome extension you create (for distribution) that uses XML-RPC. You will either have to provide your own implementation of XML-RPC or include the fixed version we're about to describe. The latter option might require that your extension's license be compatible with the Mozilla Public License. You don't have to worry about this for hacking your own copy of Firefox.

To fix the bug:

  1. Exit Firefox.

  2. Open the Components folder in the Firefox installation area and move the existing nsXmlRpcClient.js file to a safe place.

  3. Move the new file you downloaded in Step one to the Components folder.

  4. Restart Firefox.

Without this fix, most XML-RPC calls will generate errors.

6.10.2. Create an XUL Test File

Since we need to work from within the security of the chrome, we'll create a small XUL extension that uses a testing service provided by XML-RPC.com (http://www.xmlrpc.com). Their server has a function called examples.getStateList. It expects a list of numbers between 1 and 50 and returns a string that contains a comma-separated list of the names of the U.S. states that were specified. States are numbered by their date of acceptance to the Unionoldest first.

6.10.2.1 Build the frontend XUL file

Our interface needs are minor: a text field to enter some state numbers, a text field to display the results, and a button to run the XML-RPC call. Create an XUL file named xml-rpc.xul with the following contents:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE window>
<window title="XML-RPC States" 
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  style="width: 4in; height: 1.5in;">

  <script type="application/x-javascript" src="xml-rpc.js" />

  <vbox flex="1" style="margin: 8px;">
    <text value="Enter a state code:"/>
    <hbox>
      <textbox flex="1" rows="1" id="statecodes"/>
      <button label="List States" onclick="listStates( )"/>
    </hbox>
    <text value="States:"/>
    <hbox flex="1">
      <textbox flex="1" id="states" multiline="true"/>
    </hbox>
  </vbox>
</window>

6.10.2.2 Script XMP-RPC with JavaScript

Just as with SOAP and WSDL, your best bet when scripting with XML-RPC is to create a proxy object to hide the communication details from the rest of your script.

This will also make it much easier to switch from XML-RPC to SOAP or some other protocol, should you ever choose to do so.


Create a file named xml-rpc.js with the following contents:

const Cc = Components.classes;
const Ci = Components.interfaces;

var statesProxy = {
  _xmlRpcClient: null,
  
  get xmlrpc( ) {
    if ( ! this._xmlRpcClient ) {
      this._xmlRpcClient = Cc["@mozilla.org/xml-rpc/client;1"]
        .createInstance( Ci.nsIXmlRpcClient );
    }
      return this._xmlRpcClient;
  },
  
  invoke: function( call, aParams, cb ) {
    this.xmlrpc.init( "http://www.xmlrpc.com/RPC2" );
    
    var Listener = {
      onResult: function( client, ctxt, result ) {
        // assumes result is string
        window[ cb ]( result.QueryInterface( Ci.nsISupportsCString ).data );
      },
    
      onFault: function( client, ctxt, fault ) { },
      onError: function( client, ctxt, status, errorMsg ) { }
    };
    
    this.xmlrpc.asyncCall( Listener, null, call, aParams, aParams.length );
  },
  
  listStates: function( aStateNums ) {
    var xmlrpc = this.xmlrpc;
    var stateList = xmlrpc.createType( xmlrpc.ARRAY, {} );
    var stateCode;
    
    for ( var i = 0; i < aStateNums.length; i++ ) {
      stateCode = xmlrpc.createType( xmlrpc.INT, {} );
      stateCode.data = aStateNums[ i ] - 0;
      stateList.AppendElement( stateCode );
    }
    
    var params = new Array( stateList );
    
    this.invoke( "examples.getStateList", params, "listStatesCallback" );
  }
};

function listStates( ) {
  var sList = document.getElementById( "statecodes" ).value;
  var aStateNums = sList.split( /[, ]+/ );
  
  statesProxy.listStates( aStateNums );
}

function listStatesCallback( result ) {
  document.getElementById( "states" ).value = result;
}

6.10.2.3 Create the Firefox extension

Create an extension [Hack #88] and move the XUL and JavaScript file into its content folder. Assuming that the name of your extension is xmlrpc, you can then run your test with the URL chrome://xmlrpc/content/xml-rpc.xul. You can also launch Firefox from the command line with the -chrome switch to open only the XML-RPC window, as follows:

firefox --chrome chrome://xmlrpc/content/xml-rpc.xul

With the XUL open in Firefox, enter some numbers in the first field, separated by commas or spaces. Press the List States button. If all is well, the names of the matching states will appear in the second field, separated by commas, as shown in Figure 6-10.

Figure 6-10. The final, working version of the XML-RPC test file


Seth Dillingham

    Team LiB
    Previous Section Next Section