summaryrefslogtreecommitdiffstats
path: root/src/DotNetOAuth/Messaging
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOAuth/Messaging')
-rw-r--r--src/DotNetOAuth/Messaging/HttpRequestInfo.cs11
-rw-r--r--src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs18
-rw-r--r--src/DotNetOAuth/Messaging/MessagingStrings.resx6
-rw-r--r--src/DotNetOAuth/Messaging/MessagingUtilities.cs31
-rw-r--r--src/DotNetOAuth/Messaging/Response.cs70
5 files changed, 131 insertions, 5 deletions
diff --git a/src/DotNetOAuth/Messaging/HttpRequestInfo.cs b/src/DotNetOAuth/Messaging/HttpRequestInfo.cs
index bce9ccb..d9d0c72 100644
--- a/src/DotNetOAuth/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOAuth/Messaging/HttpRequestInfo.cs
@@ -58,6 +58,17 @@ namespace DotNetOAuth.Messaging {
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
/// </summary>
+ /// <param name="request">The HttpWebRequest (that was never used) to copy from.</param>
+ internal HttpRequestInfo(WebRequest request) {
+ this.HttpMethod = request.Method;
+ this.Url = request.RequestUri;
+ this.Headers = GetHeaderCollection(request.Headers);
+ this.InputStream = null;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
+ /// </summary>
/// <param name="message">The message being passed in through a mock transport.</param>
internal HttpRequestInfo(IProtocolMessage message) {
this.Message = message;
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
index 0416255..9bac8f7 100644
--- a/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOAuth/Messaging/MessagingStrings.Designer.cs
@@ -277,6 +277,24 @@ namespace DotNetOAuth.Messaging {
}
/// <summary>
+ /// Looks up a localized string similar to The stream&apos;s CanRead property returned false..
+ /// </summary>
+ internal static string StreamUnreadable {
+ get {
+ return ResourceManager.GetString("StreamUnreadable", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The stream&apos;s CanWrite property returned false..
+ /// </summary>
+ internal static string StreamUnwritable {
+ get {
+ return ResourceManager.GetString("StreamUnwritable", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Expected at most 1 binding element offering the {0} protection, but found {1}..
/// </summary>
internal static string TooManyBindingsOfferingSameProtection {
diff --git a/src/DotNetOAuth/Messaging/MessagingStrings.resx b/src/DotNetOAuth/Messaging/MessagingStrings.resx
index f549b9c..91688fb 100644
--- a/src/DotNetOAuth/Messaging/MessagingStrings.resx
+++ b/src/DotNetOAuth/Messaging/MessagingStrings.resx
@@ -189,6 +189,12 @@
<data name="SigningNotSupported" xml:space="preserve">
<value>This channel does not support signing messages. To support signing messages, a derived Channel type must override the Sign and IsSignatureValid methods.</value>
</data>
+ <data name="StreamUnreadable" xml:space="preserve">
+ <value>The stream's CanRead property returned false.</value>
+ </data>
+ <data name="StreamUnwritable" xml:space="preserve">
+ <value>The stream's CanWrite property returned false.</value>
+ </data>
<data name="TooManyBindingsOfferingSameProtection" xml:space="preserve">
<value>Expected at most 1 binding element offering the {0} protection, but found {1}.</value>
</data>
diff --git a/src/DotNetOAuth/Messaging/MessagingUtilities.cs b/src/DotNetOAuth/Messaging/MessagingUtilities.cs
index 7c95696..88aea0c 100644
--- a/src/DotNetOAuth/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOAuth/Messaging/MessagingUtilities.cs
@@ -8,6 +8,7 @@ namespace DotNetOAuth.Messaging {
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+ using System.IO;
using System.Linq;
using System.Net;
using System.Text;
@@ -46,6 +47,36 @@ namespace DotNetOAuth.Messaging {
}
/// <summary>
+ /// Copies the contents of one stream to another.
+ /// </summary>
+ /// <param name="copyFrom">The stream to copy from, at the position where copying should begin.</param>
+ /// <param name="copyTo">The stream to copy to, at the position where bytes should be written.</param>
+ /// <remarks>
+ /// Copying begins at the streams' current positions.
+ /// The positions are NOT reset after copying is complete.
+ /// </remarks>
+ internal static void CopyTo(this Stream copyFrom, Stream copyTo) {
+ if (copyFrom == null) {
+ throw new ArgumentNullException("copyFrom");
+ }
+ if (copyTo == null) {
+ throw new ArgumentNullException("copyTo");
+ }
+ if (!copyFrom.CanRead) {
+ throw new ArgumentException(MessagingStrings.StreamUnreadable, "copyFrom");
+ }
+ if (!copyTo.CanWrite) {
+ throw new ArgumentException(MessagingStrings.StreamUnwritable, "copyTo");
+ }
+
+ byte[] buffer = new byte[1024];
+ int readBytes;
+ while ((readBytes = copyFrom.Read(buffer, 0, 1024)) > 0) {
+ copyTo.Write(buffer, 0, readBytes);
+ }
+ }
+
+ /// <summary>
/// Concatenates a list of name-value pairs as key=value&amp;key=value,
/// taking care to properly encode each key and value for URL
/// transmission. No ? is prefixed to the string.
diff --git a/src/DotNetOAuth/Messaging/Response.cs b/src/DotNetOAuth/Messaging/Response.cs
index 8a7c2e1..c02acc2 100644
--- a/src/DotNetOAuth/Messaging/Response.cs
+++ b/src/DotNetOAuth/Messaging/Response.cs
@@ -8,6 +8,7 @@ namespace DotNetOAuth.Messaging {
using System;
using System.IO;
using System.Net;
+ using System.Text;
using System.Web;
/// <summary>
@@ -41,8 +42,10 @@ namespace DotNetOAuth.Messaging {
internal Response(HttpWebResponse response) {
this.Status = response.StatusCode;
this.Headers = response.Headers;
- using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
- this.Body = reader.ReadToEnd();
+ this.ResponseStream = new MemoryStream();
+ using (Stream responseStream = response.GetResponseStream()) {
+ responseStream.CopyTo(this.ResponseStream);
+ this.ResponseStream.Seek(0, SeekOrigin.Begin);
}
}
@@ -59,7 +62,21 @@ namespace DotNetOAuth.Messaging {
/// <summary>
/// Gets the body of the HTTP response.
/// </summary>
- public string Body { get; internal set; }
+ public Stream ResponseStream { get; internal set; }
+
+ /// <summary>
+ /// Gets a value indicating whether the response stream is incomplete due
+ /// to a length limitation imposed by the HttpWebRequest or calling method.
+ /// </summary>
+ public bool IsResponseTruncated { get; internal set; }
+
+ /// <summary>
+ /// Gets or sets the body of the response as a string.
+ /// </summary>
+ public string Body {
+ get { return this.ResponseStream != null ? this.GetResponseReader().ReadToEnd() : null; }
+ set { this.SetResponse(value); }
+ }
/// <summary>
/// Gets the HTTP status code to use in the HTTP response.
@@ -73,6 +90,20 @@ namespace DotNetOAuth.Messaging {
internal IProtocolMessage OriginalMessage { get; set; }
/// <summary>
+ /// Creates a text reader for the response stream.
+ /// </summary>
+ /// <returns>The text reader, initialized for the proper encoding.</returns>
+ public StreamReader GetResponseReader() {
+ this.ResponseStream.Seek(0, SeekOrigin.Begin);
+ string contentEncoding = this.Headers[HttpResponseHeader.ContentEncoding];
+ if (string.IsNullOrEmpty(contentEncoding)) {
+ return new StreamReader(this.ResponseStream);
+ } else {
+ return new StreamReader(this.ResponseStream, Encoding.GetEncoding(contentEncoding));
+ }
+ }
+
+ /// <summary>
/// Automatically sends the appropriate response to the user agent.
/// Requires a current HttpContext.
/// </summary>
@@ -84,10 +115,39 @@ namespace DotNetOAuth.Messaging {
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.StatusCode = (int)this.Status;
MessagingUtilities.ApplyHeadersToResponse(this.Headers, HttpContext.Current.Response);
- if (this.Body != null) {
- HttpContext.Current.Response.Output.Write(this.Body);
+ if (this.ResponseStream != null) {
+ try {
+ this.ResponseStream.CopyTo(HttpContext.Current.Response.OutputStream);
+ } catch (HttpException ex) {
+ if (ex.ErrorCode == -2147467259 && HttpContext.Current.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.
+ HttpContext.Current.Response.Output.Write(this.Body);
+ } else {
+ throw;
+ }
+ }
}
HttpContext.Current.Response.End();
}
+
+ /// <summary>
+ /// Sets the response to some string, encoded as UTF-8.
+ /// </summary>
+ /// <param name="body">The string to set the response to.</param>
+ internal void SetResponse(string body) {
+ if (body == null) {
+ this.ResponseStream = null;
+ return;
+ }
+
+ Encoding encoding = Encoding.UTF8;
+ this.Headers[HttpResponseHeader.ContentEncoding] = encoding.HeaderName;
+ this.ResponseStream = new MemoryStream();
+ StreamWriter writer = new StreamWriter(this.ResponseStream, encoding);
+ writer.Write(body);
+ writer.Flush();
+ this.ResponseStream.Seek(0, SeekOrigin.Begin);
+ }
}
}