diff options
Diffstat (limited to 'src')
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> |