summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2011-06-20 08:58:21 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2011-06-23 19:53:17 -0700
commit2704b0fb445ab041f4f008bef8752e2828799b85 (patch)
tree3ec119671228d1175286aaec8d6339fb5740897e /src
parent5902a697d07bbd9066b8440f2d93590bff080c4f (diff)
downloadDotNetOpenAuth-2704b0fb445ab041f4f008bef8752e2828799b85.zip
DotNetOpenAuth-2704b0fb445ab041f4f008bef8752e2828799b85.tar.gz
DotNetOpenAuth-2704b0fb445ab041f4f008bef8752e2828799b85.tar.bz2
Added OutgoingWebResponse.Respond method to replace its Send method, and avoid the ThreadAbortException that is no longer the recommended approach.
Fixes #40
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/ResponseTests.cs8
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs6
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs16
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs8
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs8
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs4
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/NonIdentityTests.cs8
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Provider/OpenIdProviderTests.cs2
-rw-r--r--src/DotNetOpenAuth.TestWeb/OpenIdProviderEndpoint.ashx2
-rw-r--r--src/DotNetOpenAuth/Messaging/Channel.cs19
-rw-r--r--src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs90
-rw-r--r--src/DotNetOpenAuth/Messaging/OutgoingWebResponseActionResult.cs2
-rw-r--r--src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs4
-rw-r--r--src/DotNetOpenAuth/OAuth2/WebServerClient.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs24
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs5
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs4
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs2
19 files changed, 156 insertions, 60 deletions
diff --git a/src/DotNetOpenAuth.Test/Messaging/ResponseTests.cs b/src/DotNetOpenAuth.Test/Messaging/ResponseTests.cs
index 63be45a..037a68e 100644
--- a/src/DotNetOpenAuth.Test/Messaging/ResponseTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/ResponseTests.cs
@@ -14,13 +14,13 @@ namespace DotNetOpenAuth.Test.Messaging {
[TestFixture]
public class ResponseTests : TestBase {
[TestCase, ExpectedException(typeof(InvalidOperationException))]
- public void SendWithoutAspNetContext() {
+ public void RespondWithoutAspNetContext() {
HttpContext.Current = null;
- new OutgoingWebResponse().Send();
+ new OutgoingWebResponse().Respond();
}
[TestCase]
- public void Send() {
+ public void Respond() {
StringWriter writer = new StringWriter();
HttpRequest httpRequest = new HttpRequest("file", "http://server", string.Empty);
HttpResponse httpResponse = new HttpResponse(writer);
@@ -31,7 +31,7 @@ namespace DotNetOpenAuth.Test.Messaging {
response.Status = System.Net.HttpStatusCode.OK;
response.Headers["someHeaderName"] = "someHeaderValue";
response.Body = "some body";
- response.Send();
+ response.Respond();
string results = writer.ToString();
// For some reason the only output in test is the body... the headers require a web host
Assert.AreEqual(response.Body, results);
diff --git a/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs
index 62ea871..a744053 100644
--- a/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOutgoingWebResponse.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.Test.Mocks {
using System;
using System.Collections.Generic;
+ using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
@@ -28,7 +29,12 @@ namespace DotNetOpenAuth.Test.Mocks {
this.OriginalMessage = message;
}
+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Use the Respond method instead, and prepare for execution to continue on this page beyond the call to Respond.")]
public override void Send() {
+ this.Respond();
+ }
+
+ public override void Respond() {
this.receivingChannel.PostMessage(this.OriginalMessage);
}
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs
index 0c52b98..9c9e446 100644
--- a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs
@@ -87,7 +87,7 @@ namespace DotNetOpenAuth.Test.OpenId {
// Ensure that the response is a suggestion that the RP try again with HMAC-SHA1
AssociateUnsuccessfulResponse renegotiateResponse = (AssociateUnsuccessfulResponse)req.ResponseMessageTestHook;
Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA1, renegotiateResponse.AssociationType);
- op.SendResponse(req);
+ op.Respond(req);
// Receive second attempt request for an HMAC-SHA1 association.
req = (AutoResponsiveRequest)op.GetRequest();
@@ -97,7 +97,7 @@ namespace DotNetOpenAuth.Test.OpenId {
// Ensure that the response is a success response.
AssociateSuccessfulResponse successResponse = (AssociateSuccessfulResponse)req.ResponseMessageTestHook;
Assert.AreEqual(protocol.Args.SignatureAlgorithm.HMAC_SHA1, successResponse.AssociationType);
- op.SendResponse(req);
+ op.Respond(req);
});
coordinator.Run();
}
@@ -168,7 +168,7 @@ namespace DotNetOpenAuth.Test.OpenId {
AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
renegotiateResponse.AssociationType = "HMAC-UNKNOWN";
renegotiateResponse.SessionType = "DH-UNKNOWN";
- op.Channel.Send(renegotiateResponse);
+ op.Channel.Respond(renegotiateResponse);
});
coordinator.Run();
}
@@ -195,7 +195,7 @@ namespace DotNetOpenAuth.Test.OpenId {
AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
renegotiateResponse.SessionType = protocol.Args.SessionType.NoEncryption;
- op.Channel.Send(renegotiateResponse);
+ op.Channel.Respond(renegotiateResponse);
});
coordinator.Run();
}
@@ -220,7 +220,7 @@ namespace DotNetOpenAuth.Test.OpenId {
AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256;
- op.Channel.Send(renegotiateResponse);
+ op.Channel.Respond(renegotiateResponse);
});
coordinator.Run();
}
@@ -245,7 +245,7 @@ namespace DotNetOpenAuth.Test.OpenId {
AssociateUnsuccessfulResponse renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA1;
renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA1;
- op.Channel.Send(renegotiateResponse);
+ op.Channel.Respond(renegotiateResponse);
// Receive second-try
request = op.Channel.ReadFromRequest<AssociateRequest>();
@@ -254,7 +254,7 @@ namespace DotNetOpenAuth.Test.OpenId {
renegotiateResponse = new AssociateUnsuccessfulResponse(request.Version, request);
renegotiateResponse.AssociationType = protocol.Args.SignatureAlgorithm.HMAC_SHA256;
renegotiateResponse.SessionType = protocol.Args.SessionType.DH_SHA256;
- op.Channel.Send(renegotiateResponse);
+ op.Channel.Respond(renegotiateResponse);
});
coordinator.Run();
}
@@ -332,7 +332,7 @@ namespace DotNetOpenAuth.Test.OpenId {
IRequest req = op.GetRequest();
Assert.IsNotNull(req, "Expected incoming request but did not receive it.");
Assert.IsTrue(req.IsResponseReady);
- op.SendResponse(req);
+ op.Respond(req);
});
coordinator.IncomingMessageFilter = message => {
Assert.AreSame(opDescription.Version, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, Protocol.Lookup(opDescription.Version).ProtocolVersion);
diff --git a/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs b/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
index 2814506..99565ed 100644
--- a/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/AuthenticationTests.cs
@@ -155,7 +155,7 @@ namespace DotNetOpenAuth.Test.OpenId {
request.LocalIdentifier = "http://localid";
request.ReturnTo = RPUri;
request.Realm = RPUri;
- rp.Channel.Send(request);
+ rp.Channel.Respond(request);
if (positive) {
if (tamper) {
try {
@@ -211,20 +211,20 @@ namespace DotNetOpenAuth.Test.OpenId {
} else {
response = new NegativeAssertionResponse(request, op.Channel);
}
- op.Channel.Send(response);
+ op.Channel.Respond(response);
if (positive && (statelessRP || !sharedAssociation)) {
var checkauthRequest = op.Channel.ReadFromRequest<CheckAuthenticationRequest>();
var checkauthResponse = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
checkauthResponse.IsValid = checkauthRequest.IsValid;
- op.Channel.Send(checkauthResponse);
+ op.Channel.Respond(checkauthResponse);
if (!tamper) {
// Respond to the replay attack.
checkauthRequest = op.Channel.ReadFromRequest<CheckAuthenticationRequest>();
checkauthResponse = new CheckAuthenticationResponse(checkauthRequest.Version, checkauthRequest);
checkauthResponse.IsValid = checkauthRequest.IsValid;
- op.Channel.Send(checkauthResponse);
+ op.Channel.Respond(checkauthResponse);
}
}
});
diff --git a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs
index 5edd51f..5f1fc45 100644
--- a/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/ChannelElements/ExtensionsBindingElementTests.cs
@@ -128,11 +128,11 @@ namespace DotNetOpenAuth.Test.OpenId.ChannelElements {
},
op => {
RegisterMockExtension(op.Channel);
- op.Channel.Send(CreateResponseWithExtensions(protocol));
- op.SendResponse(op.GetRequest()); // check_auth
+ op.Channel.Respond(CreateResponseWithExtensions(protocol));
+ op.Respond(op.GetRequest()); // check_auth
op.SecuritySettings.SignOutgoingExtensions = false;
- op.Channel.Send(CreateResponseWithExtensions(protocol));
- op.SendResponse(op.GetRequest()); // check_auth
+ op.Channel.Respond(CreateResponseWithExtensions(protocol));
+ op.Respond(op.GetRequest()); // check_auth
});
coordinator.Run();
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs
index 9be806b..0f40bc3 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestUtilities.cs
@@ -52,7 +52,7 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
requestBase.Extensions.Add(extension);
}
- rp.Channel.Send(requestBase);
+ rp.Channel.Respond(requestBase);
var response = rp.Channel.ReadFromRequest<PositiveAssertionResponse>();
var receivedResponses = response.Extensions.Cast<IOpenIdMessageExtension>();
@@ -71,7 +71,7 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
response.Extensions.Add(extensionResponse);
}
- op.Channel.Send(response);
+ op.Channel.Respond(response);
});
coordinator.Run();
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/NonIdentityTests.cs b/src/DotNetOpenAuth.Test/OpenId/NonIdentityTests.cs
index 17ab090..6e3a289 100644
--- a/src/DotNetOpenAuth.Test/OpenId/NonIdentityTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/NonIdentityTests.cs
@@ -21,7 +21,7 @@ namespace DotNetOpenAuth.Test.OpenId {
var coordinator = new OpenIdCoordinator(
rp => {
var request = new SignedResponseRequest(protocol.Version, OPUri, mode);
- rp.Channel.Send(request);
+ rp.Channel.Respond(request);
},
op => {
var request = op.Channel.ReadFromRequest<SignedResponseRequest>();
@@ -38,18 +38,18 @@ namespace DotNetOpenAuth.Test.OpenId {
var request = rp.CreateRequest(GetMockIdentifier(protocol.ProtocolVersion), RPRealmUri, RPUri);
request.IsExtensionOnly = true;
- rp.Channel.Send(request.RedirectingResponse.OriginalMessage);
+ rp.Channel.Respond(request.RedirectingResponse.OriginalMessage);
IAuthenticationResponse response = rp.GetResponse();
Assert.AreEqual(AuthenticationStatus.ExtensionsOnly, response.Status);
},
op => {
var assocRequest = op.GetRequest();
- op.SendResponse(assocRequest);
+ op.Respond(assocRequest);
var request = (IAnonymousRequest)op.GetRequest();
request.IsApproved = true;
Assert.IsNotInstanceOf<CheckIdRequest>(request);
- op.SendResponse(request);
+ op.Respond(request);
});
coordinator.Run();
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs
index 414585f..4143a08 100644
--- a/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs
@@ -171,7 +171,7 @@ namespace DotNetOpenAuth.Test.OpenId {
}
}
- provider.SendResponse(request);
+ provider.Respond(request);
}
}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Provider/OpenIdProviderTests.cs b/src/DotNetOpenAuth.Test/OpenId/Provider/OpenIdProviderTests.cs
index 75d871c..c8c3831 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Provider/OpenIdProviderTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Provider/OpenIdProviderTests.cs
@@ -105,7 +105,7 @@ namespace DotNetOpenAuth.Test.OpenId.Provider {
op => {
IRequest request = op.GetRequest();
Assert.IsInstanceOf<AutoResponsiveRequest>(request);
- op.SendResponse(request);
+ op.Respond(request);
});
coordinator.Run();
}
diff --git a/src/DotNetOpenAuth.TestWeb/OpenIdProviderEndpoint.ashx b/src/DotNetOpenAuth.TestWeb/OpenIdProviderEndpoint.ashx
index b282a3b..ca23eac 100644
--- a/src/DotNetOpenAuth.TestWeb/OpenIdProviderEndpoint.ashx
+++ b/src/DotNetOpenAuth.TestWeb/OpenIdProviderEndpoint.ashx
@@ -13,7 +13,7 @@ public class OpenIdProviderEndpoint : IHttpHandler {
authRequest.IsAuthenticated = true;
}
- provider.SendResponse(request);
+ provider.Respond(request);
}
}
diff --git a/src/DotNetOpenAuth/Messaging/Channel.cs b/src/DotNetOpenAuth/Messaging/Channel.cs
index ded5662..bff395b 100644
--- a/src/DotNetOpenAuth/Messaging/Channel.cs
+++ b/src/DotNetOpenAuth/Messaging/Channel.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Messaging {
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+ using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
@@ -297,10 +298,26 @@ namespace DotNetOpenAuth.Messaging {
/// <remarks>
/// Requires an HttpContext.Current context.
/// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Use the Respond method instead, and prepare for execution to continue on this page beyond the call to Respond.")]
public void Send(IProtocolMessage message) {
Contract.Requires<InvalidOperationException>(HttpContext.Current != null, MessagingStrings.CurrentHttpContextRequired);
Contract.Requires<ArgumentNullException>(message != null);
- this.PrepareResponse(message).Send();
+ this.PrepareResponse(message).Respond(HttpContext.Current, true);
+ }
+
+ /// <summary>
+ /// Sends an indirect message (either a request or response)
+ /// or direct message response for transmission to a remote party
+ /// and skips most of the remaining ASP.NET request handling pipeline.
+ /// </summary>
+ /// <param name="message">The one-way message to send</param>
+ /// <remarks>
+ /// Requires an HttpContext.Current context.
+ /// </remarks>
+ public void Respond(IProtocolMessage message) {
+ Contract.Requires<InvalidOperationException>(HttpContext.Current != null, MessagingStrings.CurrentHttpContextRequired);
+ Contract.Requires<ArgumentNullException>(message != null);
+ this.PrepareResponse(message).Respond();
}
/// <summary>
diff --git a/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs b/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs
index cc655cf..b4bc22d 100644
--- a/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs
+++ b/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs
@@ -6,6 +6,7 @@
namespace DotNetOpenAuth.Messaging {
using System;
+ using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.IO;
@@ -125,6 +126,7 @@ namespace DotNetOpenAuth.Messaging {
/// <remarks>
/// Requires a current HttpContext.
/// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Use the Respond method instead, and prepare for execution to continue on this page beyond the call to Respond.")]
public virtual void Send() {
Contract.Requires<InvalidOperationException>(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired);
@@ -138,27 +140,36 @@ namespace DotNetOpenAuth.Messaging {
/// <param name="context">The context of the HTTP request whose response should be set.
/// Typically this is <see cref="HttpContext.Current"/>.</param>
/// <exception cref="ThreadAbortException">Typically thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Use the Respond method instead, and prepare for execution to continue on this page beyond the call to Respond.")]
public virtual void Send(HttpContext context) {
- Contract.Requires<ArgumentNullException>(context != null);
+ this.Respond(context, true);
+ }
- context.Response.Clear();
- context.Response.StatusCode = (int)this.Status;
- MessagingUtilities.ApplyHeadersToResponse(this.Headers, context.Response);
- if (this.ResponseStream != null) {
- try {
- this.ResponseStream.CopyTo(context.Response.OutputStream);
- } catch (HttpException ex) {
- if (ex.ErrorCode == -2147467259 && context.Response.Output != null) {
- // Test scenarios can generate this, since the stream is being spoofed:
- // System.Web.HttpException: OutputStream is not available when a custom TextWriter is used.
- context.Response.Output.Write(this.Body);
- } else {
- throw;
- }
- }
- }
+ /// <summary>
+ /// Automatically sends the appropriate response to the user agent
+ /// and signals ASP.NET to short-circuit the page execution pipeline
+ /// now that the response has been completed.
+ /// </summary>
+ /// <remarks>
+ /// Requires a current HttpContext.
+ /// </remarks>
+ public virtual void Respond() {
+ Contract.Requires<InvalidOperationException>(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired);
- context.Response.End();
+ this.Respond(HttpContext.Current);
+ }
+
+ /// <summary>
+ /// Automatically sends the appropriate response to the user agent
+ /// and signals ASP.NET to short-circuit the page execution pipeline
+ /// now that the response has been completed.
+ /// </summary>
+ /// <param name="context">The context of the HTTP request whose response should be set.
+ /// Typically this is <see cref="HttpContext.Current"/>.</param>
+ public virtual void Respond(HttpContext context) {
+ Contract.Requires<ArgumentNullException>(context != null);
+
+ this.Respond(context, false);
}
/// <summary>
@@ -232,5 +243,48 @@ namespace DotNetOpenAuth.Messaging {
writer.Flush();
this.ResponseStream.Seek(0, SeekOrigin.Begin);
}
+
+ /// <summary>
+ /// Automatically sends the appropriate response to the user agent
+ /// and signals ASP.NET to short-circuit the page execution pipeline
+ /// now that the response has been completed.
+ /// </summary>
+ /// <param name="context">The context of the HTTP request whose response should be set.
+ /// Typically this is <see cref="HttpContext.Current"/>.</param>
+ /// <param name="endRequest">If set to <c>false</c>, this method calls
+ /// <see cref="HttpApplication.CompleteRequest"/> rather than <see cref="HttpResponse.End"/>
+ /// to avoid a <see cref="ThreadAbortException"/>.</param>
+ protected internal virtual void Respond(HttpContext context, bool endRequest) {
+ Contract.Requires<ArgumentNullException>(context != null);
+
+ context.Response.Clear();
+ context.Response.StatusCode = (int)this.Status;
+ MessagingUtilities.ApplyHeadersToResponse(this.Headers, context.Response);
+ if (this.ResponseStream != null) {
+ try {
+ this.ResponseStream.CopyTo(context.Response.OutputStream);
+ } catch (HttpException ex) {
+ if (ex.ErrorCode == -2147467259 && context.Response.Output != null) {
+ // Test scenarios can generate this, since the stream is being spoofed:
+ // System.Web.HttpException: OutputStream is not available when a custom TextWriter is used.
+ context.Response.Output.Write(this.Body);
+ } else {
+ throw;
+ }
+ }
+ }
+
+ if (endRequest) {
+ // This approach throws an exception in order that
+ // no more code is executed in the calling page.
+ // Microsoft no longer recommends this approach.
+ context.Response.End();
+ } else if (context.ApplicationInstance != null) {
+ // This approach doesn't throw an exception, but
+ // still tells ASP.NET to short-circuit most of the
+ // request handling pipeline to speed things up.
+ context.ApplicationInstance.CompleteRequest();
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth/Messaging/OutgoingWebResponseActionResult.cs b/src/DotNetOpenAuth/Messaging/OutgoingWebResponseActionResult.cs
index 1cfc638..f2b31e9 100644
--- a/src/DotNetOpenAuth/Messaging/OutgoingWebResponseActionResult.cs
+++ b/src/DotNetOpenAuth/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.Send();
+ this.response.Respond();
}
}
}
diff --git a/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs
index e95835c..2aab532 100644
--- a/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuth2/AuthorizationServer.cs
@@ -78,7 +78,7 @@ namespace DotNetOpenAuth.OAuth2 {
var response = this.PrepareApproveAuthorizationRequest(authorizationRequest, userName, scopes, callback);
- this.Channel.Send(response);
+ this.Channel.Respond(response);
}
/// <summary>
@@ -90,7 +90,7 @@ namespace DotNetOpenAuth.OAuth2 {
Contract.Requires<ArgumentNullException>(authorizationRequest != null);
var response = this.PrepareRejectAuthorizationRequest(authorizationRequest, callback);
- this.Channel.Send(response);
+ this.Channel.Respond(response);
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth/OAuth2/WebServerClient.cs
index ca4e1a9..fb084d1 100644
--- a/src/DotNetOpenAuth/OAuth2/WebServerClient.cs
+++ b/src/DotNetOpenAuth/OAuth2/WebServerClient.cs
@@ -45,7 +45,7 @@ namespace DotNetOpenAuth.OAuth2 {
var authorizationState = new AuthorizationState(scope) {
Callback = returnTo,
};
- this.PrepareRequestUserAuthorization(authorizationState, state).Send();
+ this.PrepareRequestUserAuthorization(authorizationState, state).Respond();
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
index 1c065b2..58dfc2f 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
@@ -326,6 +326,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </remarks>
/// <exception cref="InvalidOperationException">Thrown if <see cref="IRequest.IsResponseReady"/> is <c>false</c>.</exception>
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Code Contract requires that we cast early.")]
+ [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Use the Respond method instead, and prepare for execution to continue on this page beyond the call to Respond.")]
public void SendResponse(IRequest request) {
Contract.Requires<InvalidOperationException>(HttpContext.Current != null, MessagingStrings.CurrentHttpContextRequired);
Contract.Requires<ArgumentNullException>(request != null);
@@ -337,6 +338,27 @@ namespace DotNetOpenAuth.OpenId.Provider {
}
/// <summary>
+ /// Sends the response to a received request.
+ /// </summary>
+ /// <param name="request">The incoming OpenID request whose response is to be sent.</param>
+ /// <remarks>
+ /// <para>Requires an HttpContext.Current context. If one is not available, the caller should use
+ /// <see cref="PrepareResponse"/> instead and manually send the <see cref="OutgoingWebResponse"/>
+ /// to the client.</para>
+ /// </remarks>
+ /// <exception cref="InvalidOperationException">Thrown if <see cref="IRequest.IsResponseReady"/> is <c>false</c>.</exception>
+ [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Code Contract requires that we cast early.")]
+ public void Respond(IRequest request) {
+ Contract.Requires<InvalidOperationException>(HttpContext.Current != null, MessagingStrings.CurrentHttpContextRequired);
+ Contract.Requires<ArgumentNullException>(request != null);
+ Contract.Requires<ArgumentException>(request.IsResponseReady);
+
+ this.ApplyBehaviorsToResponse(request);
+ Request requestInternal = (Request)request;
+ this.Channel.Respond(requestInternal.Response);
+ }
+
+ /// <summary>
/// Gets the response to a received request.
/// </summary>
/// <param name="request">The request.</param>
@@ -375,7 +397,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
Contract.Requires<ArgumentNullException>(claimedIdentifier != null);
Contract.Requires<ArgumentNullException>(localIdentifier != null);
- this.PrepareUnsolicitedAssertion(providerEndpoint, relyingPartyRealm, claimedIdentifier, localIdentifier, extensions).Send();
+ this.PrepareUnsolicitedAssertion(providerEndpoint, relyingPartyRealm, claimedIdentifier, localIdentifier, extensions).Respond();
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
index e792a81..821d95c 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
@@ -180,7 +180,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
public static void SendResponse() {
var pendingRequest = PendingRequest;
PendingRequest = null;
- Provider.SendResponse(pendingRequest);
+ Provider.Respond(pendingRequest);
}
/// <summary>
@@ -222,8 +222,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
}
}
if (request.IsResponseReady) {
- Provider.SendResponse(request);
- Page.Response.End();
+ Provider.Respond(request);
PendingAuthenticationRequest = null;
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
index 5293876..8bbf04f 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
@@ -295,14 +295,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <summary>
/// Redirects the user agent to the provider for authentication.
- /// Execution of the current page terminates after this call.
/// </summary>
/// <remarks>
/// This method requires an ASP.NET HttpContext.
/// </remarks>
- /// <exception cref="ThreadAbortException">Typically thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
public void RedirectToProvider() {
- this.RedirectingResponse.Send();
+ this.RedirectingResponse.Respond();
}
#endregion
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs
index 866f942..551534a 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs
@@ -428,7 +428,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
this.RelyingParty.Channel.GetRequestFromContext(),
callback);
- response.Send();
+ response.Respond();
}
/// <summary>