From 75dab14cf5ea6e60c2f3f78d8cba812df68480ca Mon Sep 17 00:00:00 2001 From: sta Date: Tue, 14 Jan 2014 22:42:02 +0900 Subject: [PATCH] Fix for issue #29 --- websocket-sharp/HandshakeBase.cs | 46 ++++++- websocket-sharp/HandshakeRequest.cs | 8 +- websocket-sharp/HandshakeResponse.cs | 5 + .../WebSockets/TcpListenerWebSocketContext.cs | 6 +- websocket-sharp/WebSocket.cs | 7 +- websocket-sharp/WsStream.cs | 130 +++++++++++------- 6 files changed, 144 insertions(+), 58 deletions(-) diff --git a/websocket-sharp/HandshakeBase.cs b/websocket-sharp/HandshakeBase.cs index 9d16165a..542941b5 100644 --- a/websocket-sharp/HandshakeBase.cs +++ b/websocket-sharp/HandshakeBase.cs @@ -4,7 +4,7 @@ * * The MIT License * - * Copyright (c) 2012-2013 sta.blockhead + * Copyright (c) 2012-2014 sta.blockhead * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,6 +37,7 @@ namespace WebSocketSharp { #region Private Fields + private byte [] _entity; private NameValueCollection _headers; private Version _version; @@ -58,8 +59,30 @@ namespace WebSocketSharp #endregion + #region Internal Properties + + internal byte [] EntityBodyData { + get { + return _entity; + } + + set { + _entity = value; + } + } + + #endregion + #region Public Properties + public string EntityBody { + get { + return _entity != null && _entity.LongLength > 0 + ? getEncoding (_headers ["Content-Type"]).GetString (_entity) + : String.Empty; + } + } + public NameValueCollection Headers { get { return _headers; @@ -82,6 +105,27 @@ namespace WebSocketSharp #endregion + #region Private Methods + + private static Encoding getEncoding (string contentType) + { + if (contentType == null || contentType.Length == 0) + return Encoding.UTF8; + + var i = contentType.IndexOf ("charset=", StringComparison.Ordinal); + if (i == -1) + return Encoding.UTF8; + + var charset = contentType.Substring (i + 8); + i = charset.IndexOf (';'); + if (i != -1) + charset = charset.Substring (0, i); + + return Encoding.GetEncoding (charset); + } + + #endregion + #region Public Methods public byte [] ToByteArray () diff --git a/websocket-sharp/HandshakeRequest.cs b/websocket-sharp/HandshakeRequest.cs index 46fc463b..875057e2 100644 --- a/websocket-sharp/HandshakeRequest.cs +++ b/websocket-sharp/HandshakeRequest.cs @@ -192,13 +192,19 @@ namespace WebSocketSharp public override string ToString () { var buffer = new StringBuilder (64); - buffer.AppendFormat ("{0} {1} HTTP/{2}{3}", _method, _rawUrl, ProtocolVersion, CrLf); + buffer.AppendFormat ( + "{0} {1} HTTP/{2}{3}", _method, _rawUrl, ProtocolVersion, CrLf); var headers = Headers; foreach (var key in headers.AllKeys) buffer.AppendFormat ("{0}: {1}{2}", key, headers [key], CrLf); buffer.Append (CrLf); + + var entity = EntityBody; + if (entity.Length > 0) + buffer.Append (entity); + return buffer.ToString (); } diff --git a/websocket-sharp/HandshakeResponse.cs b/websocket-sharp/HandshakeResponse.cs index 8bf33847..7bcc13cf 100644 --- a/websocket-sharp/HandshakeResponse.cs +++ b/websocket-sharp/HandshakeResponse.cs @@ -175,6 +175,11 @@ namespace WebSocketSharp buffer.AppendFormat ("{0}: {1}{2}", key, headers [key], CrLf); buffer.Append (CrLf); + + var entity = EntityBody; + if (entity.Length > 0) + buffer.Append (entity); + return buffer.ToString (); } diff --git a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs index a84f7c56..d0201d29 100644 --- a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs @@ -4,7 +4,7 @@ * * The MIT License * - * Copyright (c) 2012-2013 sta.blockhead + * Copyright (c) 2012-2014 sta.blockhead * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -64,7 +64,7 @@ namespace WebSocketSharp.Net.WebSockets _client = client; _secure = secure; _stream = WsStream.CreateServerStream (client, cert, secure); - _request = HandshakeRequest.Parse (_stream.ReadHandshake ()); + _request = _stream.ReadHandshakeRequest (); _websocket = new WebSocket (this, logger); } @@ -365,7 +365,7 @@ namespace WebSocketSharp.Net.WebSockets var res = new HandshakeResponse (HttpStatusCode.Unauthorized); res.Headers ["WWW-Authenticate"] = challenge; _stream.WriteHandshake (res); - _request = HandshakeRequest.Parse (_stream.ReadHandshake ()); + _request = _stream.ReadHandshakeRequest (); } internal void SetUser ( diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 87be84a6..b614be99 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -1035,8 +1035,9 @@ namespace WebSocketSharp // As client private HandshakeResponse receiveHandshakeResponse () { - var res = HandshakeResponse.Parse (_stream.ReadHandshake ()); - _logger.Debug ("A response to this WebSocket connection request:\n" + res.ToString ()); + var res = _stream.ReadHandshakeResponse (); + _logger.Debug ( + "A response to this WebSocket connection request:\n" + res.ToString ()); return res; } @@ -1310,7 +1311,7 @@ namespace WebSocketSharp frame => { if (acceptFrame (frame)) receive (); - else + else if (_exitReceiving != null) _exitReceiving.Set (); }, ex => processException ( diff --git a/websocket-sharp/WsStream.cs b/websocket-sharp/WsStream.cs index 6a4eeb01..50137c5d 100644 --- a/websocket-sharp/WsStream.cs +++ b/websocket-sharp/WsStream.cs @@ -98,6 +98,72 @@ namespace WebSocketSharp #endregion + #region Private Methods + + private byte [] readHandshakeEntityBody (string length) + { + var len = Int64.Parse (length); + return _innerStream.ReadBytes (len, 1024); + } + + private string [] readHandshakeHeaders () + { + var read = false; + var exception = false; + + var buffer = new List (); + Action add = i => buffer.Add ((byte) i); + + var timeout = false; + var timer = new Timer ( + state => { + timeout = true; + _innerStream.Close (); + }, + null, + _handshakeTimeout, + -1); + + try { + while (buffer.Count < _handshakeLimitLen) { + if (_innerStream.ReadByte ().EqualsWith ('\r', add) && + _innerStream.ReadByte ().EqualsWith ('\n', add) && + _innerStream.ReadByte ().EqualsWith ('\r', add) && + _innerStream.ReadByte ().EqualsWith ('\n', add)) { + read = true; + break; + } + } + } + catch { + exception = true; + } + finally { + timer.Change (-1, -1); + timer.Dispose (); + } + + var reason = timeout + ? "A timeout has occurred while receiving a handshake." + : exception + ? "An exception has occurred while receiving a handshake." + : !read + ? "A handshake length is greater than the limit length." + : null; + + if (reason != null) + throw new WebSocketException (reason); + + return Encoding.UTF8.GetString (buffer.ToArray ()) + .Replace ("\r\n", "\n") + .Replace ("\n ", " ") + .Replace ("\n\t", " ") + .TrimEnd ('\n') + .Split ('\n'); + } + + #endregion + #region Internal Methods internal static WsStream CreateClientStream ( @@ -177,60 +243,24 @@ namespace WebSocketSharp WsFrame.ParseAsync (_innerStream, true, completed, error); } - public string [] ReadHandshake () + public HandshakeRequest ReadHandshakeRequest () { - var exception = false; - var read = false; - var timeout = false; + var req = HandshakeRequest.Parse (readHandshakeHeaders ()); + var contentLen = req.Headers ["Content-Length"]; + if (contentLen != null && contentLen.Length > 0) + req.EntityBodyData = readHandshakeEntityBody (contentLen); - var buffer = new List (); - Action add = i => buffer.Add ((byte) i); + return req; + } - var timer = new Timer ( - state => { - timeout = true; - _innerStream.Close (); - }, - null, - _handshakeTimeout, - -1); + public HandshakeResponse ReadHandshakeResponse () + { + var res = HandshakeResponse.Parse (readHandshakeHeaders ()); + var contentLen = res.Headers ["Content-Length"]; + if (contentLen != null && contentLen.Length > 0) + res.EntityBodyData = readHandshakeEntityBody (contentLen); - try { - while (buffer.Count < _handshakeLimitLen) { - if (_innerStream.ReadByte ().EqualsWith ('\r', add) && - _innerStream.ReadByte ().EqualsWith ('\n', add) && - _innerStream.ReadByte ().EqualsWith ('\r', add) && - _innerStream.ReadByte ().EqualsWith ('\n', add)) { - read = true; - break; - } - } - } - catch { - exception = true; - } - finally { - timer.Change (-1, -1); - timer.Dispose (); - } - - var reason = timeout - ? "A timeout has occurred while receiving a handshake." - : exception - ? "An exception has occurred while receiving a handshake." - : !read - ? "A handshake length is greater than the limit length." - : null; - - if (reason != null) - throw new WebSocketException (reason); - - return Encoding.UTF8.GetString (buffer.ToArray ()) - .Replace ("\r\n", "\n") - .Replace ("\n ", " ") - .Replace ("\n\t", " ") - .TrimEnd ('\n') - .Split ('\n'); + return res; } public bool WriteFrame (WsFrame frame)