online offline check using javascript [duplicate] - javascript

This question already has answers here:
Detect the Internet connection is offline?
(22 answers)
Closed 8 years ago.
How do you check if there is an internet connection using jQuery? That way I could have some conditionals saying "use the google cached version of JQuery during production, use either that or a local version during development, depending on the internet connection".

The best option for your specific case might be:
Right before your close </body> tag:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>
This is probably the easiest way given that your issue is centered around jQuery.
If you wanted a more robust solution you could try:
var online = navigator.onLine;
Read more about the W3C's spec on offline web apps, however be aware that this will work best in modern web browsers, doing so with older web browsers may not work as expected, or at all.
Alternatively, an XHR request to your own server isn't that bad of a method for testing your connectivity. Considering one of the other answers state that there are too many points of failure for an XHR, if your XHR is flawed when establishing it's connection then it'll also be flawed during routine use anyhow. If your site is unreachable for any reason, then your other services running on the same servers will likely be unreachable also. That decision is up to you.
I wouldn't recommend making an XHR request to someone else's service, even google.com for that matter. Make the request to your server, or not at all.
What does it mean to be "online"?
There seems to be some confusion around what being "online" means. Consider that the internet is a bunch of networks, however sometimes you're on a VPN, without access to the internet "at-large" or the world wide web. Often companies have their own networks which have limited connectivity to other external networks, therefore you could be considered "online". Being online only entails that you are connected to a network, not the availability nor reachability of the services you are trying to connect to.
To determine if a host is reachable from your network, you could do this:
function hostReachable() {
// Handle IE and more capable browsers
var xhr = new ( window.ActiveXObject || XMLHttpRequest )( "Microsoft.XMLHTTP" );
// Open new request as a HEAD to the root hostname with a random param to bust the cache
xhr.open( "HEAD", "//" + window.location.hostname + "/?rand=" + Math.floor((1 + Math.random()) * 0x10000), false );
// Issue request and handle response
try {
xhr.send();
return ( xhr.status >= 200 && (xhr.status < 300 || xhr.status === 304) );
} catch (error) {
return false;
}
}
You can also find the Gist for that here: https://gist.github.com/jpsilvashy/5725579
Details on local implementation
Some people have commented, "I'm always being returned false". That's because you're probably testing it out on your local server. Whatever server you're making the request to, you'll need to be able to respond to the HEAD request, that of course can be changed to a GET if you want.

Ok, maybe a bit late in the game but what about checking with an online image?
I mean, the OP needs to know if he needs to grab the Google CMD or the local JQ copy, but that doesn't mean the browser can't read Javascript no matter what, right?
<script>
function doConnectFunction() {
// Grab the GOOGLE CMD
}
function doNotConnectFunction() {
// Grab the LOCAL JQ
}
var i = new Image();
i.onload = doConnectFunction;
i.onerror = doNotConnectFunction;
// CHANGE IMAGE URL TO ANY IMAGE YOU KNOW IS LIVE
i.src = 'http://gfx2.hotmail.com/mail/uxp/w4/m4/pr014/h/s7.png?d=' + escape(Date());
// escape(Date()) is necessary to override possibility of image coming from cache
</script>
Just my 2 cents

5 years later-version:
Today, there are JS libraries for you, if you don't want to get into the nitty gritty of the different methods described on this page.
On of these is https://github.com/hubspot/offline. It checks for the connectivity of a pre-defined URI, by default your favicon. It automatically detects when the user's connectivity has been reestablished and provides neat events like up and down, which you can bind to in order to update your UI.

You can mimic the Ping command.
Use Ajax to request a timestamp to your own server, define a timer using setTimeout to 5 seconds, if theres no response it try again.
If there's no response in 4 attempts, you can suppose that internet is down.
So you can check using this routine in regular intervals like 1 or 3 minutes.
That seems a good and clean solution for me.

You can try by sending XHR Requests a few times, and then if you get errors it means there's a problem with the internet connection.

