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".
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('git+ssh://example.con/item'); // true - absolute URL with '+' in scheme
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' or "+" 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
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';
}
});
});
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
}
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 ":"
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.
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
}