//-----------------------------------------------------------------------
//
// Copyright (c) Andrew Arnott. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOAuth.Messaging {
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
///
/// A protocol message (request or response) that passes between Consumer and Service Provider
/// via the user agent using a redirect or form POST submission,
/// OR a direct message response.
///
///
/// An instance of this type describes the HTTP response that must be sent
/// in response to the current HTTP request.
/// It is important that this response make up the entire HTTP response.
/// A hosting ASPX page should not be allowed to render its normal HTML output
/// after this response is sent. The normal rendered output of an ASPX page
/// can be canceled by calling after this message
/// is sent on the response stream.
///
public class Response {
///
/// Initializes a new instance of the class.
///
internal Response() {
this.Status = HttpStatusCode.OK;
this.Headers = new WebHeaderCollection();
}
///
/// Initializes a new instance of the class
/// based on the contents of an .
///
/// The to clone.
internal Response(HttpWebResponse response) {
this.Status = response.StatusCode;
this.Headers = response.Headers;
this.ResponseStream = new MemoryStream();
using (Stream responseStream = response.GetResponseStream()) {
responseStream.CopyTo(this.ResponseStream);
this.ResponseStream.Seek(0, SeekOrigin.Begin);
}
}
///
/// Gets the headers that must be included in the response to the user agent.
///
///
/// The headers in this collection are not meant to be a comprehensive list
/// of exactly what should be sent, but are meant to augment whatever headers
/// are generally included in a typical response.
///
public WebHeaderCollection Headers { get; internal set; }
///
/// Gets the body of the HTTP response.
///
public Stream ResponseStream { get; internal set; }
///
/// Gets a value indicating whether the response stream is incomplete due
/// to a length limitation imposed by the HttpWebRequest or calling method.
///
public bool IsResponseTruncated { get; internal set; }
///
/// Gets or sets the body of the response as a string.
///
public string Body {
get { return this.ResponseStream != null ? this.GetResponseReader().ReadToEnd() : null; }
set { this.SetResponse(value); }
}
///
/// Gets the HTTP status code to use in the HTTP response.
///
public HttpStatusCode Status { get; internal set; }
///
/// Gets or sets a reference to the actual protocol message that
/// is being sent via the user agent.
///
internal IProtocolMessage OriginalMessage { get; set; }
///
/// Creates a text reader for the response stream.
///
/// The text reader, initialized for the proper encoding.
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));
}
}
///
/// Automatically sends the appropriate response to the user agent.
/// Requires a current HttpContext.
///
public void Send() {
if (HttpContext.Current == null) {
throw new InvalidOperationException(MessagingStrings.CurrentHttpContextRequired);
}
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.StatusCode = (int)this.Status;
MessagingUtilities.ApplyHeadersToResponse(this.Headers, HttpContext.Current.Response);
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();
}
///
/// Sets the response to some string, encoded as UTF-8.
///
/// The string to set the response to.
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);
}
}
}