Get JSONP with raw JavaScript? - javascript

I want to read the JSONP data from an external domain in raw JavaScript (no jQuery).
So let's say https://www.domain.com/abc.php?foo=bar
contains: {"error":false,"data_a":"abcabc","data_b":"123-456"}
I couldn't really find much about this on google. But if I understood it correctly it should work about like this:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script>
script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://www.domain.com/abc.php?foo=bar&callback=DataCallback";
</script>
</head>
<body>
<script>
function DataCallback(data) {
for (var key in data) {
var value = data[key];
alert(key+' = '+value);
}
}
</script>
</body>
</html>
I don't get an error, but I also don't get any alerts popping up.
Btw, I noticed that
https://www.domain.com/abc.php?foo=bar
and
https://www.domain.com/abc.php?foo=bar&callback=DataCallback
both show {"error":false,"data_a":"abcabc","data_b":"123-456"} in the browser.
Could that be the problem? Because I thought that the second link should show:
DataCallback({"error":false,"data_a":"abcabc","data_b":"123-456"})
?

You have two problems.
You are never sending the request
You have to add the script element to the document before it will be executed.
document.body.appendChild(script);
(Don't try doing that before the body exists or before you have defined your callback function)
The server is not responding with JSONP
You can't process plain JSON as if it were JSONP. The server is responding with JSON (well, when I try it, it responds with an advert for buying domains … perhaps you meant example.com?)

I have complete pure javascript jsonp example...
You can have a look if you want
https://github.com/toosha01/ajax-javascript

Related

Pulling out JSON data with src

I am trying to pull out the data with src=""; and load it into variable but with no success.
Here is the code i have been working with:
var JSONObject = document.getElementById("data").innerHTML;
console.log(JSONObject);
<script type='text/javascript' src='https://www.instagram.com/xsolvesoftware/media/' id="data"></script>
innerHTML means exactly what it says: the inner HTML. It is the HTML between <script> and </script> of which there isn't any.
If you want to read the JS then you need to getAttribute('src') and then make an HTTP request for it (e.g. with fetch or XMLHttpRequest).
The Same Origin Policy will probably block this.

JavaScript - order of execution of <script> tags

As stated in this SO question and many other similar, the order of execution of <script>s on the page should be the same as the order in which these tags are defined in the html document.
I created a simple Java (server side) test app that allows to execute a request and wait specified period of time before returning a response (relevant code snippet at the bottom of this question). It has a simple API:
http://localhost:8080/latency?time=XXX&response=YYY
Example request that will return console.log('done') after one second (1000ms):
http://localhost:8080/latency?time=1000&response=console.log(%27done%27)
Next I created a simple index.html page (served by nginx):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test order</title>
</head>
<body>
<script type="text/javascript" async=false src="http://localhost:8080/latency?time=1000&response=console.log(%27done1%27)"></script>
<script type="text/javascript" async=false src="http://localhost:8080/latency?time=100&response=console.log(%27done2%27)"></script>
<script type="text/javascript" async=false src="http://localhost:8080/latency?time=10&response=console.log(%27done3%27)"></script>
<script>console.log('static script without "src" attr');</script>
</body>
</html>
According to everything I read so far I expected the order of console output to be:
done1
done2
done3
static script without "src" attr
This is what I got (Firefox 51 dev console):
This is just the opposite order of what I expected to get. Am I missing something? Is there a way to execute these scripts in the desired order (i.e. in the order they are defined in HTML)?
As a reference, the Java part on a server side:
private String latency(HttpServletRequest request) {
long millis = Long.parseLong(request.getParameter("time"));
String response = request.getParameter("response");
try {
Thread.sleep(millis);
return (response != null) ? response : "";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
async is a boolean attribute. Its value does not matter. Remove the attribute.

jQuery requests on mobile application not working

I am making a mobile application using Intel XDK for Android devices, I have been using an emulator and my local development server (127.0.0.1) to test my PHP code. I have been contacting my server using the following ways $.ajax(), $.post() and $.get(). I then decided that I'd reached a suitable point where I should build the application APK file, push the PHP source on to a online website and test it through a proper mobile. So I did, I made the database by exporting my current data from PMA then changed all the URLs in all my requests to point to the right place and pushed my PHP source to the FTP. I then tested my application and was quite shocked by the results.
Error #1:
PHP Fatal error: Can't use function return value in write context in
/home/scrifalr/public_html/sm/api/v1/modules/register/register.php on
line 9
What I did to fix:
I checked the source and apparently after changing this !empty(trim($_POST['username'])) to empty($_POST['username']) seemed to fix that error.
So question one. Why did this error not show up on my local server and not tell me then that I can't do that?
Error #2:
I have a login/register which sends requests which all works, I changed the above PHP and they started to work. However I have a logout page which doesn't seem to work, the code is shown below:
logout.html
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="css/styles.css">
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="intelxdk.js"></script>
<script src="cordova.js"></script>
<script src="xhr.js"></script>
<script src="js/libs/app.js"></script>
<script src="js/libs/functions.js"></script>
<script src="js/logout.js"></script>
<title>Logout</title>
</head>
<body>
</body>
</html>
As you can see, it has nothing besides the includes. The following file is the JavaScript file:
logout.js
window.onload = function () {
getSessionData();
$.post(
"http://sm.script47.net/api/v1/modules/logout/logout.php", {
"userID": window.userID
}, function (data) {
alert(data);
if (data == 1) {
document.location.href = "index.html";
} else {
showTimedMessage(data, "error", 4000);
}
}
);
};
As you can see, it contains the post request and a function called getSessionData(), so after what seemed like an age of trying to debug I came to the conclusion that it is getSessionData() which is failing which again seems odd as it was working in the emulator and all the paths to the requested files are correct. Just for those who would like to see that function:
window.token = null;
window.userID = null;
window.username = null;
window.emailAddress = null;
window.IP = null;
function getSessionData() {
$.ajax({
url: 'http://sm.script47.net/api/v1/modules/sessionData/sessionData.php',
"type": "GET",
dataType: "json",
async: false // This comment is not in the code, I know I shouldn't have this I'm using it for now and it works with it like this.
}).done(function (data) {
window.token = data.token;
window.userID = data.userID;
window.username = data.username;
window.emailAddress = data.emailAddress;
});
}
So question two is that how come even after I tested it thoroughly and ensured that all the paths are correct and uploaded the exact same code, why are some requests being sent e.g. login, register yet others (logout) not working?
After some more debugging it turned out the AJAX call was failing because synchronous AJAX calls are not allowed.

Getting a JSON file using jQuery without a web server

I had a coding interview quiz for front-end working with JSON and whatnot. I submitted my file but I'd just like to learn what I was missing.
And one of the reqs was Should not require a web server, and should be able to run offline..
I used jQuery and used $.getJSON() to get the data from the .JSON file. I threw it up on my WAMP localserver and it worked flawlessly across all three major browsers (IE, Firefox, Chrome). Then I moved that project to Desktop, so essentally, without a LOCALSERVER.
On Firefox 30.0, it worked great. No problems.
Oon Google Chrome, I know you can't access local files without a web server...
On Internet Explorer 11, however... it didn't work. Why?
Here is what I am using. It's not complex.
function loadTasks() {
console.log("Loading tasks...");
$.getJSON("data.json", function(result) {
$.each(result, function(i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
});
}
and here is data.json
This seems to be a bug in jQuery. This bug has been reported to jQuery. The bugs status is fixed. But it seems, the bug is still at large.
Explanation
Generally in IE, ajax is implemented through ActiveXObjects. But in IE11, they made some tweaks to ActiveXObject implementation that if we try to do the following:
typeof(window.ActiveXObject)
instead of returning 'function', as it is said in IE docs, it returns undefined. jQuery used to use this to switch between xhr in normal browsers and between one in IE. Since the check evaluates to undefined, code used to create xhr object in normal browsers is run.(which of-course is a bug, strangely, for non-local files it working fine).
In a bug filed to bugs.jquery.com, the bug reporter asks,
To fix the problem it's enough to change the condition: use
"window.ActiveXObject !== undefined ?" instead of
"window.ActiveXObject ?"
jQuery developers does try to fix this with this commit, but the comment under the commit says its still not fixed and also suggests a possible way to approach this problem.
var activex; // save activex somewhere so that it only need to check once
if ( activex === undefined )
try {
new ActiveXObject("MSXML2.XMLHTTP.3.0");
activex = true;
} catch (e) {
activex = false
}
xhr = activex ? createActiveXHR() : createStandardXHR();
I tried running your code in my machine and it works fine in IE.
However if this is not running in your machine there should be some issue with IE settings. Apart from this if you want to read local file you can try the below code to resolve this issue for IE
function showData(){
function getLocalPath(fileName/*file name assuming in same directory*/){
// Remove any location or query part of the URL
var directoryPath = window.location.href.split("#")[0].split("?")[0];
var localPath;
if (directoryPath.charAt(9) == ":") {
localPath = unescape(directoryPath.substr(8)).replace(new RegExp("/","g"),"\\");
}
localPath = localPath.substring(0, localPath.lastIndexOf("\\")+1)+fileName;
console.log(localPath);
return localPath;
}
var content = null;
try {
var fileSystemObj = new ActiveXObject("Scripting.FileSystemObject");
var file = fileSystemObj.OpenTextFile(getLocalPath("data.json"),1);
content = file.ReadAll();
file.Close();
} catch(ex) {
console.log(ex);
}
console.log(content);
}
showData();
Run your html file in browser from file path and try running above function in console. It will output the content of json file in console.
You can create a wrapper for above code to use in XHR request. Let me know if you need help in integrating this with jQuery AJAX request.
What you we're missing was the use of appCache,
<html manifest="example.appcache">
in your HTACCESS add
AddType text/cache-manifest .appcache
inside example.appcache
CACHE MANIFEST
data.json
index.php
someimage.png
# continue for all the file needed for the web site to work
This means that once you have connected and downloaded the content once it's not needed again. on another note you not supposed to be able to access a file:// URI though XHR/ajax as there is no way to send the content if you wanted it offline you could have just embedded the content of the json file into you code as a string and just use var jsonStr = '{}'; var jsonObj = JSON.parse(jsonStr); where jsonStr is you code. this would have meant no connections to the server as there would be no ajax/XHR request
jQuery .getJSON uses ajax. http://api.jquery.com/jquery.getjson/
.ajax uses a XMLHttpRequest
The web security of chrome and other browsers block XMLHttpRequest to local files because it is a security issue.
Via Security in Depth: Local Web Pages
http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html
You receive an email message from an attacker containing a web page as
an attachment, which you download.
You open the now-local web page in your browser.
The local web page creates an iframe whose source is
https://mail.google.com/mail/.
Because you are logged in to Gmail, the frame loads the messages in
your inbox.
The local web page reads the contents of the frame by using JavaScript
to access frames[0].document.documentElement.innerHTML. (An Internet
web page would not be able to perform this step because it would come
from a non-Gmail origin; the same-origin policy would cause the read
to fail.)
The local web page places the contents of your inbox into a
and submits the data via a form POST to the attacker's web server. Now
the attacker has your inbox, which may be useful for spamming or
identify theft.
The solution for data which does not need same-origin policy security, is padded json. Since jsonp is not a secure format for data. Jsonp does not have the same-origin policy.
/* secured json */
{
"one": "Singular sensation",
"two": "Beady little eyes",
"three": "Little birds pitch by my doorstep"
}
/* padded json aka jsonp */
Mycallback ({
"one": "Singular sensation",
"two": "Beady little eyes",
"three": "Little birds pitch by my doorstep"
});
Since with jsonp the json is wrapped in a valid javascript function it can be opened the same way as any one would add any javascript to a page.
var element = document.createElement("script");
element.src = "jsonp.js";
document.body.appendChild(element);
And your callback processes the data,
function Mycallback(jsondata) {
}
This is functionally the same as a ajax request but different because it is a jsonp request, which is actually easier.
jQuery libs do directly support jsonp as well http://api.jquery.com/jquery.getjson/ See the example using Flickr's JSONP API; unless one was aware of the dual standards they may not even notice that jsonp is being used.
(function() { /* jsonp request note callback in url, otherwise same json*/
var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
$.getJSON( flickerAPI, {
tags: "mount rainier",
tagmode: "any",
format: "json"
})
.done(function( data ) {
$.each( data.items, function( i, item ) {
$( "<img>" ).attr( "src", item.media.m ).appendTo( "#images" );
if ( i === 3 ) {
return false;
}
});
});
})();
Local access to json can be enabled but it is done differently depending on browswer.
Use --allow-file-access-from-files to enable it in chrome. https://code.google.com/p/chromium/issues/detail?id=40787
FYI: they are working on encripted json https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-encryption-08 I am fairly certain that there will be no method of using this locally the intention is to make it really, really secure.
Source: https://stackoverflow.com/a/22368301/1845953
Posting the answer just in case somebody else runs into it. In my case
IE was loading a version of jquery that apparently causes "JSON
undefined" error. Here is what I did to solve it:
<!--[if lt IE 9]>
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
<!--<![endif]-->
The latest one is jquery 2.1.1: direct link but it says:
(IE <9 not supported)
So I guess jquery 1.11.1: direct link
And I found out you can develop ajax and jquery stuff in Chrome on local files if you use Chrome with this flag: --allow-file-access-from-files (source)
<meta http-equiv="X-UA-Compatible" content="IE=edge">
Try adding this meta tag and check in IE
Here's a working solution.
I've included handlebars because it's cleaner.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>JSON TEST</title>
</head>
<body>
<div id="load-tasks">
</div>
<script src="jquery.min.js"></script>
<script src="handlebars.min.js"></script>
<script id="tasks-template" type="text/x-handlebars-template">
{{#each .}}
<div class="row">
<span class="data-task">
{{this.name}}
</span> <span class="data-date">
{{this.date}}
</span> <span class="data-name">
{{this.assigned}}
</span>
</div>
{{/each}}
</script>
<script>
$(function () {
var loadTasksContainer = $('#load-tasks'),
tasksTemplate = Handlebars.compile($('#tasks-template').html());
$.ajax({
type: "GET",
url: "data.json",
dataType: "json",
cache: false,
success: function (data) {
var html = tasksTemplate(data);
loadTasksContainer.append(html);
},
error: function (xhr, status, error) {
//log error and status
}
});
});
</script>
</body>
</html>
Using JSONP you could make this work for all browsers with or without a web server or even cross domain.
Example data.jsonp file:
loadTasks([
{name:"Task 1", date:"Date 1", assigned:"John Doe"},
{name:"Task 2", date:"Date 2", assigned:"Jane Doe"}
]);
Then on your page just load the data.jsonp using a script tag:
<script>
function loadTasks(tasks) {
$.each(tasks, function (i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
}
</script>
<script src="data.jsonp"></script>
Try including an error callback ; jqxhr.responseText may still contain data.json .
data.json
{"data":{"abc":[123]}}
json.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript">
$(function() {
$.getJSON(document.location.protocol + "data.json")
.then(function(data, textStatus, jqxhr) {
var response = JSON.parse(data);
console.log(textStatus, response);
}
// `error` callback
, function(jqxhr, textStatus, errorThrown) {
var response = JSON.parse(jqxhr.responseText);
console.log(textStatus, errorThrown, response);
$("body").append(response.data.abc);
});
})
</script>
</head>
<body>
</body>
</html>
Dealing with this problem will lead you to anywhere. It is a difficult task and it could be easily solved using any http server.
If your problem is that it is difficult to set up one, try this:
https://www.npmjs.org/package/http-server
On your shell you go to the directory where are your files and then you just type
http-server ./ -p 12345
where 12345 can be changed by any valid and not already used port of your choice.

cross-site scripting

I have a javascript that sits on my server. I want to provide my visitors with javascript code that they can place on their servers in the way that Google Analytics does it. For example:
<script type="text/javascript" src="http://www.somedomain.com/script/script.js?id=2001102"></script>
I got everything working up to the point where I need to grab the id. I'm just not sure what to use for that.
I tried both location.href and location.search, but that gives me url + param of the file where the script is embeded, not "script.js?id=XSOMEIDX"
In script.js I have the following:
function requestContent() {
var script = document.createElement("script");
script.src = "http://www.somedomain.com/script/xss_script.php?id="I WANT TO INPUT ID HERE+"&url="+location.href;
document.getElementsByTagName("head")[0].appendChild(script);
}
Any how I can take id=XSOMEIDX and put it in xss_script.php?id= ?
Thanks in advance!
You can use URL rewritting to take id=XSOMEIDX and put it in xss_script.php?id=
A mod rewrite rule doing it would look like this :
RewriteRule ^/scripts/([a-zA-Z0-0]+)/script.js$ /scripts/script.php?id=$1
This way you could simply ask the people to include yoursite.com/scripts/{id}/scripts.js
how about setting up the external script tag with a certain attribute?
<script data-my-script="my_value" type="text/javascript" src="http://www.somedomain.com/script/script.js?id=2001102"></script>
in modern browsers you can then do
var scripts = document.querySelectorAll("script[src][data-my-script]");
$.each(scripts, function(i, script) { console.log(script.src); });
and iterate over the nodeList...
NOTE: querySelectorAll is not working cross-browser
NOTE: querySelectorAll is returning an array-like object

Categories