I wrote a jQuery plugin for doing this. By default it checks the current URL (because that's already loaded once from the Web) or you can specify a URL to use as an argument. Always doing a request to Google isn't the best idea because it's blocked in different countries at different times. Also you might be at the mercy of what the connection across a particular ocean/weather front/political climate might be like that day.
http://tomriley.net/blog/archives/111

i have a solution who work here to check if internet connection exist :
$.ajax({
url: "http://www.google.com",
context: document.body,
error: function(jqXHR, exception) {
alert('Offline')
},
success: function() {
alert('Online')
}
})

Sending XHR requests is bad because it could fail if that particular server is down. Instead, use googles API library to load their cached version(s) of jQuery.
You can use googles API to perform a callback after loading jQuery, and this will check if jQuery was loaded successfully. Something like the code below should work:
<script type="text/javascript">
google.load("jquery");
// Call this function when the page has been loaded
function test_connection() {
if($){
//jQuery WAS loaded.
} else {
//jQuery failed to load. Grab the local copy.
}
}
google.setOnLoadCallback(test_connection);
</script>
The google API documentation can be found here.

A much simpler solution:
<script language="javascript" src="http://maps.google.com/maps/api/js?v=3.2&sensor=false"></script>
and later in the code:
var online;
// check whether this function works (online only)
try {
var x = google.maps.MapTypeId.TERRAIN;
online = true;
} catch (e) {
online = false;
}
console.log(online);
When not online the google script will not be loaded thus resulting in an error where an exception will be thrown.

Related

Get Checksum of file from webRequest

I am writing a Google Chrome extension that contains a whitelist of SHA256 checksums for javascript files. Only files within this whitelist are supposed to execute, all others should be blocked.
Currently, i use this inefficient but working code for getting a checksum and blocking the request.
chrome.webRequest.onHeadersReceived.addListener(
function(details) {
if(details.type == "script")
{
return getURL(details.url, false, function(data) {
var content = sha256(data);
if( hashList.indexOf(content) == -1 )
{
console.error(details.url+" not in whitelist");
return {cancel: true};
}
});
}
}, {
urls: ["<all_urls>"],
types: ["main_frame","script"]
}, ["blocking", "responseHeaders"]
);
The problems with this code:
It is quite inefficient as this requires downloading every file twice.
It has to be running synchronously to stop the files before arriving at the client. This makes the delay even bigger.
I want to know / ask whether there are ways to circumvent those issues by accessing the source file without downloading it twice (didnt find anything in the documentation) or at least increase the performance by any other means.
Mr. Cameron, unfortunately it is not possible to get the request body using webRequest API.
Partially this is correct because saving the content of a request may lead to performance problems. See this discussion for more details.

Inspecting WebSocket frames in an undetectable way

How I can read WebSocket frames of a web page in a Chrome extension or Firefox add-on, in a way that cannot be detected by the page?
Inspect WebSockets frames from a Chrome Dev Tools extension formulates a similar question, but developing a NPAPI plugin no longer makes sense because it will soon be removed.
Intercepting the WebSocket data is easy. Simply execute the following script before the page constructs the WebSocket. This snippet monkey-patches the WebSocket constructor: When a new WebSocket constructor is created, the snippet subscribes to the message event, from where you can do whatever you want with the data.
This snippet is designed to be indistinguishable from native code so the modification cannot easily be detected by the page (however, see the remarks at the end of this post).
(function() {
var OrigWebSocket = window.WebSocket;
var callWebSocket = OrigWebSocket.apply.bind(OrigWebSocket);
var wsAddListener = OrigWebSocket.prototype.addEventListener;
wsAddListener = wsAddListener.call.bind(wsAddListener);
window.WebSocket = function WebSocket(url, protocols) {
var ws;
if (!(this instanceof WebSocket)) {
// Called without 'new' (browsers will throw an error).
ws = callWebSocket(this, arguments);
} else if (arguments.length === 1) {
ws = new OrigWebSocket(url);
} else if (arguments.length >= 2) {
ws = new OrigWebSocket(url, protocols);
} else { // No arguments (browsers will throw an error)
ws = new OrigWebSocket();
}
wsAddListener(ws, 'message', function(event) {
// TODO: Do something with event.data (received data) if you wish.
});
return ws;
}.bind();
window.WebSocket.prototype = OrigWebSocket.prototype;
window.WebSocket.prototype.constructor = window.WebSocket;
var wsSend = OrigWebSocket.prototype.send;
wsSend = wsSend.apply.bind(wsSend);
OrigWebSocket.prototype.send = function(data) {
// TODO: Do something with the sent data if you wish.
return wsSend(this, arguments);
};
})();
In a Chrome extension, the snippet can be run via a content script with run_at:'document_start', see Insert code into the page context using a content script.
Firefox also supports content scripts, the same logic applies (with contentScriptWhen:'start').
Note: The previous snippet is designed to be indistinguishable from native code when executed before the rest of the page. The only (unusual and fragile) ways to detect these modifications are:
Pass invalid parameters to the WebSocket constructor, catch the error and inspecting the implementation-dependent (browser-specific) stack trace. If there is one more stack frame than usual, then the constructor might be tampered (seen from the page's perspective).
Serialize the constructor. Unmodified constructors become function WebSocket() { [native code] }, whereas a patched constructor looks like function () { [native code] } (this issue is only present in Chrome; in Firefox, the serialization is identical).
Serialize the WebSocket.prototype.send method. Since the function is not bound, serializing it (WebSocket.prototype.send.toString()) reveals the non-native implementation. This could be mitigated by overriding the .toString method of .send, which in turn can be detected by the page by a strict comparison with Function.prototype.toString. If you don't need the sent data, do not override OrigWebSocket.prototype.send.
There is an alternative to Rob W's method that completely masks any interaction with the page (for Chrome)
Namely, you can take out some heavy artillery and use chrome.debugger.
Note that using it will stop you from opening Dev Tools for the page in question (or, more precisely, opening the Dev Tools will make it stop working, since only one debugger client can connect). This has been improved since: multiple debuggers can be attached.
This is a pretty low-level API; you'll need to construct your queries using the debugger protocol yourself. Also, the corresponding events are not in the 1.1 documentation, you'll need to look at the development version.
You should be able to receive WebSocket events like those and examine their payloadData:
{"method":"Network.webSocketFrameSent","params":{"requestId":"3080.31","timestamp":18090.353684,"response":{"opcode":1,"mask":true,"payloadData":"Rock it with HTML5 WebSocket"}}}
{"method":"Network.webSocketFrameReceived","params":{"requestId":"3080.31","timestamp":18090.454617,"response":{"opcode":1,"mask":false,"payloadData":"Rock it with HTML5 WebSocket"}}}
This extension sample should provide a starting point.
In fact, here's a starting point, assuming tabId is the tab you're interested in:
chrome.debugger.attach({tabId:tab.id}, "1.1", function() {
chrome.debugger.sendCommand({tabId:tabId}, "Network.enable");
chrome.debugger.onEvent.addListener(onEvent);
});
function onEvent(debuggeeId, message, params) {
if (tabId != debuggeeId.tabId)
return;
if (message == "Network.webSocketFrameSent") {
// do something with params.response.payloadData,
// it contains the data SENT
} else if (message == "Network.webSocketFrameReceived") {
// do something with params.response.payloadData,
// it contains the data RECEIVED
}
}
I have tested this approach (with the linked sample modified as above) and it works.
Just to add an exception to #Xan answer (I don't have enough rep to post a comment on his answer so I add it here cause I believe it can save some time to someone else).
That example won't work if the WebSocket connection is established in a context that was loaded via about:, data: and blob: schemes.
See here for the related bugs: Attach debugger to worker from chrome devtools extension

localStorage setItem doesn't work on ipad

In my hydbrid app (Phonegap), I am trying to write to localStorage in a very standard way :
window.localStorage.setItem("proDB", JSON.stringify(data));
or
window.localStorage["proDB"] = JSON.stringify(data);
But it doesn't work on Safari on iPad 2 (iOS 7.1).
It doesn't work and the whole app stops.
Here's the userAgent of this ipad :
Can you help me ?
Thanks
Please check whether you have Private Browsing enabled in Safari. In Safari Private Browsing mode, you get a quota of zero. Hence, all calls to localStorage.setItem will throw a quota exceeded error. Personally I think this is a huge mistake by Safari (as so many sites break), but it is what it is so we have to find a way around it. We can do this by:
Detecting whether we have a functional localStorage
Falling back to some replacement if not.
Read on if you want the details :)
1: Detecting a functional local storage
I am currently using this code to detect whether local storage is available, and fall back to a shim if not:
var DB;
try {
var x = '_localstorage_test_' + Date.now();
localStorage.setItem(x, x);
var y = localStorage.getItem(x);
localStorage.removeItem(x);
if (x !== y) {throw new Error();} // check we get back what we stored
DB = localStorage; // all fine
}
catch(e) {
// no localstorage available, use shim
DB = new MemoryStorage('my-app');
}
EDIT: Since writing this I have packaged up the feature detecting code. If you are using NPM you can install storage-available like so:
npm install --save storage-available
then you can use it in your code like this:
if (require('storage-available')('localStorage')) {
// Yay!
}
else {
// Awwww.....
}
2. Fall back to a shim
The easiest way to deal with the issue once we have detected the problem is to fall back to some other object that does not throw errors on every write.
memorystorage is a little library I wrote that follows the Web Storage API but just stores everything in memory. Because it uses the same API, you can use it as a drop-in replacement for localStorage and everything will function fine (though no data will survive page reload). It's Open Source so use as you please.
Background info
For more information on MemoryStorage and this issue in general, read my blog post on this topic: Introducing MemoryStorage.
I have set local storage key values through below logic using swift2.2
let jsStaring = "localStorage.setItem('Key', 'value')"
self.webView.stringByEvaluatingJavaScriptFromString(jsStaring)
Your first setItem example is correct. I don't believe that you can do the second option (localStorage["someKey"] = "someValue") though. Stick with the first one.
You mention hybrid - is it a PhoneGap or some other framework? Where in the app are you calling localStorage.setItem? If PhoneGap, be sure that everything has loaded via onDeviceReady first before trying to access localStorage:
<script type="text/javascript">
// Wait for PhoneGap to load
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is ready
function onDeviceReady() {
window.localStorage.setItem("key", "value");
}
</script>
Also, if the app freezes/stops working, in my experience it's because somewhere in the code you are accessing an object that is undefined. Perhaps try some debugging by checking if localStorage is undefined and logging it? Are you 100% sure that the "setItem" line is where it fails? Console.log is your friend, prove it! :)
if (localStorage === undefined) {
console.log("oops, localStorage not initialized yet.");
}
else {
window.localStorage.setItem("proDB", JSON.stringify(data));
console.log("localStorage available.");
}

Executing a script via AJAX on Firefox OS device

My question regards the Apps CSP https://developer.mozilla.org/en-US/Apps/CSP
Here it says that all the remote script, inline script, javascript URIs, and other security issues won't work on a Firefox OS app.
So, I tried to download a script that is necessary for my app (Flurry and Ad service) and neither would work on the device. The way I made the call was with AJAX, that way I would avoid the remote and inline scripting that both scripts ment. In the simulator works perfectly, but on the device the ads never show and the Flurry session never starts.
Here is the part of my code where I make the AJAX call for Flurry:
$.ajax({
url: 'https://cdn.flurry.com/js/flurry.js',
dataType: "script",
xhrFields: {
mozSystem: true
},
success: function(msg){
console && console.log("Script de Flurry: luego de la descarga en AJAX "+msg);
flurryLibrary = true;
FlurryAgent.startSession("7ZFX9Z4CVT66KJBVP7CF");
},
error:function(object,status,errortxt){
console && console.log("The script wasn't downloaded as text. The error:" +errortxt);
flurryLibrary = false;
},
always: function(object,status,errortxt){
console && console.log("The script may or may not be downloaded or executed. The error could be:" +errortxt);
}
});
In my app I use the systemXHR permission and make the calls for other websites using this line:
request = new XMLHttpRequest({ mozSystem: true });
Wich is the same as using the xhrFields{mozSystem:true} in the AJAX call.
I believe it's not a cross domain problem because in the rest of my app I make calls for xml files that are not in my domain, and the calls are returned succesfully.
So, my question is, can a Firefox OS app execute scripts that are downloaded via AJAX? Is there a way to get around this problem?
Thank you for your time.
PS: I forgot to add that my app is privileged, just in case you ask
I believe that is a security feature and the short answer to your question would be NO. To quote the CSP doc that you linked to yourself:
You cannot point a at a remote JavaScript file. This means that all JS files that you reference must be included in your app's package.
If you load a JS file using ajax from a remote server, that JS is not included in your app package. You should be careful to obey CSP restrictions. It is possible to get many things working in the simulator or even the phone while developing without fully complying to CSP, but that does not mean it is OK. When you submit your app in future to any credible marketplace (such as Firefox Marketplace), it will be reviewed carefully to make sure it does not violate CSP restrictions. As a general rule of thumb, I would say any attempt at dynamically evaluating JS code will be a security risk and most likely banned by CSP regulations.
First, I'll point out that your two examples are not equivalent.
$.ajax({
xhrFields: {
mozSystem: true
},
});
Is the same as
request = new XMLHttpRequest();
request.mozSystem = true;
which is not the same as
request = new XMLHttpRequest({ mozSystem: true });
Instead, we can follow the advice in the linked bug report and run the following at application load time:
$.ajaxSetup( {
xhr: function() {
return new window.XMLHttpRequest( {
mozSystem: true
} );
}
} );
This alone should fix your problem. However, if it doesn't work, then the next workaround here is to fetch the script resource as plain text and then load that text content as a script.
However, inline scripts and data: URLs are off-limits for privileged Firefox OS apps. We might still accomplish this goal through a blob: URL, however:
window.URL = window.URL || window.webkitURL;
var request = new XMLHttpRequest({ mozSystem: true });
request.open("GET", "https://cdn.flurry.com/js/flurry.js");
// when the Ajax request resolves, load content into a <script> tag
request.addEventListener("load", function() {
// make a new blob whose content is the script
var blob = new Blob([request.textContent], {type: 'text/javascript'});
var script = document.createElement('script');
script.src = window.URL.createObjectURL(blob);
// after the script finishes, do something else
script.addEventListener("load", function() {
flurryLibrary = true;
FlurryAgent.startSession("7ZFX9Z4CVT66KJBVP7CF");
});
document.body.appendChild(script);
});
However, if the script itself does something not allowed by the CSP, then you're definitely out of luck.
You must use mozSystem and mozAnon properties, example:
var xMLHttpRequest = new XMLHttpRequest({
mozAnon: true,
mozSystem: true
});
Its a shame this is a problem, I was hoping on getting loadScript working, as firefoxOS is an environment, and in my app all the application code is HTML5 and local, the current rule is all the scripts need to be loaded in memory in one shot, unless you url load a full page, which means you can not have a persisten wrapper around the site, and ajax inthe pages with assosiated scripts when needed. you would have thought that firefox would have enabled local lazy load for scripts at least. works in chrome, but not in firefox.

Monitor window opening, closing, DOMContentLoaded events for all current & future windows+tabs

Background:
I'm authorised to "automate" a 3rd party site for the purpose of pushing "service orders" into it and monitoring the progress of those requests.
I tried taking a normal "scraping" approach (using WWW::Mechanize, HTML::Query, etc from Perl) but ran into a lot of issues predicting what the JavaScript in the site would do under a variety of circumstances. I intend to go back to this approach if I ever receive support from the vendor of the product which runs the 3rd party site, or can get hold of some better documentation w.r.t business-rules of the product.
To avoid second guessing the JavaScript code, and to save a lot of time, I ended up taking an approach were I load the 3rd party site in Firefox on a dedicated VM, and then execute "privileged" code (i.e: nsI*) in the context of the site to "drive" and "scrape" the site.
I'm currently using nsIWebProgressListener/DOMContentLoaded (when I already have a reference to a ChromeWindow), and nsIWindowMediator window+tab enumeration called from setInterval to find new windows and tabs (when I have no way to predict them opening, nor gain a reference to their DOMWindow objects due to scoping of 3rd party JavaScript).
Question:
How can I automatically install a "hook" into each Window/Tab opened now (and in the future) by the 3rd party site's JavaScript? Something like a "window watcher" nsI~ interface for the whole of the Firefox UI would be very useful in this case.
There are so many ways you could do this, so the right choice depends on how you're going about everything else.
Here are just a few ways of listening, rather than polling.
New Chrome Windows
function ChromeWindowObserver() {
this.observe = function(subject, topic, data) {
// subject is a ChromeWindow
}
}
Components.classes["#mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher)
.registerNotification(new ChromeWindowObserver());
New Tabs
function tabListener(event) {
var browser = gBrowser.getBrowserForTab(event.target):
}
gBrowser.tabContainer.addEventListener("TabOpen", tabListener, false);
Observer Notifications (my favorite)
const dumpObserver = {
observe: function(subject, topic, data) { dump(topic + "\n"); }
}
const domObserver = {
observe: function(subject, topic, data) { dump(subject.location + "\n"); }
}
const ObserverService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
/* debug log notifications */
ObserverService.addObserver(dumpObserver, "*", false);
/* debug log all new content locations */
ObserverService.addObserver(domObserver, "content-document-global-created", false);
Side note, check out JavaScript code modules. I think that might be helpful for you when sharing data between chrome windows.

Categories

Resources