diff --git a/Example/bin/Debug_Ubuntu/example.exe b/Example/bin/Debug_Ubuntu/example.exe index 1c5dd95c..585f2b4e 100755 Binary files a/Example/bin/Debug_Ubuntu/example.exe and b/Example/bin/Debug_Ubuntu/example.exe differ diff --git a/Example/bin/Debug_Ubuntu/example.exe.mdb b/Example/bin/Debug_Ubuntu/example.exe.mdb index 496d4e27..5322718f 100644 Binary files a/Example/bin/Debug_Ubuntu/example.exe.mdb and b/Example/bin/Debug_Ubuntu/example.exe.mdb differ diff --git a/Example/bin/Debug_Ubuntu/websocket-sharp.dll b/Example/bin/Debug_Ubuntu/websocket-sharp.dll index 9ec61596..d8a55827 100755 Binary files a/Example/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb index 0df3d850..ae5b58c7 100644 Binary files a/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ diff --git a/Example1/bin/Debug_Ubuntu/example1.exe b/Example1/bin/Debug_Ubuntu/example1.exe index fe314e5b..46c3d572 100755 Binary files a/Example1/bin/Debug_Ubuntu/example1.exe and b/Example1/bin/Debug_Ubuntu/example1.exe differ diff --git a/Example1/bin/Debug_Ubuntu/example1.exe.mdb b/Example1/bin/Debug_Ubuntu/example1.exe.mdb index 29a9cb13..f3329eab 100644 Binary files a/Example1/bin/Debug_Ubuntu/example1.exe.mdb and b/Example1/bin/Debug_Ubuntu/example1.exe.mdb differ diff --git a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll index 9ec61596..d8a55827 100755 Binary files a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb index 0df3d850..ae5b58c7 100644 Binary files a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ diff --git a/Example2/bin/Debug_Ubuntu/example2.exe b/Example2/bin/Debug_Ubuntu/example2.exe index 5fd9ffb1..5ef45af6 100755 Binary files a/Example2/bin/Debug_Ubuntu/example2.exe and b/Example2/bin/Debug_Ubuntu/example2.exe differ diff --git a/Example2/bin/Debug_Ubuntu/example2.exe.mdb b/Example2/bin/Debug_Ubuntu/example2.exe.mdb index def5486d..f9f99e04 100644 Binary files a/Example2/bin/Debug_Ubuntu/example2.exe.mdb and b/Example2/bin/Debug_Ubuntu/example2.exe.mdb differ diff --git a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll index 9ec61596..d8a55827 100755 Binary files a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb index 0df3d850..ae5b58c7 100644 Binary files a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ diff --git a/Example3/bin/Debug_Ubuntu/Example3.exe b/Example3/bin/Debug_Ubuntu/Example3.exe index eead21a2..8568acf6 100755 Binary files a/Example3/bin/Debug_Ubuntu/Example3.exe and b/Example3/bin/Debug_Ubuntu/Example3.exe differ diff --git a/Example3/bin/Debug_Ubuntu/Example3.exe.mdb b/Example3/bin/Debug_Ubuntu/Example3.exe.mdb index 673e1880..ee021517 100644 Binary files a/Example3/bin/Debug_Ubuntu/Example3.exe.mdb and b/Example3/bin/Debug_Ubuntu/Example3.exe.mdb differ diff --git a/Example3/bin/Debug_Ubuntu/websocket-sharp.dll b/Example3/bin/Debug_Ubuntu/websocket-sharp.dll index 9ec61596..d8a55827 100755 Binary files a/Example3/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example3/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example3/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example3/bin/Debug_Ubuntu/websocket-sharp.dll.mdb index 0df3d850..ae5b58c7 100644 Binary files a/Example3/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/Example3/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs index 2d0b8d67..5bde46cf 100644 --- a/websocket-sharp/Net/HttpConnection.cs +++ b/websocket-sharp/Net/HttpConnection.cs @@ -1,6 +1,6 @@ // // HttpConnection.cs -// Copied from System.Net.HttpConnection +// Copied from System.Net.HttpConnection.cs // // Author: // Gonzalo Paniagua Javier (gonzalo@novell.com) @@ -222,10 +222,12 @@ namespace WebSocketSharp.Net { } catch { if (ms != null && ms.Length > 0) SendError (); + if (sock != null) { CloseSocket (); Unbind (); } + return; } @@ -252,6 +254,7 @@ namespace WebSocketSharp.Net { Close (true); return; } + HttpListener listener = context.Listener; if (last_listener != listener) { RemoveConnection (); @@ -263,6 +266,7 @@ namespace WebSocketSharp.Net { listener.RegisterContext (context); return; } + stream.BeginRead (buffer, 0, BufferSize, onread_cb, this); } @@ -340,6 +344,7 @@ namespace WebSocketSharp.Net { { if (current_line == null) current_line = new StringBuilder (); + int last = offset + len; used = 0; for (int i = offset; i < last && line_state != LineState.LF; i++) { @@ -396,15 +401,6 @@ namespace WebSocketSharp.Net { force_close |= !context.Request.KeepAlive; if (!force_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 (chunked && context.Response.ForceCloseChunked == false) { @@ -433,6 +429,7 @@ namespace WebSocketSharp.Net { if (s != null) s.Close (); } + Unbind (); RemoveConnection (); return; @@ -447,9 +444,11 @@ namespace WebSocketSharp.Net { { if (buffer == null) buffer = new byte [BufferSize]; + try { if (reuses == 1) s_timeout = 15000; + timer.Change (s_timeout, Timeout.Infinite); stream.BeginRead (buffer, 0, BufferSize, onread_cb, this); } catch { @@ -478,6 +477,7 @@ namespace WebSocketSharp.Net { i_stream = new RequestStream (stream, buffer, position, length - position, contentlength); } } + return i_stream; } @@ -489,6 +489,7 @@ namespace WebSocketSharp.Net { bool ign = (listener == null) ? true : listener.IgnoreWriteExceptions; o_stream = new ResponseStream (stream, context.Response, ign); } + return o_stream; } diff --git a/websocket-sharp/Net/HttpListener.cs b/websocket-sharp/Net/HttpListener.cs index 2cff724f..aafa11dd 100644 --- a/websocket-sharp/Net/HttpListener.cs +++ b/websocket-sharp/Net/HttpListener.cs @@ -177,48 +177,67 @@ namespace WebSocketSharp.Net { #region Private Methods - void Cleanup (bool close_existing) + void Cleanup (bool force) { lock (((ICollection)registry).SyncRoot) { - if (close_existing) { - // 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); - } + if (!force) + SendServiceUnavailable (); - lock (((ICollection)connections).SyncRoot) { - 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); - } + CleanupContextRegistry (); + CleanupConnections (); + CleanupWaitQueue (); + } + } - 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); - } + 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); + } + } - lock (((ICollection)wait_queue).SyncRoot) { - Exception exc = new ObjectDisposedException ("listener"); - foreach (ListenerAsyncResult ares in wait_queue) { - ares.Complete (exc); - } - wait_queue.Clear (); + 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); } + + wait_queue.Clear (); } } void Close (bool force) { - CheckDisposed (); EndPointManager.RemoveListener (this); Cleanup (force); } @@ -234,6 +253,22 @@ namespace WebSocketSharp.Net { 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 #region Internal Methods @@ -322,11 +357,6 @@ namespace WebSocketSharp.Net { if (disposed) return; - if (!listening) { - disposed = true; - return; - } - Close (true); disposed = true; } @@ -383,11 +413,6 @@ namespace WebSocketSharp.Net { if (disposed) return; - if (!listening) { - disposed = true; - return; - } - Close (false); disposed = true; } @@ -487,8 +512,9 @@ namespace WebSocketSharp.Net { if (!listening) return; - EndPointManager.RemoveListener (this); listening = false; + EndPointManager.RemoveListener (this); + SendServiceUnavailable (); } #endregion diff --git a/websocket-sharp/Net/HttpListenerRequest.cs b/websocket-sharp/Net/HttpListenerRequest.cs index 9015faa7..a172dea2 100644 --- a/websocket-sharp/Net/HttpListenerRequest.cs +++ b/websocket-sharp/Net/HttpListenerRequest.cs @@ -459,6 +459,7 @@ namespace WebSocketSharp.Net { IAsyncResult ares = InputStream.BeginRead (bytes, 0, length, null, null); if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (100)) return false; + if (InputStream.EndRead (ares) <= 0) return true; } catch { diff --git a/websocket-sharp/Net/HttpListenerResponse.cs b/websocket-sharp/Net/HttpListenerResponse.cs index fe47745d..183fae2b 100644 --- a/websocket-sharp/Net/HttpListenerResponse.cs +++ b/websocket-sharp/Net/HttpListenerResponse.cs @@ -166,7 +166,7 @@ namespace WebSocketSharp.Net { if (HeadersSent) throw new InvalidOperationException ("Cannot be changed after headers are sent."); - + keep_alive = value; } } @@ -175,10 +175,11 @@ namespace WebSocketSharp.Net { get { if (output_stream == null) output_stream = context.Connection.GetResponseStream (); + return output_stream; } } - + public Version ProtocolVersion { get { return version; } set { @@ -209,7 +210,7 @@ namespace WebSocketSharp.Net { if (HeadersSent) throw new InvalidOperationException ("Cannot be changed after headers are sent."); - + location = value; } } @@ -222,7 +223,7 @@ namespace WebSocketSharp.Net { if (HeadersSent) throw new InvalidOperationException ("Cannot be changed after headers are sent."); - + chunked = value; } } @@ -261,11 +262,6 @@ namespace WebSocketSharp.Net { context.Connection.Close (force); } - void IDisposable.Dispose () - { - Close (true); // TODO: Abort or Close? - } - bool FindCookie (Cookie cookie) { string name = cookie.Name; @@ -396,6 +392,15 @@ namespace WebSocketSharp.Net { #endregion + #region Explicit Interface Implementation + + void IDisposable.Dispose () + { + Close (true); // TODO: Abort or Close? + } + + #endregion + #region Public Methods public void Abort () @@ -413,7 +418,7 @@ namespace WebSocketSharp.Net { if (name == "") throw new ArgumentException ("'name' cannot be empty", "name"); - + // TODO: check for forbidden headers and invalid characters if (value.Length > 65535) throw new ArgumentOutOfRangeException ("value"); @@ -425,7 +430,7 @@ namespace WebSocketSharp.Net { { if (cookie == null) throw new ArgumentNullException ("cookie"); - + Cookies.Add (cookie); } @@ -436,7 +441,7 @@ namespace WebSocketSharp.Net { if (name == "") throw new ArgumentException ("'name' cannot be empty", "name"); - + if (value.Length > 65535) throw new ArgumentOutOfRangeException ("value"); diff --git a/websocket-sharp/Net/ResponseStream.cs b/websocket-sharp/Net/ResponseStream.cs index b3ccb5c4..bb66339f 100644 --- a/websocket-sharp/Net/ResponseStream.cs +++ b/websocket-sharp/Net/ResponseStream.cs @@ -1,6 +1,6 @@ // // ResponseStream.cs -// Copied from System.Net.ResponseStream +// Copied from System.Net.ResponseStream.cs // // Author: // 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 // 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? - 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; - bool ignore_errors; - bool disposed; - bool trailer_sent; - System.IO.Stream stream; + Stream stream; + bool trailer_sent; + + #endregion + + #region Constructor internal ResponseStream (System.IO.Stream stream, HttpListenerResponse response, bool ignore_errors) { + this.stream = stream; this.response = response; this.ignore_errors = ignore_errors; - this.stream = stream; } + #endregion + + #region Properties + public override bool CanRead { get { return false; } } @@ -77,99 +92,63 @@ namespace WebSocketSharp.Net { set { throw new NotSupportedException (); } } + #endregion - public override void Close () + #region Private Methods + + static byte [] GetChunkSizeBytes (int size, bool final) { - if (disposed == false) { - disposed = true; - byte [] bytes = null; - MemoryStream ms = GetHeaders (true); - bool chunked = response.SendChunked; - if (ms != null) { - long start = ms.Position; - if (chunked && !trailer_sent) { - bytes = GetChunkSizeBytes (0, true); - ms.Position = ms.Length; - ms.Write (bytes, 0, bytes.Length); - } - InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start)); - trailer_sent = true; - } else if (chunked && !trailer_sent) { - bytes = GetChunkSizeBytes (0, true); - InternalWrite (bytes, 0, bytes.Length); - trailer_sent = true; - } - response.Close (); - } + 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; } - public override void Flush () - { - } + #endregion - static byte [] crlf = new byte [] { 13, 10 }; - 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); - } + #region Internal Method internal void InternalWrite (byte [] buffer, int offset, int count) { if (ignore_errors) { try { stream.Write (buffer, offset, count); - } catch { } + } catch { + } } else { stream.Write (buffer, offset, count); } } - public override void Write (byte [] buffer, int offset, int count) - { - if (disposed) - throw new ObjectDisposedException (GetType ().ToString ()); + #endregion - byte [] bytes = null; - MemoryStream ms = GetHeaders (false); - bool chunked = response.SendChunked; - if (ms != null) { - long start = ms.Position; // After the possible preamble for the encoding - ms.Position = ms.Length; - if (chunked) { - bytes = GetChunkSizeBytes (count, false); - ms.Write (bytes, 0, bytes.Length); - } + #region Public Methods - int new_count = Math.Min (count, 16384 - (int) ms.Position + (int) start); - ms.Write (buffer, offset, new_count); - count -= new_count; - offset += new_count; - InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start)); - ms.SetLength (0); - ms.Capacity = 0; // 'dispose' the buffer in ms. - } else if (chunked) { - bytes = GetChunkSizeBytes (count, false); - InternalWrite (bytes, 0, bytes.Length); - } - - if (count > 0) - InternalWrite (buffer, offset, count); - if (chunked) - InternalWrite (crlf, 0, 2); + 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) + public override IAsyncResult BeginWrite ( + byte [] buffer, + int offset, + int count, + AsyncCallback cback, + object state) { if (disposed) throw new ObjectDisposedException (GetType ().ToString ()); @@ -196,6 +175,37 @@ namespace WebSocketSharp.Net { return stream.BeginWrite (buffer, offset, count, cback, state); } + public override void Close () + { + if (disposed == false) { + disposed = true; + byte [] bytes = null; + MemoryStream ms = GetHeaders (true); + bool chunked = response.SendChunked; + if (ms != null) { + long start = ms.Position; + if (chunked && !trailer_sent) { + bytes = GetChunkSizeBytes (0, true); + ms.Position = ms.Length; + ms.Write (bytes, 0, bytes.Length); + } + InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start)); + trailer_sent = true; + } else if (chunked && !trailer_sent) { + bytes = GetChunkSizeBytes (0, true); + InternalWrite (bytes, 0, bytes.Length); + trailer_sent = true; + } + + response.Close (); + } + } + + public override int EndRead (IAsyncResult ares) + { + throw new NotSupportedException (); + } + public override void EndWrite (IAsyncResult ares) { if (disposed) @@ -206,7 +216,8 @@ namespace WebSocketSharp.Net { stream.EndWrite (ares); if (response.SendChunked) stream.Write (crlf, 0, 2); - } catch { } + } catch { + } } else { stream.EndWrite (ares); if (response.SendChunked) @@ -214,30 +225,60 @@ namespace WebSocketSharp.Net { } } - public override int Read ([In,Out] byte[] buffer, int offset, int count) + public override void Flush () { - throw new NotSupportedException (); } - public override IAsyncResult BeginRead (byte [] buffer, int offset, int count, - AsyncCallback cback, object state) + public override int Read ([In,Out] byte[] buffer, int offset, int count) { throw new NotSupportedException (); } - public override int EndRead (IAsyncResult ares) + public override long Seek (long offset, SeekOrigin origin) { throw new NotSupportedException (); } - public override long Seek (long offset, SeekOrigin origin) + public override void SetLength (long value) { throw new NotSupportedException (); } - public override void SetLength (long value) + public override void Write (byte [] buffer, int offset, int count) { - throw new NotSupportedException (); + 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; // After the possible preamble for the encoding + ms.Position = ms.Length; + if (chunked) { + bytes = GetChunkSizeBytes (count, false); + ms.Write (bytes, 0, bytes.Length); + } + + int new_count = Math.Min (count, 16384 - (int) ms.Position + (int) start); + ms.Write (buffer, offset, new_count); + count -= new_count; + offset += new_count; + InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start)); + ms.SetLength (0); + ms.Capacity = 0; // 'dispose' the buffer in ms. + } else if (chunked) { + bytes = GetChunkSizeBytes (count, false); + InternalWrite (bytes, 0, bytes.Length); + } + + if (count > 0) + InternalWrite (buffer, offset, count); + + if (chunked) + InternalWrite (crlf, 0, 2); } + + #endregion } } diff --git a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll index 9ec61596..d8a55827 100755 Binary files a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll and b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb index 0df3d850..ae5b58c7 100644 Binary files a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ diff --git a/websocket-sharp/websocket-sharp.pidb b/websocket-sharp/websocket-sharp.pidb index e8813a5a..1a5b46dc 100644 Binary files a/websocket-sharp/websocket-sharp.pidb and b/websocket-sharp/websocket-sharp.pidb differ