aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs
diff options
context:
space:
mode:
Diffstat (limited to 'SocketHttpListener/Net/WebSockets/WebSocketValidate.cs')
-rw-r--r--SocketHttpListener/Net/WebSockets/WebSocketValidate.cs143
1 files changed, 143 insertions, 0 deletions
diff --git a/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs b/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs
new file mode 100644
index 000000000..00895ea01
--- /dev/null
+++ b/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using MediaBrowser.Model.Net;
+using System.Globalization;
+using WebSocketState = System.Net.WebSockets.WebSocketState;
+
+namespace SocketHttpListener.Net.WebSockets
+{
+ internal static partial class WebSocketValidate
+ {
+ internal const int MaxControlFramePayloadLength = 123;
+ private const int CloseStatusCodeAbort = 1006;
+ private const int CloseStatusCodeFailedTLSHandshake = 1015;
+ private const int InvalidCloseStatusCodesFrom = 0;
+ private const int InvalidCloseStatusCodesTo = 999;
+ private const string Separators = "()<>@,;:\\\"/[]?={} ";
+
+ internal static void ThrowIfInvalidState(WebSocketState currentState, bool isDisposed, WebSocketState[] validStates)
+ {
+ string validStatesText = string.Empty;
+
+ if (validStates != null && validStates.Length > 0)
+ {
+ foreach (WebSocketState validState in validStates)
+ {
+ if (currentState == validState)
+ {
+ // Ordering is important to maintain .NET 4.5 WebSocket implementation exception behavior.
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException(nameof(WebSocket));
+ }
+
+ return;
+ }
+ }
+
+ validStatesText = string.Join(", ", validStates);
+ }
+
+ throw new WebSocketException("net_WebSockets_InvalidState");
+ }
+
+ internal static void ValidateSubprotocol(string subProtocol)
+ {
+ if (string.IsNullOrWhiteSpace(subProtocol))
+ {
+ throw new ArgumentException("net_WebSockets_InvalidEmptySubProtocol");
+ }
+
+ string invalidChar = null;
+ int i = 0;
+ while (i < subProtocol.Length)
+ {
+ char ch = subProtocol[i];
+ if (ch < 0x21 || ch > 0x7e)
+ {
+ invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch);
+ break;
+ }
+
+ if (!char.IsLetterOrDigit(ch) &&
+ Separators.IndexOf(ch) >= 0)
+ {
+ invalidChar = ch.ToString();
+ break;
+ }
+
+ i++;
+ }
+
+ if (invalidChar != null)
+ {
+ throw new ArgumentException("net_WebSockets_InvalidCharInProtocolString");
+ }
+ }
+
+ internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, string statusDescription)
+ {
+ if (closeStatus == WebSocketCloseStatus.Empty && !string.IsNullOrEmpty(statusDescription))
+ {
+ throw new ArgumentException("net_WebSockets_ReasonNotNull");
+ }
+
+ int closeStatusCode = (int)closeStatus;
+
+ if ((closeStatusCode >= InvalidCloseStatusCodesFrom &&
+ closeStatusCode <= InvalidCloseStatusCodesTo) ||
+ closeStatusCode == CloseStatusCodeAbort ||
+ closeStatusCode == CloseStatusCodeFailedTLSHandshake)
+ {
+ // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort
+ throw new ArgumentException("net_WebSockets_InvalidCloseStatusCode");
+ }
+
+ int length = 0;
+ if (!string.IsNullOrEmpty(statusDescription))
+ {
+ length = Encoding.UTF8.GetByteCount(statusDescription);
+ }
+
+ if (length > MaxControlFramePayloadLength)
+ {
+ throw new ArgumentException("net_WebSockets_InvalidCloseStatusDescription");
+ }
+ }
+
+ internal static void ValidateArraySegment(ArraySegment<byte> arraySegment, string parameterName)
+ {
+ if (arraySegment.Array == null)
+ {
+ throw new ArgumentNullException(parameterName + "." + nameof(arraySegment.Array));
+ }
+ if (arraySegment.Offset < 0 || arraySegment.Offset > arraySegment.Array.Length)
+ {
+ throw new ArgumentOutOfRangeException(parameterName + "." + nameof(arraySegment.Offset));
+ }
+ if (arraySegment.Count < 0 || arraySegment.Count > (arraySegment.Array.Length - arraySegment.Offset))
+ {
+ throw new ArgumentOutOfRangeException(parameterName + "." + nameof(arraySegment.Count));
+ }
+ }
+
+ internal static void ValidateBuffer(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+
+ if (offset < 0 || offset > buffer.Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(offset));
+ }
+
+ if (count < 0 || count > (buffer.Length - offset))
+ {
+ throw new ArgumentOutOfRangeException(nameof(count));
+ }
+ }
+ }
+}