Modified HttpListener.cs

This commit is contained in:
sta
2013-02-19 20:27:27 +09:00
parent f521779ed7
commit a376daedf0
24 changed files with 237 additions and 163 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11 -10
View File
@@ -1,6 +1,6 @@
// //
// HttpConnection.cs // HttpConnection.cs
// Copied from System.Net.HttpConnection // Copied from System.Net.HttpConnection.cs
// //
// Author: // Author:
// Gonzalo Paniagua Javier (gonzalo@novell.com) // Gonzalo Paniagua Javier (gonzalo@novell.com)
@@ -222,10 +222,12 @@ namespace WebSocketSharp.Net {
} catch { } catch {
if (ms != null && ms.Length > 0) if (ms != null && ms.Length > 0)
SendError (); SendError ();
if (sock != null) { if (sock != null) {
CloseSocket (); CloseSocket ();
Unbind (); Unbind ();
} }
return; return;
} }
@@ -252,6 +254,7 @@ namespace WebSocketSharp.Net {
Close (true); Close (true);
return; return;
} }
HttpListener listener = context.Listener; HttpListener listener = context.Listener;
if (last_listener != listener) { if (last_listener != listener) {
RemoveConnection (); RemoveConnection ();
@@ -263,6 +266,7 @@ namespace WebSocketSharp.Net {
listener.RegisterContext (context); listener.RegisterContext (context);
return; return;
} }
stream.BeginRead (buffer, 0, BufferSize, onread_cb, this); stream.BeginRead (buffer, 0, BufferSize, onread_cb, this);
} }
@@ -340,6 +344,7 @@ namespace WebSocketSharp.Net {
{ {
if (current_line == null) if (current_line == null)
current_line = new StringBuilder (); current_line = new StringBuilder ();
int last = offset + len; int last = offset + len;
used = 0; used = 0;
for (int i = offset; i < last && line_state != LineState.LF; i++) { for (int i = offset; i < last && line_state != LineState.LF; i++) {
@@ -396,15 +401,6 @@ namespace WebSocketSharp.Net {
force_close |= !context.Request.KeepAlive; force_close |= !context.Request.KeepAlive;
if (!force_close) if (!force_close)
force_close = (context.Response.Headers ["connection"] == "close"); force_close = (context.Response.Headers ["connection"] == "close");
/*
if (!force_close) {
// bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 ||
// status_code == 413 || status_code == 414 || status_code == 500 ||
// status_code == 503);
force_close |= (context.Request.ProtocolVersion <= HttpVersion.Version10);
}
*/
if (!force_close && context.Request.FlushInput ()) { if (!force_close && context.Request.FlushInput ()) {
if (chunked && context.Response.ForceCloseChunked == false) { if (chunked && context.Response.ForceCloseChunked == false) {
@@ -433,6 +429,7 @@ namespace WebSocketSharp.Net {
if (s != null) if (s != null)
s.Close (); s.Close ();
} }
Unbind (); Unbind ();
RemoveConnection (); RemoveConnection ();
return; return;
@@ -447,9 +444,11 @@ namespace WebSocketSharp.Net {
{ {
if (buffer == null) if (buffer == null)
buffer = new byte [BufferSize]; buffer = new byte [BufferSize];
try { try {
if (reuses == 1) if (reuses == 1)
s_timeout = 15000; s_timeout = 15000;
timer.Change (s_timeout, Timeout.Infinite); timer.Change (s_timeout, Timeout.Infinite);
stream.BeginRead (buffer, 0, BufferSize, onread_cb, this); stream.BeginRead (buffer, 0, BufferSize, onread_cb, this);
} catch { } catch {
@@ -478,6 +477,7 @@ namespace WebSocketSharp.Net {
i_stream = new RequestStream (stream, buffer, position, length - position, contentlength); i_stream = new RequestStream (stream, buffer, position, length - position, contentlength);
} }
} }
return i_stream; return i_stream;
} }
@@ -489,6 +489,7 @@ namespace WebSocketSharp.Net {
bool ign = (listener == null) ? true : listener.IgnoreWriteExceptions; bool ign = (listener == null) ? true : listener.IgnoreWriteExceptions;
o_stream = new ResponseStream (stream, context.Response, ign); o_stream = new ResponseStream (stream, context.Response, ign);
} }
return o_stream; return o_stream;
} }
+70 -44
View File
@@ -177,48 +177,67 @@ namespace WebSocketSharp.Net {
#region Private Methods #region Private Methods
void Cleanup (bool close_existing) void Cleanup (bool force)
{ {
lock (((ICollection)registry).SyncRoot) { lock (((ICollection)registry).SyncRoot) {
if (close_existing) { if (!force)
// Need to copy this since closing will call UnregisterContext SendServiceUnavailable ();
ICollection keys = registry.Keys;
var all = new HttpListenerContext [keys.Count]; CleanupContextRegistry ();
keys.CopyTo (all, 0); CleanupConnections ();
registry.Clear (); CleanupWaitQueue ();
for (int i = all.Length - 1; i >= 0; i--) }
all [i].Connection.Close (true); }
void CleanupConnections ()
{
lock (((ICollection)connections).SyncRoot) {
if (connections.Count == 0)
return;
// Need to copy this since closing will call RemoveConnection
ICollection keys = connections.Keys;
var conns = new HttpConnection [keys.Count];
keys.CopyTo (conns, 0);
connections.Clear ();
for (int i = conns.Length - 1; i >= 0; i--)
conns [i].Close (true);
}
}
void CleanupContextRegistry ()
{
lock (((ICollection)registry).SyncRoot) {
if (registry.Count == 0)
return;
// Need to copy this since closing will call UnregisterContext
ICollection keys = registry.Keys;
var all = new HttpListenerContext [keys.Count];
keys.CopyTo (all, 0);
registry.Clear ();
for (int i = all.Length - 1; i >= 0; i--)
all [i].Connection.Close (true);
}
}
void CleanupWaitQueue ()
{
lock (((ICollection)wait_queue).SyncRoot) {
if (wait_queue.Count == 0)
return;
var exc = new ObjectDisposedException (GetType ().ToString ());
foreach (var ares in wait_queue) {
ares.Complete (exc);
} }
lock (((ICollection)connections).SyncRoot) { wait_queue.Clear ();
ICollection keys = connections.Keys;
var conns = new HttpConnection [keys.Count];
keys.CopyTo (conns, 0);
connections.Clear ();
for (int i = conns.Length - 1; i >= 0; i--)
conns [i].Close (true);
}
lock (((ICollection)ctx_queue).SyncRoot) {
var ctxs = ctx_queue.ToArray ();
ctx_queue.Clear ();
for (int i = ctxs.Length - 1; i >= 0; i--)
ctxs [i].Connection.Close (true);
}
lock (((ICollection)wait_queue).SyncRoot) {
Exception exc = new ObjectDisposedException ("listener");
foreach (ListenerAsyncResult ares in wait_queue) {
ares.Complete (exc);
}
wait_queue.Clear ();
}
} }
} }
void Close (bool force) void Close (bool force)
{ {
CheckDisposed ();
EndPointManager.RemoveListener (this); EndPointManager.RemoveListener (this);
Cleanup (force); Cleanup (force);
} }
@@ -234,6 +253,22 @@ namespace WebSocketSharp.Net {
return context; return context;
} }
void SendServiceUnavailable ()
{
lock (((ICollection)ctx_queue).SyncRoot) {
if (ctx_queue.Count == 0)
return;
var ctxs = ctx_queue.ToArray ();
ctx_queue.Clear ();
foreach (var ctx in ctxs) {
var res = ctx.Response;
res.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
res.Close();
}
}
}
#endregion #endregion
#region Internal Methods #region Internal Methods
@@ -322,11 +357,6 @@ namespace WebSocketSharp.Net {
if (disposed) if (disposed)
return; return;
if (!listening) {
disposed = true;
return;
}
Close (true); Close (true);
disposed = true; disposed = true;
} }
@@ -383,11 +413,6 @@ namespace WebSocketSharp.Net {
if (disposed) if (disposed)
return; return;
if (!listening) {
disposed = true;
return;
}
Close (false); Close (false);
disposed = true; disposed = true;
} }
@@ -487,8 +512,9 @@ namespace WebSocketSharp.Net {
if (!listening) if (!listening)
return; return;
EndPointManager.RemoveListener (this);
listening = false; listening = false;
EndPointManager.RemoveListener (this);
SendServiceUnavailable ();
} }
#endregion #endregion
@@ -459,6 +459,7 @@ namespace WebSocketSharp.Net {
IAsyncResult ares = InputStream.BeginRead (bytes, 0, length, null, null); IAsyncResult ares = InputStream.BeginRead (bytes, 0, length, null, null);
if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (100)) if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (100))
return false; return false;
if (InputStream.EndRead (ares) <= 0) if (InputStream.EndRead (ares) <= 0)
return true; return true;
} catch { } catch {
+10 -5
View File
@@ -175,6 +175,7 @@ namespace WebSocketSharp.Net {
get { get {
if (output_stream == null) if (output_stream == null)
output_stream = context.Connection.GetResponseStream (); output_stream = context.Connection.GetResponseStream ();
return output_stream; return output_stream;
} }
} }
@@ -261,11 +262,6 @@ namespace WebSocketSharp.Net {
context.Connection.Close (force); context.Connection.Close (force);
} }
void IDisposable.Dispose ()
{
Close (true); // TODO: Abort or Close?
}
bool FindCookie (Cookie cookie) bool FindCookie (Cookie cookie)
{ {
string name = cookie.Name; string name = cookie.Name;
@@ -396,6 +392,15 @@ namespace WebSocketSharp.Net {
#endregion #endregion
#region Explicit Interface Implementation
void IDisposable.Dispose ()
{
Close (true); // TODO: Abort or Close?
}
#endregion
#region Public Methods #region Public Methods
public void Abort () public void Abort ()
+138 -97
View File
@@ -1,6 +1,6 @@
// //
// ResponseStream.cs // ResponseStream.cs
// Copied from System.Net.ResponseStream // Copied from System.Net.ResponseStream.cs
// //
// Author: // Author:
// Gonzalo Paniagua Javier (gonzalo@novell.com) // Gonzalo Paniagua Javier (gonzalo@novell.com)
@@ -40,22 +40,37 @@ namespace WebSocketSharp.Net {
// Update: we send a single packet for the first non-chunked Write // Update: we send a single packet for the first non-chunked Write
// What happens when we set content-length to X and write X-1 bytes then close? // What happens when we set content-length to X and write X-1 bytes then close?
// what if we don't set content-length at all? // what if we don't set content-length at all?
class ResponseStream : Stream class ResponseStream : Stream {
{
#region Private Static Field
static byte [] crlf = new byte [] { 13, 10 };
#endregion
#region Private Fields
bool disposed;
bool ignore_errors;
HttpListenerResponse response; HttpListenerResponse response;
bool ignore_errors; Stream stream;
bool disposed; bool trailer_sent;
bool trailer_sent;
System.IO.Stream stream; #endregion
#region Constructor
internal ResponseStream (System.IO.Stream stream, HttpListenerResponse response, bool ignore_errors) internal ResponseStream (System.IO.Stream stream, HttpListenerResponse response, bool ignore_errors)
{ {
this.stream = stream;
this.response = response; this.response = response;
this.ignore_errors = ignore_errors; this.ignore_errors = ignore_errors;
this.stream = stream;
} }
#endregion
#region Properties
public override bool CanRead { public override bool CanRead {
get { return false; } get { return false; }
} }
@@ -77,6 +92,88 @@ namespace WebSocketSharp.Net {
set { throw new NotSupportedException (); } set { throw new NotSupportedException (); }
} }
#endregion
#region Private Methods
static byte [] GetChunkSizeBytes (int size, bool final)
{
string str = String.Format ("{0:x}\r\n{1}", size, final ? "\r\n" : "");
return Encoding.ASCII.GetBytes (str);
}
MemoryStream GetHeaders (bool closing)
{
if (response.HeadersSent)
return null;
MemoryStream ms = new MemoryStream ();
response.SendHeaders (closing, ms);
return ms;
}
#endregion
#region Internal Method
internal void InternalWrite (byte [] buffer, int offset, int count)
{
if (ignore_errors) {
try {
stream.Write (buffer, offset, count);
} catch {
}
} else {
stream.Write (buffer, offset, count);
}
}
#endregion
#region Public Methods
public override IAsyncResult BeginRead (
byte [] buffer,
int offset,
int count,
AsyncCallback cback,
object state)
{
throw new NotSupportedException ();
}
public override IAsyncResult BeginWrite (
byte [] buffer,
int offset,
int count,
AsyncCallback cback,
object state)
{
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
byte [] bytes = null;
MemoryStream ms = GetHeaders (false);
bool chunked = response.SendChunked;
if (ms != null) {
long start = ms.Position;
ms.Position = ms.Length;
if (chunked) {
bytes = GetChunkSizeBytes (count, false);
ms.Write (bytes, 0, bytes.Length);
}
ms.Write (buffer, offset, count);
buffer = ms.GetBuffer ();
offset = (int) start;
count = (int) (ms.Position - start);
} else if (chunked) {
bytes = GetChunkSizeBytes (count, false);
InternalWrite (bytes, 0, bytes.Length);
}
return stream.BeginWrite (buffer, offset, count, cback, state);
}
public override void Close () public override void Close ()
{ {
@@ -99,39 +196,52 @@ namespace WebSocketSharp.Net {
InternalWrite (bytes, 0, bytes.Length); InternalWrite (bytes, 0, bytes.Length);
trailer_sent = true; trailer_sent = true;
} }
response.Close (); response.Close ();
} }
} }
MemoryStream GetHeaders (bool closing) public override int EndRead (IAsyncResult ares)
{ {
if (response.HeadersSent) throw new NotSupportedException ();
return null; }
MemoryStream ms = new MemoryStream ();
response.SendHeaders (closing, ms); public override void EndWrite (IAsyncResult ares)
return ms; {
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
if (ignore_errors) {
try {
stream.EndWrite (ares);
if (response.SendChunked)
stream.Write (crlf, 0, 2);
} catch {
}
} else {
stream.EndWrite (ares);
if (response.SendChunked)
stream.Write (crlf, 0, 2);
}
} }
public override void Flush () public override void Flush ()
{ {
} }
static byte [] crlf = new byte [] { 13, 10 }; public override int Read ([In,Out] byte[] buffer, int offset, int count)
static byte [] GetChunkSizeBytes (int size, bool final)
{ {
string str = String.Format ("{0:x}\r\n{1}", size, final ? "\r\n" : ""); throw new NotSupportedException ();
return Encoding.ASCII.GetBytes (str);
} }
internal void InternalWrite (byte [] buffer, int offset, int count) public override long Seek (long offset, SeekOrigin origin)
{ {
if (ignore_errors) { throw new NotSupportedException ();
try { }
stream.Write (buffer, offset, count);
} catch { } public override void SetLength (long value)
} else { {
stream.Write (buffer, offset, count); throw new NotSupportedException ();
}
} }
public override void Write (byte [] buffer, int offset, int count) public override void Write (byte [] buffer, int offset, int count)
@@ -164,80 +274,11 @@ namespace WebSocketSharp.Net {
if (count > 0) if (count > 0)
InternalWrite (buffer, offset, count); InternalWrite (buffer, offset, count);
if (chunked) if (chunked)
InternalWrite (crlf, 0, 2); InternalWrite (crlf, 0, 2);
} }
public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count, #endregion
AsyncCallback cback, object state)
{
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
byte [] bytes = null;
MemoryStream ms = GetHeaders (false);
bool chunked = response.SendChunked;
if (ms != null) {
long start = ms.Position;
ms.Position = ms.Length;
if (chunked) {
bytes = GetChunkSizeBytes (count, false);
ms.Write (bytes, 0, bytes.Length);
}
ms.Write (buffer, offset, count);
buffer = ms.GetBuffer ();
offset = (int) start;
count = (int) (ms.Position - start);
} else if (chunked) {
bytes = GetChunkSizeBytes (count, false);
InternalWrite (bytes, 0, bytes.Length);
}
return stream.BeginWrite (buffer, offset, count, cback, state);
}
public override void EndWrite (IAsyncResult ares)
{
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
if (ignore_errors) {
try {
stream.EndWrite (ares);
if (response.SendChunked)
stream.Write (crlf, 0, 2);
} catch { }
} else {
stream.EndWrite (ares);
if (response.SendChunked)
stream.Write (crlf, 0, 2);
}
}
public override int Read ([In,Out] byte[] buffer, int offset, int count)
{
throw new NotSupportedException ();
}
public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
AsyncCallback cback, object state)
{
throw new NotSupportedException ();
}
public override int EndRead (IAsyncResult ares)
{
throw new NotSupportedException ();
}
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
} }
} }
Binary file not shown.
Binary file not shown.