359

There are the Uri.IsWellFormedUriString and Uri.TryCreate methods, but they seem to return true for file paths, etc.

How do I check whether a string is a valid (not necessarily active) HTTP URL for input validation purposes?

John Smith
  • 7,243
  • 6
  • 49
  • 61
Louis Rhys
  • 34,517
  • 56
  • 153
  • 221
  • 3
    Do not use regex.IsMatch at all to validate Url. Can kill cpu. https://stackoverflow.com/questions/31227785/why-does-checking-this-string-with-regex-ismatch-cause-cpu-to-reach-100 – inesmar Oct 28 '19 at 15:23

11 Answers11

597

Try this to validate HTTP URLs (uriName is the URI you want to test):

Uri uriResult;
bool result = Uri.TryCreate(uriName, UriKind.Absolute, out uriResult) 
    && uriResult.Scheme == Uri.UriSchemeHttp;

Or, if you want to accept both HTTP and HTTPS URLs as valid (per J0e3gan's comment):

Uri uriResult;
bool result = Uri.TryCreate(uriName, UriKind.Absolute, out uriResult) 
    && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
Arabela Paslaru
  • 6,754
  • 1
  • 15
  • 10
  • 7
    Should this read uriResult.Scheme instead of uriName.Scheme? I'm using the overload to TryCreate that takes String instead of Uri as it's first parameter. –  Jan 02 '13 at 10:58
  • 8
    You may want to add more conditions to the uriResult.Scheme == ... Specifically https. It depends on what you need this for, but this small change was all I needed for it to work perfectly for me. – Fiarr Jan 22 '14 at 19:04
  • 14
    To be clear per @Fiarr's comment, the "small change" needed to account for HTTPS in addition to HTTP URLs is: `bool result = Uri.TryCreate(uriName, UriKind.Absolute, out uriResult) && uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps;` – J0e3gan Nov 02 '14 at 09:40
  • Here's an extension method for a string which does all the above: public static bool IsUrl(this string str) { Uri uriResult; bool result = Uri.TryCreate(str, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); return result; } – Rob Sedgwick Oct 06 '15 at 15:34
  • What if url contains hashbang? – mtkachenko Feb 05 '16 at 08:21
  • jon schneider has incorporated j0e3gan's comment into the answer posted here. – barlop Aug 02 '16 at 13:12
  • 3
    this way fails for URL like _http://abcde_. It says this is a valid URL. – Kailash P Sep 22 '16 at 13:49
  • @KailashP a URL in that format could indeed be valid, for example on my company's intranet http://devinfo takes me to a sharepoint page – navigator_ Oct 20 '16 at 16:36
  • If the URL is deemed to be a relative URL, accessing `uriResult.Scheme` will throw an exception. – Jonathan Wood Nov 26 '16 at 00:34
  • @JonathanWood In this case if a relative URL is passed in for 'uriName', 'Uri.TryCreate(uriName, UriKind.Absolute, out uriResult)' will return false and 'uriResult.Scheme' will not be accessed, so no exception will be thrown. – raveturned Jan 27 '17 at 13:55
  • What's the advantage over using Uri.IsWellFormedUriString, which is shorter? – Jay Regal Mar 17 '17 at 14:47
  • 3
    Or in .NET Core, C#7 (where the constants in the Uri class are gone...): `bool result = Uri.TryCreate(uriName, UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == "http" || uriResult.Scheme == "https");` – Richard Jun 08 '17 at 10:14
  • 4
    @KailashP is right - I don't think I like this code without an extra check: `&& uriResult != null`! – Ian Grainger Jul 21 '17 at 11:21
  • 13
    Looks like this technique fails 22 out of 75 tests https://dotnetfiddle.net/XduN3A – whitneyland Oct 21 '17 at 20:04
  • @Lee what is the better option to test the url? – Radu Feb 21 '18 at 08:44
  • Does this mean - Url complies with RFC3986 ? – Marcus Mar 28 '18 at 08:51
  • @whitneyland : Do you have any solution for this please ? – Sagar Panwala Sep 16 '19 at 10:44
  • This approach says the following is a valid url `https://www.somesite.com/">` but if supplied by the user this definitely is NOT a "url" you'd want to put in the href of an html anchor tag. :-) – RonC Nov 02 '22 at 15:17
194

This method works fine both in http and https. Just one line :)

if (Uri.IsWellFormedUriString("https://www.google.com", UriKind.Absolute))

