diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2008-09-10 22:18:15 -0700 |
---|---|---|
committer | Andrew <andrewarnott@gmail.com> | 2008-09-10 22:18:15 -0700 |
commit | f6d28fb14c91c97f6cc8b85c442987082997866a (patch) | |
tree | c517bf2a41709319255b5b5312f3fc56c06bff6e /src | |
parent | d33318e787968182f95c183d1891c9a7d59a3b69 (diff) | |
download | DotNetOpenAuth-f6d28fb14c91c97f6cc8b85c442987082997866a.zip DotNetOpenAuth-f6d28fb14c91c97f6cc8b85c442987082997866a.tar.gz DotNetOpenAuth-f6d28fb14c91c97f6cc8b85c442987082997866a.tar.bz2 |
Code coverage work is as complete as our implementation will currently allow.
Diffstat (limited to 'src')
-rw-r--r-- | src/DotNetOAuth.Test/DotNetOAuth.Test.csproj | 1 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs | 45 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/OAuthChannelTests.cs | 99 | ||||
-rw-r--r-- | src/DotNetOAuth/DotNetOAuth.csproj | 2 | ||||
-rw-r--r-- | src/DotNetOAuth/IWebRequestHandler.cs | 31 | ||||
-rw-r--r-- | src/DotNetOAuth/Messaging/Response.cs | 14 | ||||
-rw-r--r-- | src/DotNetOAuth/OAuthChannel.cs | 51 | ||||
-rw-r--r-- | src/DotNetOAuth/StandardWebRequestHandler.cs | 59 |
8 files changed, 284 insertions, 18 deletions
diff --git a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj index 5fce735..e734d18 100644 --- a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj +++ b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj @@ -65,6 +65,7 @@ <Compile Include="Messaging\ProtocolExceptionTests.cs" />
<Compile Include="Mocks\TestDirectedMessage.cs" />
<Compile Include="Mocks\TestBadChannel.cs" />
+ <Compile Include="Mocks\TestWebRequestHandler.cs" />
<Compile Include="OAuthChannelTests.cs" />
<Compile Include="Messaging\MessageSerializerTests.cs" />
<Compile Include="Mocks\TestChannel.cs" />
diff --git a/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs b/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs new file mode 100644 index 0000000..4eecb1f --- /dev/null +++ b/src/DotNetOAuth.Test/Mocks/TestWebRequestHandler.cs @@ -0,0 +1,45 @@ +//-----------------------------------------------------------------------
+// <copyright file="TestWebRequestHandler.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.Mocks {
+ using System;
+ using System.IO;
+ using System.Net;
+ using System.Text;
+ using DotNetOAuth.Messaging;
+
+ internal class TestWebRequestHandler : IWebRequestHandler {
+ private StringBuilder postEntity;
+
+ internal Func<HttpWebRequest, Response> Callback { get; set; }
+
+ internal Stream RequestEntityStream {
+ get {
+ if (this.postEntity == null) {
+ return null;
+ }
+ return new MemoryStream(Encoding.UTF8.GetBytes(this.postEntity.ToString()));
+ }
+ }
+
+ #region IWebRequestHandler Members
+
+ public TextWriter GetRequestStream(HttpWebRequest request) {
+ this.postEntity = new StringBuilder();
+ return new StringWriter(this.postEntity);
+ }
+
+ public Response GetResponse(HttpWebRequest request) {
+ if (this.Callback == null) {
+ throw new InvalidOperationException("Set the Callback property first.");
+ }
+
+ return this.Callback(request);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOAuth.Test/OAuthChannelTests.cs b/src/DotNetOAuth.Test/OAuthChannelTests.cs index e47f98f..2d00800 100644 --- a/src/DotNetOAuth.Test/OAuthChannelTests.cs +++ b/src/DotNetOAuth.Test/OAuthChannelTests.cs @@ -18,13 +18,25 @@ namespace DotNetOAuth.Test { [TestClass]
public class OAuthChannelTests : TestBase {
- private Channel channel;
+ private OAuthChannel channel;
+ private TestWebRequestHandler webRequestHandler;
[TestInitialize]
public override void SetUp() {
base.SetUp();
- this.channel = new OAuthChannel(new TestMessageTypeProvider());
+ this.webRequestHandler = new TestWebRequestHandler();
+ this.channel = new OAuthChannel(new TestMessageTypeProvider(), this.webRequestHandler);
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentNullException))]
+ public void CtorNullHandler() {
+ new OAuthChannel(new TestMessageTypeProvider(), null);
+ }
+
+ [TestMethod]
+ public void CtorDefault() {
+ new OAuthChannel();
}
[TestMethod]
@@ -90,6 +102,40 @@ namespace DotNetOAuth.Test { Assert.IsNull(testMessage.EmptyMember);
}
+ [TestMethod, ExpectedException(typeof(ArgumentNullException))]
+ public void RequestNull() {
+ this.channel.Request(null);
+ }
+
+ [TestMethod, ExpectedException(typeof(ArgumentException))]
+ public void RequestNullRecipient() {
+ IDirectedProtocolMessage message = new TestDirectedMessage(MessageTransport.Direct);
+ this.channel.Request(message);
+ }
+
+ [TestMethod, ExpectedException(typeof(NotSupportedException))]
+ public void RequestBadPreferredScheme() {
+ TestDirectedMessage message = new TestDirectedMessage(MessageTransport.Direct);
+ message.Recipient = new Uri("http://localtest");
+ this.channel.PreferredTransmissionScheme = (MessageScheme)100;
+ this.channel.Request(message);
+ }
+
+ [TestMethod]
+ public void RequestUsingAuthorizationHeader() {
+ this.ParameterizedRequestTest(MessageScheme.AuthorizationHeaderRequest);
+ }
+
+ [TestMethod]
+ public void RequestUsingGet() {
+ this.ParameterizedRequestTest(MessageScheme.GetRequest);
+ }
+
+ [TestMethod]
+ public void RequestUsingPost() {
+ this.ParameterizedRequestTest(MessageScheme.PostRequest);
+ }
+
private static string CreateAuthorizationHeader(IDictionary<string, string> fields) {
if (fields == null) {
throw new ArgumentNullException("fields");
@@ -146,6 +192,55 @@ namespace DotNetOAuth.Test { return request;
}
+ private static HttpRequestInfo ConvertToRequestInfo(HttpWebRequest request, Stream postEntity) {
+ HttpRequestInfo info = new HttpRequestInfo {
+ HttpMethod = request.Method,
+ Url = request.RequestUri,
+ Headers = request.Headers,
+ InputStream = postEntity,
+ };
+ return info;
+ }
+
+ private void ParameterizedRequestTest(MessageScheme scheme) {
+ TestDirectedMessage request = new TestDirectedMessage(MessageTransport.Direct) {
+ Age = 15,
+ Name = "Andrew",
+ Location = new Uri("http://hostb/pathB"),
+ Recipient = new Uri("http://localtest"),
+ };
+
+ Response rawResponse = null;
+ this.webRequestHandler.Callback = (req) => {
+ Assert.IsNotNull(req);
+ HttpRequestInfo reqInfo = ConvertToRequestInfo(req, this.webRequestHandler.RequestEntityStream);
+ Assert.AreEqual(scheme == MessageScheme.PostRequest ? "POST" : "GET", reqInfo.HttpMethod);
+ var incomingMessage = this.channel.ReadFromRequest(reqInfo) as TestMessage;
+ Assert.AreEqual(request.Age, incomingMessage.Age);
+ Assert.AreEqual(request.Name, incomingMessage.Name);
+ Assert.AreEqual(request.Location, incomingMessage.Location);
+
+ var responseFields = new Dictionary<string, string> {
+ { "age", request.Age.ToString() },
+ { "Name", request.Name },
+ { "Location", request.Location.AbsoluteUri },
+ };
+ rawResponse = new Response {
+ Body = MessagingUtilities.CreateQueryString(responseFields),
+ };
+ return rawResponse;
+ };
+
+ this.channel.PreferredTransmissionScheme = scheme;
+ IProtocolMessage response = this.channel.Request(request);
+ Assert.IsNotNull(response);
+ Assert.IsInstanceOfType(response, typeof(TestMessage));
+ TestMessage responseMessage = (TestMessage)response;
+ Assert.AreEqual(request.Age, responseMessage.Age);
+ Assert.AreEqual(request.Name, responseMessage.Name);
+ Assert.AreEqual(request.Location, responseMessage.Location);
+ }
+
private void ParameterizedReceiveTest(MessageScheme scheme) {
var fields = new Dictionary<string, string> {
{ "age", "15" },
diff --git a/src/DotNetOAuth/DotNetOAuth.csproj b/src/DotNetOAuth/DotNetOAuth.csproj index b710061..1657b57 100644 --- a/src/DotNetOAuth/DotNetOAuth.csproj +++ b/src/DotNetOAuth/DotNetOAuth.csproj @@ -67,6 +67,7 @@ </ItemGroup>
<ItemGroup>
<Compile Include="Consumer.cs" />
+ <Compile Include="IWebRequestHandler.cs" />
<Compile Include="Messaging\DictionaryXmlReader.cs" />
<Compile Include="Messaging\DictionaryXmlWriter.cs" />
<Compile Include="Messaging\Channel.cs" />
@@ -93,6 +94,7 @@ <Compile Include="Messaging\ProtocolException.cs" />
<Compile Include="Messaging\MessageSerializer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="StandardWebRequestHandler.cs" />
<Compile Include="Util.cs" />
<Compile Include="Protocol.cs" />
<Compile Include="ServiceProvider.cs" />
diff --git a/src/DotNetOAuth/IWebRequestHandler.cs b/src/DotNetOAuth/IWebRequestHandler.cs new file mode 100644 index 0000000..6281d5c --- /dev/null +++ b/src/DotNetOAuth/IWebRequestHandler.cs @@ -0,0 +1,31 @@ +//-----------------------------------------------------------------------
+// <copyright file="IWebRequestHandler.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth {
+ using System.IO;
+ using System.Net;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// A contract for <see cref="HttpWebRequest"/> handling.
+ /// </summary>
+ internal interface IWebRequestHandler {
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>The writer the caller should write out the entity data to.</returns>
+ TextWriter GetRequestStream(HttpWebRequest request);
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="Response"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>An instance of <see cref="Response"/> describing the response.</returns>
+ Response GetResponse(HttpWebRequest request);
+ }
+}
diff --git a/src/DotNetOAuth/Messaging/Response.cs b/src/DotNetOAuth/Messaging/Response.cs index 81089ed..8a7c2e1 100644 --- a/src/DotNetOAuth/Messaging/Response.cs +++ b/src/DotNetOAuth/Messaging/Response.cs @@ -6,6 +6,7 @@ namespace DotNetOAuth.Messaging {
using System;
+ using System.IO;
using System.Net;
using System.Web;
@@ -33,6 +34,19 @@ namespace DotNetOAuth.Messaging { }
/// <summary>
+ /// Initializes a new instance of the <see cref="Response"/> class
+ /// based on the contents of an <see cref="HttpWebResponse"/>.
+ /// </summary>
+ /// <param name="response">The <see cref="HttpWebResponse"/> to clone.</param>
+ internal Response(HttpWebResponse response) {
+ this.Status = response.StatusCode;
+ this.Headers = response.Headers;
+ using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
+ this.Body = reader.ReadToEnd();
+ }
+ }
+
+ /// <summary>
/// Gets the headers that must be included in the response to the user agent.
/// </summary>
/// <remarks>
diff --git a/src/DotNetOAuth/OAuthChannel.cs b/src/DotNetOAuth/OAuthChannel.cs index 052bdcd..ff789b2 100644 --- a/src/DotNetOAuth/OAuthChannel.cs +++ b/src/DotNetOAuth/OAuthChannel.cs @@ -18,10 +18,16 @@ namespace DotNetOAuth { /// </summary>
internal class OAuthChannel : Channel {
/// <summary>
+ /// The object that will transmit <see cref="HttpWebRequest"/> instances
+ /// and return their responses.
+ /// </summary>
+ private IWebRequestHandler webRequestHandler;
+
+ /// <summary>
/// Initializes a new instance of the <see cref="OAuthChannel"/> class.
/// </summary>
internal OAuthChannel()
- : this(new OAuthMessageTypeProvider()) {
+ : this(new OAuthMessageTypeProvider(), new StandardWebRequestHandler()) {
}
/// <summary>
@@ -31,14 +37,29 @@ namespace DotNetOAuth { /// An injected message type provider instance.
/// Except for mock testing, this should always be <see cref="OAuthMessageTypeProvider"/>.
/// </param>
+ /// <param name="webRequestHandler">
+ /// An instance to a <see cref="IWebRequestHandler"/> that will be used when submitting HTTP
+ /// requests and waiting for responses.
+ /// </param>
/// <remarks>
/// This overload for testing purposes only.
/// </remarks>
- internal OAuthChannel(IMessageTypeProvider messageTypeProvider)
+ internal OAuthChannel(IMessageTypeProvider messageTypeProvider, IWebRequestHandler webRequestHandler)
: base(messageTypeProvider) {
+ if (webRequestHandler == null) {
+ throw new ArgumentNullException("webRequestHandler");
+ }
+
+ this.webRequestHandler = webRequestHandler;
+ this.PreferredTransmissionScheme = MessageScheme.AuthorizationHeaderRequest;
}
/// <summary>
+ /// Gets or sets the method used in direct requests to transmit the message payload.
+ /// </summary>
+ internal MessageScheme PreferredTransmissionScheme { get; set; }
+
+ /// <summary>
/// Searches an incoming HTTP request for data that could be used to assemble
/// a protocol request message.
/// </summary>
@@ -105,10 +126,13 @@ namespace DotNetOAuth { if (request == null) {
throw new ArgumentNullException("request");
}
+ if (request.Recipient == null) {
+ throw new ArgumentException(MessagingStrings.DirectedMessageMissingRecipient, "request");
+ }
HttpWebRequest httpRequest;
- MessageScheme transmissionMethod = MessageScheme.AuthorizationHeaderRequest;
+ MessageScheme transmissionMethod = this.PreferredTransmissionScheme;
switch (transmissionMethod) {
case MessageScheme.AuthorizationHeaderRequest:
httpRequest = this.InitializeRequestAsAuthHeader(request);
@@ -123,20 +147,15 @@ namespace DotNetOAuth { throw new NotSupportedException();
}
- // Submit the request and await the reply.
- Dictionary<string, string> responseFields;
- try {
- using (HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse()) {
- using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
- string queryString = reader.ReadToEnd();
- responseFields = HttpUtility.ParseQueryString(queryString).ToDictionary();
- }
- }
- } catch (WebException ex) {
- throw new ProtocolException(MessagingStrings.ErrorInRequestReplyMessage, ex);
+ Response response = this.webRequestHandler.GetResponse(httpRequest);
+ if (response.Body == null) {
+ return null;
}
-
+ var responseFields = HttpUtility.ParseQueryString(response.Body).ToDictionary();
Type messageType = this.MessageTypeProvider.GetResponseMessageType(request, responseFields);
+ if (messageType == null) {
+ return null;
+ }
var responseSerialize = MessageSerializer.Get(messageType);
var responseMessage = responseSerialize.Deserialize(responseFields);
@@ -214,7 +233,7 @@ namespace DotNetOAuth { httpRequest.ContentType = "application/x-www-form-urlencoded";
string requestBody = MessagingUtilities.CreateQueryString(fields);
httpRequest.ContentLength = requestBody.Length;
- using (StreamWriter writer = new StreamWriter(httpRequest.GetRequestStream())) {
+ using (TextWriter writer = this.webRequestHandler.GetRequestStream(httpRequest)) {
writer.Write(requestBody);
}
diff --git a/src/DotNetOAuth/StandardWebRequestHandler.cs b/src/DotNetOAuth/StandardWebRequestHandler.cs new file mode 100644 index 0000000..715da72 --- /dev/null +++ b/src/DotNetOAuth/StandardWebRequestHandler.cs @@ -0,0 +1,59 @@ +//-----------------------------------------------------------------------
+// <copyright file="StandardWebRequestHandler.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth {
+ using System;
+ using System.IO;
+ using System.Net;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// The default handler for transmitting <see cref="HttpWebRequest"/> instances
+ /// and returning the responses.
+ /// </summary>
+ internal class StandardWebRequestHandler : IWebRequestHandler {
+ #region IWebRequestHandler Members
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>The stream the caller should write out the entity data to.</returns>
+ public TextWriter GetRequestStream(HttpWebRequest request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ try {
+ return new StreamWriter(request.GetRequestStream());
+ } catch (WebException ex) {
+ throw new ProtocolException(MessagingStrings.ErrorInRequestReplyMessage, ex);
+ }
+ }
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="Response"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>An instance of <see cref="Response"/> describing the response.</returns>
+ public Response GetResponse(HttpWebRequest request) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+
+ try {
+ using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
+ return new Response(response);
+ }
+ } catch (WebException ex) {
+ throw new ProtocolException(MessagingStrings.ErrorInRequestReplyMessage, ex);
+ }
+ }
+
+ #endregion
+ }
+}
|