Using jQuery.getJSON in Chrome Extension - google-chrome

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.)

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
});

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.

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();

The syntax is a little off. There's no need for the callback( bit. This works flawlessly. Tested in the javascript console of Chrome on this StackOverflow page (which includes jQuery):
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function(data) {
console.log(data);
});

As many of you will know, Google Chrome doesn't support any of the handy GM_ functions at the moment.
As such, it is impossible to do cross site AJAX requests due to various sandbox restrictions (even using great tools like James Padolsey's Cross Domain Request Script)
I needed a way for users to know when my Greasemonkey script had been updated in Chrome (since Chrome doesn't do that either...). I came up with a solution which is documented here (and in use in my Lighthouse++ script) and worth a read for those of you wanting to version check your scripts:
http://blog.bandit.co.nz/post/1048347342/version-check-chrome-greasemonkey-script

Related

Apps Script webhooks and Access-Control-Allow-Origin header missing

I have a Google Apps Script project acting as a webhook. When calling the endpoint using a library like htmx, the preflight check fails and the request subsequently fails. When calling directly with fetch or XMLHttpRequest, it works fine.
I have a sample endpoint with a simple doPost for testing:
const doPost = (request = {}) => {
const { postData: { contents, type } = {} } = request;
return ContentService.createTextOutput(contents);
};
This Codepen sample shows how requests with HTMX fail while fetch and XHRHttpRequest are successful.
Some things I've learned:
The OPTIONS header sent in a preflight results in a 405 error, aborting the request entirely. You can mimic this by sending an OPTIONS request via Postman (or similar) to the web app URL.
The error doesn't include Access-Control-Allow-Origin header, which is what shows as the failure reason in the console.
HTMX sends non-standard headers, which trigger preflight requests in modern browsers. However, you can strip all headers out, which should bypass the preflight, but doesn't. See this related discussion in the repo.
In this kind of situation, what is the best method for debugging? I'm not really sure what else to try to get this working.
This is an issue with HTMX, that requires modification of its source code. The source of the problem is that HTMX adds some event listeners to xhr.upload that makes the browsers mark the request as "not simple", triggering the CORS preflight request:
If the request is made using an XMLHttpRequest object, no event listeners are registered on the object returned by the XMLHttpRequest.upload property used in the request; that is, given an XMLHttpRequest instance xhr, no code has called xhr.upload.addEventListener() to add an event listener to monitor the upload
The specific part of HTMX source code:
forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
forEach([xhr, xhr.upload], function (target) {
target.addEventListener(eventName, function(event){
triggerEvent(elt, "htmx:xhr:" + eventName, {
lengthComputable:event.lengthComputable,
loaded:event.loaded,
total:event.total
});
})
});
});
Sadly, the addEventListener uses anonymous functions, so there's no way to remove them with removeEventListener AFAIK.
But if you are willing to use a custom HTMX script in your app until the authors fix this issue (e.g. add ability to prevent event listener creation on xhr.upload), just remove the xhr.upload from the list in the second row:
forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
forEach([xhr], function (target) {
target.addEventListener(eventName, function(event){
triggerEvent(elt, "htmx:xhr:" + eventName, {
lengthComputable:event.lengthComputable,
loaded:event.loaded,
total:event.total
});
})
});
});
With this modification your original suggestion of removing non-standard HTMX-specific headers via evt.detail.headers = [] will work, since now this request becomes "simple", so no more CORS preflight is made by the browsers.
Note: the modification may break the HTMX file upload, I did not test it.

On page load, async ajax call to load div content(html and js and css) result in deprecated error in chrome 80

