summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs')
-rw-r--r--src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs91
1 files changed, 72 insertions, 19 deletions
diff --git a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
index d13da7b..9e9deb4 100644
--- a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
@@ -10,6 +10,7 @@ namespace DotNetOpenAuth.Messaging {
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
+ using System.Globalization;
using System.IO;
using System.Net;
using System.ServiceModel.Channels;
@@ -54,6 +55,7 @@ namespace DotNetOpenAuth.Messaging {
this.HttpMethod = request.HttpMethod;
this.Url = request.Url;
+ this.UrlBeforeRewriting = GetPublicFacingUrl(request);
this.RawUrl = request.RawUrl;
this.Headers = GetHeaderCollection(request.Headers);
this.InputStream = request.InputStream;
@@ -87,6 +89,7 @@ namespace DotNetOpenAuth.Messaging {
this.HttpMethod = httpMethod;
this.Url = requestUrl;
+ this.UrlBeforeRewriting = requestUrl;
this.RawUrl = rawUrl;
this.Headers = headers;
this.InputStream = inputStream;
@@ -102,6 +105,7 @@ namespace DotNetOpenAuth.Messaging {
this.HttpMethod = listenerRequest.HttpMethod;
this.Url = listenerRequest.Url;
+ this.UrlBeforeRewriting = listenerRequest.Url;
this.RawUrl = listenerRequest.RawUrl;
this.Headers = new WebHeaderCollection();
foreach (string key in listenerRequest.Headers) {
@@ -125,6 +129,7 @@ namespace DotNetOpenAuth.Messaging {
this.HttpMethod = request.Method;
this.Headers = request.Headers;
this.Url = requestUri;
+ this.UrlBeforeRewriting = requestUri;
this.RawUrl = MakeUpRawUrlFromUrl(requestUri);
}
@@ -146,6 +151,7 @@ namespace DotNetOpenAuth.Messaging {
this.HttpMethod = request.Method;
this.Url = request.RequestUri;
+ this.UrlBeforeRewriting = request.RequestUri;
this.RawUrl = MakeUpRawUrlFromUrl(request.RequestUri);
this.Headers = GetHeaderCollection(request.Headers);
this.InputStream = null;
@@ -190,27 +196,13 @@ namespace DotNetOpenAuth.Messaging {
internal string RawUrl { get; set; }
/// <summary>
- /// Gets the full URL of a request before rewriting.
+ /// Gets or sets the full public URL used by the remote client to initiate this request,
+ /// before any URL rewriting and before any changes made by web farm load distributors.
/// </summary>
- internal Uri UrlBeforeRewriting {
- get {
- if (this.Url == null || this.RawUrl == null) {
- return null;
- }
-
- // 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(this.Url, this.RawUrl);
- }
- }
+ internal Uri UrlBeforeRewriting { get; set; }
/// <summary>
- /// Gets the query part of the URL (The ? and everything after it).
+ /// Gets the query part of the URL (The ? and everything after it), after URL rewriting.
/// </summary>
internal string Query {
get { return this.Url != null ? this.Url.Query : null; }
@@ -297,7 +289,56 @@ namespace DotNetOpenAuth.Messaging {
/// <c>true</c> if this request's URL was rewritten; otherwise, <c>false</c>.
/// </value>
internal bool IsUrlRewritten {
- get { return this.Url.PathAndQuery != this.RawUrl; }
+ get { return this.Url != this.UrlBeforeRewriting; }
+ }
+
+ /// <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(HttpRequest request, NameValueCollection serverVariables) {
+ Contract.Requires(request != null);
+ Contract.Requires(serverVariables != null);
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ ErrorUtilities.VerifyArgumentNotNull(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;
+ 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>
@@ -316,6 +357,18 @@ namespace DotNetOpenAuth.Messaging {
}
/// <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>
+ private static Uri GetPublicFacingUrl(HttpRequest request) {
+ Contract.Requires(request != null);
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+
+ return GetPublicFacingUrl(request, request.ServerVariables);
+ }
+
+ /// <summary>
/// Makes up a reasonable guess at the raw URL from the possibly rewritten URL.
/// </summary>
/// <param name="url">A full URL.</param>