Fix for issue #40, and refactored.
This commit is contained in:
parent
6d987ed025
commit
6772efd75c
@ -65,19 +65,19 @@ namespace WebSocketSharp.Net
|
|||||||
private HttpListenerContext _context;
|
private HttpListenerContext _context;
|
||||||
private bool _contextWasBound;
|
private bool _contextWasBound;
|
||||||
private StringBuilder _currentLine;
|
private StringBuilder _currentLine;
|
||||||
private EndPointListener _epListener;
|
|
||||||
private InputState _inputState;
|
private InputState _inputState;
|
||||||
private RequestStream _inputStream;
|
private RequestStream _inputStream;
|
||||||
private HttpListener _lastListener;
|
private HttpListener _lastListener;
|
||||||
private LineState _lineState;
|
private LineState _lineState;
|
||||||
|
private EndPointListener _listener;
|
||||||
private ResponseStream _outputStream;
|
private ResponseStream _outputStream;
|
||||||
private int _position;
|
private int _position;
|
||||||
private ListenerPrefix _prefix;
|
private ListenerPrefix _prefix;
|
||||||
private MemoryStream _requestBuffer;
|
private MemoryStream _requestBuffer;
|
||||||
private int _reuses;
|
private int _reuses;
|
||||||
private bool _secure;
|
|
||||||
private Socket _socket;
|
private Socket _socket;
|
||||||
private Stream _stream;
|
private Stream _stream;
|
||||||
|
private object _sync;
|
||||||
private int _timeout;
|
private int _timeout;
|
||||||
private Timer _timer;
|
private Timer _timer;
|
||||||
|
|
||||||
@ -88,11 +88,10 @@ namespace WebSocketSharp.Net
|
|||||||
public HttpConnection (Socket socket, EndPointListener listener)
|
public HttpConnection (Socket socket, EndPointListener listener)
|
||||||
{
|
{
|
||||||
_socket = socket;
|
_socket = socket;
|
||||||
_epListener = listener;
|
_listener = listener;
|
||||||
_secure = listener.IsSecure;
|
|
||||||
|
|
||||||
var netStream = new NetworkStream (socket, false);
|
var netStream = new NetworkStream (socket, false);
|
||||||
if (_secure) {
|
if (listener.IsSecure) {
|
||||||
var sslStream = new SslStream (netStream, false);
|
var sslStream = new SslStream (netStream, false);
|
||||||
sslStream.AuthenticateAsServer (listener.Certificate);
|
sslStream.AuthenticateAsServer (listener.Certificate);
|
||||||
_stream = sslStream;
|
_stream = sslStream;
|
||||||
@ -101,6 +100,7 @@ namespace WebSocketSharp.Net
|
|||||||
_stream = netStream;
|
_stream = netStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_sync = new object ();
|
||||||
_timeout = 90000; // 90k ms for first request, 15k ms from then on.
|
_timeout = 90000; // 90k ms for first request, 15k ms from then on.
|
||||||
_timer = new Timer (onTimeout, this, Timeout.Infinite, Timeout.Infinite);
|
_timer = new Timer (onTimeout, this, Timeout.Infinite, Timeout.Infinite);
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ namespace WebSocketSharp.Net
|
|||||||
|
|
||||||
public bool IsSecure {
|
public bool IsSecure {
|
||||||
get {
|
get {
|
||||||
return _secure;
|
return _listener.IsSecure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,21 +161,53 @@ namespace WebSocketSharp.Net
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private void closeSocket ()
|
private void close ()
|
||||||
{
|
{
|
||||||
if (_socket == null)
|
if (_socket == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
lock (_sync) {
|
||||||
|
if (_socket == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
disposeTimer ();
|
||||||
|
disposeRequestBuffer ();
|
||||||
|
disposeStream ();
|
||||||
|
closeSocket ();
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind ();
|
||||||
|
removeConnection ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeSocket ()
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
_socket.Close ();
|
_socket.Shutdown (SocketShutdown.Both);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
_socket = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeConnection ();
|
_socket.Close ();
|
||||||
|
_socket = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeRequestBuffer ()
|
||||||
|
{
|
||||||
|
if (_requestBuffer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_requestBuffer.Dispose ();
|
||||||
|
_requestBuffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disposeStream ()
|
||||||
|
{
|
||||||
|
if (_stream == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_stream.Dispose ();
|
||||||
|
_stream = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disposeTimer ()
|
private void disposeTimer ()
|
||||||
@ -183,17 +215,14 @@ namespace WebSocketSharp.Net
|
|||||||
if (_timer == null)
|
if (_timer == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var timer = _timer;
|
|
||||||
_timer = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
timer.Change (Timeout.Infinite, Timeout.Infinite);
|
_timer.Change (Timeout.Infinite, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer != null)
|
_timer.Dispose ();
|
||||||
timer.Dispose ();
|
_timer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init ()
|
private void init ()
|
||||||
@ -212,80 +241,78 @@ namespace WebSocketSharp.Net
|
|||||||
private static void onRead (IAsyncResult asyncResult)
|
private static void onRead (IAsyncResult asyncResult)
|
||||||
{
|
{
|
||||||
var conn = (HttpConnection) asyncResult.AsyncState;
|
var conn = (HttpConnection) asyncResult.AsyncState;
|
||||||
|
if (conn._socket == null)
|
||||||
|
return;
|
||||||
|
|
||||||
var read = -1;
|
lock (conn._sync) {
|
||||||
try {
|
if (conn._socket == null)
|
||||||
conn._timer.Change (Timeout.Infinite, Timeout.Infinite);
|
return;
|
||||||
read = conn._stream.EndRead (asyncResult);
|
|
||||||
conn._requestBuffer.Write (conn._buffer, 0, read);
|
|
||||||
if (conn._requestBuffer.Length > 32768) {
|
|
||||||
conn.SendError ("Bad request", 400);
|
|
||||||
conn.Close (true);
|
|
||||||
|
|
||||||
|
var read = -1;
|
||||||
|
try {
|
||||||
|
conn._timer.Change (Timeout.Infinite, Timeout.Infinite);
|
||||||
|
read = conn._stream.EndRead (asyncResult);
|
||||||
|
conn._requestBuffer.Write (conn._buffer, 0, read);
|
||||||
|
if (conn._requestBuffer.Length > 32768) {
|
||||||
|
conn.SendError ("Bad request", 400);
|
||||||
|
conn.Close (true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
var requestBuffer = conn._requestBuffer;
|
||||||
|
if (requestBuffer != null && requestBuffer.Length > 0)
|
||||||
|
conn.SendError ();
|
||||||
|
|
||||||
|
conn.close ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch {
|
|
||||||
if (conn._requestBuffer != null && conn._requestBuffer.Length > 0)
|
|
||||||
conn.SendError ();
|
|
||||||
|
|
||||||
if (conn._socket != null) {
|
if (read <= 0) {
|
||||||
conn.disposeTimer ();
|
conn.close ();
|
||||||
conn.closeSocket ();
|
return;
|
||||||
conn.unbind ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
if (conn.processInput (conn._requestBuffer.GetBuffer ())) {
|
||||||
}
|
if (!conn._context.HaveError) {
|
||||||
|
conn._context.Request.FinishInitialization ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conn.SendError ();
|
||||||
|
conn.Close (true);
|
||||||
|
|
||||||
if (read <= 0) {
|
return;
|
||||||
conn.disposeTimer ();
|
}
|
||||||
conn.closeSocket ();
|
|
||||||
conn.unbind ();
|
|
||||||
|
|
||||||
return;
|
if (!conn._listener.BindContext (conn._context)) {
|
||||||
}
|
conn.SendError ("Invalid host", 400);
|
||||||
|
conn.Close (true);
|
||||||
|
|
||||||
if (conn.processInput (conn._requestBuffer.GetBuffer ())) {
|
return;
|
||||||
if (!conn._context.HaveError) {
|
}
|
||||||
conn._context.Request.FinishInitialization ();
|
|
||||||
}
|
var listener = conn._context.Listener;
|
||||||
else {
|
if (conn._lastListener != listener) {
|
||||||
conn.SendError ();
|
conn.removeConnection ();
|
||||||
conn.Close (true);
|
listener.AddConnection (conn);
|
||||||
|
conn._lastListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn._contextWasBound = true;
|
||||||
|
listener.RegisterContext (conn._context);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conn._epListener.BindContext (conn._context)) {
|
conn._stream.BeginRead (conn._buffer, 0, _bufferSize, onRead, conn);
|
||||||
conn.SendError ("Invalid host", 400);
|
|
||||||
conn.Close (true);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var listener = conn._context.Listener;
|
|
||||||
if (conn._lastListener != listener) {
|
|
||||||
conn.removeConnection ();
|
|
||||||
listener.AddConnection (conn);
|
|
||||||
conn._lastListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn._contextWasBound = true;
|
|
||||||
listener.RegisterContext (conn._context);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conn._stream.BeginRead (conn._buffer, 0, _bufferSize, onRead, conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onTimeout (object state)
|
private static void onTimeout (object state)
|
||||||
{
|
{
|
||||||
var conn = (HttpConnection) state;
|
var conn = (HttpConnection) state;
|
||||||
conn.disposeTimer ();
|
conn.close ();
|
||||||
conn.closeSocket ();
|
|
||||||
conn.unbind ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// true -> Done processing.
|
// true -> Done processing.
|
||||||
@ -363,7 +390,7 @@ namespace WebSocketSharp.Net
|
|||||||
private void removeConnection ()
|
private void removeConnection ()
|
||||||
{
|
{
|
||||||
if (_lastListener == null)
|
if (_lastListener == null)
|
||||||
_epListener.RemoveConnection (this);
|
_listener.RemoveConnection (this);
|
||||||
else
|
else
|
||||||
_lastListener.RemoveConnection (this);
|
_lastListener.RemoveConnection (this);
|
||||||
}
|
}
|
||||||
@ -371,7 +398,7 @@ namespace WebSocketSharp.Net
|
|||||||
private void unbind ()
|
private void unbind ()
|
||||||
{
|
{
|
||||||
if (_contextWasBound) {
|
if (_contextWasBound) {
|
||||||
_epListener.UnbindContext (_context);
|
_listener.UnbindContext (_context);
|
||||||
_contextWasBound = false;
|
_contextWasBound = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,7 +409,13 @@ namespace WebSocketSharp.Net
|
|||||||
|
|
||||||
internal void Close (bool force)
|
internal void Close (bool force)
|
||||||
{
|
{
|
||||||
if (_socket != null) {
|
if (_socket == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (_sync) {
|
||||||
|
if (_socket == null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_outputStream != null) {
|
if (_outputStream != null) {
|
||||||
_outputStream.Close ();
|
_outputStream.Close ();
|
||||||
_outputStream = null;
|
_outputStream = null;
|
||||||
@ -400,6 +433,7 @@ namespace WebSocketSharp.Net
|
|||||||
(!_chunked || (_chunked && !res.ForceCloseChunked))) {
|
(!_chunked || (_chunked && !res.ForceCloseChunked))) {
|
||||||
// Don't close. Keep working.
|
// Don't close. Keep working.
|
||||||
_reuses++;
|
_reuses++;
|
||||||
|
disposeRequestBuffer ();
|
||||||
unbind ();
|
unbind ();
|
||||||
init ();
|
init ();
|
||||||
BeginReadRequest ();
|
BeginReadRequest ();
|
||||||
@ -407,24 +441,7 @@ namespace WebSocketSharp.Net
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var socket = _socket;
|
close ();
|
||||||
_socket = null;
|
|
||||||
|
|
||||||
disposeTimer ();
|
|
||||||
|
|
||||||
try {
|
|
||||||
socket.Shutdown (SocketShutdown.Both);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socket != null)
|
|
||||||
socket.Close ();
|
|
||||||
|
|
||||||
unbind ();
|
|
||||||
removeConnection ();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,17 +454,15 @@ namespace WebSocketSharp.Net
|
|||||||
if (_buffer == null)
|
if (_buffer == null)
|
||||||
_buffer = new byte [_bufferSize];
|
_buffer = new byte [_bufferSize];
|
||||||
|
|
||||||
try {
|
if (_reuses == 1)
|
||||||
if (_reuses == 1)
|
_timeout = 15000;
|
||||||
_timeout = 15000;
|
|
||||||
|
|
||||||
|
try {
|
||||||
_timer.Change (_timeout, Timeout.Infinite);
|
_timer.Change (_timeout, Timeout.Infinite);
|
||||||
_stream.BeginRead (_buffer, 0, _bufferSize, onRead, this);
|
_stream.BeginRead (_buffer, 0, _bufferSize, onRead, this);
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
disposeTimer ();
|
close ();
|
||||||
closeSocket ();
|
|
||||||
unbind ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,11 +473,16 @@ namespace WebSocketSharp.Net
|
|||||||
|
|
||||||
public RequestStream GetRequestStream (bool chunked, long contentlength)
|
public RequestStream GetRequestStream (bool chunked, long contentlength)
|
||||||
{
|
{
|
||||||
if (_inputStream == null) {
|
if (_inputStream != null || _socket == null)
|
||||||
|
return _inputStream;
|
||||||
|
|
||||||
|
lock (_sync) {
|
||||||
|
if (_socket == null)
|
||||||
|
return _inputStream;
|
||||||
|
|
||||||
var buffer = _requestBuffer.GetBuffer ();
|
var buffer = _requestBuffer.GetBuffer ();
|
||||||
var length = buffer.Length;
|
var length = buffer.Length;
|
||||||
|
disposeRequestBuffer ();
|
||||||
_requestBuffer = null;
|
|
||||||
if (chunked) {
|
if (chunked) {
|
||||||
_chunked = true;
|
_chunked = true;
|
||||||
_context.Response.SendChunked = true;
|
_context.Response.SendChunked = true;
|
||||||
@ -473,21 +493,28 @@ namespace WebSocketSharp.Net
|
|||||||
_inputStream = new RequestStream (
|
_inputStream = new RequestStream (
|
||||||
_stream, buffer, _position, length - _position, contentlength);
|
_stream, buffer, _position, length - _position, contentlength);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return _inputStream;
|
return _inputStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseStream GetResponseStream ()
|
public ResponseStream GetResponseStream ()
|
||||||
{
|
{
|
||||||
// TODO: Can we get this stream before reading the input?
|
// TODO: Can we get this stream before reading the input?
|
||||||
if (_outputStream == null) {
|
|
||||||
|
if (_outputStream != null || _socket == null)
|
||||||
|
return _outputStream;
|
||||||
|
|
||||||
|
lock (_sync) {
|
||||||
|
if (_socket == null)
|
||||||
|
return _outputStream;
|
||||||
|
|
||||||
var listener = _context.Listener;
|
var listener = _context.Listener;
|
||||||
var ignore = listener == null ? true : listener.IgnoreWriteExceptions;
|
var ignore = listener == null ? true : listener.IgnoreWriteExceptions;
|
||||||
_outputStream = new ResponseStream (_stream, _context.Response, ignore);
|
_outputStream = new ResponseStream (_stream, _context.Response, ignore);
|
||||||
}
|
|
||||||
|
|
||||||
return _outputStream;
|
return _outputStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendError ()
|
public void SendError ()
|
||||||
@ -497,21 +524,29 @@ namespace WebSocketSharp.Net
|
|||||||
|
|
||||||
public void SendError (string message, int status)
|
public void SendError (string message, int status)
|
||||||
{
|
{
|
||||||
try {
|
if (_socket == null)
|
||||||
var res = _context.Response;
|
return;
|
||||||
res.StatusCode = status;
|
|
||||||
res.ContentType = "text/html";
|
|
||||||
|
|
||||||
var description = status.GetStatusDescription ();
|
lock (_sync) {
|
||||||
var error = message != null && message.Length > 0
|
if (_socket == null)
|
||||||
? String.Format ("<h1>{0} ({1})</h1>", description, message)
|
return;
|
||||||
: String.Format ("<h1>{0}</h1>", description);
|
|
||||||
|
|
||||||
var entity = res.ContentEncoding.GetBytes (error);
|
try {
|
||||||
res.Close (entity, false);
|
var res = _context.Response;
|
||||||
}
|
res.StatusCode = status;
|
||||||
catch {
|
res.ContentType = "text/html";
|
||||||
// Response was already closed.
|
|
||||||
|
var desc = status.GetStatusDescription ();
|
||||||
|
var msg = message != null && message.Length > 0
|
||||||
|
? String.Format ("<h1>{0} ({1})</h1>", desc, message)
|
||||||
|
: String.Format ("<h1>{0}</h1>", desc);
|
||||||
|
|
||||||
|
var entity = res.ContentEncoding.GetBytes (msg);
|
||||||
|
res.Close (entity, false);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// Response was already closed.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user