Skip to content

Commit a9584eb

Browse files
authored
Added support for custom Http Headers for Websocket (#22)
1 parent 5322967 commit a9584eb

File tree

5 files changed

+115
-7
lines changed

5 files changed

+115
-7
lines changed

WebSockets.Client/System.Net.WebSockets.Client.nfproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
</Compile>
3939
<Compile Include="..\WebSockets\ClientWebSocket\ClientWebSocketOptions.cs">
4040
<Link>ClientWebSocket\ClientWebSocketOptions.cs</Link>
41+
</Compile>
42+
<Compile Include="..\WebSockets\ClientWebSocket\ClientWebSocketHeaders.cs">
43+
<Link>ClientWebSocket\ClientWebSocketHeaders.cs</Link>
4144
</Compile>
4245
<Compile Include="..\WebSockets\MessageReceivedEventArgs.cs">
4346
<Link>MessageReceivedEventArgs.cs</Link>

WebSockets/ClientWebSocket/ClientWebSocket.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ public ClientWebSocket(ClientWebSocketOptions options = null) : base(options)
111111
/// Connect to a WebSocket server.
112112
/// </summary>
113113
/// <param name="uri">The URI of the WebSocket server to connect to.</param>
114-
public void Connect(string uri)
114+
/// <param name="headers">Optional <see cref="ClientWebSocketHeaders"/> for setting custom headers.</param>
115+
public void Connect(string uri, ClientWebSocketHeaders headers = null)
115116
{
116117
State = WebSocketFrame.WebSocketState.Connecting;
117118

@@ -195,7 +196,7 @@ public void Connect(string uri)
195196
_networkStream = new NetworkStream(_tcpSocket, true);
196197
}
197198

198-
WebSocketClientConnect(ep, prefix, Host);
199+
WebSocketClientConnect(ep, prefix, Host, headers);
199200
}
200201
catch (SocketException ex)
201202
{
@@ -212,15 +213,27 @@ private void WebSocket_ConnectionClosed(object sender, EventArgs e)
212213
_tcpSocket.Close();
213214
}
214215

215-
private void WebSocketClientConnect(IPEndPoint remoteEndPoint, string prefix = "/", string host = null)
216+
private void WebSocketClientConnect(IPEndPoint remoteEndPoint, string prefix = "/", string host = null, ClientWebSocketHeaders customHeaders = null)
216217
{
218+
string customHeaderString = string.Empty;
219+
if (customHeaders != null)
220+
{
221+
var headerKeys = customHeaders.Keys;
222+
foreach (string key in headerKeys)
223+
{
224+
if (!string.IsNullOrEmpty(key))
225+
{
226+
customHeaderString += $"{key}: {customHeaders[key]}\r\n";
227+
}
228+
}
229+
}
217230
if (prefix[0] != '/') throw new Exception("websocket prefix has to start with '/'");
218231

219232
byte[] keyBuf = new byte[16];
220233
new Random().NextBytes(keyBuf);
221234
string swk = Convert.ToBase64String(keyBuf);
222235

223-
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");
236+
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");
224237
_networkStream.Write(sendBuffer, 0, sendBuffer.Length);
225238

226239
string beginHeader = ($"HTTP/1.1 101".ToLower());
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections;
3+
using System.Text;
4+
5+
namespace System.Net.WebSockets
6+
{
7+
/// <summary>
8+
/// A Dictionary to store custom Http Headers to use with the ClientWebsocket
9+
/// </summary>
10+
public class ClientWebSocketHeaders
11+
{
12+
private Hashtable _headers = new Hashtable();
13+
14+
/// <summary>
15+
/// Gets the number of headers.
16+
/// </summary>
17+
public int Count { get { return _headers.Count; } }
18+
19+
/// <summary>
20+
/// Gets all header keys.
21+
/// </summary>
22+
public string[] Keys { get { return GetKeys(); } }
23+
24+
/// <summary>
25+
/// Gets all header values.
26+
/// </summary>
27+
public string[] Values { get { return GetValues(); } }
28+
29+
/// <summary>
30+
/// Gets a value header or Sets a header value
31+
/// </summary>
32+
public string this[string key]
33+
{
34+
get
35+
{
36+
return _headers[key] as string;
37+
}
38+
set
39+
{
40+
41+
_headers[key] = value;
42+
43+
}
44+
}
45+
46+
/// <summary>
47+
/// Removes a header from the dictionary
48+
/// </summary>
49+
public void Remove(string value)
50+
{
51+
_headers.Remove(value);
52+
53+
}
54+
55+
private string[] GetKeys()
56+
{
57+
var keys = _headers.Keys;
58+
string[] returnkeys = new string[keys.Count];
59+
60+
int i = 0;
61+
foreach (object key in keys)
62+
{
63+
returnkeys[i] = key as string;
64+
i++;
65+
}
66+
67+
return returnkeys;
68+
}
69+
70+
private string[] GetValues()
71+
{
72+
var values = _headers.Values;
73+
string[] returnkeys = new string[values.Count];
74+
75+
int i = 0;
76+
foreach (object value in values)
77+
{
78+
returnkeys[i] = value as string;
79+
i++;
80+
}
81+
82+
return returnkeys;
83+
}
84+
}
85+
}

WebSockets/System.Net.WebSockets.nfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
</ItemGroup>
3434
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
3535
<ItemGroup>
36+
<Compile Include="ClientWebSocket\ClientWebSocketHeaders.cs" />
3637
<Compile Include="MessageReceivedEventArgs.cs" />
3738
<Compile Include="Properties\AssemblyInfo.cs" />
3839
<Compile Include="WebSocket.cs" />

WebSockets/WebSocket.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,15 @@ internal void HardClose()
302302
ConnectionClosed?.Invoke(this, new EventArgs());
303303

304304
//Let the tcp socket linger for a second so it can try and send all data out before final close.
305-
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, 1);
306-
307-
_socket.Close();
305+
try
306+
{
307+
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, 1);
308+
_socket.Close();
309+
}
310+
catch (ObjectDisposedException e)
311+
{
312+
Debug.WriteLine("socket could not be closed properly because it was already disposed");
313+
}
308314
}
309315

310316
internal bool QueueMessageToSend(SendMessageFrame frame)

0 commit comments

Comments
 (0)