Check if a JavaScript string is a URL
Asked Answered
H

38

563

Is there a way in JavaScript to check if a string is a URL?

RegExes are excluded because the URL is most likely written like stackoverflow; that is to say that it might not have a .com, www or http.

Hart answered 19/4, 2011 at 13:26 Comment(13)
If it is missing the http, it is per default no url.Adkins
@Adkins that is to say that if it doesn't specify a protocol and use the colon character (preferably with two forward slashes next) then it is not a URL?Decennary
@marcel because the algo's append a .com, .net, .biz, .org, .gov, .mil, etc to the name and test to see if it works, given a certain preferential order. Alternately, they ask google if it's likely a domain name.Decennary
As you can read in the URL RFC, the only part actually neccessary to make a String a valid URL is the colon. Valid URLs look like: <scheme>:<scheme-specific-part>Adkins
@Hart could you give an example or two o the url you want to parse and what you expect to get out of it ?Montparnasse
@Montparnasse Actually I'm searching in Google chrome bookmarks so I've got a bunch of data. I can display all the content of the bookmarks tree and the urls are underlined when I display them.Hart
@Bruno: But those bookmarked URLs do contain a protocol and the like.Shag
@Marcel Korpel Yes but when I display the content of the tree bookmark the tree itself must have a way of knowing the difference between urls and plain text (an attribute ?).Hart
You are talking about the bookmark manager, aren't you?Shag
No I'm searching directly in the Google Chrome API so I'm going through the tree of bookmarks.Hart
At code.google.com/chrome/extensions/bookmarks.html you can see that titles and URLs are saved in two separate ‘fields’ in a ‘record’ (object).Shag
see https://mcmap.net/q/74463/-trying-to-validate-url-using-javascriptBerk
How you test whether something is a URL is highly context-dependent and too vague without further qualification. Does it matter to you whether it conforms to the URL RFC spec, works when making an OS system call to open the URL, parses as an href in an anchor element, works when calling window.open(url), points to something that really exists, works in the browser location bar, or a combination of the above? You'll get very different answers depending on which of these you care about.Lagerkvist
P
410

A related question with an answer

Or this Regexp from Devshed:

function validURL(str) {
  var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
    '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
    '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
    '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
    '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
    '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  return !!pattern.test(str);
}
Palmer answered 19/4, 2011 at 13:29 Comment(28)
@TechyTimo's answer below is a nice improvement that works out of box https://mcmap.net/q/73330/-check-if-a-javascript-string-is-a-urlDanged
They've rejected my edit, but you need to change the protocol part to this '^((ft|htt)ps?:\\/\\/)?' to check for ftp/ftps as well as http/https.Indeterminism
Fails on valid url web.archive.org/web/20170817095211/https://github.com/Microsoft/…Cortes
Fails on en.m.wikipedia.org/wiki/C_Sharp_(programming_language)Catechumen
www.jayakumar it is a valid url? it returning trueFlypaper
Fails to validate this very ordinary URL -> http://denstoredanske.dk/Sprog,_religion_og_filosofi/Filosofi/Logik/syllogisme Needed to add , to the "port and path"-section.Ariadne
Does this solution support non-latin letters?Shool
zh.wikipedia.org/wiki/Wikipedia:关于中文维基百科/en should work. This is discussed in : #1548399Deciduous
String fualksdhjakjsdh is also considered validTreva
I think this answer is outdates, suggest not to use it in productionMarcelenemarcelia
This answer is outdated, just easily use new URL() inside a try-catch developer.mozilla.org/en-US/docs/Web/API/URLDakar
Is it just me or this gets incredible slow as the URL length increases?Dulosis
if we put "111111111111111111111111111111111111111111111111" as input server will hang. I faced this issue and then chenged my code to str.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);Overrun
Fails on links with @ - like https://medium.com/@User_name/Catty
@DenisPetrov you need to add the @ as symbol port and path part should look like this '(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*'Rammish
return true for base64 imagesDemure
Try "test-test-test-test-test-test-test-test-test.web.app" takes forever and might say "too much recursion". I am searching for another solutionas this lead to a problem report in my application.Fleischer
@AndreasRiedmüller Try my expression, which described here: #5717593Returnable
Return true test('my-image.png')...Interpret
If returns true even if I use image.png as the test parameter.Protuberate
@Overrun Do you know why 111111111111111111111111111111111111111111111111 cause the server to hang?Sacrament
This e.g. is a valid URL, on which most reexps listed here are failing: https://wäre.möchte.comInterchangeable
Fails this one medium.com/@gordon_zhu/…Base
holy crap.. I hate regexps. As flexible as they get, solutions that they provide are far from readable in lots of cases. "Set and forget" is how one can describe tasks that involve regexps. And I'd add "and never return". It's like reading some stuff from Beethoven for the first time - before you can hear what's really encoded behind those notes, you'll have to spend lot's of time digging through. With regexps it's always just like the first time for me.Eucalyptus
Fails on a simple https://google.com/Bactria
The regex need a couple of minor adjustments. Instead of just a-z in the path and query string, it needs A-Z as well. Valid URLs are case insensitive.Been
When i put url: localhost.com/endecodeUrl?pli=1#gid=855848563 It is not valid? Why?Gamophyllous
This froze my browser.Guthrun
W
652

If you want to check whether a string is valid HTTP URL, you can use URL constructor (it will throw on malformed string):

function isValidHttpUrl(string) {
  let url;
  
  try {
    url = new URL(string);
  } catch (_) {
    return false;  
  }

  return url.protocol === "http:" || url.protocol === "https:";
}

Note: Per RFC 3886, URL must begin with a scheme (not limited to http/https), e. g.:

  • www.example.com is not valid URL (missing scheme)
  • javascript:void(0) is valid URL, although not an HTTP one
  • http://.. is valid URL with the host being .. (whether it resolves depends on your DNS)
  • https://example..com is valid URL, same as above
