Modified reading the handshake

This commit is contained in:
sta 2014-01-16 17:16:40 +09:00
parent f48805a2d1
commit 413d5058f8
2 changed files with 86 additions and 68 deletions

View File

@ -4,8 +4,8 @@
*
* 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
* in the Software without restriction, including without limitation the rights
@ -15,7 +15,7 @@
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -31,30 +31,41 @@ using System;
namespace WebSocketSharp
{
/// <summary>
/// Represents the exception that occurred when attempting to perform an operation
/// on the WebSocket connection.
/// Represents the exception that occurred when attempting to perform an
/// operation on the WebSocket connection.
/// </summary>
public class WebSocketException : Exception
{
#region Internal Constructors
internal WebSocketException ()
: this (CloseStatusCode.ABNORMAL)
: this (CloseStatusCode.ABNORMAL, null, null)
{
}
internal WebSocketException (CloseStatusCode code)
: this (code, null)
: this (code, null, null)
{
}
internal WebSocketException (string reason)
: this (CloseStatusCode.ABNORMAL, reason)
: this (CloseStatusCode.ABNORMAL, reason, null)
{
}
internal WebSocketException (string reason, Exception innerException)
: this (CloseStatusCode.ABNORMAL, reason, innerException)
{
}
internal WebSocketException (CloseStatusCode code, string reason)
: base (reason ?? code.GetMessage ())
: this (code, reason, null)
{
}
internal WebSocketException (
CloseStatusCode code, string reason, Exception innerException)
: base (reason ?? code.GetMessage (), innerException)
{
Code = code;
}
@ -64,10 +75,12 @@ namespace WebSocketSharp
#region Public Properties
/// <summary>
/// Gets the <see cref="CloseStatusCode"/> associated with the <see cref="WebSocketException"/>.
/// Gets the <see cref="CloseStatusCode"/> associated with the
/// <see cref="WebSocketException"/>.
/// </summary>
/// <value>
/// One of the <see cref="CloseStatusCode"/> values, indicates the causes of the <see cref="WebSocketException"/>.
/// One of the <see cref="CloseStatusCode"/> values, indicates the cause of
/// the <see cref="WebSocketException"/>.
/// </value>
public CloseStatusCode Code {
get; private set;

View File

@ -42,7 +42,7 @@ namespace WebSocketSharp
{
#region Private Const Fields
private const int _handshakeLimitLen = 8192;
private const int _handshakeHeadersLimitLen = 8192;
private const int _handshakeTimeout = 90000;
#endregion
@ -100,61 +100,33 @@ namespace WebSocketSharp
#region Private Methods
private byte [] readHandshakeEntityBody (string length)
private static byte [] readHandshakeEntityBody (Stream stream, string length)
{
var len = Int64.Parse (length);
return len > 1024
? _innerStream.ReadBytes (len, 1024)
: _innerStream.ReadBytes ((int) len);
? stream.ReadBytes (len, 1024)
: stream.ReadBytes ((int) len);
}
private string [] readHandshakeHeaders ()
private static string [] readHandshakeHeaders (Stream stream)
{
var read = false;
var exception = false;
var buffer = new List<byte> ();
Action<int> 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;
}
var read = false;
while (buffer.Count < _handshakeHeadersLimitLen) {
if (stream.ReadByte ().EqualsWith ('\r', add) &&
stream.ReadByte ().EqualsWith ('\n', add) &&
stream.ReadByte ().EqualsWith ('\r', add) &&
stream.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);
if (!read)
throw new WebSocketException (
"The header part of a handshake is greater than the limit length.");
return Encoding.UTF8.GetString (buffer.ToArray ())
.Replace ("\r\n", "\n")
@ -208,6 +180,48 @@ namespace WebSocketSharp
return new WsStream (conn.Stream, conn.IsSecure);
}
internal T ReadHandshake<T> (Func<string [], T> parser)
where T : HandshakeBase
{
var timeout = false;
var timer = new Timer (
state => {
timeout = true;
_innerStream.Close ();
},
null,
_handshakeTimeout,
-1);
T handshake = null;
Exception exception = null;
try {
handshake = parser (readHandshakeHeaders (_innerStream));
var contentLen = handshake.Headers ["Content-Length"];
if (contentLen != null && contentLen.Length > 0)
handshake.EntityBodyData = readHandshakeEntityBody (
_innerStream, contentLen);
}
catch (Exception ex) {
exception = ex;
}
finally {
timer.Change (-1, -1);
timer.Dispose ();
}
var reason = timeout
? "A timeout has occurred while receiving a handshake."
: exception != null
? "An exception has occurred while receiving a handshake."
: null;
if (reason != null)
throw new WebSocketException (reason, exception);
return handshake;
}
internal bool Write (byte [] data)
{
lock (_forWrite) {
@ -240,29 +254,20 @@ namespace WebSocketSharp
return WsFrame.Parse (_innerStream, true);
}
public void ReadFrameAsync (Action<WsFrame> completed, Action<Exception> error)
public void ReadFrameAsync (
Action<WsFrame> completed, Action<Exception> error)
{
WsFrame.ParseAsync (_innerStream, true, completed, error);
}
public HandshakeRequest ReadHandshakeRequest ()
{
var req = HandshakeRequest.Parse (readHandshakeHeaders ());
var contentLen = req.Headers ["Content-Length"];
if (contentLen != null && contentLen.Length > 0)
req.EntityBodyData = readHandshakeEntityBody (contentLen);
return req;
return ReadHandshake<HandshakeRequest> (HandshakeRequest.Parse);
}
public HandshakeResponse ReadHandshakeResponse ()
{
var res = HandshakeResponse.Parse (readHandshakeHeaders ());
var contentLen = res.Headers ["Content-Length"];
if (contentLen != null && contentLen.Length > 0)
res.EntityBodyData = readHandshakeEntityBody (contentLen);
return res;
return ReadHandshake<HandshakeResponse> (HandshakeResponse.Parse);
}
public bool WriteFrame (WsFrame frame)