summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.Core
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.Core')
-rw-r--r--src/DotNetOpenAuth.Core/Assumes.cs7
-rw-r--r--src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj4
-rw-r--r--src/DotNetOpenAuth.Core/Loggers/ILog.cs80
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/Channel.cs71
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs17
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/EmptyDictionary.cs1
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/EmptyList.cs1
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/EnumerableCacheExtensions.cs (renamed from src/DotNetOpenAuth.Core/Messaging/EnumerableCache.cs)2
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs27
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs424
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs19
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs133
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs2
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/ReadOnlyDictionary.cs224
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/UntrustedWebRequestHandler.cs2
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/UriStyleMessageFormatter.cs2
-rw-r--r--src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs4
-rw-r--r--src/DotNetOpenAuth.Core/Reporting.cs8
-rw-r--r--src/DotNetOpenAuth.Core/Requires.cs8
-rw-r--r--src/DotNetOpenAuth.Core/Settings.StyleCop6
20 files changed, 638 insertions, 404 deletions
diff --git a/src/DotNetOpenAuth.Core/Assumes.cs b/src/DotNetOpenAuth.Core/Assumes.cs
index b61fbd4..f29f09f 100644
--- a/src/DotNetOpenAuth.Core/Assumes.cs
+++ b/src/DotNetOpenAuth.Core/Assumes.cs
@@ -12,6 +12,7 @@ namespace DotNetOpenAuth {
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
+ using System.Runtime.Serialization;
using System.Text;
/// <summary>
@@ -39,7 +40,7 @@ namespace DotNetOpenAuth {
[Pure, DebuggerStepThrough]
internal static void True(bool condition, string unformattedMessage, params object[] args) {
if (!condition) {
- Fail(String.Format(CultureInfo.CurrentCulture, unformattedMessage, args));
+ Fail(string.Format(CultureInfo.CurrentCulture, unformattedMessage, args));
}
}
@@ -84,8 +85,8 @@ namespace DotNetOpenAuth {
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info"/> parameter is null. </exception>
/// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult"/> is zero (0). </exception>
protected InternalErrorException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context)
+ SerializationInfo info,
+ StreamingContext context)
: base(info, context) {
}
}
diff --git a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
index 9b8a613..c46e6b8 100644
--- a/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
+++ b/src/DotNetOpenAuth.Core/DotNetOpenAuth.Core.csproj
@@ -28,10 +28,11 @@
<Compile Include="Messaging\CachedDirectWebResponse.cs" />
<Compile Include="Messaging\ChannelContract.cs" />
<Compile Include="Messaging\DataBagFormatterBase.cs" />
+ <Compile Include="Messaging\HttpRequestHeaders.cs" />
<Compile Include="Messaging\IHttpIndirectResponse.cs" />
<Compile Include="Messaging\IMessageOriginalPayload.cs" />
<Compile Include="Messaging\DirectWebRequestOptions.cs" />
- <Compile Include="Messaging\EnumerableCache.cs" />
+ <Compile Include="Messaging\EnumerableCacheExtensions.cs" />
<Compile Include="Messaging\HostErrorException.cs" />
<Compile Include="Messaging\IHttpDirectResponse.cs" />
<Compile Include="Messaging\IExtensionMessage.cs" />
@@ -127,6 +128,7 @@
<Compile Include="Loggers\NoOpLogger.cs" />
<Compile Include="Loggers\TraceLogger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Messaging\ReadOnlyDictionary.cs" />
<Compile Include="Reporting.cs" />
<Compile Include="Requires.cs" />
<Compile Include="Strings.Designer.cs">
diff --git a/src/DotNetOpenAuth.Core/Loggers/ILog.cs b/src/DotNetOpenAuth.Core/Loggers/ILog.cs
index 8094296..e801b2a 100644
--- a/src/DotNetOpenAuth.Core/Loggers/ILog.cs
+++ b/src/DotNetOpenAuth.Core/Loggers/ILog.cs
@@ -122,8 +122,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="args">An Object array containing zero or more objects to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -143,8 +143,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg0">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -165,8 +165,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg1">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -188,8 +188,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg2">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -253,8 +253,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="args">An Object array containing zero or more objects to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -274,8 +274,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg0">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -296,8 +296,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg1">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -319,8 +319,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg2">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -384,8 +384,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="args">An Object array containing zero or more objects to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -405,8 +405,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg0">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -427,8 +427,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg1">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -450,8 +450,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg2">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -515,8 +515,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="args">An Object array containing zero or more objects to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -536,8 +536,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg0">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -558,8 +558,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg1">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -581,8 +581,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg2">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -646,8 +646,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="args">An Object array containing zero or more objects to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -667,8 +667,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg0">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -689,8 +689,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg1">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
@@ -712,8 +712,8 @@ namespace DotNetOpenAuth.Loggers
/// <param name="arg2">An Object to format</param>
/// <remarks>
/// <para>
- /// The message is formatted using the <c>String.Format</c> method. See
- /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
+ /// The message is formatted using the <c>string.Format</c> method. See
+ /// <see cref="string.Format(string, object[])"/> for details of the syntax of the format string and the behavior
/// of the formatting.
/// </para>
/// <para>
diff --git a/src/DotNetOpenAuth.Core/Messaging/Channel.cs b/src/DotNetOpenAuth.Core/Messaging/Channel.cs
index 26a8179..16e39d3 100644
--- a/src/DotNetOpenAuth.Core/Messaging/Channel.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/Channel.cs
@@ -69,7 +69,7 @@ namespace DotNetOpenAuth.Messaging {
/// <summary>
/// The HTML that should be returned to the user agent as part of a 301 Redirect.
/// </summary>
- /// <value>A string that should be used as the first argument to String.Format, where the {0} should be replaced with the URL to redirect to.</value>
+ /// <value>A string that should be used as the first argument to string.Format, where the {0} should be replaced with the URL to redirect to.</value>
private const string RedirectResponseBodyFormat = @"<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href=""{0}"">here</a>.</h2>
</body></html>";
@@ -409,7 +409,7 @@ namespace DotNetOpenAuth.Messaging {
/// <returns>True if the expected message was recognized and deserialized. False otherwise.</returns>
/// <exception cref="InvalidOperationException">Thrown when <see cref="HttpContext.Current"/> is null.</exception>
/// <exception cref="ProtocolException">Thrown when a request message of an unexpected type is received.</exception>
- public bool TryReadFromRequest<TRequest>(HttpRequestInfo httpRequest, out TRequest request)
+ public bool TryReadFromRequest<TRequest>(HttpRequestBase httpRequest, out TRequest request)
where TRequest : class, IProtocolMessage {
Requires.NotNull(httpRequest, "httpRequest");
Contract.Ensures(Contract.Result<bool>() == (Contract.ValueAtReturn<TRequest>(out request) != null));
@@ -450,7 +450,7 @@ namespace DotNetOpenAuth.Messaging {
/// <returns>The deserialized message. Never null.</returns>
/// <exception cref="ProtocolException">Thrown if the expected message was not recognized in the response.</exception>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This returns and verifies the appropriate message type.")]
- public TRequest ReadFromRequest<TRequest>(HttpRequestInfo httpRequest)
+ public TRequest ReadFromRequest<TRequest>(HttpRequestBase httpRequest)
where TRequest : class, IProtocolMessage {
Requires.NotNull(httpRequest, "httpRequest");
TRequest request;
@@ -466,11 +466,11 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
/// <param name="httpRequest">The request to search for an embedded message.</param>
/// <returns>The deserialized message, if one is found. Null otherwise.</returns>
- public IDirectedProtocolMessage ReadFromRequest(HttpRequestInfo httpRequest) {
+ public IDirectedProtocolMessage ReadFromRequest(HttpRequestBase httpRequest) {
Requires.NotNull(httpRequest, "httpRequest");
- if (Logger.Channel.IsInfoEnabled && httpRequest.UrlBeforeRewriting != null) {
- Logger.Channel.InfoFormat("Scanning incoming request for messages: {0}", httpRequest.UrlBeforeRewriting.AbsoluteUri);
+ if (Logger.Channel.IsInfoEnabled && httpRequest.GetPublicFacingUrl() != null) {
+ Logger.Channel.InfoFormat("Scanning incoming request for messages: {0}", httpRequest.GetPublicFacingUrl().AbsoluteUri);
}
IDirectedProtocolMessage requestMessage = this.ReadFromRequestCore(httpRequest);
if (requestMessage != null) {
@@ -599,6 +599,16 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets the HTTP context for the current HTTP request.
+ /// </summary>
+ /// <returns>An HttpContextBase instance.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Allocates memory")]
+ protected internal virtual HttpContextBase GetHttpContext() {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ return new HttpContextWrapper(HttpContext.Current);
+ }
+
+ /// <summary>
/// Gets the current HTTP request being processed.
/// </summary>
/// <returns>The HttpRequestInfo for the current request.</returns>
@@ -607,16 +617,13 @@ namespace DotNetOpenAuth.Messaging {
/// </remarks>
/// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current">HttpContext.Current</see> == <c>null</c>.</exception>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Costly call should not be a property.")]
- protected internal virtual HttpRequestInfo GetRequestFromContext() {
+ protected internal virtual HttpRequestBase GetRequestFromContext() {
Requires.ValidState(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired);
- Contract.Ensures(Contract.Result<HttpRequestInfo>() != null);
- Contract.Ensures(Contract.Result<HttpRequestInfo>().Url != null);
- Contract.Ensures(Contract.Result<HttpRequestInfo>().RawUrl != null);
- Contract.Ensures(Contract.Result<HttpRequestInfo>().UrlBeforeRewriting != null);
+ Contract.Ensures(Contract.Result<HttpRequestBase>() != null);
Contract.Assume(HttpContext.Current.Request.Url != null);
Contract.Assume(HttpContext.Current.Request.RawUrl != null);
- return new HttpRequestInfo(HttpContext.Current.Request);
+ return new HttpRequestWrapper(HttpContext.Current.Request);
}
/// <summary>
@@ -638,6 +645,22 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Applies message prescribed HTTP response headers to an outgoing web response.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ /// <param name="response">The HTTP response.</param>
+ protected static void ApplyMessageTemplate(IMessage message, OutgoingWebResponse response) {
+ Requires.NotNull(message, "message");
+ var httpMessage = message as IHttpDirectResponse;
+ if (httpMessage != null) {
+ response.Status = httpMessage.HttpStatusCode;
+ foreach (string headerName in httpMessage.Headers) {
+ response.Headers.Add(headerName, httpMessage.Headers[headerName]);
+ }
+ }
+ }
+
+ /// <summary>
/// Releases unmanaged and - optionally - managed resources
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
@@ -731,16 +754,16 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
/// <param name="request">The request to search for an embedded message.</param>
/// <returns>The deserialized message, if one is found. Null otherwise.</returns>
- protected virtual IDirectedProtocolMessage ReadFromRequestCore(HttpRequestInfo request) {
+ protected virtual IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request) {
Requires.NotNull(request, "request");
- Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.UrlBeforeRewriting.AbsoluteUri);
+ Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.GetPublicFacingUrl().AbsoluteUri);
// Search Form data first, and if nothing is there search the QueryString
- Contract.Assume(request.Form != null && request.QueryStringBeforeRewriting != null);
+ Contract.Assume(request.Form != null && request.GetQueryStringBeforeRewriting() != null);
var fields = request.Form.ToDictionary();
if (fields.Count == 0 && request.HttpMethod != "POST") { // OpenID 2.0 section 4.1.2
- fields = request.QueryStringBeforeRewriting.ToDictionary();
+ fields = request.GetQueryStringBeforeRewriting().ToDictionary();
}
MessageReceivingEndpoint recipient;
@@ -1038,22 +1061,6 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
- /// Applies message prescribed HTTP response headers to an outgoing web response.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="response">The HTTP response.</param>
- protected void ApplyMessageTemplate(IMessage message, OutgoingWebResponse response) {
- Requires.NotNull(message, "message");
- var httpMessage = message as IHttpDirectResponse;
- if (httpMessage != null) {
- response.Status = httpMessage.HttpStatusCode;
- foreach (string headerName in httpMessage.Headers) {
- response.Headers.Add(headerName, httpMessage.Headers[headerName]);
- }
- }
- }
-
- /// <summary>
/// Prepares to send a request to the Service Provider as the query string in a GET request.
/// </summary>
/// <param name="requestMessage">The message to be transmitted to the ServiceProvider.</param>
diff --git a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs
index 43df1f5..9d4b93e 100644
--- a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs
@@ -110,7 +110,7 @@ namespace DotNetOpenAuth.Messaging {
/// <param name="decodeOnceOnly">The nonce store to use to ensure that this instance is only decoded once.</param>
protected DataBagFormatterBase(ICryptoKeyStore cryptoKeyStore = null, string bucket = null, bool signed = false, bool encrypted = false, bool compressed = false, TimeSpan? minimumAge = null, TimeSpan? maximumAge = null, INonceStore decodeOnceOnly = null)
: this(signed, encrypted, compressed, maximumAge, decodeOnceOnly) {
- Requires.True(!String.IsNullOrEmpty(bucket) || cryptoKeyStore == null, null);
+ Requires.True(!string.IsNullOrEmpty(bucket) || cryptoKeyStore == null, null);
Requires.True(cryptoKeyStore != null || (!signed && !encrypted), null);
this.cryptoKeyStore = cryptoKeyStore;
@@ -190,15 +190,22 @@ namespace DotNetOpenAuth.Messaging {
/// <summary>
/// Deserializes a <see cref="DataBag"/>, including decompression, decryption, signature and nonce validation where applicable.
/// </summary>
- /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be nulll.</param>
+ /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be null.</param>
/// <param name="value">The serialized form of the <see cref="DataBag"/> to deserialize. Must not be null or empty.</param>
- /// <returns>The deserialized value. Never null.</returns>
+ /// <param name="messagePartName">The name of the parameter whose value is to be deserialized. Used for error message generation.</param>
+ /// <returns>
+ /// The deserialized value. Never null.
+ /// </returns>
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "No apparent problem. False positive?")]
- public T Deserialize(IProtocolMessage containingMessage, string value) {
+ public T Deserialize(IProtocolMessage containingMessage, string value, string messagePartName) {
+ Requires.NotNull(containingMessage, "containingMessage");
+ Requires.NotNullOrEmpty(value, "value");
+ Requires.NotNullOrEmpty(messagePartName, "messagePartName");
+
string symmetricSecretHandle = null;
if (this.encrypted && this.cryptoKeyStore != null) {
string valueWithoutHandle;
- MessagingUtilities.ExtractKeyHandleAndPayload(containingMessage, "<TODO>", value, out symmetricSecretHandle, out valueWithoutHandle);
+ MessagingUtilities.ExtractKeyHandleAndPayload(containingMessage, messagePartName, value, out symmetricSecretHandle, out valueWithoutHandle);
value = valueWithoutHandle;
}
diff --git a/src/DotNetOpenAuth.Core/Messaging/EmptyDictionary.cs b/src/DotNetOpenAuth.Core/Messaging/EmptyDictionary.cs
index a686d45..f21be78 100644
--- a/src/DotNetOpenAuth.Core/Messaging/EmptyDictionary.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/EmptyDictionary.cs
@@ -75,6 +75,7 @@ namespace DotNetOpenAuth.Messaging {
/// Gets or sets the value with the specified key.
/// </summary>
/// <param name="key">The key being read or written.</param>
+ /// <returns>Nothing. It always throws.</returns>
public TValue this[TKey key] {
get { throw new KeyNotFoundException(); }
set { throw new NotSupportedException(); }
diff --git a/src/DotNetOpenAuth.Core/Messaging/EmptyList.cs b/src/DotNetOpenAuth.Core/Messaging/EmptyList.cs
index 6790e19..5d64118 100644
--- a/src/DotNetOpenAuth.Core/Messaging/EmptyList.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/EmptyList.cs
@@ -53,6 +53,7 @@ namespace DotNetOpenAuth.Messaging {
/// Gets or sets the <typeparamref name="T"/> at the specified index.
/// </summary>
/// <param name="index">The index of the element in the list to change.</param>
+ /// <returns>Nothing. It always throws.</returns>
public T this[int index] {
get {
throw new ArgumentOutOfRangeException("index");
diff --git a/src/DotNetOpenAuth.Core/Messaging/EnumerableCache.cs b/src/DotNetOpenAuth.Core/Messaging/EnumerableCacheExtensions.cs
index afbdf30..5e9cf93 100644
--- a/src/DotNetOpenAuth.Core/Messaging/EnumerableCache.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/EnumerableCacheExtensions.cs
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------
-// <copyright file="EnumerableCache.cs" company="Outercurve Foundation">
+// <copyright file="EnumerableCacheExtensions.cs" company="Outercurve Foundation">
// Copyright (c) Outercurve Foundation. All rights reserved.
// This code is released under the Microsoft Public License (Ms-PL).
// </copyright>
diff --git a/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs b/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs
new file mode 100644
index 0000000..9579a81
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Messaging/HttpRequestHeaders.cs
@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------
+// <copyright file="HttpRequestHeaders.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Messaging {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Well known HTTP headers.
+ /// </summary>
+ internal static class HttpRequestHeaders {
+ /// <summary>
+ /// The Authorization header, which specifies the credentials that the client presents in order to authenticate itself to the server.
+ /// </summary>
+ internal const string Authorization = "Authorization";
+
+ /// <summary>
+ /// The Content-Type header, which specifies the MIME type of the accompanying body data.
+ /// </summary>
+ internal const string ContentType = "Content-Type";
+ }
+}
diff --git a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
index 49ecb36..ed948ce 100644
--- a/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/HttpRequestInfo.cs
@@ -25,101 +25,51 @@ namespace DotNetOpenAuth.Messaging {
/// ASP.NET does not let us fully initialize that class, so we have to write one
/// of our one.
/// </remarks>
- public class HttpRequestInfo {
+ public class HttpRequestInfo : HttpRequestBase {
/// <summary>
- /// The key/value pairs found in the entity of a POST request.
+ /// The HTTP verb in the request.
/// </summary>
- private NameValueCollection form;
+ private readonly string httpMethod;
/// <summary>
- /// The key/value pairs found in the querystring of the incoming request.
+ /// The full request URL.
/// </summary>
- private NameValueCollection queryString;
+ private readonly Uri requestUri;
/// <summary>
- /// Backing field for the <see cref="QueryStringBeforeRewriting"/> property.
+ /// The HTTP headers.
/// </summary>
- private NameValueCollection queryStringBeforeRewriting;
+ private readonly NameValueCollection headers;
/// <summary>
- /// Backing field for the <see cref="Message"/> property.
+ /// The variables defined in the query part of the URL.
/// </summary>
- private IDirectedProtocolMessage message;
+ private readonly NameValueCollection queryString;
/// <summary>
- /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
+ /// The POSTed form variables.
/// </summary>
- /// <param name="request">The ASP.NET structure to copy from.</param>
- public HttpRequestInfo(HttpRequest request) {
- Requires.NotNull(request, "request");
- Contract.Ensures(this.HttpMethod == request.HttpMethod);
- Contract.Ensures(this.Url == request.Url);
- Contract.Ensures(this.RawUrl == request.RawUrl);
- Contract.Ensures(this.UrlBeforeRewriting != null);
- Contract.Ensures(this.Headers != null);
- Contract.Ensures(this.InputStream == request.InputStream);
- Contract.Ensures(this.form == request.Form);
- Contract.Ensures(this.queryString == request.QueryString);
-
- 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;
-
- // These values would normally be calculated, but we'll reuse them from
- // HttpRequest since they're already calculated, and there's a chance (<g>)
- // that ASP.NET does a better job of being comprehensive about gathering
- // these as well.
- this.form = request.Form;
- this.queryString = request.QueryString;
-
- Reporting.RecordRequestStatistics(this);
- }
+ private readonly NameValueCollection form;
/// <summary>
- /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
+ /// The server variables collection.
/// </summary>
- /// <param name="httpMethod">The HTTP method (i.e. GET or POST) of the incoming request.</param>
- /// <param name="requestUrl">The URL being requested.</param>
- /// <param name="rawUrl">The raw URL that appears immediately following the HTTP verb in the request,
- /// before any URL rewriting takes place.</param>
- /// <param name="headers">Headers in the HTTP request.</param>
- /// <param name="inputStream">The entity stream, if any. (POST requests typically have these). Use <c>null</c> for GET requests.</param>
- public HttpRequestInfo(string httpMethod, Uri requestUrl, string rawUrl, WebHeaderCollection headers, Stream inputStream) {
- Requires.NotNullOrEmpty(httpMethod, "httpMethod");
- Requires.NotNull(requestUrl, "requestUrl");
- Requires.NotNull(rawUrl, "rawUrl");
- Requires.NotNull(headers, "headers");
-
- this.HttpMethod = httpMethod;
- this.Url = requestUrl;
- this.UrlBeforeRewriting = requestUrl;
- this.RawUrl = rawUrl;
- this.Headers = headers;
- this.InputStream = inputStream;
-
- Reporting.RecordRequestStatistics(this);
- }
+ private readonly NameValueCollection serverVariables;
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
/// </summary>
- /// <param name="listenerRequest">Details on the incoming HTTP request.</param>
- public HttpRequestInfo(HttpListenerRequest listenerRequest) {
- Requires.NotNull(listenerRequest, "listenerRequest");
-
- 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) {
- this.Headers[key] = listenerRequest.Headers[key];
- }
+ /// <param name="request">The request.</param>
+ /// <param name="requestUri">The request URI.</param>
+ internal HttpRequestInfo(HttpRequestMessageProperty request, Uri requestUri) {
+ Requires.NotNull(request, "request");
+ Requires.NotNull(requestUri, "requestUri");
- this.InputStream = listenerRequest.InputStream;
+ this.httpMethod = request.Method;
+ this.headers = request.Headers;
+ this.requestUri = requestUri;
+ this.form = new NameValueCollection();
+ this.serverVariables = new NameValueCollection();
Reporting.RecordRequestStatistics(this);
}
@@ -127,297 +77,179 @@ namespace DotNetOpenAuth.Messaging {
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
/// </summary>
- /// <param name="request">The WCF incoming request structure to get the HTTP information from.</param>
- /// <param name="requestUri">The URI of the service endpoint.</param>
- public HttpRequestInfo(HttpRequestMessageProperty request, Uri requestUri) {
- Requires.NotNull(request, "request");
+ /// <param name="httpMethod">The HTTP method.</param>
+ /// <param name="requestUri">The request URI.</param>
+ /// <param name="form">The form variables.</param>
+ /// <param name="headers">The HTTP headers.</param>
+ internal HttpRequestInfo(string httpMethod, Uri requestUri, NameValueCollection form = null, NameValueCollection headers = null) {
+ Requires.NotNullOrEmpty(httpMethod, "httpMethod");
Requires.NotNull(requestUri, "requestUri");
- this.HttpMethod = request.Method;
- this.Headers = request.Headers;
- this.Url = requestUri;
- this.UrlBeforeRewriting = requestUri;
- this.RawUrl = MakeUpRawUrlFromUrl(requestUri);
-
- Reporting.RecordRequestStatistics(this);
+ this.httpMethod = httpMethod;
+ this.requestUri = requestUri;
+ this.form = form ?? new NameValueCollection();
+ this.queryString = HttpUtility.ParseQueryString(requestUri.Query);
+ this.headers = headers ?? new NameValueCollection();
+ this.serverVariables = new NameValueCollection();
}
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
/// </summary>
- internal HttpRequestInfo() {
- Contract.Ensures(this.HttpMethod == "GET");
- Contract.Ensures(this.Headers != null);
+ /// <param name="listenerRequest">Details on the incoming HTTP request.</param>
+ internal HttpRequestInfo(HttpListenerRequest listenerRequest) {
+ Requires.NotNull(listenerRequest, "listenerRequest");
- this.HttpMethod = "GET";
- this.Headers = new WebHeaderCollection();
+ this.httpMethod = listenerRequest.HttpMethod;
+ this.requestUri = listenerRequest.Url;
+ this.queryString = listenerRequest.QueryString;
+ this.headers = listenerRequest.Headers;
+ this.form = ParseFormData(listenerRequest.HttpMethod, listenerRequest.Headers, listenerRequest.InputStream);
+ this.serverVariables = new NameValueCollection();
+
+ Reporting.RecordRequestStatistics(this);
}
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
/// </summary>
- /// <param name="request">The HttpWebRequest (that was never used) to copy from.</param>
- internal HttpRequestInfo(WebRequest request) {
- Requires.NotNull(request, "request");
+ /// <param name="httpMethod">The HTTP method.</param>
+ /// <param name="requestUri">The request URI.</param>
+ /// <param name="headers">The headers.</param>
+ /// <param name="inputStream">The input stream.</param>
+ internal HttpRequestInfo(string httpMethod, Uri requestUri, NameValueCollection headers, Stream inputStream) {
+ Requires.NotNullOrEmpty(httpMethod, "httpMethod");
+ Requires.NotNull(requestUri, "requestUri");
- 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;
+ this.httpMethod = httpMethod;
+ this.requestUri = requestUri;
+ this.headers = headers;
+ this.queryString = HttpUtility.ParseQueryString(requestUri.Query);
+ this.form = ParseFormData(httpMethod, headers, inputStream);
+ this.serverVariables = new NameValueCollection();
Reporting.RecordRequestStatistics(this);
}
/// <summary>
- /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
+ /// Gets the HTTP method.
/// </summary>
- /// <param name="message">The message being passed in through a mock transport. May be null.</param>
- /// <param name="httpMethod">The HTTP method that the incoming request came in on, whether or not <paramref name="message"/> is null.</param>
- internal HttpRequestInfo(IDirectedProtocolMessage message, HttpDeliveryMethods httpMethod) {
- this.message = message;
- this.HttpMethod = MessagingUtilities.GetHttpVerb(httpMethod);
+ public override string HttpMethod {
+ get { return this.httpMethod; }
}
/// <summary>
- /// Gets or sets the message that is being sent over a mock transport (for testing).
+ /// Gets the headers.
/// </summary>
- internal virtual IDirectedProtocolMessage Message {
- get { return this.message; }
- set { this.message = value; }
+ public override NameValueCollection Headers {
+ get { return this.headers; }
}
/// <summary>
- /// Gets or sets the verb in the request (i.e. GET, POST, etc.)
- /// </summary>
- internal string HttpMethod { get; set; }
-
- /// <summary>
- /// Gets or sets the entire URL of the request, after any URL rewriting.
- /// </summary>
- internal Uri Url { get; set; }
-
- /// <summary>
- /// Gets or sets the raw URL that appears immediately following the HTTP verb in the request,
- /// before any URL rewriting takes place.
+ /// Gets the URL.
/// </summary>
- internal string RawUrl { get; set; }
-
- /// <summary>
- /// 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; set; }
-
- /// <summary>
- /// 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; }
+ public override Uri Url {
+ get { return this.requestUri; }
}
/// <summary>
- /// Gets or sets the collection of headers that came in with the request.
- /// </summary>
- internal WebHeaderCollection Headers { get; set; }
-
- /// <summary>
- /// Gets or sets the entity, or body of the request, if any.
+ /// Gets the raw URL.
/// </summary>
- internal Stream InputStream { get; set; }
-
- /// <summary>
- /// Gets the key/value pairs found in the entity of a POST request.
- /// </summary>
- internal NameValueCollection Form {
- get {
- Contract.Ensures(Contract.Result<NameValueCollection>() != null);
- if (this.form == null) {
- ContentType contentType = string.IsNullOrEmpty(this.Headers[HttpRequestHeader.ContentType]) ? null : new ContentType(this.Headers[HttpRequestHeader.ContentType]);
- if (this.HttpMethod == "POST" && contentType != null && string.Equals(contentType.MediaType, Channel.HttpFormUrlEncoded, StringComparison.Ordinal)) {
- StreamReader reader = new StreamReader(this.InputStream);
- long originalPosition = 0;
- if (this.InputStream.CanSeek) {
- originalPosition = this.InputStream.Position;
- }
- this.form = HttpUtility.ParseQueryString(reader.ReadToEnd());
- if (this.InputStream.CanSeek) {
- this.InputStream.Seek(originalPosition, SeekOrigin.Begin);
- }
- } else {
- this.form = new NameValueCollection();
- }
- }
-
- return this.form;
- }
+ public override string RawUrl {
+ get { return this.requestUri.AbsolutePath + this.requestUri.Query; }
}
/// <summary>
- /// Gets the key/value pairs found in the querystring of the incoming request.
+ /// Gets the form.
/// </summary>
- internal NameValueCollection QueryString {
- get {
- if (this.queryString == null) {
- this.queryString = this.Query != null ? HttpUtility.ParseQueryString(this.Query) : new NameValueCollection();
- }
-
- return this.queryString;
- }
+ public override NameValueCollection Form {
+ get { return this.form; }
}
/// <summary>
- /// Gets the query data from the original request (before any URL rewriting has occurred.)
+ /// Gets the query string.
/// </summary>
- /// <returns>A <see cref="NameValueCollection"/> containing all the parameters in the query string.</returns>
- internal NameValueCollection QueryStringBeforeRewriting {
- get {
- if (this.queryStringBeforeRewriting == null) {
- // 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.
- if (!this.IsUrlRewritten) {
- // No rewriting has taken place.
- this.queryStringBeforeRewriting = this.QueryString;
- } else {
- // Rewriting detected! Recover the original request URI.
- ErrorUtilities.VerifyInternal(this.UrlBeforeRewriting != null, "UrlBeforeRewriting is null, so the query string cannot be determined.");
- this.queryStringBeforeRewriting = HttpUtility.ParseQueryString(this.UrlBeforeRewriting.Query);
- }
- }
-
- return this.queryStringBeforeRewriting;
- }
+ public override NameValueCollection QueryString {
+ get { return this.queryString; }
}
/// <summary>
- /// Gets a value indicating whether the request's URL was rewritten by ASP.NET
- /// or some other module.
+ /// Gets the server variables.
/// </summary>
- /// <value>
- /// <c>true</c> if this request's URL was rewritten; otherwise, <c>false</c>.
- /// </value>
- internal bool IsUrlRewritten {
- get { return this.Url != this.UrlBeforeRewriting; }
+ public override NameValueCollection ServerVariables {
+ get { return this.serverVariables; }
}
/// <summary>
- /// Gets the public facing URL for the given incoming HTTP request.
+ /// Creates an <see cref="HttpRequestBase"/> instance that describes the specified 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) {
- 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);
- }
+ /// <param name="requestUri">The request URI.</param>
+ /// <returns>An instance of <see cref="HttpRequestBase"/>.</returns>
+ public static HttpRequestBase Create(HttpRequestMessageProperty request, Uri requestUri) {
+ return new HttpRequestInfo(request, requestUri);
}
/// <summary>
- /// Gets the query or form data from the original request (before any URL rewriting has occurred.)
+ /// Creates an <see cref="HttpRequestBase"/> instance that describes the specified HTTP request.
/// </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;
+ /// <param name="listenerRequest">The listener request.</param>
+ /// <returns>An instance of <see cref="HttpRequestBase"/>.</returns>
+ public static HttpRequestBase Create(HttpListenerRequest listenerRequest) {
+ return new HttpRequestInfo(listenerRequest);
}
/// <summary>
- /// Gets the public facing URL for the given incoming HTTP request.
+ /// Creates an <see cref="HttpRequestBase"/> instance that describes the specified 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) {
- Requires.NotNull(request, "request");
- return GetPublicFacingUrl(request, request.ServerVariables);
+ /// <param name="httpMethod">The HTTP method.</param>
+ /// <param name="requestUri">The request URI.</param>
+ /// <param name="form">The form variables.</param>
+ /// <param name="headers">The HTTP headers.</param>
+ /// <returns>An instance of <see cref="HttpRequestBase"/>.</returns>
+ public static HttpRequestBase Create(string httpMethod, Uri requestUri, NameValueCollection form = null, NameValueCollection headers = null) {
+ return new HttpRequestInfo(httpMethod, requestUri, form, headers);
}
/// <summary>
- /// Makes up a reasonable guess at the raw URL from the possibly rewritten URL.
+ /// Creates an <see cref="HttpRequestBase"/> instance that describes the specified HTTP request.
/// </summary>
- /// <param name="url">A full URL.</param>
- /// <returns>A raw URL that might have come in on the HTTP verb.</returns>
- private static string MakeUpRawUrlFromUrl(Uri url) {
- Requires.NotNull(url, "url");
- return url.AbsolutePath + url.Query + url.Fragment;
+ /// <param name="httpMethod">The HTTP method.</param>
+ /// <param name="requestUri">The request URI.</param>
+ /// <param name="headers">The headers.</param>
+ /// <param name="inputStream">The input stream.</param>
+ /// <returns>An instance of <see cref="HttpRequestBase"/>.</returns>
+ public static HttpRequestBase Create(string httpMethod, Uri requestUri, NameValueCollection headers, Stream inputStream) {
+ return new HttpRequestInfo(httpMethod, requestUri, headers, inputStream);
}
/// <summary>
- /// Converts a NameValueCollection to a WebHeaderCollection.
+ /// Reads name=value pairs from the POSTed form entity when the HTTP headers indicate that that is the payload of the entity.
/// </summary>
- /// <param name="pairs">The collection a HTTP headers.</param>
- /// <returns>A new collection of the given headers.</returns>
- private static WebHeaderCollection GetHeaderCollection(NameValueCollection pairs) {
- Requires.NotNull(pairs, "pairs");
-
- WebHeaderCollection headers = new WebHeaderCollection();
- foreach (string key in pairs) {
- try {
- headers.Add(key, pairs[key]);
- } catch (ArgumentException ex) {
- Logger.Messaging.WarnFormat(
- "{0} thrown when trying to add web header \"{1}: {2}\". {3}",
- ex.GetType().Name,
- key,
- pairs[key],
- ex.Message);
+ /// <param name="httpMethod">The HTTP method.</param>
+ /// <param name="headers">The headers.</param>
+ /// <param name="inputStream">The input stream.</param>
+ /// <returns>The non-null collection of form variables.</returns>
+ private static NameValueCollection ParseFormData(string httpMethod, NameValueCollection headers, Stream inputStream) {
+ Requires.NotNullOrEmpty(httpMethod, "httpMethod");
+ Requires.NotNull(headers, "headers");
+
+ ContentType contentType = string.IsNullOrEmpty(headers[HttpRequestHeaders.ContentType]) ? null : new ContentType(headers[HttpRequestHeaders.ContentType]);
+ if (inputStream != null && httpMethod == "POST" && contentType != null && string.Equals(contentType.MediaType, Channel.HttpFormUrlEncoded, StringComparison.Ordinal)) {
+ var reader = new StreamReader(inputStream);
+ long originalPosition = 0;
+ if (inputStream.CanSeek) {
+ originalPosition = inputStream.Position;
+ }
+ string postEntity = reader.ReadToEnd();
+ if (inputStream.CanSeek) {
+ inputStream.Seek(originalPosition, SeekOrigin.Begin);
}
- }
- return headers;
- }
+ return HttpUtility.ParseQueryString(postEntity);
+ }
-#if CONTRACTS_FULL
- /// <summary>
- /// Verifies conditions that should be true for any valid state of this object.
- /// </summary>
- [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Called by code contracts.")]
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
- [ContractInvariantMethod]
- private void ObjectInvariant() {
+ return new NameValueCollection();
}
-#endif
}
}
diff --git a/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs b/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs
index f911264..9086ee9 100644
--- a/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/IDataBagFormatter.cs
@@ -24,10 +24,13 @@ namespace DotNetOpenAuth.Messaging {
/// <summary>
/// Deserializes a <see cref="DataBag"/>.
/// </summary>
- /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be nulll.</param>
+ /// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be null.</param>
/// <param name="data">The serialized form of the <see cref="DataBag"/> to deserialize. Must not be null or empty.</param>
- /// <returns>The deserialized value. Never null.</returns>
- T Deserialize(IProtocolMessage containingMessage, string data);
+ /// <param name="messagePartName">The name of the parameter whose value is to be deserialized. Used for error message generation.</param>
+ /// <returns>
+ /// The deserialized value. Never null.
+ /// </returns>
+ T Deserialize(IProtocolMessage containingMessage, string data, string messagePartName);
}
/// <summary>
@@ -51,7 +54,7 @@ namespace DotNetOpenAuth.Messaging {
/// <returns>A non-null, non-empty value.</returns>
string IDataBagFormatter<T>.Serialize(T message) {
Requires.NotNull(message, "message");
- Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>()));
+ Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));
throw new System.NotImplementedException();
}
@@ -61,10 +64,14 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
/// <param name="containingMessage">The message that contains the <see cref="DataBag"/> serialized value. Must not be nulll.</param>
/// <param name="data">The serialized form of the <see cref="DataBag"/> to deserialize. Must not be null or empty.</param>
- /// <returns>The deserialized value. Never null.</returns>
- T IDataBagFormatter<T>.Deserialize(IProtocolMessage containingMessage, string data) {
+ /// <param name="messagePartName">Name of the message part whose value is to be deserialized. Used for exception messages.</param>
+ /// <returns>
+ /// The deserialized value. Never null.
+ /// </returns>
+ T IDataBagFormatter<T>.Deserialize(IProtocolMessage containingMessage, string data, string messagePartName) {
Requires.NotNull(containingMessage, "containingMessage");
Requires.NotNullOrEmpty(data, "data");
+ Requires.NotNullOrEmpty(messagePartName, "messagePartName");
Contract.Ensures(Contract.Result<T>() != null);
throw new System.NotImplementedException();
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
index 1305620..b26deeb 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>
@@ -448,7 +446,7 @@ namespace DotNetOpenAuth.Messaging {
internal static string CombineKeyHandleAndPayload(string handle, string payload) {
Requires.NotNullOrEmpty(handle, "handle");
Requires.NotNullOrEmpty(payload, "payload");
- Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>()));
+ Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));
return handle + "!" + payload;
}
@@ -1248,7 +1246,7 @@ namespace DotNetOpenAuth.Messaging {
Requires.NotNull(args, "args");
Contract.Ensures(Contract.Result<string>() != null);
- if (args.Count() == 0) {
+ if (!args.Any()) {
return string.Empty;
}
StringBuilder sb = new StringBuilder(args.Count() * 10);
@@ -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>
diff --git a/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs b/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs
index 9569e34..a5fe782 100644
--- a/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponseActionResult.cs
@@ -34,7 +34,7 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
/// <param name="context">The context in which to set the response.</param>
public override void ExecuteResult(ControllerContext context) {
- this.response.Respond();
+ this.response.Respond(context.HttpContext);
}
}
}
diff --git a/src/DotNetOpenAuth.Core/Messaging/ReadOnlyDictionary.cs b/src/DotNetOpenAuth.Core/Messaging/ReadOnlyDictionary.cs
new file mode 100644
index 0000000..0ba1ff5
--- /dev/null
+++ b/src/DotNetOpenAuth.Core/Messaging/ReadOnlyDictionary.cs
@@ -0,0 +1,224 @@
+//-----------------------------------------------------------------------
+// <copyright file="ReadOnlyDictionary.cs" company="Microsoft Corporation">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Messaging {
+ using System;
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Represents a read-only dictionary.
+ /// </summary>
+ /// <typeparam name="K">The type of the key.</typeparam>
+ /// <typeparam name="V">The type of the value.</typeparam>
+ internal class ReadOnlyDictionary<K, V> : IDictionary<K, V> {
+ /// <summary>
+ /// Contains base dictionary.
+ /// </summary>
+ private readonly IDictionary<K, V> baseDictionary;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ReadOnlyDictionary&lt;K, V&gt;"/> class.
+ /// </summary>
+ /// <param name="baseDictionary">The base dictionary.</param>
+ public ReadOnlyDictionary(IDictionary<K, V> baseDictionary) {
+ this.baseDictionary = baseDictionary;
+ }
+
+ /// <summary>
+ /// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </summary>
+ /// <returns>
+ /// An <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </returns>
+ public ICollection<K> Keys {
+ get { return this.baseDictionary.Keys; }
+ }
+
+ /// <summary>
+ /// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </summary>
+ /// <returns>
+ /// An <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </returns>
+ public ICollection<V> Values {
+ get { return this.baseDictionary.Values; }
+ }
+
+ /// <summary>
+ /// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
+ /// </summary>
+ /// <returns>
+ /// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
+ /// </returns>
+ public int Count {
+ get { return this.baseDictionary.Count; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
+ /// </summary>
+ /// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
+ /// </returns>
+ public bool IsReadOnly {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Gets or sets the element with the specified key.
+ /// </summary>
+ /// <param name="key">The key being read or written.</param>
+ /// <returns>
+ /// The element with the specified key.
+ /// </returns>
+ /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.
+ /// </exception>
+ /// <exception cref="T:System.Collections.Generic.KeyNotFoundException">
+ /// The property is retrieved and <paramref name="key"/> is not found.
+ /// </exception>
+ /// <exception cref="T:System.NotSupportedException">
+ /// The property is set and the <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.
+ /// </exception>
+ public V this[K key] {
+ get { return this.baseDictionary[key]; }
+ set { throw new NotSupportedException(); }
+ }
+
+ /// <summary>
+ /// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </summary>
+ /// <param name="key">The object to use as the key of the element to add.</param>
+ /// <param name="value">The object to use as the value of the element to add.</param>
+ /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.
+ /// </exception>
+ /// <exception cref="T:System.ArgumentException">
+ /// An element with the same key already exists in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </exception>
+ /// <exception cref="T:System.NotSupportedException">
+ /// The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.
+ /// </exception>
+ public void Add(K key, V value) {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key.
+ /// </summary>
+ /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</param>
+ /// <returns>
+ /// true if the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the key; otherwise, false.
+ /// </returns>
+ /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.
+ /// </exception>
+ public bool ContainsKey(K key) {
+ return this.baseDictionary.ContainsKey(key);
+ }
+
+ /// <summary>
+ /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </summary>
+ /// <param name="key">The key of the element to remove.</param>
+ /// <returns>
+ /// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2"/>.
+ /// </returns>
+ /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.
+ /// </exception>
+ /// <exception cref="T:System.NotSupportedException">
+ /// The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.
+ /// </exception>
+ public bool Remove(K key) {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Gets the value associated with the specified key.
+ /// </summary>
+ /// <param name="key">The key whose value to get.</param>
+ /// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param>
+ /// <returns>
+ /// true if the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key; otherwise, false.
+ /// </returns>
+ /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.
+ /// </exception>
+ public bool TryGetValue(K key, out V value) {
+ return this.baseDictionary.TryGetValue(key, out value);
+ }
+
+ /// <summary>
+ /// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
+ /// </summary>
+ /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
+ /// <exception cref="T:System.NotSupportedException">
+ /// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
+ /// </exception>
+ public void Add(KeyValuePair<K, V> item) {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
+ /// </summary>
+ /// <exception cref="T:System.NotSupportedException">
+ /// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
+ /// </exception>
+ public void Clear() {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
+ /// </summary>
+ /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
+ /// <returns>
+ /// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
+ /// </returns>
+ public bool Contains(KeyValuePair<K, V> item) {
+ return this.baseDictionary.Contains(item);
+ }
+
+ /// <summary>
+ /// Copies to.
+ /// </summary>
+ /// <param name="array">The array.</param>
+ /// <param name="arrayIndex">Index of the array.</param>
+ public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) {
+ this.baseDictionary.CopyTo(array, arrayIndex);
+ }
+
+ /// <summary>
+ /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
+ /// </summary>
+ /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
+ /// <returns>
+ /// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
+ /// </returns>
+ /// <exception cref="T:System.NotSupportedException">
+ /// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
+ /// </exception>
+ public bool Remove(KeyValuePair<K, V> item) {
+ throw new NotSupportedException();
+ }
+
+ /// <summary>
+ /// Returns an enumerator that iterates through the collection.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
+ /// </returns>
+ public IEnumerator<KeyValuePair<K, V>> GetEnumerator() {
+ return this.baseDictionary.GetEnumerator();
+ }
+
+ /// <summary>
+ /// Returns an enumerator that iterates through a collection.
+ /// </summary>
+ /// <returns>
+ /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
+ /// </returns>
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return this.baseDictionary.GetEnumerator();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.Core/Messaging/UntrustedWebRequestHandler.cs b/src/DotNetOpenAuth.Core/Messaging/UntrustedWebRequestHandler.cs
index c490127..25a7bbb 100644
--- a/src/DotNetOpenAuth.Core/Messaging/UntrustedWebRequestHandler.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/UntrustedWebRequestHandler.cs
@@ -383,7 +383,7 @@ namespace DotNetOpenAuth.Messaging {
/// <exception cref="ProtocolException">Thrown when the URI is disallowed for security reasons.</exception>
private void EnsureAllowableRequestUri(Uri requestUri, bool requireSsl) {
ErrorUtilities.VerifyProtocol(this.IsUriAllowable(requestUri), MessagingStrings.UnsafeWebRequestDetected, requestUri);
- ErrorUtilities.VerifyProtocol(!requireSsl || String.Equals(requestUri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase), MessagingStrings.InsecureWebRequestWithSslRequired, requestUri);
+ ErrorUtilities.VerifyProtocol(!requireSsl || string.Equals(requestUri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase), MessagingStrings.InsecureWebRequestWithSslRequired, requestUri);
}
/// <summary>
diff --git a/src/DotNetOpenAuth.Core/Messaging/UriStyleMessageFormatter.cs b/src/DotNetOpenAuth.Core/Messaging/UriStyleMessageFormatter.cs
index 84e75b0..92b1928 100644
--- a/src/DotNetOpenAuth.Core/Messaging/UriStyleMessageFormatter.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/UriStyleMessageFormatter.cs
@@ -46,7 +46,7 @@ namespace DotNetOpenAuth.Messaging {
/// <param name="decodeOnceOnly">The nonce store to use to ensure that this instance is only decoded once.</param>
protected internal UriStyleMessageFormatter(ICryptoKeyStore cryptoKeyStore = null, string bucket = null, bool signed = false, bool encrypted = false, bool compressed = false, TimeSpan? minimumAge = null, TimeSpan? maximumAge = null, INonceStore decodeOnceOnly = null)
: base(cryptoKeyStore, bucket, signed, encrypted, compressed, minimumAge, maximumAge, decodeOnceOnly) {
- Requires.True((cryptoKeyStore != null && !String.IsNullOrEmpty(bucket)) || (!signed && !encrypted), null);
+ Requires.True((cryptoKeyStore != null && !string.IsNullOrEmpty(bucket)) || (!signed && !encrypted), null);
}
/// <summary>
diff --git a/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs
index 950a7cd..e57b211 100644
--- a/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs
+++ b/src/DotNetOpenAuth.Core/Properties/AssemblyInfo.cs
@@ -67,6 +67,8 @@ using System.Web.UI;
[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.ResourceServer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.Client, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.Client.UI, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.AspNet.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.AspNet, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
#else
[assembly: InternalsVisibleTo("DotNetOpenAuth.Test")]
@@ -88,5 +90,7 @@ using System.Web.UI;
[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.AuthorizationServer")]
[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.ResourceServer")]
[assembly: InternalsVisibleTo("DotNetOpenAuth.OAuth2.Client")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.AspNet.Test")]
+[assembly: InternalsVisibleTo("DotNetOpenAuth.AspNet")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
#endif
diff --git a/src/DotNetOpenAuth.Core/Reporting.cs b/src/DotNetOpenAuth.Core/Reporting.cs
index a7940b6..951bb7c 100644
--- a/src/DotNetOpenAuth.Core/Reporting.cs
+++ b/src/DotNetOpenAuth.Core/Reporting.cs
@@ -170,7 +170,7 @@ namespace DotNetOpenAuth {
/// <param name="category">The category within the event. Null and empty strings are allowed, but considered the same.</param>
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "PersistentCounter instances are stored in a table for later use.")]
internal static void RecordEventOccurrence(string eventName, string category) {
- Contract.Requires(!String.IsNullOrEmpty(eventName));
+ Contract.Requires(!string.IsNullOrEmpty(eventName));
// In release builds, just quietly return.
if (string.IsNullOrEmpty(eventName)) {
@@ -213,7 +213,7 @@ namespace DotNetOpenAuth {
/// </summary>
/// <param name="feature">The feature.</param>
internal static void RecordFeatureUse(string feature) {
- Contract.Requires(!String.IsNullOrEmpty(feature));
+ Contract.Requires(!string.IsNullOrEmpty(feature));
// In release builds, just quietly return.
if (string.IsNullOrEmpty(feature)) {
@@ -297,7 +297,7 @@ namespace DotNetOpenAuth {
/// Records statistics collected from incoming requests.
/// </summary>
/// <param name="request">The request.</param>
- internal static void RecordRequestStatistics(HttpRequestInfo request) {
+ internal static void RecordRequestStatistics(HttpRequestBase request) {
Contract.Requires(request != null);
// In release builds, just quietly return.
@@ -311,7 +311,7 @@ namespace DotNetOpenAuth {
}
if (Configuration.IncludeLocalRequestUris && !observedRequests.IsFull) {
- var requestBuilder = new UriBuilder(request.UrlBeforeRewriting);
+ var requestBuilder = new UriBuilder(request.GetPublicFacingUrl());
requestBuilder.Query = null;
requestBuilder.Fragment = null;
observedRequests.Add(requestBuilder.Uri.AbsoluteUri);
diff --git a/src/DotNetOpenAuth.Core/Requires.cs b/src/DotNetOpenAuth.Core/Requires.cs
index 8aa15dd..7a196a3 100644
--- a/src/DotNetOpenAuth.Core/Requires.cs
+++ b/src/DotNetOpenAuth.Core/Requires.cs
@@ -24,16 +24,18 @@ namespace DotNetOpenAuth {
/// <typeparam name="T">The type of the parameter</typeparam>
/// <param name="value">The value.</param>
/// <param name="parameterName">Name of the parameter.</param>
+ /// <returns>The tested value, guaranteed to not be null.</returns>
#if !CLR4
[ContractArgumentValidator]
#endif
[Pure, DebuggerStepThrough]
- internal static void NotNull<T>(T value, string parameterName) where T : class {
+ internal static T NotNull<T>(T value, string parameterName) where T : class {
if (value == null) {
throw new ArgumentNullException(parameterName);
}
Contract.EndContractBlock();
+ return value;
}
/// <summary>
@@ -134,7 +136,7 @@ namespace DotNetOpenAuth {
[Pure, DebuggerStepThrough]
internal static void True(bool condition, string parameterName, string unformattedMessage, params object[] args) {
if (!condition) {
- throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, unformattedMessage, args), parameterName);
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, unformattedMessage, args), parameterName);
}
Contract.EndContractBlock();
@@ -185,7 +187,7 @@ namespace DotNetOpenAuth {
[Pure, DebuggerStepThrough]
internal static void ValidState(bool condition, string unformattedMessage, params object[] args) {
if (!condition) {
- throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, unformattedMessage, args));
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, unformattedMessage, args));
}
Contract.EndContractBlock();
diff --git a/src/DotNetOpenAuth.Core/Settings.StyleCop b/src/DotNetOpenAuth.Core/Settings.StyleCop
index 017d610..ac744c0 100644
--- a/src/DotNetOpenAuth.Core/Settings.StyleCop
+++ b/src/DotNetOpenAuth.Core/Settings.StyleCop
@@ -1,6 +1,6 @@
<StyleCopSettings Version="4.3">
<Analyzers>
- <Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.DocumentationRules">
+ <Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
<RuleSettings>
@@ -10,7 +10,7 @@
</Rules>
<AnalyzerSettings />
</Analyzer>
- <Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.MaintainabilityRules">
+ <Analyzer AnalyzerId="StyleCop.CSharp.MaintainabilityRules">
<Rules>
<Rule Name="StatementMustNotUseUnnecessaryParenthesis">
<RuleSettings>
@@ -20,7 +20,7 @@
</Rules>
<AnalyzerSettings />
</Analyzer>
- <Analyzer AnalyzerId="Microsoft.StyleCop.CSharp.ReadabilityRules">
+ <Analyzer AnalyzerId="StyleCop.CSharp.ReadabilityRules">
<Rules>
<Rule Name="UseStringEmptyForEmptyStrings">
<RuleSettings>