Wavell answered 18/4, 2017 at 8:22 Comment(28)
This throws an exception for a string such as www.google.com indicating that this is not a valid URL, when it is a valid URLLend
@Lend no, it's not; e.g. you can't use as href attribute for <a>. Valid URL must begin with a scheme name, e.g. https://.Wavell
new URL('javascript:alert(23)')Mallemuck
@Lend Like Pavlo said, your comment isn't correct. Try using an anchor element to link to an external page... the url ends up like... (example.com/www.example.com) rather than going to (example.com).Ethmoid
@Wavell this returns true isValidUrl("javascript:void(0)")Groundnut
I like this for teaching me new things about js! It has no false negatives that I could find. It does have some false positives: http://.. Or http:///aJaela
URL is working starting from Edge so everything below it might not work as you expect. Make sure you check the compatibility first.Strage
This a lot simpler answer. Definitely more understandable for people who don't get regexes.Sunnisunnite
@Mugshep not in Chrome: codesandbox.io/s/boring-cherry-dw2zm Did you mean https://google..com? It is a valid URL, see updated answer.Wavell
You're right - it was 'google..com'. Thanks for the update though - useful clarification.Matte
Another false positive is http:/aCoddle
Doesn't quantify between url string and URL object. ie: let url = new URL("https://google.com"); isValidUrl(url). I suppose you could then test via toString.call(url) for [object String] or [object URL].Immolate
@Immolate true, but the question asked whether a string is a URLWavell
Then the simplest test is toString.call(url) === "[object URL]"Immolate
Great solution and I like the approach! But URL-API is not supported in IE... =/Persecution
I know I'm pretty late to the party, but using new for side-effects (without using the constructors return value) is considered a bad coding practice and many style guides (such as airbnb's widely known one) are already forbidding it with ESLint etc.Semipermeable
Should be the best answer. OP asked for a non-regexp solutionDion
URL constructor accepts values with some infractions. For example, http:///a passes as valid URL, http:///\\a too. The easiest way to make the validator as more strictd is compare stringified value of created URL with initial value like in example: function IsUrl(s: string): boolean { let parsedUrl: URL; try { parsedUrl = new URL(s); } catch { return false; } return parsedUrl.toString() === s && !parsedUrl.pathname.includes("//"); }Returnable
FWIW new URL('#') return as validCheke
isValidHttpUrl("http://www") returns true.Bulwerlytton
Is "http:/localhost" valid URL? One slash after the colon?Tole
@Avatar, http://www is, in fact, a valid URL! It's not a URL that resolves to anything but it's technically formatted correctly. Hostnames themselves are actually pretty poorly defined as explained in this article digging into the history of the specifications: netmeister.org/blog/hostnames.html But basically, you want servername to be valid because in lots of contexts like an intranet, that is a valid URL (I know it makes the "U" part seem silly)Fricative
isValidHttpUrl("http:/sdasdasdasdas") returns trueMycah
URL("1") -> will be validatedBatfish
I did downvote initially, but I'm going to use it myself because 1_I didn't find a better answer. 2_Despite the edge cases where it's failing, it does the job for my use cases. Thank you.Rebekahrebekkah
validation for http://fooo fails with this use caseFanfaronade
Space in the url will also pass this check :(Hodson
Note that this won't be supported in some environments - e.g. React Native.Ghastly
P
410

A related question with an answer

Or this Regexp from Devshed:

function validURL(str) {
  var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
    '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
    '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
    '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
    '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
    '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  return !!pattern.test(str);
}
Palmer answered 19/4, 2011 at 13:29 Comment(28)
@TechyTimo's answer below is a nice improvement that works out of box https://mcmap.net/q/73330/-check-if-a-javascript-string-is-a-urlDanged
They've rejected my edit, but you need to change the protocol part to this '^((ft|htt)ps?:\\/\\/)?' to check for ftp/ftps as well as http/https.Indeterminism
Fails on valid url web.archive.org/web/20170817095211/https://github.com/Microsoft/…Cortes
Fails on en.m.wikipedia.org/wiki/C_Sharp_(programming_language)Catechumen
www.jayakumar it is a valid url? it returning trueFlypaper
Fails to validate this very ordinary URL -> http://denstoredanske.dk/Sprog,_religion_og_filosofi/Filosofi/Logik/syllogisme Needed to add , to the "port and path"-section.Ariadne
Does this solution support non-latin letters?Shool
zh.wikipedia.org/wiki/Wikipedia:关于中文维基百科/en should work. This is discussed in : #1548399Deciduous
String fualksdhjakjsdh is also considered validTreva
I think this answer is outdates, suggest not to use it in productionMarcelenemarcelia
This answer is outdated, just easily use new URL() inside a try-catch developer.mozilla.org/en-US/docs/Web/API/URLDakar
Is it just me or this gets incredible slow as the URL length increases?Dulosis
if we put "111111111111111111111111111111111111111111111111" as input server will hang. I faced this issue and then chenged my code to str.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);Overrun
Fails on links with @ - like https://medium.com/@User_name/Catty
@DenisPetrov you need to add the @ as symbol port and path part should look like this '(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*'Rammish
return true for base64 imagesDemure
Try "test-test-test-test-test-test-test-test-test.web.app" takes forever and might say "too much recursion". I am searching for another solutionas this lead to a problem report in my application.Fleischer
@AndreasRiedmüller Try my expression, which described here: #5717593Returnable
Return true test('my-image.png')...Interpret
If returns true even if I use image.png as the test parameter.Protuberate
@Overrun Do you know why 111111111111111111111111111111111111111111111111 cause the server to hang?Sacrament
This e.g. is a valid URL, on which most reexps listed here are failing: https://wäre.möchte.comInterchangeable
Fails this one medium.com/@gordon_zhu/…Base
holy crap.. I hate regexps. As flexible as they get, solutions that they provide are far from readable in lots of cases. "Set and forget" is how one can describe tasks that involve regexps. And I'd add "and never return". It's like reading some stuff from Beethoven for the first time - before you can hear what's really encoded behind those notes, you'll have to spend lot's of time digging through. With regexps it's always just like the first time for me.Eucalyptus
Fails on a simple https://google.com/Bactria
The regex need a couple of minor adjustments. Instead of just a-z in the path and query string, it needs A-Z as well. Valid URLs are case insensitive.Been
When i put url: localhost.com/endecodeUrl?pli=1#gid=855848563 It is not valid? Why?Gamophyllous
This froze my browser.Guthrun
P
166
function isURL(str) {
  var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
  '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+ // domain name
  '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
  '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
  '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
  '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  return pattern.test(str);
}
Piatt answered 29/1, 2013 at 11:50 Comment(16)
returns false for "magnet:?xt=urn:btih:123"Amendment
fails for google search image links : http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707Lloyd
This regex fails for a lot of common cases. You can improve it by adding a few more characters to the “port and path” and “query string” lines, but this approach probably isn’t the best idea. See my answer for alternatives.Selfeducated
this is unusable slowLurlenelurline
@HernánEche What so you mean by slow? start = new Date(); isURL("http://michalstefanow.com"); end = new Date(); diff = end - start; console.log(diff) I put a kettle on, went to a toilet, called my mum and the thing was done in no time...Unwrap
For refrence sake, with the back slashes it's var pattern = new RegExp('^(https?:\\/\\/)?'+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ '((\\d{1,3}\\.){3}\\d{1,3}))'+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ '(\\?[;&a-z\d%_.~+=-]*)?'+ '(\\#[-a-z\d_]*)?$','i'); Duster
why is it always return true to me even my str value is "hwa".Induction
It returns true for aaa.Drabbet
returns true for dfdsfdsfdfdsfsdfsWhiney
This absolutely should not be the correct answer. It fails many test cases and more importantly it hangs your page on even a short string: isURL('12345678901234567890123') add some more characters and it's even worse.Jaela
@alexnaumov aaa is no doubt a valid, working top-level TLD in some Intranet networks. Try nslookup aaa and it will query your DNS server for it instead of rejecting it outright.Lagerkvist
return true for 'America/New_York'Briefing
doesn't work you can type www and submit it bypasses this regular expression.Inebriant
Not sure how this got this many upvotes. Returns true for asdsdasd.Selfregulating
Returns true for only https. Bad solutionCarpophore
Equally bad as the accepted solution - it returns true for ** fualksdhjakjsdh**Treva
H
117

Rather than using a regular expression, I would recommend making use of an anchor element.

when you set the href property of an anchor, various other properties are set.

var parser = document.createElement('a');
parser.href = "http://example.com:3000/pathname/?search=test#hash";

parser.protocol; // => "http:"
parser.hostname; // => "example.com"
parser.port;     // => "3000"
parser.pathname; // => "/pathname/"
parser.search;   // => "?search=test"
parser.hash;     // => "#hash"
parser.host;     // => "example.com:3000"

source

However, if the value href is bound to is not a valid url, then the value of those auxiliary properties will be the empty string.

Edit: as pointed out in the comments: if an invalid url is used, the properties of the current URL may be substituted.

So, as long as you're not passing in the URL of the current page, you can do something like:

function isValidURL(str) {
   var a  = document.createElement('a');
   a.href = str;
   return (a.host && a.host != window.location.host);
}
Holeproof answered 9/1, 2016 at 15:0 Comment(12)
This isn't the case (in Chrome 48 at least). If the url passed to a.href is invalid, parser.host returns the hostname of the page you're currently on, not the expected false.Heliolatry
Gah! that's weird. I swear I tested this! I think it's fair to say that this wont really ever have to be used ON the current page, so the conditional can just be changed. I'll edit the post.Holeproof
it is not a very typical use case, but this technique does not work in the context of Firefox browser window (important for addon development)Acknowledge
@SamBeckham This is definitely a concern when using this method, but I just want to point out that this isn't a special behavior. If you have a link on your page that's invalid, like <a href="invalidurl">, it does go to your domain. It gets added to the end of the current url. So Chrome is doing the correct thing by giving you the current hostname from the "parser" element.Visitant
function isValidURL(str): so much better than using regex! Thank you!Chloroform
Pretty simple way to hack around the problem. These properties are experimental though: developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElementEparchy
Nice workaround. But it doesn't handle chrome://extensions and returns true. But for Chrome extensions, it isn't a valid URL.Excerpta
isValidURL("javascript:void(0)") returns an empty string "" instead of true or false. To improve, the return statement should be return (!!a.host && a.host !== window.location.host); - notice the double-bang before a.hostEstremadura
isValidURL('http://www'); returns trueBulwerlytton
@Bulwerlytton because http://www is a valid url.Devalue
This is weird and hacky - nobody should use this for URL validation.Levator
Same with new URL(...)Bactria
W
106

I am using below function to validate URL with or without http/https:

function isValidURL(string) {
  var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
  return (res !== null)
};

var testCase1 = "http://en.wikipedia.org/wiki/Procter_&_Gamble";
console.log(isValidURL(testCase1)); // return true

var testCase2 = "http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707";
console.log(isValidURL(testCase2)); // return true

var testCase3 = "https://sdfasd";
console.log(isValidURL(testCase3)); // return false

var testCase4 = "dfdsfdsfdfdsfsdfs";
console.log(isValidURL(testCase4)); // return false

var testCase5 = "magnet:?xt=urn:btih:123";
console.log(isValidURL(testCase5)); // return false

var testCase6 = "https://stackoverflow.com/";
console.log(isValidURL(testCase6)); // return true

var testCase7 = "https://w";
console.log(isValidURL(testCase7)); // return false

var testCase8 = "https://sdfasdp.ppppppppppp";
console.log(isValidURL(testCase8)); // return false
Wishywashy answered 16/4, 2018 at 4:4 Comment(15)
Seems a nice solution! Could you add some tests showing it works in some corner cases (see for example these comments)?Pleach
@Pleach added test cases. Please checkWishywashy
Not bad, fails to pass http://⌘.ws or 142.42.1.1 and it allows http://.www.foo.bar./ but it doesn't hang like some of the other regex including the top rated answers.Jaela
@Jaela I checked your answer. Your answer is failing for https://sdfasdp.ppppppppppp i.e. returning true but mine returns false which is expected I think.Wishywashy
@Pleach added this testCase https://w as well. My solution returns false for it and this testCase as well https://sdfasdp.pppppppppppWishywashy
I think both of the regex I quoted use {2} for the domain because there's no fixed limit. Yours uses {2,6} but I just looked and saw things like .accountants as valid domains. Certainly easy to change that term on any of these.Jaela
@Pleach did you check my answer?Wishywashy
its returning true for [email protected]...should it? I guess it should notShame
Pretty good. However, it returns true for strings that contain spaces. For example "example example.io" returns true.Seaworthy
This fails when the URL has a port.Pitapat
this code is not validating protocol See your self url = 'htt1ps://googl1e.com' console.log(url + ' -> ' + isValidURL(url))Tasteful
isValidURL("http://www.test"); returns true.Bulwerlytton
this code is not working right for "[email protected]".Ether
When URL tested was &&, the function returned null or blanks. By changing return (res !== null) to return (res != null) function returns false as expected.Tend
Nice answer, but seems that the bracket in http(s) is not necessary. Also, mind explain what does the dot in (http(s)?:\/\/. do? Is it match any character excpet lien break? ThanksScissors
E
52

To Validate Url using javascript is shown below

function ValidURL(str) {
  var regex = /(?:https?):\/\/(\w+:?\w*)?(\S+)(:\d+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
  if(!regex .test(str)) {
    alert("Please enter valid URL.");
    return false;
  } else {
    return true;
  }
}
Edinburgh answered 14/5, 2015 at 4:11 Comment(2)
"mailto:[email protected]" this is a link but ur code is not work. How can I fix?Merril
URLs that use http or https are only for web addresses. There are a multitude of others that do not use those schemes and they are valid also.Lightless
B
31

Rely on a library: https://www.npmjs.com/package/valid-url

import { isWebUri } from 'valid-url';
// ...
if (!isWebUri(url)) {
    return "Not a valid url.";
}
Bruch answered 20/10, 2016 at 2:38 Comment(1)
this one gives me a lot of trouble with weird urls that are actually parsed by the browser, e.g.: having a { in the urlForgetmenot
S
27

Improvement on the accepted answer...

  • Check for ftp/ftps as protocol
  • Has double escaping for backslashes (\\)
  • Ensures that domains have a dot and an extension (.com .io .xyz)
  • Allows full colon (:) in the path e.g. http://thingiverse.com/download:1894343
  • Allows ampersand (&) in path e.g http://en.wikipedia.org/wiki/Procter_&_Gamble
  • Allows @ symbol in path e.g. https://medium.com/@techytimo

    isURL(str) {
      var pattern = new RegExp('^((ft|htt)ps?:\\/\\/)?'+ // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name and extension
      '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
      '(\\:\\d+)?'+ // port
      '(\\/[-a-z\\d%@_.~+&:]*)*'+ // path
      '(\\?[;&a-z\\d%@_.,~+&:=-]*)?'+ // query string
      '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
      return pattern.test(str);
    }
    
Sterculiaceous answered 8/8, 2017 at 11:55 Comment(8)
No it shouldn't be the accepted answer. Like some of the others it hangs on a mere 33 character string: isURL('123456789012345678901234567890123') and fails many edge case tests: foo.com/blah_blah_(wikipedia)_(again) //incorrectly returns false.Jaela
That is because localhost:8080 isn't a valid URL.Danged
Working sample: runkit.com/shanekenyon87/5bc0e57263c77b0012db05dcDanged
Should be ftps://localhost:8080 =)Kuehnel
It doesn't seem to work: hangs on long input (like @aanmarks said)Hypozeuxis
en.m.wikipedia.org/wiki/C_Sharp_(programming_language) What about this one? It returns false.Catechumen
If you want to catch incomplete links, such as https://www.test, you might want to add: if(str.indexOf('www.')>-1 && (str.split('.').length - 1)<2) { return false; }Bulwerlytton
Most of the times is works. However, it fails is if there is an anchor in the link. Like links from Google image search that end with #imgrc=JTm9w8QlF8abcd. Can this be corrected/added? .... Shouldn't it be the fragment locator part in the regex?Bulwerlytton
L
24

You can use the URL native API:

  const isUrl = string => {
      try { return Boolean(new URL(string)); }
      catch(e){ return false; }
  }
Loeb answered 14/3, 2018 at 17:5 Comment(2)
Looks very similar to the answer provided by @pavlo, only variable names changed ;)Trompe
there should really be a simple native method to check for this by now - this answer looked very promising but it returns true early as @Pleach mentioned above.Magnifico
S
20

Use validator.js

ES6

import isURL from 'validator/lib/isURL'

isURL(string)

No ES6

var validator = require('validator');

validator.isURL(string)

You can also fine tune this function's behavior by passing optional options object as the second argument of isURL

Here is the default options object:

let options = {
    protocols: [
        'http',
        'https',
        'ftp'
    ],
    require_tld: true,
    require_protocol: false,
    require_host: true,
    require_valid_protocol: true,
    allow_underscores: false,
    host_whitelist: false,
    host_blacklist: false,
    allow_trailing_dot: false,
    allow_protocol_relative_urls: false,
    disallow_auth: false
}

isURL(string, options)

host_whitelist and host_blacklist can be arrays of hosts. They also support regular expressions.

let options = {
    host_blacklist: ['foo.com', 'bar.com'],
}

isURL('http://foobar.com', options) // => true
isURL('http://foo.bar.com/', options) // => true
isURL('http://qux.com', options) // => true

isURL('http://bar.com/', options) // => false
isURL('http://foo.com/', options) // => false


options = {
    host_blacklist: ['bar.com', 'foo.com', /\.foo\.com$/],
}

isURL('http://foobar.com', options) // => true
isURL('http://foo.bar.com/', options) // => true
isURL('http://qux.com', options) // => true

isURL('http://bar.com/', options) // => false
isURL('http://foo.com/', options) // => false
isURL('http://images.foo.com/', options) // => false
isURL('http://cdn.foo.com/', options) // => false
isURL('http://a.b.c.foo.com/', options) // => false
Spital answered 22/6, 2019 at 12:48 Comment(5)
Nice! Small library (less than 40k minified), popular library (over 3M weekly downloads on npm), gives you tons of flexibility on specifying the validity of the URLs for your particular use case, and has a number of other validators besides URL. This is by far the best answer, IMHO.Requiem
Nice library. It can validate URL but also many other things.Lemuelah
This worked for me when creating a New Relic Synthetics script. Very useful.Elianore
The best solution by farJolley
I am sorry, @JavidJamae? Is 40K a small library when "minified"? There's a 3D video game .kkrieger the size of which is less than 100K ^^Stites
D
16

Here is yet another method.

// ***note***: if the incoming value is empty(""), the function returns true

var elm;
function isValidURL(u){
  //A precaution/solution for the problem written in the ***note***
  if(u!==""){  
      if(!elm){
      elm = document.createElement('input');
      elm.setAttribute('type', 'url');
      }
  elm.value = u;
  return elm.validity.valid;
  }
  else{
      return false
  }
}

console.log(isValidURL(''));
console.log(isValidURL('http://www.google.com/'));
console.log(isValidURL('//google.com'));
console.log(isValidURL('google.com'));
console.log(isValidURL('localhost:8000'));
Disjunctive answered 18/4, 2018 at 22:24 Comment(3)
Educational code! The mechanism here is probably identical to how new URL(string) in Pavlo's code works. Both tests have identical results with all the edge cases I tested. I like his code because it is simpler and doesn't involve creating elements, but yours is a few times faster (probably because it doesn't create the el after the first use).Jaela
Thank you! I implemented your advice. Be aware however: Older browsers and/or mobile device WebView may have not implemented the <input type =url> element; thus the input value would be treated just like a regular text (no URL validation). REF: developer.mozilla.org/en-US/docs/Web/HTML/Element/input/urlJacey
To avoid empty values from returning true using the Constrain validation API, you also have to set required to true on the input field.Alexaalexander
J
15

As has been noted the perfect regex is elusive but still seems to be a reasonable approach (alternatives are server side tests or the new experimental URL API). However the high ranking answers are often returning false for common URLs but even worse will freeze your app/page for minutes on even as simple a string as isURL('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'). It's been pointed out in some of the comments, but most probably haven't entered a bad value to see it. Hanging like that makes that code unusable in any serious application. I think it's due to the repeated case insensitive sets in code like ((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|' .... Take out the 'i' and it doesn't hang but will of course not work as desired. But even with the ignore case flag those tests reject high unicode values that are allowed.

The best already mentioned is:

function isURL(str) {
  return /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(str); 
}

That comes from Github segmentio/is-url. The good thing about a code repository is you can see the testing and any issues and also the test strings run through it. There's a branch that would allow strings missing protocol like google.com, though you're probably making too many assumptions then. The repository has been updated and I'm not planning on trying to keep up a mirror here. It's been broken up into separate tests to avoid RegEx redos which can be exploited for DOS attacks (I don't think you have to worry about that with client side js, but you do have to worry about your page hanging for so long that your visitor leaves your site).

There is one other repository I've seen that may even be better for isURL at dperini/regex-weburl.js, but it is highly complex. It has a bigger test list of valid and invalid URLs. The simple one above still passes all the positives and only fails to block a few odd negatives like http://a.b--c.de/ as well as the special ips.

Whichever you choose, run it through this function which I've adapted from the tests on dperini/regex-weburl.js, while using your browser's Developer Tools inpector.

function testIsURL() {
//should match
console.assert(isURL("http://foo.com/blah_blah"));
console.assert(isURL("http://foo.com/blah_blah/"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)"));
console.assert(isURL("http://foo.com/blah_blah_(wikipedia)_(again)"));
console.assert(isURL("http://www.example.com/wpstyle/?p=364"));
console.assert(isURL("https://www.example.com/foo/?bar=baz&inga=42&quux"));
console.assert(isURL("http://✪df.ws/123"));
console.assert(isURL("http://userid:[email protected]:8080"));
console.assert(isURL("http://userid:[email protected]:8080/"));
console.assert(isURL("http://[email protected]"));
console.assert(isURL("http://[email protected]/"));
console.assert(isURL("http://[email protected]:8080"));
console.assert(isURL("http://[email protected]:8080/"));
console.assert(isURL("http://userid:[email protected]"));
console.assert(isURL("http://userid:[email protected]/"));
console.assert(isURL("http://142.42.1.1/"));
console.assert(isURL("http://142.42.1.1:8080/"));
console.assert(isURL("http://➡.ws/䨹"));
console.assert(isURL("http://⌘.ws"));
console.assert(isURL("http://⌘.ws/"));
console.assert(isURL("http://foo.com/blah_(wikipedia)#cite-1"));
console.assert(isURL("http://foo.com/blah_(wikipedia)_blah#cite-1"));
console.assert(isURL("http://foo.com/unicode_(✪)_in_parens"));
console.assert(isURL("http://foo.com/(something)?after=parens"));
console.assert(isURL("http://☺.damowmow.com/"));
console.assert(isURL("http://code.google.com/events/#&product=browser"));
console.assert(isURL("http://j.mp"));
console.assert(isURL("ftp://foo.bar/baz"));
console.assert(isURL("http://foo.bar/?q=Test%20URL-encoded%20stuff"));
console.assert(isURL("http://مثال.إختبار"));
console.assert(isURL("http://例子.测试"));
console.assert(isURL("http://उदाहरण.परीक्षा"));
console.assert(isURL("http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com"));
console.assert(isURL("http://1337.net"));
console.assert(isURL("http://a.b-c.de"));
console.assert(isURL("http://223.255.255.254"));
console.assert(isURL("postgres://u:[email protected]:5702/db"));
console.assert(isURL("https://[email protected]/13176"));

//SHOULD NOT MATCH:
console.assert(!isURL("http://"));
console.assert(!isURL("http://."));
console.assert(!isURL("http://.."));
console.assert(!isURL("http://../"));
console.assert(!isURL("http://?"));
console.assert(!isURL("http://??"));
console.assert(!isURL("http://??/"));
console.assert(!isURL("http://#"));
console.assert(!isURL("http://##"));
console.assert(!isURL("http://##/"));
console.assert(!isURL("http://foo.bar?q=Spaces should be encoded"));
console.assert(!isURL("//"));
console.assert(!isURL("//a"));
console.assert(!isURL("///a"));
console.assert(!isURL("///"));
console.assert(!isURL("http:///a"));
console.assert(!isURL("foo.com"));
console.assert(!isURL("rdar://1234"));
console.assert(!isURL("h://test"));
console.assert(!isURL("http:// shouldfail.com"));
console.assert(!isURL(":// should fail"));
console.assert(!isURL("http://foo.bar/foo(bar)baz quux"));
console.assert(!isURL("ftps://foo.bar/"));
console.assert(!isURL("http://-error-.invalid/"));
console.assert(!isURL("http://a.b--c.de/"));
console.assert(!isURL("http://-a.b.co"));
console.assert(!isURL("http://a.b-.co"));
console.assert(!isURL("http://0.0.0.0"));
console.assert(!isURL("http://10.1.1.0"));
console.assert(!isURL("http://10.1.1.255"));
console.assert(!isURL("http://224.1.1.1"));
console.assert(!isURL("http://1.1.1.1.1"));
console.assert(!isURL("http://123.123.123"));
console.assert(!isURL("http://3628126748"));
console.assert(!isURL("http://.www.foo.bar/"));
console.assert(!isURL("http://www.foo.bar./"));
console.assert(!isURL("http://.www.foo.bar./"));
console.assert(!isURL("http://10.1.1.1"));}

And then test that string of 'a's.

See this comparison of isURL regex by Mathias Bynens for more info before you post a seemingly great regex.

Jaela answered 9/3, 2018 at 1:52 Comment(3)
I checked your answer. Your answer is failing for sdfasdp.ppppppppppp i.e. returning true but expected is falseWishywashy
I think that's a valid URL, structurally. Not an expert on the standard but I don't think there's a limit on the length of the .com portion (I know .online is legit).Jaela
I barely knew how to write a regex a couple of months ago. The problem is severe. Both of the regex I quoted can complete isURL('a'.repeat(100)) millions of times/sec (the more complex one from dperini is actually faster). Some of the high ranking answers of the form ([a-zA-Z]+)* would take hours to complete that once. Look up RegEx redos for more information.Jaela
B
15

This function disallows localhost and only allows URLs for web pages (ie, only allows http or https protocol).

It also only allows safe characters as defined here: https://www.urlencoder.io/learn/

function isValidWebUrl(url) {
   let regEx = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/gm;
   return regEx.test(url);
}
Bruit answered 7/8, 2020 at 21:4 Comment(1)
This best met my use case. Does the /g make any sense, though, since you can't match more than one and wouldn't want to?Kinsfolk
I
12

(I don't have reps to comment on ValidURL example; hence post this as an answer.)

While use of protocol relative URLs is not encouraged (The Protocol-relative URL), they do get employed sometimes. To validate such an URL with a regular expression the protocol part could be optional, e.g.:

function isValidURL(str) {
    var pattern = new RegExp('^((https?:)?\\/\\/)?'+ // protocol
        '(?:\\S+(?::\\S*)?@)?' + // authentication
        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
        '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
        '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
        '(\\#[-a-z\\d_]*)?$','i'); // fragment locater
    if (!pattern.test(str)) {
        return false;
    } else {
        return true;
    }
}

As others noted, regular expression does not seem to be the best suited approach for validating URLs, though.

Isabel answered 11/7, 2017 at 21:26 Comment(3)
I thought at first this was pretty good but it fails many of the tests at mathiasbynens.be/demo/url-regex, and then it hangs on isValidURL("https://[email protected]/13176")Jaela
Yes, like I said, I merely commented on the protocol part. I added the authentication clause to handle @. It doesn't hang in my browsers.Isabel
Sorry, I was going through several of these to evaluate them and missed that yours was commenting on the given answer. I think your correction even helped me get started on these when I first visited this page. Not hanging now.Jaela
B
9

One function that I have been using to validate a URL "string" is:

var matcher = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/;

function isUrl(string){
  return matcher.test(string);
}

This function will return a boolean whether the string is a URL.

Examples:

isUrl("https://google.com");     // true
isUrl("http://google.com");      // true
isUrl("http://google.de");       // true
isUrl("//google.de");            // true
isUrl("google.de");              // false
isUrl("http://google.com");      // true
isUrl("http://localhost");       // true
isUrl("https://sdfasd");         // false
Brophy answered 31/1, 2018 at 3:16 Comment(0)
S
9

This is quite difficult to do with pure regex because URLs have many 'inconveniences'.

  1. For example domain names have complicated restrictions on hyphens:

    a. It is allowed to have many consecutive hyphens in the middle.

    b. but the first character and last character of the domain name cannot be a hyphen

    c. The 3rd and 4th character cannot be both hyphen

  2. Similarly port number can only be in the range 1-65535. This is easy to check if you extract the port part and convert to int but quite difficult to check with a regular expression.

  3. There is also no easy way to check valid domain extensions. Some countries have second-level domains(such as 'co.uk'), or the extension can be a long word such as '.international'. And new TLDs are added regularly. This type of things can only be checked against a hard-coded list. (see https://en.wikipedia.org/wiki/Top-level_domain)

  4. Then there are magnet urls, ftp addresses etc. These all have different requirements.

Nevertheless, here is a function that handles pretty much everything except:

  • Case 1. c
  • Accepts any 1-5 digit port number
  • Accepts any extension 2-13 chars
  • Does not accept ftp, magnet, etc...

function isValidURL(input) {
    pattern = '^(https?:\\/\\/)?' + // protocol
        '((([a-zA-Z\\d]([a-zA-Z\\d-]{0,61}[a-zA-Z\\d])*\\.)+' + // sub-domain + domain name
        '[a-zA-Z]{2,13})' + // extension
        '|((\\d{1,3}\\.){3}\\d{1,3})' + // OR ip (v4) address
        '|localhost)' + // OR localhost
        '(\\:\\d{1,5})?' + // port
        '(\\/[a-zA-Z\\&\\d%_.~+-:@]*)*' + // path
        '(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
        '(\\#[-a-zA-Z&\\d_]*)?$'; // fragment locator
    regex = new RegExp(pattern);
    return regex.test(input);
}

let tests = [];
tests.push(['', false]);
tests.push(['http://en.wikipedia.org/wiki/Procter_&_Gamble', true]);
tests.push(['https://sdfasd', false]);
tests.push(['http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707', true]);
tests.push(['https://stackoverflow.com/', true]);
tests.push(['https://w', false]);
tests.push(['aaa', false]);
tests.push(['aaaa', false]);
tests.push(['oh.my', true]);
tests.push(['dfdsfdsfdfdsfsdfs', false]);
tests.push(['google.co.uk', true]);
tests.push(['test-domain.MUSEUM', true]);
tests.push(['-hyphen-start.gov.tr', false]);
tests.push(['hyphen-end-.com', false]);
tests.push(['https://sdfasdp.international', true]);
tests.push(['https://sdfasdp.pppppppp', false]);
tests.push(['https://sdfasdp.ppppppppppppppppppp', false]);
tests.push(['https://sdfasd', false]);
tests.push(['https://sub1.1234.sub3.sub4.sub5.co.uk/?', true]);
tests.push(['http://www.google-com.123', false]);
tests.push(['http://my--testdomain.com', false]);
tests.push(['http://my2nd--testdomain.com', true]);
tests.push(['http://thingiverse.com/download:1894343', true]);
tests.push(['https://medium.com/@techytimo', true]);
tests.push(['http://localhost', true]);
tests.push(['localhost', true]);
tests.push(['localhost:8080', true]);
tests.push(['localhost:65536', true]);
tests.push(['localhost:80000', false]);
tests.push(['magnet:?xt=urn:btih:123', true]);

for (let i = 0; i < tests.length; i++) {
    console.log('Test #' + i + (isValidURL(tests[i][0]) == tests[i][1] ? ' passed' : ' failed') + ' on ["' + tests[i][0] + '", ' + tests[i][1] + ']');
}
Strunk answered 10/2, 2019 at 19:51 Comment(1)
see https://mcmap.net/q/73330/-check-if-a-javascript-string-is-a-url for compare output of above regex & output of URL() classAvouch
O
8

There's a lot of answers already, but here's another contribution: Taken directly from the URL polyfill validity check, use an input element with type="url" to take advantage of the browser's built-in validity check:

var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;

if (!inputElement.checkValidity()) {
    throw new TypeError('Invalid URL');
}

Source

Outgrow answered 11/6, 2020 at 8:45 Comment(0)
U
4

Mathias Bynens has compiled a list of well-known URL regexes with test URLs. There is little reason to write a new regular expression; just pick an existing one that suits you best.

But the comparison table for those regexes also shows that it is next to impossible to do URL validation with a single regular expression. All of the regexes in Bynens' list produce false positives and false negatives.

I suggest that you use an existing URL parser (for example new URL('http://www.example.com/') in JavaScript) and then apply the checks you want to perform against the parsed and normalized form of the URL resp. its components. Using the JavaScript URL interface has the additional benefit that it will only accept such URLs that are really accepted by the browser.

You should also keep in mind that technically incorrect URLs may still work. For example http://w_w_w.example.com/, http://www..example.com/, http://123.example.com/ all have an invalid hostname part but every browser I know will try to open them without complaints, and when you specify IP addresses for those invalid names in /etc/hosts/ such URLs will even work but only on your computer.

The question is, therefore, not so much whether a URL is valid, but rather which URLs work and should be allowed in a particular context.

If you want to do URL validation there are a lot of details and edge cases that are easy to overlook:

  • URLs may contain credentials as in http://user:[email protected]/.
  • Port numbers must be in the range of 0-65535, but you may still want to exclude the wildcard port 0.
  • Port numbers may have leading zeros as in http://www.example.com:000080/.
  • IPv4 addresses are by no means restricted to 4 decimal integers in the range of 0-255. You can use one to four integers, and they can be decimal, octal or hexadecimal. The URLs https://010.010.000010.010/, https://0x8.0x8.0x0008.0x8/, https://8.8.2056/, https://8.526344/, https://134744072/ are all valid and just creative ways of writing https://8.8.8.8/.
  • Allowing loopback addresses (http://127.0.0.1/), private IP addresses (http://192.168.1.1), link-local addresses (http://169.254.100.200) and so on may have an impact on security or privacy. If, for instance, you allow them as the address of user avatars in a forum, you cause the users' browsers to send unsolicited network requests in their local network and in the internet of things such requests may cause funny and not so funny things to happen in your home.
  • For the same reasons, you may want to discard links to not fully qualified hostnames, in other words hostnames without a dot.
  • But hostnames may always have a trailing dot (like in http://www.stackoverflow.com.).
  • The hostname portion of a link may contain angle brackets for IPv6 addresses as in http://[::1].
  • IPv6 addresses also have ranges for private networks or link-local addresses etc.
  • If you block certain IPv4 addresses, keep in mind that for example https://127.0.0.1 and https://[::ffff:127.0.0.1] point to the same resource (if the loopback device of your machine is IPv6 ready).
  • The hostname portion of URLs may now contain Unicode, so that the character range [-0-9a-zA-z] is definitely no longer sufficient.
  • Many registries for top-level domains define specific restrictions, for example on the allowed set of Unicode characters. Or they subdivide their namespace (like co.uk and many others).
  • Top-level domains must not contain decimal digits, and the hyphen is not allowed unless for the IDN A-label prefix "xn--".
  • Unicode top-level domains (and their punycode encoding with "xn--") must still contain only letters but who wants to check that in a regex?

Which of these limitations and rules apply is a question of project requirements and taste.

I have recently written a URL validator for a web app that is suitable for user-supplied URLs in forums, social networks, or the like. Feel free to use it as a base for your own one:

I have also written a blog post The Gory Details of URL Validation with more in-depth information.

Umont answered 17/1, 2020 at 9:51 Comment(0)
L
3

this working with me

function isURL(str) {
  var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
  var pattern = new RegExp(regex); 
return pattern.test(str);
}
Leanaleanard answered 16/4, 2019 at 16:2 Comment(2)
This answer was already given above 4 years ago by kavitha Reddy.Jaela
i just made it more simple and abstractLeanaleanard
I
3

There are a couple of tests using the URL constructor which do not delineate whether the input is a string or URL object.

// Testing whether something is a URL
function isURL(url) {
    return toString.call(url) === "[object URL]";
}

// Testing whether the input is both a string and valid url:
function isUrl(url) {
    try {
        return toString.call(url) === "[object String]" && !!(new URL(url));
    } catch (_) {
        return false;  
    }
}
Immolate answered 10/3, 2020 at 22:45 Comment(0)
R
3

I had revised all the comments, notes and remarks is this topic and have made a new regular expression:

^((javascript:[\w-_]+(\([\w-_\s,.]*\))?)|(mailto:([\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+\.)*[\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+@([\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+\.)*[\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+)|(\w+:\/\/(([\w\u00C0-\u1FFF\u2C00-\uD7FF-]+\.)*([\w\u00C0-\u1FFF\u2C00-\uD7FF-]*\.?))(:\d+)?(((\/[^\s#$%^&*?]+)+|\/)(\?[\w\u00C0-\u1FFF\u2C00-\uD7FF:;&%_,.~+=-]+)?)?(#[\w\u00C0-\u1FFF\u2C00-\uD7FF-_]+)?))$

You can test and improve it here https://regexr.com/668mt .

I checked this expression on next values:

http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707
http://192.168.0.4:55/
https://web.archive.org/web/20170817095211/https://github.com/Microsoft/vscode/issues/32405
http://www.example.com
javascript:void()
http://.
https://example.
https://en.m.wikipedia.org/wiki/C_Sharp_(programming_language)
http://zh.wikipedia.org/wiki/Wikipedia:关于中文维基百科/en?a#a
https://medium.com/@User_name/
https://test-test-test-test-test-test-test-test-test.web.app/
http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707
https://sdfasdp.ppppppppppp
mailto:[email protected]
https://тест.юа
Returnable answered 24/9, 2021 at 12:42 Comment(0)
U
3

Since Node v19.9.0 you can use URL.canParse(input, [base]).

  • input: <string> The absolute or relative input URL to parse. If input is relative, then base is required. If input is absolute, the base is ignored. If input is not a string, it is converted to a string first.
  • base: <string> The base URL to resolve against if the input is not absolute. If base is not a string, it is converted to a string first.

https://nodejs.org/api/url.html#urlcanparseinput-base

URL.canParse('https://example.org/foo'); // TRUE
URL.canParse('nothttps://example.org/foo'); // FALSE

Browser support is (very) limited at the moment. See https://developer.mozilla.org/en-US/docs/Web/API/URL/canParse_static

Upon answered 5/7, 2023 at 8:21 Comment(1)
Not gonna work: just pass these strings to it: http://.com or https://[email protected] and many more cases that are not even edge/rare case.Laevorotatory
F
2

If you need to also support https://localhost:3000 then use this modified version of [Devshed]s regex.

    function isURL(url) {
        if(!url) return false;
        var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
            '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
            '((\\d{1,3}\\.){3}\\d{1,3}))|' + // OR ip (v4) address
            'localhost' + // OR localhost
            '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
            '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
            '(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator
        return pattern.test(url);
    }
Foretop answered 13/1, 2020 at 23:8 Comment(0)
G
2

I change the function to Match + make a change here with the slashes and its work: (http:// and https) both

function isValidUrl(userInput) {
    var res = userInput.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
    if(res == null)
       return false;
    else
       return true;
}
Glassine answered 4/2, 2020 at 18:53 Comment(1)
In 2021, this worked for me in all URL configurationsZellner
A
2

Using URL Class

/**
  * The given value must start with a protocol (e.g., http:// or https://)
  * If the value doesn't start with a protocol,
  * the function may return false.
*/
function testWithUrlClass(urlStr) {
    try {
    new URL(urlStr);
    return true;
  } catch(e) {
    return false;
  }
}

difficult to do with pure regex because URLs have many 'inconveniences'.

function isValidUrl(str) {
    /* const pattern = new RegExp(
      '^(https?:\\/\\/)?' + // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
      '(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
      '(\\#[-a-z\\d_]*)?$', // fragment locator
      'i'
    ); */
    
    /* reference from https://mcmap.net/q/73330/-check-if-a-javascript-string-is-a-url*/
    const newModi = new RegExp(
       '^(https?:\\/\\/)?' + // protocol
       '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}' + // domain name
       '|((\\d{1,3}\\.){3}\\d{1,3})' + // OR IP (v4) address
       '|localhost)' + // OR localhost
       // '(\\:\\d+) + // port (one or more digits)
       '(\\:\\d{1,5})?' + // port (digits limit 1 to 5)
       // '(\\/[-a-z\\d%_.~+]*)*'+ // path
       '(\\/[a-zA-Z\\&\\d%_.~+-:@]*)*' + // path
       // '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
      '(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
      // '(\\#[-a-z\\d_]*)?$', // fragment locator
      '(\\#[-a-zA-Z&\\d_]*)?$', // fragment locator
    );
    
    return newModi.test(str);
  }

Valid Url Cases:

  1. only domain name
  2. full url with fragment also
  3. if url doesn't contains http or https protocol
  4. if url doesn't contains 'www.' before the domain
  5. url has sub domain

Run Below Snippet or run on jsFiddle for see Output of this regex method.

in Snippet & jsFiddle link - even you can also compare the output of above regex way & URL() class (checked url is valid or not by URL class method)

I hope you like this...

:) Happy Coding!

function isValidUrl(str) {
    /* const pattern = new RegExp(
      '^(https?:\\/\\/)?' + // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
      '(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
      '(\\#[-a-z\\d_]*)?$', // fragment locator
      'i'
    ); */
    
     /* reference from https://mcmap.net/q/73330/-check-if-a-javascript-string-is-a-url*/
    const newModi = new RegExp(
       '^(https?:\\/\\/)?' + // protocol
       '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}' + // domain name
       '|((\\d{1,3}\\.){3}\\d{1,3})' + // OR IP (v4) address
       '|localhost)' + // OR localhost
       // '(\\:\\d+) + // port (one or more digits)
       '(\\:\\d{1,5})?' + // port (digits limit 1 to 5)
       // '(\\/[-a-z\\d%_.~+]*)*'+ // path
       '(\\/[a-zA-Z\\&\\d%_.~+-:@]*)*' + // path
       // '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
      '(\\?[a-zA-Z\\&\\d%_.,~+-:@=;&]*)?' + // query string
      // '(\\#[-a-z\\d_]*)?$', // fragment locator
      '(\\#[-a-zA-Z&\\d_]*)?$', // fragment locator
    );
    
    return newModi.test(str);
  }

const testLinks  = [
    ['test', false],
  ['test.com', true],
  ['http://test.com', true],
    ['www.test.com', true],
  ['http://www.test.com', true],
  ['test.com/products', true],
  ['help.test.com', true],
  ['www.help.test.com', true],
  ['http://example.com', true],
  ['https://www.example.com/path', true],
  ['www.example.com', true],
  ['example.com/path', true],
  ['example.com?query=param', true],
  ['ftp://example.com', false],
  ['http://192.168.0.1', true],
  ['http://192.168.0.1:8080', true],
  ['http://example.com#section', true],
  ['http://example.com:8080/path?query=param', true],
  ['/product/sas.png', false],
  ['?query=param', false],
  ['#section', false],
  ['http://example.com?param=123&name=John', true],
  ['http://example.com?param1=123&param2=456', true],
  ['https://example.com/path?query=param#section', true],
  ['?name=John&age=30', false],
  ['#section-content', false],
  ['http://example.com#', true],
  ['https://example.com/path?', true],
  ['', false], // Empty string 
  [null, false], // Null value 
  [undefined, false], // Undefined value 
  
  
  // additional urls
  ['http://en.wikipedia.org/wiki/Procter_&_Gamble', true],
  ['https://sdfasd', false],
  ['http://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&docid=nIv5rk2GyP3hXM&tbnid=isiOkMe3nCtexM:&ved=0CAUQjRw&url=http%3A%2F%2Fanimalcrossing.wikia.com%2Fwiki%2FLion&ei=ygZXU_2fGKbMsQTf4YLgAQ&bvm=bv.65177938,d.aWc&psig=AFQjCNEpBfKnal9kU7Zu4n7RnEt2nerN4g&ust=1398298682009707', true],
  
  ['https://stackoverflow.com/', true],
  ['https://w', false],
  ['aaa', false],
  ['aaaa', false],
  ['oh.my', true],
  ['dfdsfdsfdfdsfsdfs', false],
  ['google.co.uk', true],
  '-hyphen-start.gov.tr',
  ['test-domain.MUSEUM', true],
  ['-hyphen-start.gov.tr', false],
  ['hyphen-end-.com', false],
  ['https://sdfasdp.international', true],
  ['https://sdfasdp.pppppppp', false],
  ['https://sdfasdp.ppppppppppppppppppp', false],
  ['https://sdfasd', false],
  ['https://sub1.1234.sub3.sub4.sub5.co.uk/?', true],
  ['http://www.google-com.123', false],
  ['http://my--testdomain.com', false],
  ['http://my2nd--testdomain.com', true],
  ['http://thingiverse.com/download:1894343', true],
  ['https://medium.com/@techytimo', true],
  ['http://localhost', true],
  ['localhost', true],
  ['localhost:8080', true],
  ['localhost:65536', true],
  ['localhost:80000', false],
  ['magnet:?xt=urn:btih:123', true],
  ['test:8080', false],
  ['test.com:8080', false],
];

const validUrlResults = [];

const resElem = document.getElementById('result');
var resStr = '';
testLinks.forEach((e) => {
    let testResult = isValidUrl(e[0]);
  if (testResult === true) {
    validUrlResults.push(e[0]);
  }
  
    resStr += '<li><span class="input">' + e[0] + '</span> <span class="outputBool">'+ testWithUrlClass(e[0]) + '</span> <span class="outputBool">'+ testResult + '</span>  <span>' + (testResult === e[1] ? 'passed' : 'failed') + '</span></li>';
});

resElem.innerHTML = resElem.innerHTML + resStr;

// console.log(validUrlResults);

/**
  * The given value must start with a protocol (e.g., http:// or https://)
  * If the value doesn't start with a protocol,
  * the function may return false.
*/
function testWithUrlClass(urlStr) {
    try {
    new URL(urlStr);
    return true;
  } catch(e) {
    return false;
  }
}
li {
  margin-bottom: 15px;
}
.input {
  display: inline-block;
  width: 40%;
  word-break: break-all;
}

.outputBool {
 display: inline-block;
  width: 15%;
}
<ul id="result">
  <li>
    <span class="input"><b>Inputs</b></span>
    <span class="outputBool"><b>With Url Class</b></span>
    <span class="outputBool"><b>With Regex</b></span>
    <span><b>Regex passed as Expected?</b></span>
  </li>
</ul>
Avouch answered 21/7, 2023 at 7:50 Comment(1)
JFI these did not work while being certainly a valid URL: https://en.wikipedia.org/wiki/Harry_Potter_(film_series), http://正妹.香港/, and http://www.نبی.com/. and this guy passed while it is not a valid URL: www.aa. BTW thanks for this regex, it is the first one that has passed most of my unit tests :sweat_smile:. And as for the URL, do not use it. it will parse this as a valid URL: www...google...comLaevorotatory
T
1

I think using the native URL API is better than a complex regex patterns as @pavlo suggested. It has some drawbacks though which we can fix by some extra code. This approach fails for the following valid url.

//cdn.google.com/script.js

We can add the missing protocol beforehand to avoid that. It also fails to detect following invalid url.

http://w
http://..

So why check the whole url? we can just check the domain. I borrowed the regex to verify domain from here.

function isValidUrl(string) {
    if (string && string.length > 1 && string.slice(0, 2) == '//') {
        string = 'http:' + string; //dummy protocol so that URL works
    }
    try {
        var url = new URL(string);
        return url.hostname && url.hostname.match(/^([a-z0-9])(([a-z0-9-]{1,61})?[a-z0-9]{1})?(\.[a-z0-9](([a-z0-9-]{1,61})?[a-z0-9]{1})?)?(\.[a-zA-Z]{2,4})+$/) ? true : false;
    } catch (_) {
        return false;
    }
}

The hostname attribute is empty string for javascript:void(0), so it works for that too, and you can also add IP address verifier too. I'd like to stick to native API's most, and hope it starts to support everything in near future.

Trompe answered 16/4, 2018 at 22:11 Comment(1)
Interesting, but may still need to work on the regex as it's now introduced false negatives which new URL doesn't have in the tests I've done. This is calling: http://142.42.1.1 //false and blocking high unicode strings.Jaela
L
1

The question asks a validation method for an url such as stackoverflow, without the protocol or any dot in the hostname. So, it's not a matter of validating url sintax, but checking if it's a valid url, by actually calling it.

I tried several methods for knowing if the url true exists and is callable from within the browser, but did not find any way to test with javascript the response header of the call:

  • adding an anchor element is fine for firing the click() method.
  • making ajax call to the challenging url with 'GET' is fine, but has it's various limitations due to CORS policies and it is not the case of using ajax, for as the url maybe any outside my server's domain.
  • using the fetch API has a workaround similar to ajax.
  • other problem is that I have my server under https protocol and throws an exception when calling non secure urls.

So, the best solution I can think of is getting some tool to perform CURL using javascript trying something like curl -I <url>. Unfortunately I did not find any and in appereance it's not possible. I will appreciate any comments on this.

But, in the end, I have a server running PHP and as I use Ajax for almost all my requests, I wrote a function on the server side to perform the curl request there and return to the browser.

Regarding the single word url on the question 'stackoverflow' it will lead me to https://daniserver.com.ar/stackoverflow, where daniserver.com.ar is my own domain.

Linseed answered 22/4, 2018 at 17:49 Comment(1)
The OP should probably have indicated more of what his intent was. The problem certainly varies upon your needs and whether it's more important to exclude false positives or include false negatives. As the problem is stated there seems to be no answer to me. Can you really take foo and assume it's http or https or .com or .es or any of the countless suffixes? Do you keep throwing the kitchen sink at it until you get a true?Jaela
S
1

This seems to be one of the hardest problems in CS ;)

Here's another incomplete solution that works well enough for me and better than the others I've seen here. I'm using a input[type=url] for this in order to support IE11, otherwise it would be much simpler using window.URL to perform the validation instead:

const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
function isValidIpv4(ip) {
  if (!ipv4Regex.test(ip)) return false;
  return !ip.split('.').find(n => n > 255);
}

const domainRegex = /(?:[a-z0-9-]{1,63}\.){1,125}[a-z]{2,63}$/i;
function isValidDomain(domain) {
  return isValidIpv4(domain) || domainRegex.test(domain);
}

let input;
function validateUrl(url) {
  if (! /^https?:\/\//.test(url)) url = `http://${url}`; // assuming Babel is used
  // to support IE11 we'll resort to input[type=url] instead of window.URL:
  // try { return isValidDomain(new URL(url).host) && url; } catch(e) { return false; }
  if (!input) { input = document.createElement('input'); input.type = 'url'; }
  input.value = url;
  if (! input.validity.valid) return false;
  const domain = url.split(/^https?:\/\//)[1].split('/')[0].split('@').pop();
  return isValidDomain(domain) && url;
}

console.log(validateUrl('google'), // false
  validateUrl('user:[email protected]'),
  validateUrl('https://google.com'),
  validateUrl('100.100.100.100/abc'),
  validateUrl('100.100.100.256/abc')); // false

In order to accept incomplete inputs such as "www.mydomain.com" it will also make it valid assuming the protocol is "http" in those cases and returning the valid URL if the address is valid. It returns false when invalid.

It also supports IPv4 domains, but not IPv6.

Schulze answered 26/7, 2018 at 19:24 Comment(0)
N
1

In my case my only requirement is that the user input won't be interpreted as a relative link when placed in the href of an a tag and the answers here were either a bit OTT for that or allowed URLs not meeting my requirements, so this is what I'm going with:

^https?://.+$

The same thing could be achieved pretty easily without regex.

Ns answered 25/3, 2019 at 15:34 Comment(0)
S
1

If you can change the input type, I think this solution would be much easier:

You can simple use type="url" in your input and the check it with checkValidity() in js

E.g:

your.html

<input id="foo" type="url">

your.js

// The selector is JQuery, but the function is plain JS
$("#foo").on("keyup", function() {
    if (this.checkValidity()) {
        // The url is valid
    } else {
        // The url is invalid
    }
});
Schear answered 9/8, 2019 at 10:39 Comment(0)
D
0

Here's just a very simple check to make sure there's a valid protocol, and the domain extension must be two or more characters.

is_valid_url = ( $url ) => {

    let $url_object = null;

    try {
        $url_object = new URL( $url );
    } catch ( $error ) {
        return false;
    }

    const $protocol = $url_object.protocol;
    const $protocol_position = $url.lastIndexOf( $protocol );
    const $domain_extension_position = $url.lastIndexOf( '.' );

    return (
        $protocol_position === 0 &&
        [ 'http:', 'https:' ].indexOf( $protocol ) !== - 1 &&
        $domain_extension_position > 2 && $url.length - $domain_extension_position > 2
    );

};
Deanery answered 2/4, 2019 at 15:1 Comment(0)
D
0

This is defiantly not the most effective approach, but it is readable and easy to form to whatever you need. And it's easier to add regex/complexity from here. So here is a very pragmatic approach

const validFirstBits = ["ftp://", "http://", "https://", "www."];
const invalidPatterns = [" ", "//.", ".."];

export function isUrl(word) {
// less than www.1.dk
if (!word || word.length < 8) return false;

// Let's check and see, if our candidate starts with some of our valid first bits
const firstBitIsValid = validFirstBits.some(bit => word.indexOf(bit) === 0);
if (!firstBitIsValid) return false;

const hasInvalidPatterns = invalidPatterns.some(
    pattern => word.indexOf(pattern) !== -1,
);

if (hasInvalidPatterns) return false;

const dotSplit = word.split(".");
if (dotSplit.length > 1) {
    const lastBit = dotSplit.pop(); // string or undefined
    if (!lastBit) return false;
    const length = lastBit.length;
    const lastBitIsValid =
        length > 1 || (length === 1 && !isNaN(parseInt(lastBit)));
    return !!lastBitIsValid;
}

    return false;
}

TEST:

import { isUrl } from "./foo";

describe("Foo", () => {
    test("should validate correct urls correctly", function() {
        const validUrls = [
            "http://example.com",
            "http://example.com/blah",
            "http://127.0.0.1",
            "http://127.0.0.1/wow",
            "https://example.com",
            "https://example.com/blah",
            "https://127.0.0.1:1234",
            "ftp://example.com",
            "ftp://example.com/blah",
            "ftp://127.0.0.1",
            "www.example.com",
            "www.example.com/blah",
        ];

        validUrls.forEach(url => {
            expect(isUrl(url) && url).toEqual(url);
        });
    });

    test("should validate invalid urls correctly", function() {
        const inValidUrls = [
            "http:// foo.com",
            "http:/foo.com",
            "http://.foo.com",
            "http://foo..com",
            "http://.com",
            "http://foo",
            "http://foo.c",
        ];

        inValidUrls.forEach(url => {
            expect(!isUrl(url) && url).toEqual(url);
        });
    });
});
Downandout answered 2/10, 2019 at 19:21 Comment(0)
E
0

2020 Update. To expand on both excellent answerd from @iamnewton and @Fernando Chavez Herrera I've started to see @ being used in the path of URLs.

So the updated regex is:

RegExp('(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$', 'i');

If you want to allow it in the query string and hash, use:

RegExp('(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-@]*)?(\\#[-a-z\\d_@]*)?$', 'i');

That being said, I'm not sure if there's a whitepaper rule disallowing @ in the query string or hash.

Edmead answered 18/5, 2020 at 18:26 Comment(0)
F
0

You can use ajax request to check if a string is valid url and accessible

(function() {



$("input").change(function() {

const check = $.ajax({
        url : this.value,
        dataType: "jsonp"
});

check.then(function() {
   console.log("Site is valid and registered");
});

//expected output
check.catch(function(reason) {
    if(reason.status === 200) {
        return console.log("Site is valid and registered");
    }
    console.log("Not a valid site");
})

});

})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" placeholder="Please input url to check ? ">
Footton answered 24/4, 2021 at 18:7 Comment(3)
If your're doing this, please switch to using the native URL class.Camass
can you elaborate your reason ? @HimanshuPantFootton
Because you will effectively send a request to the provided url.Camass
P
0

Other way is use Node.JS DNS module.

The DNS module provides a way of performing name resolutions, and with it you can verify if the url is valid.

const dns = require('dns');
const url = require('url'); 

const lookupUrl = "https://stackoverflow.com";
const parsedLookupUrl = url.parse(lookupUrl);

dns.lookup(parsedLookupUrl.protocol ? parsedLookupUrl.host 
           : parsedLookupUrl.path, (error,address,family)=>{

              console.log(error || !address ? lookupUrl + ' is an invalid url!' 
                           : lookupUrl + ' is a valid url: ' + ' at ' + address);
    
              }
);

That way you can check if the url is valid and if it exists

Platter answered 20/7, 2021 at 16:24 Comment(0)
S
0
function isURL(_url)
{
    let result = false;
    let w = window;

    if (!w._check_input)
    {
        let input = document.createElement("input");
        input.type      = "url";
        input.required  = true;

        w._check_input = input;
    }

    w._check_input.value = _url;
    if (w._check_input.checkValidity()) result = true;

    return result;
}
Sclater answered 24/10, 2022 at 15:57 Comment(0)
G
0

call this function. If the string is not a valid URL a meaningful error occurs.

function encodedURL(string) {
  return new URL(string).href;
}

console.log(encodedURL("http://www.example.com?q=<foo>"));
console.log(encodedURL("www.example.com"));

So, for example:

Gudgeon answered 6/6, 2023 at 20:37 Comment(1)
Not gonna work: just pass these strings to it: http://.com, www...gogle...com or https://[email protected] and many more cases that are not even edge/rare case.Laevorotatory
G
-3

This is extension to @palvo's answer.

function isValidHttpUrl(string) {
  let url;
  try {
    url = new URL(string);
  } catch (_) {
    return false;  
  }
  return (url.protocol === "http:" || url.protocol === "https:") && (url.href == string || url.origin == string);
}

try followings :-

  • isValidHttpUrl("https:ewe/dsdsd");
  • isValidHttpUrl("https://ewe/dsdsd");

Tested in Chrome

Guntar answered 27/1, 2022 at 7:50 Comment(3)
What does this do that @pavlo's answer does not? I see the extra code near the end but I don't understand its purpose.Drice
@lnt this answer does not add anything new and the code seems wrong as well.Discipline
Check this in browser, there is trailing slash, which gets handled by this code. try this url - https:abc/dsdsdGuntar

© 2022 - 2024 — McMap. All rights reserved.