On page load, async ajax call to load div(tab) content(html and js and css) result in "Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience." in chrome 80.
First time this problem happened. Second time onwards on click to div(tab) this error is not happening. jquery version is 1.12.3. Tried with setTimeout,
$(document).ready(function(){
$.ajax({
url: 'tabPage',
dataType: 'html',
async: true,
data:'tabId=1&searchedEmpUserId='+searchedEmpUserId+'&menuId='+menuId,
success: function(data) {
// load content from file into #content-holder
$('#content-holder').html(data);
}});}
... but same error is coming.
Tried with
$("#content-holder").load('tabPage?tabId='+tabId+'&searchedEmpUserId='+searchedEmpUserId+'&menuId='+menuId, function(){
unBlockUI();
});
..that also same error. If HTML response text is not set then only error is not coming.
Any help is appreciated.
What I understand from dig down the issue, ajax call is asynchronous but html() or load() is synchronous. So jquery send method call has to change so that async call can be done by default. So async param is replaced with async || true in jquery 1.12.3 min js. It worked for me.

Api empty output on client side

I am working on api of a script i recently coded.
on browser the output of the file is working fine see here : http://www.lilink.it/api.php?u=http://www.designzzz.com/&method=get_short_url
but if i do the calling on client side it returns empty. here is the code for client side :
<script type="text/javascript">
$(document).ready(function() {
// method 1
$.get('http://lilink.it/api.php', {method: 'get_short_url', u: 'http://www.blastingart.com/ayaz-malik'},
function(data){
alert(data.status + data.res);
}, "json"
);
// method 2
$.getJSON('http://lilink.it/api.php?method=get_short_url&u=http://www.blastingart.com/ayaz-malik', function(data) {
if (data.status == 1) {
alert(data.status + data.res);
}
});
});
</script>
Probably, you are trying to make a cross-domain request. Cross domain requests are denied in modern web browsers for security reasons. But it's possible to implement them using special techniques. See:
http://usejquery.com/posts/the-jquery-cross-domain-ajax-guide
You probably have problem about the Same Origin Policy: more info here

MVC 3 jQuery UI autocomplete not displaying the results

I have searched many times and find examples which match my code structure perfect. Yet I am not getting the results from my ajax to display on the input box.
I get results from the POST that have been evaulated with firebug and everything looks great.
Here is the javascript im using.
<script type="text/javascript" language="javascript">
$(function () {
$("input.FamousPerson-List").autocomplete({
source: function (request, response) {
$.ajax({
url: "/FamousPeople/FPPAutoComplete",
type: "POST",
dataType: "json",
data: {
searchText: request.term,
maxResults: 12
},
success: function (data) {
response($.map(data, function (item) {
return {
value: item.DisplayName
}
}))
}
});
}
});
});
Here is a link of the actual code I am using on the web.AutoCompleteTesting Type just about any letter in one of the boxes below to invoke it.
Thanks.
If you look closely at the request being sent up, you'll notice that a callback parameter is being added. Weird, right? Since you're doing a local AJAX post, not a cross-domain (JSONP) one.
I noticed that your project includes jQuery Validate. According to this answer to a question dealing with a similar problem (performing a JSONP request instead of a normal JSON request even though you asked for one), it's a known issue in jQuery validate.
Judging by the other answer, you can change your version of jQuery or perhaps use a patched version of jQuery validate (found here).

jQuery $.ajax() is firing the server request but never gets response on google chrome only

I tested this on firefox and ie and worked. But when testing on chrome, I see in the firebug console that the request never loads.
This is the test page: http://gotune.to/index2.php
And here is the function + $.ajax() request.
function getProgress(id) {
$.ajax({
type: 'POST',
cache: false,
url: "getprogress.php",
//Pass our upload identifier as a parameter.
data: {uid: id},
success: function (d) {
//Get the output as an integer.
var progress = parseInt(d, 10);
//If upload progress is not 100, change bar percentage and update again.
if (progress != '100') {
$('#ProgressBar').css('width', progress + '%');
//We aren't done, update again.
getProgress(id);
}
}
});
}
UPDATE
Tried with
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus+" - "+errorThrown);
}
But still not working.
After a web research for this issue if found this:
Turns out it's a bug, in any webkit
based browser all ajax is essentially
blocked until the file upload is
complete. to bypass this you have to
dynamically create an iframe and run
the ajax requests from within it.
So is a problem of the webkit browsers, thanks #ifaour for your time.
THE BUG REPORT CAN BE FOUND HERE: https://bugs.webkit.org/show_bug.cgi?id=23933