summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs')
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
new file mode 100644
index 0000000..95ec983
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ChannelElements/OAuth2ClientChannel.cs
@@ -0,0 +1,135 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuth2ClientChannel.cs" company="Outercurve Foundation">
+// Copyright (c) Outercurve Foundation. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Specialized;
+ using System.Diagnostics.Contracts;
+ using System.Net;
+ using System.Web;
+
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// The messaging channel used by OAuth 2.0 Clients.
+ /// </summary>
+ internal class OAuth2ClientChannel : OAuth2ChannelBase {
+ /// <summary>
+ /// The messages receivable by this channel.
+ /// </summary>
+ private static readonly Type[] MessageTypes = new Type[] {
+ typeof(AccessTokenSuccessResponse),
+ typeof(AccessTokenFailedResponse),
+ typeof(EndUserAuthorizationSuccessAuthCodeResponse),
+ typeof(EndUserAuthorizationSuccessAccessTokenResponse),
+ typeof(EndUserAuthorizationFailedResponse),
+ typeof(UnauthorizedResponse),
+ };
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OAuth2ClientChannel"/> class.
+ /// </summary>
+ internal OAuth2ClientChannel() : base(MessageTypes) {
+ }
+
+ /// <summary>
+ /// Prepares an HTTP request that carries a given message.
+ /// </summary>
+ /// <param name="request">The message to send.</param>
+ /// <returns>
+ /// The <see cref="HttpWebRequest"/> prepared to send the request.
+ /// </returns>
+ /// <remarks>
+ /// This method must be overridden by a derived class, unless the <see cref="Channel.RequestCore"/> method
+ /// is overridden and does not require this method.
+ /// </remarks>
+ protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) {
+ HttpWebRequest httpRequest;
+ if ((request.HttpMethods & HttpDeliveryMethods.GetRequest) != 0) {
+ httpRequest = InitializeRequestAsGet(request);
+ } else if ((request.HttpMethods & HttpDeliveryMethods.PostRequest) != 0) {
+ httpRequest = InitializeRequestAsPost(request);
+ } else {
+ throw new NotSupportedException();
+ }
+
+ return httpRequest;
+ }
+
+ /// <summary>
+ /// Gets the protocol message that may be in the given HTTP response.
+ /// </summary>
+ /// <param name="response">The response that is anticipated to contain an protocol message.</param>
+ /// <returns>
+ /// The deserialized message parts, if found. Null otherwise.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown when the response is not valid.</exception>
+ protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) {
+ // The spec says direct responses should be JSON objects, but Facebook uses HttpFormUrlEncoded instead, calling it text/plain
+ // Others return text/javascript. Again bad.
+ string body = response.GetResponseReader().ReadToEnd();
+ if (response.ContentType.MediaType == JsonEncoded || response.ContentType.MediaType == JsonTextEncoded) {
+ return this.DeserializeFromJson(body);
+ } else if (response.ContentType.MediaType == HttpFormUrlEncoded || response.ContentType.MediaType == PlainTextEncoded) {
+ return HttpUtility.ParseQueryString(body).ToDictionary();
+ } else {
+ throw ErrorUtilities.ThrowProtocol(OAuthStrings.UnexpectedResponseContentType, response.ContentType.MediaType);
+ }
+ }
+
+ /// <summary>
+ /// Gets the protocol message that may be embedded in the given HTTP request.
+ /// </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 override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestBase request) {
+ Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.GetPublicFacingUrl().AbsoluteUri);
+
+ var fields = request.GetQueryStringBeforeRewriting().ToDictionary();
+
+ // Also read parameters from the fragment, if it's available.
+ // Typically the fragment is not available because the browser doesn't send it to a web server
+ // but this request may have been fabricated by an installed desktop app, in which case
+ // the fragment is available.
+ string fragment = request.GetPublicFacingUrl().Fragment;
+ if (!string.IsNullOrEmpty(fragment)) {
+ foreach (var pair in HttpUtility.ParseQueryString(fragment.Substring(1)).ToDictionary()) {
+ fields.Add(pair.Key, pair.Value);
+ }
+ }
+
+ MessageReceivingEndpoint recipient;
+ try {
+ recipient = request.GetRecipient();
+ } catch (ArgumentException ex) {
+ Logger.Messaging.WarnFormat("Unrecognized HTTP request: ", ex);
+ return null;
+ }
+
+ return (IDirectedProtocolMessage)this.Receive(fields, recipient);
+ }
+
+ /// <summary>
+ /// Queues a message for sending in the response stream where the fields
+ /// are sent in the response stream in querystring style.
+ /// </summary>
+ /// <param name="response">The message to send as a response.</param>
+ /// <returns>
+ /// The pending user agent redirect based message to be sent as an HttpResponse.
+ /// </returns>
+ /// <remarks>
+ /// This method implements spec OAuth V1.0 section 5.3.
+ /// </remarks>
+ protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) {
+ // Clients don't ever send direct responses.
+ throw new NotImplementedException();
+ }
+ }
+}