diff options
Diffstat (limited to 'src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs')
-rw-r--r-- | src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs | 129 |
1 files changed, 124 insertions, 5 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs index fbf6b4f..664db71 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs @@ -153,9 +153,7 @@ namespace DotNetOpenAuth.Messaging { [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Expensive call should not be a property.")] public static Uri GetRequestUrlFromContext() { Requires.ValidState(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); - HttpContext context = HttpContext.Current; - - return HttpRequestInfo.GetPublicFacingUrl(context.Request, context.Request.ServerVariables); + return new HttpRequestWrapper(HttpContext.Current.Request).GetPublicFacingUrl(); } /// <summary> @@ -1352,8 +1350,8 @@ namespace DotNetOpenAuth.Messaging { /// <param name="request">The request to get recipient information from.</param> /// <returns>The recipient.</returns> /// <exception cref="ArgumentException">Thrown if the HTTP request is something we can't handle.</exception> - internal static MessageReceivingEndpoint GetRecipient(this HttpRequestInfo request) { - return new MessageReceivingEndpoint(request.UrlBeforeRewriting, GetHttpDeliveryMethod(request.HttpMethod)); + internal static MessageReceivingEndpoint GetRecipient(this HttpRequestBase request) { + return new MessageReceivingEndpoint(request.GetPublicFacingUrl(), GetHttpDeliveryMethod(request.HttpMethod)); } /// <summary> @@ -1484,6 +1482,22 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Converts a dictionary to a <see cref="NameValueCollection"/> + /// </summary> + /// <param name="data">The existing dictionary.</param> + /// <returns>The new collection.</returns> + internal static NameValueCollection ToNameValueCollection(this IDictionary<string, string> data) { + Requires.NotNull(data, "data"); + + var nvc = new NameValueCollection(); + foreach (var entry in data) { + nvc.Add(entry.Key, entry.Value); + } + + return nvc; + } + + /// <summary> /// Sorts the elements of a sequence in ascending order by using a specified comparer. /// </summary> /// <typeparam name="TSource">The type of the elements of source.</typeparam> @@ -1663,6 +1677,111 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Gets the query data from the original request (before any URL rewriting has occurred.) + /// </summary> + /// <param name="request">The request.</param> + /// <returns> + /// A <see cref="NameValueCollection"/> containing all the parameters in the query string. + /// </returns> + internal static NameValueCollection GetQueryStringBeforeRewriting(this HttpRequestBase request) { + // This request URL may have been rewritten by the host site. + // For openid protocol purposes, we really need to look at + // the original query parameters before any rewriting took place. + Uri beforeRewriting = GetPublicFacingUrl(request); + if (beforeRewriting == request.Url) { + // No rewriting has taken place. + return request.QueryString; + } else { + // Rewriting detected! Recover the original request URI. + ErrorUtilities.VerifyInternal(beforeRewriting != null, "UrlBeforeRewriting is null, so the query string cannot be determined."); + return HttpUtility.ParseQueryString(beforeRewriting.Query); + } + } + + /// <summary> + /// Gets a value indicating whether the request's URL was rewritten by ASP.NET + /// or some other module. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>A value indicating whether there is evidence that the URL of the request has been changed to some internal server (farm) representation.</returns> + /// <value> + /// <c>true</c> if this request's URL was rewritten; otherwise, <c>false</c>. + /// </value> + internal static bool GetIsUrlRewritten(this HttpRequestBase request) { + return request.Url != GetPublicFacingUrl(request); + } + + /// <summary> + /// Gets the public facing URL for the given incoming HTTP request. + /// </summary> + /// <param name="request">The request.</param> + /// <param name="serverVariables">The server variables to consider part of the request.</param> + /// <returns> + /// The URI that the outside world used to create this request. + /// </returns> + /// <remarks> + /// Although the <paramref name="serverVariables"/> value can be obtained from + /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them + /// in so we can simulate injected values from our unit tests since the actual property + /// is a read-only kind of <see cref="NameValueCollection"/>. + /// </remarks> + internal static Uri GetPublicFacingUrl(this HttpRequestBase request, NameValueCollection serverVariables) { + Requires.NotNull(request, "request"); + Requires.NotNull(serverVariables, "serverVariables"); + + // Due to URL rewriting, cloud computing (i.e. Azure) + // and web farms, etc., we have to be VERY careful about what + // we consider the incoming URL. We want to see the URL as it would + // appear on the public-facing side of the hosting web site. + // HttpRequest.Url gives us the internal URL in a cloud environment, + // So we use a variable that (at least from what I can tell) gives us + // the public URL: + if (serverVariables["HTTP_HOST"] != null) { + ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols."); + string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme; + Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]); + UriBuilder publicRequestUri = new UriBuilder(request.Url); + publicRequestUri.Scheme = scheme; + publicRequestUri.Host = hostAndPort.Host; + publicRequestUri.Port = hostAndPort.Port; // CC missing Uri.Port contract that's on UriBuilder.Port + return publicRequestUri.Uri; + } else { + // Failover to the method that works for non-web farm enviroments. + // We use Request.Url for the full path to the server, and modify it + // with Request.RawUrl to capture both the cookieless session "directory" if it exists + // and the original path in case URL rewriting is going on. We don't want to be + // fooled by URL rewriting because we're comparing the actual URL with what's in + // the return_to parameter in some cases. + // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless + // session, but not the URL rewriting problem. + return new Uri(request.Url, request.RawUrl); + } + } + + /// <summary> + /// Gets the public facing URL for the given incoming HTTP request. + /// </summary> + /// <param name="request">The request.</param> + /// <returns>The URI that the outside world used to create this request.</returns> + internal static Uri GetPublicFacingUrl(this HttpRequestBase request) { + Requires.NotNull(request, "request"); + return GetPublicFacingUrl(request, request.ServerVariables); + } + + /// <summary> + /// Gets the query or form data from the original request (before any URL rewriting has occurred.) + /// </summary> + /// <param name="request">The request.</param> + /// <returns> + /// A set of name=value pairs. + /// </returns> + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Expensive call")] + internal static NameValueCollection GetQueryOrForm(this HttpRequestBase request) { + Requires.NotNull(request, "request"); + return request.HttpMethod == "GET" ? GetQueryStringBeforeRewriting(request) : request.Form; + } + + /// <summary> /// Creates a symmetric algorithm for use in encryption/decryption. /// </summary> /// <param name="key">The symmetric key to use for encryption/decryption.</param> |