diff --git a/WebSockets.Client/System.Net.WebSockets.Client.nfproj b/WebSockets.Client/System.Net.WebSockets.Client.nfproj index b42f938..4cc0112 100644 --- a/WebSockets.Client/System.Net.WebSockets.Client.nfproj +++ b/WebSockets.Client/System.Net.WebSockets.Client.nfproj @@ -38,6 +38,9 @@ ClientWebSocket\ClientWebSocketOptions.cs + + + ClientWebSocket\ClientWebSocketHeaders.cs MessageReceivedEventArgs.cs diff --git a/WebSockets/ClientWebSocket/ClientWebSocket.cs b/WebSockets/ClientWebSocket/ClientWebSocket.cs index 3c6eb24..d20080f 100644 --- a/WebSockets/ClientWebSocket/ClientWebSocket.cs +++ b/WebSockets/ClientWebSocket/ClientWebSocket.cs @@ -111,7 +111,8 @@ public ClientWebSocket(ClientWebSocketOptions options = null) : base(options) /// Connect to a WebSocket server. /// /// The URI of the WebSocket server to connect to. - public void Connect(string uri) + /// Optional for setting custom headers. + public void Connect(string uri, ClientWebSocketHeaders headers = null) { State = WebSocketFrame.WebSocketState.Connecting; @@ -195,7 +196,7 @@ public void Connect(string uri) _networkStream = new NetworkStream(_tcpSocket, true); } - WebSocketClientConnect(ep, prefix, Host); + WebSocketClientConnect(ep, prefix, Host, headers); } catch (SocketException ex) { @@ -212,15 +213,27 @@ private void WebSocket_ConnectionClosed(object sender, EventArgs e) _tcpSocket.Close(); } - private void WebSocketClientConnect(IPEndPoint remoteEndPoint, string prefix = "/", string host = null) + private void WebSocketClientConnect(IPEndPoint remoteEndPoint, string prefix = "/", string host = null, ClientWebSocketHeaders customHeaders = null) { + string customHeaderString = string.Empty; + if (customHeaders != null) + { + var headerKeys = customHeaders.Keys; + foreach (string key in headerKeys) + { + if (!string.IsNullOrEmpty(key)) + { + customHeaderString += $"{key}: {customHeaders[key]}\r\n"; + } + } + } if (prefix[0] != '/') throw new Exception("websocket prefix has to start with '/'"); byte[] keyBuf = new byte[16]; new Random().NextBytes(keyBuf); string swk = Convert.ToBase64String(keyBuf); - byte[] sendBuffer = Encoding.UTF8.GetBytes($"GET {prefix} HTTP/1.1\r\nHost: {(host != null ? host : remoteEndPoint.Address.ToString())}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: {swk}\r\nSec-WebSocket-Version: 13\r\n\r\n"); + byte[] sendBuffer = Encoding.UTF8.GetBytes($"GET {prefix} HTTP/1.1\r\nHost: {(host != null ? host : remoteEndPoint.Address.ToString())}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: {swk}\r\nSec-WebSocket-Version: 13\r\n{customHeaderString}\r\n"); _networkStream.Write(sendBuffer, 0, sendBuffer.Length); string beginHeader = ($"HTTP/1.1 101".ToLower()); diff --git a/WebSockets/ClientWebSocket/ClientWebSocketHeaders.cs b/WebSockets/ClientWebSocket/ClientWebSocketHeaders.cs new file mode 100644 index 0000000..6c2f747 --- /dev/null +++ b/WebSockets/ClientWebSocket/ClientWebSocketHeaders.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using System.Text; + +namespace System.Net.WebSockets +{ + /// + /// A Dictionary to store custom Http Headers to use with the ClientWebsocket + /// + public class ClientWebSocketHeaders + { + private Hashtable _headers = new Hashtable(); + + /// + /// Gets the number of headers. + /// + public int Count { get { return _headers.Count; } } + + /// + /// Gets all header keys. + /// + public string[] Keys { get { return GetKeys(); } } + + /// + /// Gets all header values. + /// + public string[] Values { get { return GetValues(); } } + + /// + /// Gets a value header or Sets a header value + /// + public string this[string key] + { + get + { + return _headers[key] as string; + } + set + { + + _headers[key] = value; + + } + } + + /// + /// Removes a header from the dictionary + /// + public void Remove(string value) + { + _headers.Remove(value); + + } + + private string[] GetKeys() + { + var keys = _headers.Keys; + string[] returnkeys = new string[keys.Count]; + + int i = 0; + foreach (object key in keys) + { + returnkeys[i] = key as string; + i++; + } + + return returnkeys; + } + + private string[] GetValues() + { + var values = _headers.Values; + string[] returnkeys = new string[values.Count]; + + int i = 0; + foreach (object value in values) + { + returnkeys[i] = value as string; + i++; + } + + return returnkeys; + } + } +} diff --git a/WebSockets/System.Net.WebSockets.nfproj b/WebSockets/System.Net.WebSockets.nfproj index 8d38d06..7a6ccfb 100644 --- a/WebSockets/System.Net.WebSockets.nfproj +++ b/WebSockets/System.Net.WebSockets.nfproj @@ -33,6 +33,7 @@ + diff --git a/WebSockets/WebSocket.cs b/WebSockets/WebSocket.cs index c9400db..eca396c 100644 --- a/WebSockets/WebSocket.cs +++ b/WebSockets/WebSocket.cs @@ -302,9 +302,15 @@ internal void HardClose() ConnectionClosed?.Invoke(this, new EventArgs()); //Let the tcp socket linger for a second so it can try and send all data out before final close. - _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, 1); - - _socket.Close(); + try + { + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, 1); + _socket.Close(); + } + catch (ObjectDisposedException e) + { + Debug.WriteLine("socket could not be closed properly because it was already disposed"); + } } internal bool QueueMessageToSend(SendMessageFrame frame)