GWT loading remote JSONP XSS

In almost all browsers there is one thing that everybody wants to do, but you just can’t, Load cross site data. That is you can’t unless you are using JSONP. Basically you load the data into its own script tag tell the server you are loading it from to wrap the data in a callback that you have defined. This will fire an event after the data has loaded. Perfect.

I wanted to use it in GWT … now I can.

package com.peterfranza.gwt.cle.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.RootPanel;

public class JSONPLoader {

	private LoaderCallback callback;

	public void load(String jsonUrl, LoaderCallback callback) {
		this.callback = callback;
		String callbackString = "jsonLoad_" +
			DOM.createUniqueId().replace("-", "_") + "_callback";
		String url = jsonUrl + (jsonUrl.contains("?") ? "&" : "?")
			+ "_callback=" + callbackString;
		publishCallbackMethod(callbackString);
		Element fr1 = DOM.createElement("script");		
		fr1.setAttribute("src", url);
		RootPanel.get().getElement().appendChild(fr1);

	}

	private native void publishCallbackMethod(String callback) /*-{
		var ptr = this;
  		$wnd[callback] = function(obj) {
  			ptr.@com.peterfranza.gwt.cle.client.JSONPLoader::loadremotedata(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(callback, obj);
  		};
	}-*/;

	@SuppressWarnings("unused")
	private void loadremotedata(String cbp, JavaScriptObject obj) {
	  callback.onLoad(new JSONObject(obj));
	}

	public interface LoaderCallback {
		void onLoad(JSONObject object);
	}

}

Usage:

JSONPLoader loader = new JSONPLoader();
loader.load("http://pipes.yahoo.com/pipes/pipe.run?_id=CPreCvz42xG4eaOWouNLYQ&_render=json&location=madison&section=mcy", new LoaderCallback() {

	@Override
	public void onLoad(JSONObject object) {
		Window.alert("loaded " + object.size());
	}
});

Notice that the json url does not specify the _callback parameter, this is because it is added by the JSONPLoader class.