//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Messaging {
using System;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Mime;
using System.Text;
///
/// Details on the incoming response from a direct web request to a remote party.
///
[ContractVerification(true)]
[ContractClass(typeof(IncomingWebResponseContract))]
public abstract class IncomingWebResponse : IDisposable {
///
/// The encoding to use in reading a response that does not declare its own content encoding.
///
private const string DefaultContentEncoding = "ISO-8859-1";
///
/// Initializes a new instance of the class.
///
protected internal IncomingWebResponse() {
this.Status = HttpStatusCode.OK;
this.Headers = new WebHeaderCollection();
}
///
/// Initializes a new instance of the class.
///
/// The original request URI.
/// The response to initialize from. The network stream is used by this class directly.
protected IncomingWebResponse(Uri requestUri, HttpWebResponse response) {
Requires.NotNull(requestUri, "requestUri");
Requires.NotNull(response, "response");
this.RequestUri = requestUri;
if (!string.IsNullOrEmpty(response.ContentType)) {
try {
this.ContentType = new ContentType(response.ContentType);
} catch (FormatException) {
Logger.Messaging.ErrorFormat("HTTP response to {0} included an invalid Content-Type header value: {1}", response.ResponseUri.AbsoluteUri, response.ContentType);
}
}
this.ContentEncoding = string.IsNullOrEmpty(response.ContentEncoding) ? DefaultContentEncoding : response.ContentEncoding;
this.FinalUri = response.ResponseUri;
this.Status = response.StatusCode;
this.Headers = response.Headers;
}
///
/// Initializes a new instance of the class.
///
/// The request URI.
/// The final URI to respond to the request.
/// The headers.
/// The status code.
/// Type of the content.
/// The content encoding.
protected IncomingWebResponse(Uri requestUri, Uri responseUri, WebHeaderCollection headers, HttpStatusCode statusCode, string contentType, string contentEncoding) {
Requires.NotNull(requestUri, "requestUri");
this.RequestUri = requestUri;
this.Status = statusCode;
if (!string.IsNullOrEmpty(contentType)) {
try {
this.ContentType = new ContentType(contentType);
} catch (FormatException) {
Logger.Messaging.ErrorFormat("HTTP response to {0} included an invalid Content-Type header value: {1}", responseUri.AbsoluteUri, contentType);
}
}
this.ContentEncoding = string.IsNullOrEmpty(contentEncoding) ? DefaultContentEncoding : contentEncoding;
this.Headers = headers;
this.FinalUri = responseUri;
}
///
/// Gets the type of the content.
///
public ContentType ContentType { get; private set; }
///
/// Gets the content encoding.
///
public string ContentEncoding { get; private set; }
///
/// Gets the URI of the initial request.
///
public Uri RequestUri { get; private set; }
///
/// Gets the URI that finally responded to the request.
///
///
/// This can be different from the in cases of
/// redirection during the request.
///
public Uri FinalUri { get; internal set; }
///
/// 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 HTTP status code to use in the HTTP response.
///
public HttpStatusCode Status { get; internal set; }
///
/// Gets the body of the HTTP response.
///
public abstract Stream ResponseStream { get; }
///
/// Returns a that represents the current .
///
///
/// A that represents the current .
///
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format(CultureInfo.CurrentCulture, "RequestUri = {0}", this.RequestUri));
sb.AppendLine(string.Format(CultureInfo.CurrentCulture, "ResponseUri = {0}", this.FinalUri));
sb.AppendLine(string.Format(CultureInfo.CurrentCulture, "StatusCode = {0}", this.Status));
sb.AppendLine(string.Format(CultureInfo.CurrentCulture, "ContentType = {0}", this.ContentType));
sb.AppendLine(string.Format(CultureInfo.CurrentCulture, "ContentEncoding = {0}", this.ContentEncoding));
sb.AppendLine("Headers:");
foreach (string header in this.Headers) {
sb.AppendLine(string.Format(CultureInfo.CurrentCulture, "\t{0}: {1}", header, this.Headers[header]));
}
return sb.ToString();
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Creates a text reader for the response stream.
///
/// The text reader, initialized for the proper encoding.
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Costly operation")]
public abstract StreamReader GetResponseReader();
///
/// Gets an offline snapshot version of this instance.
///
/// The maximum bytes from the response stream to cache.
/// A snapshot version of this instance.
///
/// If this instance is a creating a snapshot
/// will automatically close and dispose of the underlying response stream.
/// If this instance is a , the result will
/// be the self same instance.
///
internal abstract CachedDirectWebResponse GetSnapshot(int maximumBytesToCache);
///
/// Releases unmanaged and - optionally - managed resources
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing) {
if (disposing) {
Stream responseStream = this.ResponseStream;
if (responseStream != null) {
responseStream.Dispose();
}
}
}
}
}