MSDN: IsWellFormedUriString

Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
Kishath
  • 5,560
  • 4
  • 17
  • 22
  • 31
    This will return true for non-HTTP URIs (i.e. [any other scheme](https://msdn.microsoft.com/en-us/library/system.uri.scheme(v=vs.110).aspx) such as `file://` or `ldap://`. This solution should be coupled with a check against the scheme - e.g. `if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) ...` – Squiggle Jun 12 '17 at 09:43
  • Is this RFC3986 compliant? – Marcus Mar 28 '18 at 09:08
  • 3
    @Squiggle That's exactly what I want it to check, ***everything*** since I'm making a Downloader. So, this answer is the best method for me. – Beyondo Nov 27 '18 at 14:54
  • Problem is that IsWellFormedUriString renders spaces at the end as valid part of an URL. And no it don't thinks they are %20s, since adding a valid symbol after the spaces results in invalid URL: "a" - valid "a " - valid ?! "a a" - invalid ?!? – Ivan Caravanio Jan 15 '21 at 22:23
  • For simple string URL validation, I think this is better, it simply returns false if you use "http:\\test.com" instead of "http://test.com" whereas `.TryCreate` is smart enough to correct the invalid slashes. But in my case this string was used elsewhere to make a REST call and caused an exception. – Ryan Thomas May 19 '21 at 14:37
  • CAUTION: This will return `true` for url like `javascript:alert("xss")` – Alex from Jitbit Jul 22 '22 at 20:11
34

Try that:

bool IsValidURL(string URL)
{
    string Pattern = @"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$";
    Regex Rgx = new Regex(Pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
    return Rgx.IsMatch(URL);
}

It will accept URL like that:

  • http(s)://www.example.com
  • http(s)://stackoverflow.example.com
  • http(s)://www.example.com/page
  • http(s)://www.example.com/page?id=1&product=2
  • http(s)://www.example.com/page#start
  • http(s)://www.example.com:8080
  • http(s)://127.0.0.1
  • 127.0.0.1
  • www.example.com
  • example.com
Marco Concas
  • 1,665
  • 20
  • 25
31
    public static bool CheckURLValid(this string source)
    {
        Uri uriResult;
        return Uri.TryCreate(source, UriKind.Absolute, out uriResult) && uriResult.Scheme == Uri.UriSchemeHttp;
    }

Usage:

string url = "htts://adasd.xc.";
if(url.CheckUrlValid())
{
  //valid process
}

UPDATE: (single line of code) Thanks @GoClimbColorado

public static bool CheckURLValid(this string source) => Uri.TryCreate(source, UriKind.Absolute, out Uri uriResult) && uriResult.Scheme == Uri.UriSchemeHttps;

Usage:

string url = "htts://adasd.xc.";
if(url.CheckUrlValid())
{
  //valid process
}
Erçin Dedeoğlu
  • 4,950
  • 4
  • 49
  • 69
20

All the answers here either allow URLs with other schemes (e.g., file://, ftp://) or reject human-readable URLs that don't start with http:// or https:// (e.g., www.google.com) which is not good when dealing with user inputs.

Here's how I do it:

public static bool ValidHttpURL(string s, out Uri resultURI)
{
    if (!Regex.IsMatch(s, @"^https?:\/\/", RegexOptions.IgnoreCase))
        s = "http://" + s;

    if (Uri.TryCreate(s, UriKind.Absolute, out resultURI))
        return (resultURI.Scheme == Uri.UriSchemeHttp || 
                resultURI.Scheme == Uri.UriSchemeHttps);

    return false;
}

Usage:

string[] inputs = new[] {
                          "https://www.google.com",
                          "http://www.google.com",
                          "www.google.com",
                          "google.com",
                          "javascript:alert('Hack me!')"
                        };
foreach (string s in inputs)
{
    Uri uriResult;
    bool result = ValidHttpURL(s, out uriResult);
    Console.WriteLine(result + "\t" + uriResult?.AbsoluteUri);
}

Output:

True    https://www.google.com/
True    http://www.google.com/
True    http://www.google.com/
True    http://google.com/
False
  • 1
    This lets through single words like "mooooooooo" but used in conjunction with Uri.IsWellFormedUriString could be good – Epirocks Mar 18 '19 at 17:59
  • @Epirocks That's a good point. The problem is that `http://mooooooooo` is, in fact, a valid Uri. Therefore, you can't check for `Uri.IsWellFormedUriString` after inserting "http://" and if you check for it before, anything that doesn't have a `Scheme` will be rejected. Maybe what can be done is we check for `s.Contains('.')` instead. – 41686d6564 stands w. Palestine Mar 19 '19 at 09:40
  • moooooo by itself doesn't look like a url as it has no protocol on it. What I did was take out your regex match call, and &&'ed it with IsWellFormedUriString as well. – Epirocks Mar 19 '19 at 11:02
  • @Epirocks Exactly! The problem is that if you use `IsWellFormedUriString` before adding the `http://`, you'll end up rejecting things like `google.com` and if you use it after adding the `http://`, it'll still return true for `http://mooooooooo`. That's why I suggested checking if the string contains a `.` instead. – 41686d6564 stands w. Palestine Mar 19 '19 at 11:05
  • that's fine for me anyway I don't want to accept a url without http or https on it. So I use IsWellFormedUriString first, then use your function without regex. bool bResult = (Uri.IsWellFormedUriString(s, UriKind.Absolute) && ValidHttpURL(s, out uriResult)); Thanks – Epirocks Mar 20 '19 at 16:14
  • It's important to note that URL's like `htt://google.com` are accepted – Wouter Vanherck Nov 10 '20 at 10:23
7

After Uri.TryCreate you can check Uri.Scheme to see if it HTTP(s).

J0e3gan
  • 8,740
  • 10
  • 53
  • 80
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
4

As an alternative approach to using a regex, this code uses Uri.TryCreate per the OP, but then also checks the result to ensure that its Scheme is one of http or https:

bool passed =
  Uri.TryCreate(url, UriKind.Absolute, out Uri uriResult)
    && (uriResult.Scheme == Uri.UriSchemeHttp
      || uriResult.Scheme == Uri.UriSchemeHttps);
jlmt
  • 1,947
  • 1
  • 13
  • 16
Ifeanyi Chukwu
  • 3,187
  • 3
  • 28
  • 32
3

This would return bool:

Uri.IsWellFormedUriString(a.GetAttribute("href"), UriKind.Absolute)
  • 2
    I think the OP specifically mentioned, he doesn't like Uri.IsWellFormedUriString as it gives true for file paths. Do you have a solution for this problem? – Isantipov Jun 20 '14 at 12:23
3

Problem: Valid URLs should include all of the following “prefixes”: https, http, www

  • Url must contain http:// or https://
  • Url may contain only one instance of www.
  • Url Host name type must be Dns
  • Url max length is 100

Solution:

public static bool IsValidUrl(string webSiteUrl)
{
   if (webSiteUrl.StartsWith("www."))
   {
       webSiteUrl = "http://" + webSiteUrl;
   }
        
   return Uri.TryCreate(webSiteUrl, UriKind.Absolute, out Uri uriResult)
            && (uriResult.Scheme == Uri.UriSchemeHttp
             || uriResult.Scheme == Uri.UriSchemeHttps) && uriResult.Host.Replace("www.", "").Split('.').Count() > 1 && uriResult.HostNameType == UriHostNameType.Dns && uriResult.Host.Length > uriResult.Host.LastIndexOf(".") + 1 && 100 >= webSiteUrl.Length;
}

Validated with Unit Tests

Positive Unit Test:

    [TestCase("http://www.example.com/")]
    [TestCase("https://www.example.com")]
    [TestCase("http://example.com")]
    [TestCase("https://example.com")]
    [TestCase("www.example.com")]
    public void IsValidUrlTest(string url)
    {
        bool result = UriHelper.IsValidUrl(url);

        Assert.AreEqual(result, true);
    }

Negative Unit Test:

    [TestCase("http.www.example.com")]
    [TestCase("http:www.example.com")]
    [TestCase("http:/www.example.com")]
    [TestCase("http://www.example.")]
    [TestCase("http://www.example..com")]
    [TestCase("https.www.example.com")]
    [TestCase("https:www.example.com")]
    [TestCase("https:/www.example.com")]
    [TestCase("http:/example.com")]
    [TestCase("https:/example.com")]
    public void IsInvalidUrlTest(string url)
    {
        bool result = UriHelper.IsValidUrl(url);

        Assert.AreEqual(result, false);
    }

Note: IsValidUrl method should not validate any relative url path like example.com

See:

Should I Use Relative or Absolute URLs?

Manish Kumar
  • 191
  • 1
  • 9
1
Uri uri = null;
if (!Uri.TryCreate(url, UriKind.Absolute, out uri) || null == uri)
    return false;
else
    return true;

Here url is the string you have to test.

J0e3gan
  • 8,740
  • 10
  • 53
  • 80
Eranda
  • 868
  • 1
  • 10
  • 27
0

I've created this function to help me with URL validation, you can customize it as you like, note this is written in python3.10.6

def url_validator(url: str) -> bool:
    """
    use this func to filter out the urls to follow only valid urls
    :param: url
    :type: str
    :return: True if the passed url is valid otherwise return false
    :rtype: bool
    """

    #the following regex is copied from Django source code 
    # to validate a url using regax
    
    regex = re.compile(
        r"^(?:http|ftp)s?://"  # http:// or https://
        r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|"  # domain...
        r"localhost|"  # localhost...
        r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"  # ...or ip
        r"(?::\d+)?"  # optional port
        r"(?:/?|[/?]\S+)$",
        re.IGNORECASE,
    )


    blocked_sites: list[str] = []

    for site in blocked_sites:
        if site in url or site == url:
            return False

    # if none of the above then ensure that the url is valid and then return True otherwise return False
    if re.match(regex, url):
        return True

    return False
Radwan
  • 54
  • 3