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.
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.
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.
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 ":"
var pat = /^https?:\/\//i;
if (pat.test(urlString))
{
//do stuff
}
For protocol relative urls, use this regex:
/^https?:\/\/|^\/\//i
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:
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)
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
I've seen a few comments about invalid output:
localhost
http:example.com
However, those URLs are indeed relative URLs. It's easy to test:
- Create some folders on your localhost webroot, say
a/b/c/
- Create an index.html file and place following link into it:
<a href="localhost">test</a>
- 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)
- 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
var adress = 'http://roflmao.com';
if (adress.substr(0,7) == 'http://' || adress.substr(0,8) == 'https://') {
//
}