How to "ping" a web site?

Is there a way, using AppleScript(ObjC) or Shell, to know if a web site is online, without loading it?

Just ping them.

set a1 to connectionCheck("www.google.com") of me


on connectionCheck(aSite)
	try
		do shell script "/sbin/ping -c 1 " & aSite
		set the connection_status to true
	on error
		set the connection_status to false
	end try
	
	return connection_status
end connectionCheck
1 Like

ping isn’t ideal for this purpose, as the only thing it can tell you is whether a host is able to reply to ping requests, and that assumes the able host doesn’t ignore such requests, which is what some internet hosts specifically do in order to prevent a pingflood. But this means that the absence of a response doesn’t imply that the host is truly offline. Conversely, a host may respond to a ping, but this doesn’t imply anything about what’s going on with its other ports, such as whether its website is currently online.

The gold standard for testing whether a website is online is to send an HTTP request message to the website’s host, but rather than requesting the entire website as a response, you can simply request its headers, e.g.

bash: /dev/tcp

#!/usr/bin/env bash
exec 5<>/dev/tcp/www.google.com/80
printf 'HEAD / HTTP/1.0
Host: www.google.com

' >&5
cat <&5 & exec 5>&-

AppleScript:

do shell script "bash -c \"exec 5<>/dev/tcp/www.google.com/80
printf '%s\\n\\n' 'HEAD / HTTP/1.0' 'Host: www.google.com' '' >&5
cat <&5 & exec 5>&- \""

Of course, you can use more powerful commandline tools:

nc: via zsh

#!/usr/bin/env zsh
printf "HEAD / HTTP/1.0\r\n\r\n" |
nc -i 1 "www.google.com" 80

If you want a fully-native AppleScript alternative, you can leverage the URL class, which resolves URLs into an IPv4 address, which will be absent if the host isn’t available:

"https://google.com" as URL

(* Result: { 
      class:URL, scheme:secure http URL, 
      path:"https://google.com", host:{
      class:Internet address,
      DNS form:"google.com", port:443,
      dotted decimal form:"142.250.200.14"
} } *)

"https://g00gle.com" as URL

(* Result: { 
      class:URL, scheme:secure http URL, 
      path:"https://g00gle.com", host:{
      class:Internet address,
      DNS form:"g00gle.com", port:443
} } *)

Note that the non-existent website "g00gle.com", when coerced to a URL, returns a record for which the host’s dotted decimal form property is missing.

Putting this into a handler that returns true or false according to whether a host is reachable:

on hostIsReachable at host name as text
        local scheme
        set scheme to "https://"
        if the host name starts with "http" then set scheme to ""
        tell the scheme & the host name as {URL, «class furl»} ¬
                to if (its class is URL) then tell (the host & the ¬
                {dotted decimal form:missing value}) to return ¬
                the dotted decimal form is not missing value
end hostIsReachable

hostIsReachable at "google.com" --> true
hostIsReachable at "g00gle.com" --> false
1 Like

I don’t think the script I presented is the best one. That’s just the starting point for discussion.

The script I presented is part of a program that checks connections to multiple domains to check the Internet connection and decides whether or not to connect by majority vote.

Even though you can’t access the web, there are a number of stages of disability that can be combined.

Internet connection, DNS information is confused, web server (httpd) is down, and so on.

The key here is to clarify the prerequisites for what kind of trouble you are prepared for.

I wanted the questioner to think about what was inadequate and what should be done. Not in the outfield, but in the questioner himself.

@Piyomaru
Yes, I noticed that ping is not reliable at all.

@CJK
Your last script seems to be an excellent alternative to curl. Fast enough and simpler.
Although I have a question: some times, I’m silently redirected to a ‘provider’ site saying the domain is available. Do you think it’s possible to get the resulting url?

Some sites block ping requests and others may block header requests (405 errors), so another approach would be this AppleScript:

use scripting additions

set asite to "www.example.com"
try
	-- for sites blocking header requests with 405 Method Not Allowed errors
	(do shell script "nc -zw2 " & asite & " 80 &> /dev/null") as integer
	set status to true
on error
	set status to false
end try
log (status) as boolean

I dont think you would be able to obtain this from my AppleScript method, but you should be able to by way of NSURLSessionTask’s URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler: method, passing missing value to the completionHandler: parameter.

Admittedly, I’ve never used this particular method myself, but perhaps we can both have a play around with it to gauge its viability. My reservation is around whether this would handle multiple redirects.