Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using jQuery.getJSON in Chrome Extension

I need to do a cross-domain request in a chrome extension. I know I can it via message passing but I'd rather stick to just jQuery idioms (so my javascript can also work as a <script src="">).

I do the normal:

$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function(data) {
  console.log(data);
});

but in the error console I see:

Uncaught ReferenceError: jsonp1271044791817 is not defined

Is jQuery not inserting the callback function correctly into the document? What can I do to make this work?

(If I paste the code into a chrome console, it works fine, but if I put it as the page.js in an extension is when the problem appears.)

like image 212
Paul Tarjan Avatar asked Apr 12 '10 04:04

Paul Tarjan


3 Answers

Alas, none of these worked, so I ended up doing the communication via the background.html.

background.html

<script src="http://code.jquery.com/jquery-1.4.2.js"></script>
<script>
function onRequest(request, sender, callback) {
  if (request.action == 'getJSON') {
    $.getJSON(request.url, callback);
  }
}

chrome.extension.onRequest.addListener(onRequest);
</script>

javascripts/page.js

chrome_getJSON = function(url, callback) {
  console.log("sending RPC");
  chrome.extension.sendRequest({action:'getJSON',url:url}, callback);
}

$(function(){
  // use chrome_getJSON instead of $.getJSON
});
like image 193
Paul Tarjan Avatar answered Nov 09 '22 13:11

Paul Tarjan


If you specify "api.flickr.com" in your manifest.json file you will not need to use the JSONP callback, script injection style of cross domain request.

For example:

"permissions": ["http://api.flickr.com"],

This should work beautifully in you code. I would remove the querystring parameter "&jsoncallback" as there is no JSONP work needed.

The reason why your current code is not working is your code is injecting into pages DOM, content scripts have access to the DOM but no access to javascript context, so there is no method to call on callback.

like image 45
Kinlan Avatar answered Nov 09 '22 14:11

Kinlan


My impressions it that this fails because the jQuery callback function is being created within the 'isolated world' of the Chrome extension and is inaccessible when the response comes back:

http://code.google.com/chrome/extensions/content_scripts.html#execution-environment

I'm using Prototype and jQuery for various reasons, but my quick fix should be easy to parse:

// Add the callback function to the page
s = new Element('script').update("function boom(e){console.log(e);}");
$$('body')[0].insert(s);

// Tell jQuery which method to call in the response
function shrink_link(oldLink, callback){
    jQuery.ajax({
        type: "POST",
        url: "http://api.awe.sm/url.json",
        data: {
            v: 3,
            url: oldLink,
            key: "5c8b1a212434c2153c2f2c2f2c765a36140add243bf6eae876345f8fd11045d9",
            tool: "mKU7uN",
            channel: "twitter"
        },
        dataType: "jsonp",
        jsonpCallback: callback
    });
}

// And make it so.
shrink_link('http://www.google.com', "boom");

Alternatively you can try using the extension XHR capability:

http://code.google.com/chrome/extensions/xhr.html

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // JSON.parse does not evaluate the attacker's scripts.
    var resp = JSON.parse(xhr.responseText);
  }
}
xhr.send();
like image 2
MrChrisRodriguez Avatar answered Nov 09 '22 13:11

MrChrisRodriguez