1
//-----------------------------------------------------------------------
2 // <copyright file="UriUtil.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth
{
9 using System
.Collections
.Specialized
;
10 using System
.Diagnostics
.CodeAnalysis
;
12 using System
.Text
.RegularExpressions
;
15 using DotNetOpenAuth
.Messaging
;
18 /// Utility methods for working with URIs.
20 internal static class UriUtil
{
22 /// Tests a URI for the presence of an OAuth payload.
24 /// <param name="uri">The URI to test.</param>
25 /// <returns>True if the URI contains an OAuth message.</returns>
26 internal static bool QueryStringContainsOAuthParameters(Uri uri
) {
31 NameValueCollection nvc
= HttpUtility
.ParseQueryString(uri
.Query
);
32 return nvc
.Keys
.OfType
<string>().Any(key
=> key
.StartsWith(OAuth
.Protocol
.V10
.ParameterPrefix
, StringComparison
.Ordinal
));
36 /// Determines whether some <see cref="Uri"/> is using HTTPS.
38 /// <param name="uri">The Uri being tested for security.</param>
40 /// <c>true</c> if the URI represents an encrypted request; otherwise, <c>false</c>.
42 internal static bool IsTransportSecure(this Uri uri
) {
44 throw new ArgumentNullException("uri");
47 return string.Equals(uri
.Scheme
, "https", StringComparison
.OrdinalIgnoreCase
);
51 /// Equivalent to UriBuilder.ToString() but omits port # if it may be implied.
52 /// Equivalent to UriBuilder.Uri.ToString(), but doesn't throw an exception if the Host has a wildcard.
54 /// <param name="builder">The UriBuilder to render as a string.</param>
55 /// <returns>The string version of the Uri.</returns>
56 internal static string ToStringWithImpliedPorts(this UriBuilder builder
) {
57 ErrorUtilities
.VerifyArgumentNotNull(builder
, "builder");
59 // We only check for implied ports on HTTP and HTTPS schemes since those
60 // are the only ones supported by OpenID anyway.
61 if ((builder
.Port
== 80 && string.Equals(builder
.Scheme
, "http", StringComparison
.OrdinalIgnoreCase
)) ||
62 (builder
.Port
== 443 && string.Equals(builder
.Scheme
, "https", StringComparison
.OrdinalIgnoreCase
))) {
63 // An implied port may be removed.
64 string url
= builder
.ToString();
66 // Be really careful to only remove the first :80 or :443 so we are guaranteed
67 // we're removing only the port (and not something in the query string that
69 return Regex
.Replace(url
, @"^(https?://[^:]+):\d+", m
=> m
.Groups
[1].Value
, RegexOptions
.IgnoreCase
);
71 // The port must be explicitly given anyway.
72 return builder
.ToString();
77 /// Validates that a URL will be resolvable at runtime.
79 /// <param name="page">The page hosting the control that receives this URL as a property.</param>
80 /// <param name="designMode">If set to <c>true</c> the page is in design-time mode rather than runtime mode.</param>
81 /// <param name="value">The URI to check.</param>
82 /// <exception cref="UriFormatException">Thrown if the given URL is not a valid, resolvable URI.</exception>
83 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId
= "System.Uri", Justification
= "Just to throw an exception on invalid input.")]
84 internal static void ValidateResolvableUrl(Page page
, bool designMode
, string value) {
85 if (string.IsNullOrEmpty(value)) {
89 if (page
!= null && !designMode
) {
90 // Validate new value by trying to construct a Realm object based on it.
91 new Uri(page
.Request
.Url
, page
.ResolveUrl(value)); // throws an exception on failure.
93 // We can't fully test it, but it should start with either ~/ or a protocol.
94 if (Regex
.IsMatch(value, @"^https?://")) {
95 new Uri(value); // make sure it's fully-qualified, but ignore wildcards
96 } else if (value.StartsWith("~/", StringComparison
.Ordinal
)) {
99 throw new UriFormatException();