Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if online resource is reachable with JavaScript, not requiring the The Same Origin Policy to allow it

I want to check if a server is reachable with a JavaScript function.

By reachable, I mean, if the server answers, I don't care which HTTP status code, it's reachable.

Stackoverflow/Google helped me to this function:

function check(target)
{
    var xhr = new XMLHttpRequest();
    var target = "https://"+target+"/index.php";
    var num = Math.round(Math.random() * 10000);

    xhr.open("HEAD", target + "?num=" + num, true);
    xhr.send();
    xhr.addEventListener("readystatechange", processRequest, false);

    function processRequest(e)
    {
      if (xhr.readyState == 4)
      {
        if (xhr.status !== 0)
        {
          return true;
        }
        else
        {
          return false;
        }
      }
    }
}

Which works just fine, if the target allows the action with Access-Control-Allow-Origin: * (or the client specifically). But that is not the case.

I've come across a number of solutions, which all seem to rely on that.

How can I check if a server is reachable, independent of the Access-Control-Allow-Origin settings on the server, with JavaScript?

edit: I just wanted to add, that I can not modify the target (e.g. change headers), but I'm able to identify resources that are supposed to be available (e.g. https://target/this-specific-site.php)

edit2: I'm trying to implement a solution, as suggested by @Vic; try it here:

function chk(){

var img = new Image();   // Create new image element

img.onload = function(){
    return false;
};

img.onerror = function() {
    return true;
};

// Try to change this URL to nonexistant image
img.src = 'https://www.google.com/images/srpr/logo3w.png'; // Set source path

}

if (chk())
{
alert("IMAGE LOADED");
}
else
{
alert("IMAGE FAILED TO LOAD ("+chk()+")");
}

but the function appears to return undefined, so the check fails.

edit3: I need the function to give me a return value.

like image 702
SaAtomic Avatar asked Mar 13 '17 07:03

SaAtomic


2 Answers

In modern browsers, you can use the fetch API and its no-cors request Mode which will return an opaque response (you won't be able to do anything else from it) :

fetch('http://google.com', {mode: 'no-cors'}).then(r=>{
  console.log('google is reachable');
  })
  .catch(e=>{
    console.log('google is not there');
    });
fetch('http://fakeservertahtdoesntexist.com', {mode: 'no-cors'}).then(r=>{
  console.log('fake is reachable');
  })
  .catch(e=>{
    console.log('fake is not there');
    });

Weirdly enough, my FF doesn't throw though (but it doesn't then either), while my chrome does throw.

like image 79
Kaiido Avatar answered Oct 30 '22 22:10

Kaiido


You could add a script tag with a src attribute referencing a file you know exists on the server and then using the onerror event to detect if it is not found:

<script src="nonexistent.js" onerror="alert('error!')"></script>

Credit to last comment of this answer.

You shouldn't run into cross origin issues using this solution.

Update

If you don't want to take the chance and run scripts you can use the img tag instead. Use the onerror event to detect failure and the onload event to detect success:

<html>
    <head>
        <img src="https://www.google.com/images/srpr/logo3w.pngx" onerror="failure()" onload="success()" height="0" width="0">
        <script>
            let _isSuccess = false;
            function success() {
                _isSuccess = true;
            }

            function failure() {
                _isSuccess = false;
            }

            function isSuccess() {
                console.log(`is success == ${_isSuccess}`);
                return _isSuccess;
            }

        </script>
    </head>
    <body onload="isSuccess()">
        <h1>Hello World!</h1>
    </body>
</html>
like image 3
Perspectivus Avatar answered Oct 30 '22 20:10

Perspectivus