//----------------------------------------------------------------------- // // 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(); } } } } }