summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs56
-rw-r--r--src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs63
2 files changed, 99 insertions, 20 deletions
diff --git a/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs b/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs
index 05ac306..fd77746 100644
--- a/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs
@@ -5,6 +5,8 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Test.Messaging {
+ using System;
+ using System.Collections.Specialized;
using System.Web;
using DotNetOpenAuth.Messaging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -92,5 +94,59 @@ namespace DotNetOpenAuth.Test.Messaging {
HttpRequestInfo info = new HttpRequestInfo();
Assert.IsNull(info.QueryString["hi"]);
}
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply X_FORWARDED_PROTO and HOST
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder1() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_X_FORWARDED_PROTO"] = "https";
+ serverVariables["HTTP_HOST"] = "somehost";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("https://somehost/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply X_FORWARDED_PROTO and HOST:port
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder2() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_X_FORWARDED_PROTO"] = "https";
+ serverVariables["HTTP_HOST"] = "somehost:999";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("https://somehost:999/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply just HOST
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder3() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_HOST"] = "somehost";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("http://somehost/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply just HOST:port
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder4() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_HOST"] = "somehost:79";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("http://somehost:79/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
}
}
diff --git a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
index 2fd7be4..9e9deb4 100644
--- a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
@@ -293,28 +293,24 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
- /// Gets the query or form data from the original request (before any URL rewriting has occurred.)
- /// </summary>
- /// <returns>A set of name=value pairs.</returns>
- [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Expensive call")]
- internal NameValueCollection GetQueryOrFormFromContext() {
- NameValueCollection query;
- if (this.HttpMethod == "GET") {
- query = this.QueryStringBeforeRewriting;
- } else {
- query = this.Form;
- }
- return query;
- }
-
- /// <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) {
+ /// <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
@@ -323,10 +319,10 @@ namespace DotNetOpenAuth.Messaging {
// 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 (request.ServerVariables["HTTP_HOST"] != null) {
+ 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 = request.ServerVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
- Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + request.ServerVariables["HTTP_HOST"]);
+ 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;
@@ -346,6 +342,33 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets the query or form data from the original request (before any URL rewriting has occurred.)
+ /// </summary>
+ /// <returns>A set of name=value pairs.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Expensive call")]
+ internal NameValueCollection GetQueryOrFormFromContext() {
+ NameValueCollection query;
+ if (this.HttpMethod == "GET") {
+ query = this.QueryStringBeforeRewriting;
+ } else {
+ query = this.Form;
+ }
+ return query;
+ }
+
+ /// <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>