//----------------------------------------------------------------------- // // Copyright (c) Outercurve Foundation. All rights reserved. // //----------------------------------------------------------------------- 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; /// /// The messaging channel used by OAuth 2.0 Clients. /// internal class OAuth2ClientChannel : OAuth2ChannelBase { /// /// Initializes a new instance of the class. /// internal OAuth2ClientChannel() { } /// /// Prepares an HTTP request that carries a given message. /// /// The message to send. /// /// The prepared to send the request. /// /// /// This method must be overridden by a derived class, unless the method /// is overridden and does not require this method. /// 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; } /// /// Gets the protocol message that may be in the given HTTP response. /// /// The response that is anticipated to contain an protocol message. /// /// The deserialized message parts, if found. Null otherwise. /// /// Thrown when the response is not valid. protected override IDictionary 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("Unexpected response Content-Type {0}", response.ContentType.MediaType); } } /// /// Gets the protocol message that may be embedded in the given HTTP request. /// /// The request to search for an embedded message. /// /// The deserialized message, if one is found. Null otherwise. /// protected override IDirectedProtocolMessage ReadFromRequestCore(HttpRequestInfo request) { Logger.Channel.DebugFormat("Incoming HTTP request: {0} {1}", request.HttpMethod, request.UrlBeforeRewriting.AbsoluteUri); var fields = request.QueryStringBeforeRewriting.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.UrlBeforeRewriting.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); } /// /// Queues a message for sending in the response stream where the fields /// are sent in the response stream in querystring style. /// /// The message to send as a response. /// /// The pending user agent redirect based message to be sent as an HttpResponse. /// /// /// This method implements spec OAuth V1.0 section 5.3. /// protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) { // Clients don't ever send direct responses. throw new NotImplementedException(); } } }