How to test if a URL string is absolute or relative?

JavascriptJqueryStringUrl

Javascript Problem Overview


How can I test a URL if it is a relative or absolute path in Javascript or jQuery? I want to handle accordingly depending if the passed in URL is a local or external path.

if (urlString starts with http:// or https://)
 //do this

Javascript Solutions


Solution 1 - Javascript

FAST

If you only need to test for http:// or https:// then the most efficient way is:

if (urlString.indexOf('http://') === 0 || urlString.indexOf('https://') === 0)

UNIVERSAL

However, I would suggest a more universal, non case-sensitive, protocol-agnostic approach:

var r = new RegExp('^(?:[a-z]+:)?//', 'i');
r.test('http://example.com'); // true - regular http absolute URL
r.test('HTTP://EXAMPLE.COM'); // true - HTTP upper-case absolute URL
r.test('https://www.exmaple.com'); // true - secure http absolute URL
r.test('ftp://example.com/file.txt'); // true - file transfer absolute URL
r.test('//cdn.example.com/lib.js'); // true - protocol-relative absolute URL
r.test('/myfolder/test.txt'); // false - relative URL
r.test('test'); // false - also relative URL

Explain the RegExp
^(?:[a-z]+:)?//

^ - beginning of the string
(?: - beginning of a non-captured group
[a-z]+ - any character of 'a' to 'z' 1 or more times
: - string (colon character)
)? - end of the non-captured group. Group appearing 0 or 1 times
// - string (two forward slash characters)
'i' - non case-sensitive flag

Solution 2 - Javascript

var pat = /^https?:\/\//i;
if (pat.test(urlString))
{
	//do stuff
}

For protocol relative urls, use this regex:

/^https?:\/\/|^\/\//i

Solution 3 - Javascript

Original Answer

A very fast and very flexible check is:

if (url.indexOf('://') > 0 || url.indexOf('//') === 0 ) {
	// URL is absolute; either "http://example.com" or "//example.com"
} else {
	// URL is relative
}

This will recognize an absolute URL, if:

  • URL contains "://" anywhere after the first character, or
  • URL starts with "//" (protocol relative)

  • No regex.
  • No jQuery or other dependency.
  • No hardcoded protocol names that make the condition case sensitive.
  • No string manipulation (e.g. toLowerCase or similar).
  • Only checks for "relative or absolute" but does not make any other sanity checks, can be used for web URLs or any internal protocol.

Update 1 (full function example)

Here is a quick function that returns true/false for the given URL:

function isUrlAbsolute(url) { 
	return (url.indexOf('://') > 0 || url.indexOf('//') === 0);
}

And same in ES6:

const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0)

Update 2 (URLs inside URL param)

To additionally address URLs in format /redirect?target=http://example.org I recommend to use this code:

function isUrlAbsolute(url) {
	if (url.indexOf('//') === 0) {return true;} // URL is protocol-relative (= absolute)
	if (url.indexOf('://') === -1) {return false;} // URL has no protocol (= relative)
	if (url.indexOf('.') === -1) {return false;} // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
	if (url.indexOf('/') === -1) {return false;} // URL does not contain a single slash (= relative)
	if (url.indexOf(':') > url.indexOf('/')) {return false;} // The first colon comes after the first slash (= relative)
	if (url.indexOf('://') < url.indexOf('.')) {return true;} // Protocol is defined before first dot (= absolute)
	return false; // Anything else must be relative
}

And the same in short form and ES 6

// Traditional JS, shortened
function isUrlAbsolute(url) {
	return url.indexOf('//') === 0 ? true : url.indexOf('://') === -1 ? false : url.indexOf('.') === -1 ? false : url.indexOf('/') === -1 ? false : url.indexOf(':') > url.indexOf('/') ? false : url.indexOf('://') < url.indexOf('.') ? true : false;
}

// ES 6
const isUrlAbsolute = (url) => (url.indexOf('//') === 0 ? true : url.indexOf('://') === -1 ? false : url.indexOf('.') === -1 ? false : url.indexOf('/') === -1 ? false : url.indexOf(':') > url.indexOf('/') ? false : url.indexOf('://') < url.indexOf('.') ? true : false)

Here are some test cases:

// Test
console.log( isUrlAbsolute('http://stackoverflow.com') ) // -> true
console.log( isUrlAbsolute('//stackoverflow.com') ) // -> true
console.log( isUrlAbsolute('stackoverflow.com') ) // -> false
console.log( isUrlAbsolute('Ftp://example.net') ) // -> true
console.log( isUrlAbsolute('/redirect?target=http://example.org') ) // -> false

Update 3 (clarify relative URLs)

I've seen a few comments about invalid output:

  • Solution returns false for localhost
  • Answer fails on http:example.com

However, those URLs are indeed relative URLs. It's easy to test:

> 1. Create some folders on your localhost webroot, say a/b/c/ > 2. Create an index.html file and place following link into it: <a href="localhost">test</a> > 3. Open the index page in your browser: http://localhost/a/b/c/index.html and click on the link. You will end on http://localhost/a/b/c/localhost (and not on http://localhost) > 4. Same happens when placing the link http:example.com into your index.html file. You end on http://localhost/a/b/c/example.com instead of http://example.com

Solution 4 - Javascript

Depending on your needs, I think that a more reliable way to determine this is to use the built-in URL interface to construct a couple URL objects and compare origins.

new URL(document.baseURI).origin === new URL(urlToTest, document.baseURI).origin;

This allows the browser to parse and figure all this out for you, without having to worry about the side effects of edge cases.

Solution 5 - Javascript

Use a regex:

