Please subscribe to RSS Feed! :)

Disclaimer: If you are reading this via PlanetPlanet or a non-javascript aggregator, please visit the real page to read more
You know, we are living in a world of SOA. And even if we don’t like the new world order of the web, sometimes it can make our lifes easier.
We think that, right?
Right now I’m working on the re-implementation on my DjangoFAIed project. Which means, I’m in need of a separation between shiny new bling bling named web frontend and boring looking jsonrpc or xmlrpc for the web backend.
As you know, I’m working with Django for the daily system development, so here I’m in love with Django and RPC4Django.
The good thing about RPC4Django is that it gives me an easy way to provide two RPC types but only writing one backend.
So, having this in place, and doing some xmlrpc calls from the FAI side of life, I just need to find a way to deal with the web frontend.
So, here we are, my high rated topic: XMLHttpRequests, Javascript and Browsers, and what are they supporting.
There are at least 4 browsers I would care about:
No. 1 is my choice when developing some bling bling, No. 2 comes to my mind if I want to have a fast Javascript Execution time, No. 3 and No. 4, oh well, I use FF and Chrome even on windows, and I never had to do anything with Apple ;)
Now, let’s setup a testbed for the application. Let’s assume:
Now, I hope you have a django installation (I’m already using 1.2 beta) and installed RPC4Django. Create a new django application and add to the __init__.py file these methods:
|
1
2 3 4 5 6 |
# Create your views here.
from rpc4django import rpcmethod @rpcmethod(name="hello_world",signature=['string']) |
This is how we define a new xmlrpc/jsonrpc call which just returns “Hello World”.
Now add to your djangoproject urls.py this endpoint for our RPC calls:
(r'^RPC2/$', 'rpc4django.views.serve_rpc_request')
and add your new application and the rpc4django application to your settings.INSTALLED_APPS.
Setup your apache installation to serve your application, don’t forget your wsgi_handler.py.
Now, if we start a browser and enter “http://testrpc/RPC2/” into the location bar, you will get something like this:

(Picture taken from: David Fischer RPC4Django)
To test if our application is working just create this little xmlrpc client app:
|
1
2 3 4 5 6 |
#!/usr/bin/python
import xmlrpclib if __name__=="__main__": |
It should print out “Hello World”.
As said before, we are using jQuery as DOM library to make our lifes easier, regarding Events and Ajax things.
Let’s see how this goes:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<html><head><title>testhtml</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script> <script src="json2.js"></script> <script>// < ![CDATA[ (function($){ // jsonRPC taken from http://plugins.jquery.com/project/jsonRpc (C) by <a href="http://veged.ya.ru/">Sergey Berezhnoy $.jsonRpc = $.jsonRpc || function(options) { options.type = options.type || 'GET'; var ajaxOptions = { contentType: 'application/json', dataType: options.type == 'GET' ? 'jsonp' : 'json', processData: options.type == 'GET' }; var data = { function send() { if (typeof JSON == 'undefined') { })(jQuery); |
This page includes the jQuery Script from the Google API CDN, you need to get the json2.js from http://www.json.org/
and put it in your documentroot or in your directory where the html file is saved.
When you point your browser now to this page, and you click with your mouse on “click here”, the javascript fires an click event, and inside this click event, it starts to make a Ajax Request against our rpc django app.
The result of this ajax request should be, that the content of the “<DIV> with the ID of “#testOutput will change its content and displays “Hello World”.
“Oh, but you can’t do XMLHttpRequests across different domains! It will fail, and you should know about the same origin policy !” you will say now, and you are right.
But, thanks to the “Web Applications Working Group” we have something new: CORS or simply named: Cross Origin Resource Sharing.
What is “CORS”? you will ask now. The working draft abstracts it like this:
This document defines a mechanism to enable client-side cross-origin requests. Specifications that want to enable cross-origin requests in an API they define can use the algorithms defined by this specification. If such an API is used on http://example.org resources, a resource on http://hello-world.example can opt in using the mechanism described by this specification (e.g., specifying Access-Control-Allow-Origin: http://example.org as response header), which would allow that resource to be fetched cross-origin from http://example.org.
(from: Cross-Origin Resource Sharing, W3C Working Draft 17 March 2009
This really sounds important, right? What it just says is, that now it’s possible to make Cross Site XMLHttpRequests under special cicumstancas.
What we just need to know is that Mozilla implemented this feature already in all Firefox Browsers >= 3.5.
Mozilla calls it “HTTP access control“.
Now, you will bring this example to work when you enable mod_header of your apache installation and add to your test virtualhost something like this:
|
1
2 3 4 5 6 7 |
<virtualhost *:80>
Header set Access-Control-Allow-Origin "*" DocumentRoot /whereever/that/is/ ServerName testrpc AddDefaultCharset utf-8 <some more config statements about wsgi and your django application> </some></virtualhost> |
Pay a bit of attention to the “Header” line. What it will do is easy: It will spit out a new Access-Control-Allow-Origin Header, which is set for anybody to make cross site XHR requests to your site.
It’s just like a bit when you tell Adobe Flash Crossdomain.xml to ‘allow-from-domain “*”‘. Different names, same result.
Now, restart your apache server and try the demo page again, now it should work like a charm. The contents of the div will change to “Hello World” and we are done.
Oh well, not quite done. Now we need to test this positive result in another browser, let’s choose Google Chrome.
To make a long story short, somehow this example doesn’t work, but regarding all the postings on the fantastic lazyweb, Google Chrome does support CORS!
Well, not really. It does support this feature under special circumstancas. This document tells us more.
Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers,
but they’re limited by the same origin policy.
Extensions aren’t so limited. An extension can talk to remote servers outside of its origin, as
long as it first requests cross-origin permissions.
(taken from: Google Chrome Extentions: Cross-Origin XMLHttpRequest)
There is another explanation.
Content scripts are JavaScript files that run in the context of web pages. By using the standard Document Object Model (DOM), they can read details of the web pages the browser visits, or make changes to them.
Here are some examples of what content scripts can do:
- Find unlinked URLs in web pages and convert them into hyperlinks
- Increase the font size to make text more legible
- Find and process microformat data in the DOM
However, content scripts have some limitations. They cannot:
- Use chrome.* APIs (except for parts of chrome.extension)
- Use variables or functions defined by their extension’s pages
- Use variables or functions defined by web pages or by other content scripts
- Make cross-site XMLHttpRequests
(taken from: Google Chrome Extentions: Content Scripts)
Now we have a good, fast and cool browser named Chrome, and it does not work as expected.
It should support this out of the box, and it should work like Mozillas implementation.
There are discussions in the background, regarding Greasemonkey and CORS.
Honestly, I’m writing “intranet” applications, I don’t want to use CORS in external applications. But regarding the CORS specification, I do like the way how this goes.
No need anymore to do cross site XHR via iframe (which works, but is actually painful). Furthermore, it can be a nice standard.
What we need to avoid is that really good browsers like Mozilla FF and Googles Chrome are doing what we always hated about MS: Going two different ways.
I also don’t want to write two or three different JS implementation to do the one thing. I really don’t want to support more then one browsers javascript implementation.
So, how can I get this to work without doing the old painful “iframe” way, and without writing a google extention?