Refactored HttpListenerResponse.cs

This commit is contained in:
sta 2014-08-20 23:19:29 +09:00
parent e7aa1a469d
commit d942e75419
2 changed files with 46 additions and 48 deletions

View File

@ -58,14 +58,14 @@ namespace WebSocketSharp.Net
private bool _chunked; private bool _chunked;
private Encoding _contentEncoding; private Encoding _contentEncoding;
private long _contentLength; private long _contentLength;
private bool _contentLengthSet; private bool _contentLengthWasSet;
private string _contentType; private string _contentType;
private HttpListenerContext _context; private HttpListenerContext _context;
private CookieCollection _cookies; private CookieCollection _cookies;
private bool _disposed; private bool _disposed;
private bool _forceCloseChunked; private bool _forceCloseChunked;
private WebHeaderCollection _headers; private WebHeaderCollection _headers;
private bool _headersSent; private bool _headersWereSent;
private bool _keepAlive; private bool _keepAlive;
private string _location; private string _location;
private ResponseStream _outputStream; private ResponseStream _outputStream;
@ -105,7 +105,7 @@ namespace WebSocketSharp.Net
internal bool HeadersSent { internal bool HeadersSent {
get { get {
return _headersSent; return _headersWereSent;
} }
} }
@ -117,8 +117,8 @@ namespace WebSocketSharp.Net
/// Gets or sets the encoding for the entity body data included in the response. /// Gets or sets the encoding for the entity body data included in the response.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="Encoding"/> that represents the encoding for the entity body data, or /// A <see cref="Encoding"/> that represents the encoding for the entity body data,
/// <see langword="null"/> if no encoding is specified. /// or <see langword="null"/> if no encoding is specified.
/// </value> /// </value>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
/// The response has already been sent. /// The response has already been sent.
@ -142,7 +142,7 @@ namespace WebSocketSharp.Net
/// Gets or sets the size of the entity body data included in the response. /// Gets or sets the size of the entity body data included in the response.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="long"/> that represents the value of the Content-Length entity-header field. /// A <see cref="long"/> that represents the value of the Content-Length entity-header.
/// The value is a number of bytes in the entity body data. /// The value is a number of bytes in the entity body data.
/// </value> /// </value>
/// <exception cref="ArgumentOutOfRangeException"> /// <exception cref="ArgumentOutOfRangeException">
@ -165,7 +165,7 @@ namespace WebSocketSharp.Net
if (value < 0) if (value < 0)
throw new ArgumentOutOfRangeException ("Less than zero.", "value"); throw new ArgumentOutOfRangeException ("Less than zero.", "value");
_contentLengthSet = true; _contentLengthWasSet = true;
_contentLength = value; _contentLength = value;
} }
} }
@ -174,8 +174,7 @@ namespace WebSocketSharp.Net
/// Gets or sets the media type of the entity body included in the response. /// Gets or sets the media type of the entity body included in the response.
/// </summary> /// </summary>
/// <value> /// <value>
/// The type of the content. A <see cref="string"/> that represents the value of /// A <see cref="string"/> that represents the value of the Content-Type entity-header.
/// the Content-Type entity-header field.
/// </value> /// </value>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// The value specified for a set operation is empty. /// The value specified for a set operation is empty.
@ -208,10 +207,10 @@ namespace WebSocketSharp.Net
} }
/// <summary> /// <summary>
/// Gets or sets the cookies returned with the response. /// Gets or sets the cookies sent with the response.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="CookieCollection"/> that contains the cookies returned with the response. /// A <see cref="CookieCollection"/> that contains the cookies sent with the response.
/// </value> /// </value>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
/// The response has already been sent. /// The response has already been sent.
@ -232,10 +231,10 @@ namespace WebSocketSharp.Net
} }
/// <summary> /// <summary>
/// Gets or sets the HTTP headers returned to the client. /// Gets or sets the HTTP headers sent to the client.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="WebHeaderCollection"/> that contains the headers returned to the client. /// A <see cref="WebHeaderCollection"/> that contains the headers sent to the client.
/// </value> /// </value>
/// <exception cref="ArgumentNullException"> /// <exception cref="ArgumentNullException">
/// The value specified for a set operation is <see langword="null"/>. /// The value specified for a set operation is <see langword="null"/>.
@ -256,7 +255,7 @@ namespace WebSocketSharp.Net
/* /*
* "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, * "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding,
* or WWW-Authenticate header using the Headers property, an exception * or WWW-Authenticate header using the Headers property, an exception
* will be thrown. Use the KeepAlive or ContentLength64 properties to set * will be thrown. Use the ContentLength64 or KeepAlive properties to set
* these headers. You cannot set the Transfer-Encoding or WWW-Authenticate * these headers. You cannot set the Transfer-Encoding or WWW-Authenticate
* headers manually." * headers manually."
*/ */
@ -316,7 +315,7 @@ namespace WebSocketSharp.Net
/// Gets or sets the HTTP version used in the response. /// Gets or sets the HTTP version used in the response.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="Version"/> that represents the HTTP version used in the response. /// A <see cref="Version"/> that represents the version used in the response.
/// </value> /// </value>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// The value specified for a set operation doesn't have its <c>Major</c> property set to 1 or /// The value specified for a set operation doesn't have its <c>Major</c> property set to 1 or
@ -343,7 +342,7 @@ namespace WebSocketSharp.Net
throw new ArgumentNullException ("value"); throw new ArgumentNullException ("value");
if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1)) if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
throw new ArgumentException ("Neither 1.0 nor 1.1.", "value"); throw new ArgumentException ("Not 1.0 or 1.1.", "value");
_version = value; _version = value;
} }
@ -353,7 +352,7 @@ namespace WebSocketSharp.Net
/// Gets or sets the URL to which the client is redirected to locate a requested resource. /// Gets or sets the URL to which the client is redirected to locate a requested resource.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="string"/> that represents the value of the Location response-header field. /// A <see cref="string"/> that represents the value of the Location response-header.
/// </value> /// </value>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// The value specified for a set operation is empty. /// The value specified for a set operation is empty.
@ -406,7 +405,7 @@ namespace WebSocketSharp.Net
/// Gets or sets the HTTP status code returned to the client. /// Gets or sets the HTTP status code returned to the client.
/// </summary> /// </summary>
/// <value> /// <value>
/// An <see cref="int"/> that represents the HTTP status code for the response to the request. /// An <see cref="int"/> that represents the status code for the response to the request.
/// The default value is <see cref="HttpStatusCode.OK"/>. /// The default value is <see cref="HttpStatusCode.OK"/>.
/// </value> /// </value>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
@ -428,7 +427,7 @@ namespace WebSocketSharp.Net
checkDisposedOrHeadersSent (); checkDisposedOrHeadersSent ();
if (value < 100 || value > 999) if (value < 100 || value > 999)
throw new System.Net.ProtocolViolationException ( throw new System.Net.ProtocolViolationException (
"StatusCode must be between 100 and 999."); "StatusCode isn't between 100 and 999.");
_statusCode = value; _statusCode = value;
_statusDescription = value.GetStatusDescription (); _statusDescription = value.GetStatusDescription ();
@ -439,7 +438,7 @@ namespace WebSocketSharp.Net
/// Gets or sets the description of the HTTP status code returned to the client. /// Gets or sets the description of the HTTP status code returned to the client.
/// </summary> /// </summary>
/// <value> /// <value>
/// A <see cref="string"/> that represents the description of the HTTP status code. /// A <see cref="string"/> that represents the description of the status code.
/// </value> /// </value>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
/// The response has already been sent. /// The response has already been sent.
@ -455,9 +454,9 @@ namespace WebSocketSharp.Net
set { set {
checkDisposedOrHeadersSent (); checkDisposedOrHeadersSent ();
_statusDescription = value == null || value.Length == 0 _statusDescription = value != null && value.Length > 0
? _statusCode.GetStatusDescription () ? value
: value; : _statusCode.GetStatusDescription ();
} }
} }
@ -474,9 +473,9 @@ namespace WebSocketSharp.Net
if (found.Count == 0) if (found.Count == 0)
return true; return true;
var version = cookie.Version; var ver = cookie.Version;
foreach (var c in found) foreach (var c in found)
if (c.Version == version) if (c.Version == ver)
return true; return true;
return false; return false;
@ -493,7 +492,7 @@ namespace WebSocketSharp.Net
if (_disposed) if (_disposed)
throw new ObjectDisposedException (GetType ().ToString ()); throw new ObjectDisposedException (GetType ().ToString ());
if (_headersSent) if (_headersWereSent)
throw new InvalidOperationException ("Cannot be changed after headers are sent."); throw new InvalidOperationException ("Cannot be changed after headers are sent.");
} }
@ -520,7 +519,7 @@ namespace WebSocketSharp.Net
#region Internal Methods #region Internal Methods
internal void SendHeaders (bool closing, MemoryStream stream) internal void SendHeaders (MemoryStream stream, bool closing)
{ {
if (_contentType != null) { if (_contentType != null) {
var contentType = _contentEncoding != null && var contentType = _contentEncoding != null &&
@ -539,17 +538,17 @@ namespace WebSocketSharp.Net
_headers.SetInternally ("Date", DateTime.UtcNow.ToString ("r", provider), true); _headers.SetInternally ("Date", DateTime.UtcNow.ToString ("r", provider), true);
if (!_chunked) { if (!_chunked) {
if (!_contentLengthSet && closing) { if (!_contentLengthWasSet && closing) {
_contentLengthSet = true; _contentLengthWasSet = true;
_contentLength = 0; _contentLength = 0;
} }
if (_contentLengthSet) if (_contentLengthWasSet)
_headers.SetInternally ("Content-Length", _contentLength.ToString (provider), true); _headers.SetInternally ("Content-Length", _contentLength.ToString (provider), true);
} }
var version = _context.Request.ProtocolVersion; var ver = _context.Request.ProtocolVersion;
if (!_contentLengthSet && !_chunked && version >= HttpVersion.Version11) if (!_contentLengthWasSet && !_chunked && ver > HttpVersion.Version10)
_chunked = true; _chunked = true;
/* Apache forces closing the connection for these status codes: /* Apache forces closing the connection for these status codes:
@ -581,7 +580,7 @@ namespace WebSocketSharp.Net
if (_chunked) if (_chunked)
_headers.SetInternally ("Transfer-Encoding", "chunked", true); _headers.SetInternally ("Transfer-Encoding", "chunked", true);
int reuses = _context.Connection.Reuses; var reuses = _context.Connection.Reuses;
if (reuses >= 100) { if (reuses >= 100) {
_forceCloseChunked = true; _forceCloseChunked = true;
if (!connClose) { if (!connClose) {
@ -605,21 +604,21 @@ namespace WebSocketSharp.Net
foreach (Cookie cookie in _cookies) foreach (Cookie cookie in _cookies)
_headers.SetInternally ("Set-Cookie", cookie.ToResponseString (), true); _headers.SetInternally ("Set-Cookie", cookie.ToResponseString (), true);
var encoding = _contentEncoding ?? Encoding.Default; var enc = _contentEncoding ?? Encoding.Default;
var writer = new StreamWriter (stream, encoding, 256); var writer = new StreamWriter (stream, enc, 256);
writer.Write ("HTTP/{0} {1} {2}\r\n", _version, _statusCode, _statusDescription); writer.Write ("HTTP/{0} {1} {2}\r\n", _version, _statusCode, _statusDescription);
var headers = _headers.ToStringMultiValue (true); var headers = _headers.ToStringMultiValue (true);
writer.Write (headers); writer.Write (headers);
writer.Flush (); writer.Flush ();
var preamble = encoding.CodePage == 65001 ? 3 : encoding.GetPreamble ().Length; var preamble = enc.CodePage == 65001 ? 3 : enc.GetPreamble ().Length;
if (_outputStream == null) if (_outputStream == null)
_outputStream = _context.Connection.GetResponseStream (); _outputStream = _context.Connection.GetResponseStream ();
// Assumes that the stream was at position 0. // Assumes that the stream was at position 0.
stream.Position = preamble; stream.Position = preamble;
_headersSent = true; _headersWereSent = true;
} }
#endregion #endregion
@ -627,7 +626,7 @@ namespace WebSocketSharp.Net
#region Public Methods #region Public Methods
/// <summary> /// <summary>
/// Closes the connection to the client without sending a response. /// Closes the connection to the client without returning a response.
/// </summary> /// </summary>
public void Abort () public void Abort ()
{ {
@ -753,7 +752,7 @@ namespace WebSocketSharp.Net
} }
/// <summary> /// <summary>
/// Sends the response to the client, and releases the resources used by /// Returns the response to the client and releases the resources used by
/// this <see cref="HttpListenerResponse"/> instance. /// this <see cref="HttpListenerResponse"/> instance.
/// </summary> /// </summary>
public void Close () public void Close ()
@ -765,7 +764,7 @@ namespace WebSocketSharp.Net
} }
/// <summary> /// <summary>
/// Sends the response with the specified array of <see cref="byte"/> to the client, and /// Returns the response with the specified array of <see cref="byte"/> to the client and
/// releases the resources used by this <see cref="HttpListenerResponse"/> instance. /// releases the resources used by this <see cref="HttpListenerResponse"/> instance.
/// </summary> /// </summary>
/// <param name="responseEntity"> /// <param name="responseEntity">
@ -862,7 +861,7 @@ namespace WebSocketSharp.Net
/// A <see cref="Cookie"/> to set. /// A <see cref="Cookie"/> to set.
/// </param> /// </param>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// <paramref name="cookie"/> already exists in the cookies, and couldn't be replaced. /// <paramref name="cookie"/> already exists in the cookies and couldn't be replaced.
/// </exception> /// </exception>
/// <exception cref="ArgumentNullException"> /// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>. /// <paramref name="cookie"/> is <see langword="null"/>.
@ -890,14 +889,13 @@ namespace WebSocketSharp.Net
#region Explicit Interface Implementation #region Explicit Interface Implementation
/// <summary> /// <summary>
/// Releases all resource used by the <see cref="HttpListenerResponse"/>. /// Releases all resources used by the <see cref="HttpListenerResponse"/>.
/// </summary> /// </summary>
void IDisposable.Dispose () void IDisposable.Dispose ()
{ {
if (_disposed) if (_disposed)
return; return;
// TODO: Abort or Close?
close (true); // Same as Abort. close (true); // Same as Abort.
} }

View File

@ -127,7 +127,7 @@ namespace WebSocketSharp.Net
return null; return null;
var stream = new MemoryStream (); var stream = new MemoryStream ();
_response.SendHeaders (closing, stream); _response.SendHeaders (stream, closing);
return stream; return stream;
} }