if (/^(?:[a-z]+:)?\/\//i.test(url))

Solution 6 - Javascript

Even more Universal RFC-compliant URI approach:

(?:^[a-z][a-z0-9+\.-]*:|\/\/) regex explanation

The other solutions listed here would fail for links like mailto:[email protected]

RFC 3986 defines a Scheme as:

scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

3.1. Scheme https://www.rfc-editor.org/rfc/rfc3986#section-3.1

While the protocol-relative url is technically valid as per section 4.2, Paul Irish has swung back the other way and considers this an anti-pattern. See http://www.paulirish.com/2010/the-protocol-relative-url/

4.2. Relative Reference https://www.rfc-editor.org/rfc/rfc3986#section-4.2

If you'd like the regex without protocol-relative url's use:

^[a-z][a-z0-9+\.-]*:

To see a full list of other types of valid uri edge cases, check out the list here: https://en.wikipedia.org/wiki/URI_scheme

Solution 7 - Javascript

Nowdays, when a lot of services use protocol-relative URL (eg. //cdn.example.com/libary.js), this method is safer:

var isAbsolute = new RegExp('^([a-z]+://|//)', 'i');

if (isAbsolute.test(urlString)) {
  // go crazy here
}

Solution 8 - Javascript

Don't use low-level stuff like regexp etc. These things have been solved by so many other people. Especially the edge cases.

Have a look at URI.js, it should do the job: http://medialize.github.io/URI.js/docs.html#is

var uri = new URI("http://example.org/");
uri.is("absolute") === true;

Solution 9 - Javascript

Here's a pretty robust solution for the browser environment:

Let the browser handle everything. No need for some complicated/error prone regexes.

const isAbsoluteUrl = (url) => {
  const link = document.createElement('a');
  link.href = url;
  return link.origin + link.pathname + link.search + link.hash === url;
};

Solution 10 - Javascript

You can use a try, catch block to help with this. Rather than using a regular expression, you can use the URL interface at every step.

isExternalUrl (urlString) {
  try {
    const url = new URL(urlString) // THROW ON MISSING SCHEME

    // DOES THIS URL ORIGINATE FROM THIS WEBSITE?
    if (url.origin !== new URL(document.URL, document.baseURI).origin) {
      return true // IS EXTERNAL URL
    }
  } catch (_e) {
    // THROWS WHEN URL DOES NOT HAVE A SCHEME
    new URL(urlString, document.baseURL) // THROW AN EXCEPTION IF THE URL IS TRULY MALFORMED IN SOME WAY
  }

  return false
}

Solution 11 - Javascript

var external = RegExp('^(https?:)?//');
if(external.test(el)){
    // do something
}

EDIT:

With the next regular expression, you can even check if the link goes to the same domain or to an external one:

var external = RegExp('^((f|ht)tps?:)?//(?!' + location.host + ')');
if(external.test(el)){
    // do something
}

Solution 12 - Javascript

var adress = 'http://roflmao.com';
if (adress.substr(0,7) == 'http://' || adress.substr(0,8) == 'https://') {
    //
}

Solution 13 - Javascript

Neither of the mentioned solutions solved a redirect_url hack where the hacker entered /\/example.com or /\\/example.com. This is what I came up with to determine if our redirect url was relative:

var isRelative = !redirectUrl.match(/(\:|\/\\*\/)/);  // Don't allow "//" (with optional "\"'s) or ":"

Solution 14 - Javascript

It should not start with a slash or hash, and it should not contain a double slash if not preceded by question mark or hash? I would not test that with a single regexp, it would be very complicated to match "no double slash".

function test(s) {
    return s.charAt(0) != "#"
      && s.charAt(0) != "/"
      && ( s.indexOf("//") == -1 
        || s.indexOf("//") > s.indexOf("#")
        || s.indexOf("//") > s.indexOf("?")
    );
}
    

would be easier, clearer and imho faster.

Solution 15 - Javascript

Following function will get called when click event occurs on a hyperlink i.e 'a' tag if the tag contains url will be relative or contains same host then that new page will get loaded into same browser tab, If it contains different url then page will load in new browser tab

jQuery(document).ready(function() {
	$('a').click(function(){

		var a = this;
		var a_href = $(this).attr('href');
		var regex = new RegExp('^(?:[a-z]+:)?//', 'i');		

		if(a.host == location.host || regex.test(a_href) == false){
			a.target = '_self';
		}else{
			a.target = '_blank';
		}
	}); 
});

Solution 16 - Javascript

var isExternalURL = url.toLowerCase().indexOf('http://') === 0 || url.toLowerCase().indexOf('https://') === 0 ;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTruMan1View Question on Stackoverflow
Solution 1 - JavascriptGeoView Answer on Stackoverflow
Solution 2 - JavascriptstrahView Answer on Stackoverflow
Solution 3 - JavascriptPhilippView Answer on Stackoverflow
Solution 4 - JavascriptBradView Answer on Stackoverflow
Solution 5 - JavascriptSLaksView Answer on Stackoverflow
Solution 6 - JavascriptEvanView Answer on Stackoverflow
Solution 7 - JavascriptrgtkView Answer on Stackoverflow
Solution 8 - JavascriptkopporView Answer on Stackoverflow
Solution 9 - JavascriptEtienne MartinView Answer on Stackoverflow
Solution 10 - JavascriptJonathanView Answer on Stackoverflow
Solution 11 - JavascriptdavidsView Answer on Stackoverflow
Solution 12 - JavascriptOptimusCrimeView Answer on Stackoverflow
Solution 13 - JavascriptDustinView Answer on Stackoverflow
Solution 14 - JavascriptBergiView Answer on Stackoverflow
Solution 15 - JavascriptPrajyotView Answer on Stackoverflow
Solution 16 - JavascriptrinjanView Answer on Stackoverflow