summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.Core/UriUtil.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.Core/UriUtil.cs')
-rw-r--r--src/DotNetOpenAuth.Core/UriUtil.cs117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.Core/UriUtil.cs b/src/DotNetOpenAuth.Core/UriUtil.cs
new file mode 100644
index 0000000..57360f5
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/UriUtil.cs
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------
+// <copyright file="UriUtil.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth {
+ using System;
+ using System.Collections.Specialized;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text.RegularExpressions;
+ using System.Web;
+ using System.Web.UI;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// Utility methods for working with URIs.
+ /// </summary>
+ [ContractVerification(true)]
+ internal static class UriUtil {
+ /// <summary>
+ /// Tests a URI for the presence of an OAuth payload.
+ /// </summary>
+ /// <param name="uri">The URI to test.</param>
+ /// <param name="prefix">The prefix.</param>
+ /// <returns>
+ /// True if the URI contains an OAuth message.
+ /// </returns>
+ [ContractVerification(false)] // bugs/limitations in CC static analysis
+ internal static bool QueryStringContainPrefixedParameters(this Uri uri, string prefix) {
+ Requires.NotNullOrEmpty(prefix, "prefix");
+ if (uri == null) {
+ return false;
+ }
+
+ NameValueCollection nvc = HttpUtility.ParseQueryString(uri.Query);
+ Contract.Assume(nvc != null); // BCL
+ return nvc.Keys.OfType<string>().Any(key => key.StartsWith(prefix, StringComparison.Ordinal));
+ }
+
+ /// <summary>
+ /// Determines whether some <see cref="Uri"/> is using HTTPS.
+ /// </summary>
+ /// <param name="uri">The Uri being tested for security.</param>
+ /// <returns>
+ /// <c>true</c> if the URI represents an encrypted request; otherwise, <c>false</c>.
+ /// </returns>
+ internal static bool IsTransportSecure(this Uri uri) {
+ Requires.NotNull(uri, "uri");
+ return string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase);
+ }
+
+ /// <summary>
+ /// Equivalent to UriBuilder.ToString() but omits port # if it may be implied.
+ /// Equivalent to UriBuilder.Uri.ToString(), but doesn't throw an exception if the Host has a wildcard.
+ /// </summary>
+ /// <param name="builder">The UriBuilder to render as a string.</param>
+ /// <returns>The string version of the Uri.</returns>
+ internal static string ToStringWithImpliedPorts(this UriBuilder builder) {
+ Requires.NotNull(builder, "builder");
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ // We only check for implied ports on HTTP and HTTPS schemes since those
+ // are the only ones supported by OpenID anyway.
+ if ((builder.Port == 80 && string.Equals(builder.Scheme, "http", StringComparison.OrdinalIgnoreCase)) ||
+ (builder.Port == 443 && string.Equals(builder.Scheme, "https", StringComparison.OrdinalIgnoreCase))) {
+ // An implied port may be removed.
+ string url = builder.ToString();
+
+ // Be really careful to only remove the first :80 or :443 so we are guaranteed
+ // we're removing only the port (and not something in the query string that
+ // looks like a port.
+ string result = Regex.Replace(url, @"^(https?://[^:]+):\d+", m => m.Groups[1].Value, RegexOptions.IgnoreCase);
+ Contract.Assume(result != null); // Regex.Replace never returns null
+ return result;
+ } else {
+ // The port must be explicitly given anyway.
+ return builder.ToString();
+ }
+ }
+
+ /// <summary>
+ /// Validates that a URL will be resolvable at runtime.
+ /// </summary>
+ /// <param name="page">The page hosting the control that receives this URL as a property.</param>
+ /// <param name="designMode">If set to <c>true</c> the page is in design-time mode rather than runtime mode.</param>
+ /// <param name="value">The URI to check.</param>
+ /// <exception cref="UriFormatException">Thrown if the given URL is not a valid, resolvable URI.</exception>
+ [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Uri", Justification = "Just to throw an exception on invalid input.")]
+ internal static void ValidateResolvableUrl(Page page, bool designMode, string value) {
+ if (string.IsNullOrEmpty(value)) {
+ return;
+ }
+
+ if (page != null && !designMode) {
+ Contract.Assume(page.Request != null);
+
+ // Validate new value by trying to construct a Realm object based on it.
+ string relativeUrl = page.ResolveUrl(value);
+ Contract.Assume(page.Request.Url != null);
+ Contract.Assume(relativeUrl != null);
+ new Uri(page.Request.Url, relativeUrl); // throws an exception on failure.
+ } else {
+ // We can't fully test it, but it should start with either ~/ or a protocol.
+ if (Regex.IsMatch(value, @"^https?://")) {
+ new Uri(value); // make sure it's fully-qualified, but ignore wildcards
+ } else if (value.StartsWith("~/", StringComparison.Ordinal)) {
+ // this is valid too
+ } else {
+ throw new UriFormatException();
+ }
+ }
+ }
+ }
+}