This of course begs for Cross Site Scripting(XSS.) If the call to their API to happen from a user's browser, then it counts against that individual user's 5000 query limit. One obvious way to accomplish is this is with Flex. That's because the Yahoo API server farm has an open policy for Flash.
Another way is via JavaScript. Of course I can't make an XMLHttpRequest directly from a user's browser to Yahoo because of browser security. Luckily Yahoo encourages Cross Site Script. You can make a request to their local search API with response output set to JSON and with a callback method. From there you just need some sneaky JavaScript:
function search(lat,lng,cat){
var reqUrl = "http://local.yahooapis.com/LocalSearchService"+
"/V2/localSearch?appid=YahooDemo&"+
"output=json&callback=showResults";
var req = reqUrl + "&query="+cat+"&latitude="
+lat+"&longitude="+lng;
var rdiv = document.getElementById("resultlist");
var jsonp = document.createElement("script");
jsonp.setAttribute("type","text/javascript");
jsonp.setAttribute("src",req);
rdiv.appendChild(jsonp);
}
The sneaky part here is creating a "script" DOM element, setting its src attribute to the dynamic URL, and then dropping it into the main page DOM. It gets evaluated immediately. The URL response looks like:
showResults({"ResultSet":{"totalResultsAvailable":3423,"totalResultsReturned":10,"firstResultPosition"
:1,"ResultSetMapUrl":"http:\/\/local.yahoo.com\/mapview?stx=coffee&radius=50&ed=sh5iF6131DyGMtZvcmi9jNSxMpMwUjolfcSc44DLrkDbXpY-"
,"Result":[{"Title":"City Espresso Gourmet Coffee","Address":"630 Blossom Hill Rd","City":"San Jose"
,"State":"CA","Phone":"(408) 972-4500","Latitude":"37.250463","Longitude":"-121.8436","Rating":{"AverageRating"
:"","TotalRatings":"0","TotalReviews":"0"},"Distance":"1.18","Url":"http:\/\/local.yahoo.com\/details
?id=21609154&stx=coffee&csz=San+Jose+CA&ed=WbZ4Ba160SzTaXFlbDSmVAyxneC9N59mhMtS3xZb6kL86aeI4P1iTZT5BJOOXR5qK9HSoV5KX0wL"
,"ClickUrl":"http:\/\/local.yahoo.com\/details?id=21609154&stx=coffee&csz=San+Jose+CA&ed=WbZ4Ba160SzTaXFlbDSmVAyxneC9N59mhMtS3xZb6kL86aeI4P1iTZT5BJOOXR5qK9HSoV5KX0wL"
,"MapUrl":"http:\/\/maps.yahoo.com\/maps_result?name=City+Espresso+Gourmet+Coffee&desc=4089724500&csz
=San+Jose+CA&qty=9&cs=9&ed=WbZ4Ba160SzTaXFlbDSmVAyxneC9N59mhMtS3xZb6kL86aeI4P1iTZT5BJOOXR5qK9HSoV5KX0wL
&gid1=21609154","BusinessUrl":"","BusinessClickUrl":""}]}});
The function showResults gets evaluated with the results from Yahoo. How nice of Yahoo to support JSONP. The eBay APIs also have great support for this technique.
2 comments:
Out of curiosity; what does this actually accomplish? Does it just drive down the 5000 requests a user has to make? The resulting object doesn't have any session/cookie information so I don't see how it could be used for anything malicious (but perhaps I am being naive).
For my purposes, the point is exactly to drive down the 5000 request limit. It basically removes the limit, since all requests will be tied to an end user's IP address, not to the IP address of a web server. It's great the metering is not tied to an API key.
As for malicious uses... I guess that's what people first think of when it comes to cross site scripting. That certainly wasn't my intention. I think Yahoo clearly wanted to enable XSS for exactly the kind of thing that I did. XSS gets a bad name, but there's nothing inherently evil about it.
Post a Comment