aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener.Portable
diff options
context:
space:
mode:
Diffstat (limited to 'SocketHttpListener.Portable')
-rw-r--r--SocketHttpListener.Portable/ByteOrder.cs17
-rw-r--r--SocketHttpListener.Portable/CloseEventArgs.cs90
-rw-r--r--SocketHttpListener.Portable/CloseStatusCode.cs94
-rw-r--r--SocketHttpListener.Portable/CompressionMethod.cs23
-rw-r--r--SocketHttpListener.Portable/ErrorEventArgs.cs46
-rw-r--r--SocketHttpListener.Portable/Ext.cs1083
-rw-r--r--SocketHttpListener.Portable/Fin.cs8
-rw-r--r--SocketHttpListener.Portable/HttpBase.cs104
-rw-r--r--SocketHttpListener.Portable/HttpResponse.cs161
-rw-r--r--SocketHttpListener.Portable/Mask.cs8
-rw-r--r--SocketHttpListener.Portable/MessageEventArgs.cs96
-rw-r--r--SocketHttpListener.Portable/Net/AuthenticationSchemeSelector.cs6
-rw-r--r--SocketHttpListener.Portable/Net/ChunkStream.cs371
-rw-r--r--SocketHttpListener.Portable/Net/ChunkedInputStream.cs160
-rw-r--r--SocketHttpListener.Portable/Net/CookieHelper.cs144
-rw-r--r--SocketHttpListener.Portable/Net/EndPointListener.cs391
-rw-r--r--SocketHttpListener.Portable/Net/EndPointManager.cs166
-rw-r--r--SocketHttpListener.Portable/Net/HttpConnection.cs558
-rw-r--r--SocketHttpListener.Portable/Net/HttpListener.cs293
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerBasicIdentity.cs70
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerContext.cs198
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerPrefixCollection.cs97
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerRequest.cs654
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerResponse.cs525
-rw-r--r--SocketHttpListener.Portable/Net/HttpStatusCode.cs321
-rw-r--r--SocketHttpListener.Portable/Net/HttpStreamAsyncResult.cs77
-rw-r--r--SocketHttpListener.Portable/Net/HttpVersion.cs16
-rw-r--r--SocketHttpListener.Portable/Net/ListenerPrefix.cs148
-rw-r--r--SocketHttpListener.Portable/Net/RequestStream.cs231
-rw-r--r--SocketHttpListener.Portable/Net/ResponseStream.cs453
-rw-r--r--SocketHttpListener.Portable/Net/WebHeaderCollection.cs391
-rw-r--r--SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs348
-rw-r--r--SocketHttpListener.Portable/Net/WebSockets/WebSocketContext.cs183
-rw-r--r--SocketHttpListener.Portable/Opcode.cs43
-rw-r--r--SocketHttpListener.Portable/PayloadData.cs149
-rw-r--r--SocketHttpListener.Portable/Primitives/HttpListenerException.cs17
-rw-r--r--SocketHttpListener.Portable/Primitives/ICertificate.cs12
-rw-r--r--SocketHttpListener.Portable/Primitives/IStreamFactory.cs18
-rw-r--r--SocketHttpListener.Portable/Primitives/ITextEncoding.cs17
-rw-r--r--SocketHttpListener.Portable/Properties/AssemblyInfo.cs30
-rw-r--r--SocketHttpListener.Portable/Rsv.cs8
-rw-r--r--SocketHttpListener.Portable/SocketHttpListener.Portable.csproj108
-rw-r--r--SocketHttpListener.Portable/SocketHttpListener.Portable.nuget.targets6
-rw-r--r--SocketHttpListener.Portable/WebSocket.cs887
-rw-r--r--SocketHttpListener.Portable/WebSocketException.cs60
-rw-r--r--SocketHttpListener.Portable/WebSocketFrame.cs578
-rw-r--r--SocketHttpListener.Portable/WebSocketState.cs35
-rw-r--r--SocketHttpListener.Portable/packages.config5
-rw-r--r--SocketHttpListener.Portable/project.json17
49 files changed, 0 insertions, 9521 deletions
diff --git a/SocketHttpListener.Portable/ByteOrder.cs b/SocketHttpListener.Portable/ByteOrder.cs
deleted file mode 100644
index f5db52fd7..000000000
--- a/SocketHttpListener.Portable/ByteOrder.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the values that indicate whether the byte order is a Little-endian or Big-endian.
- /// </summary>
- public enum ByteOrder : byte
- {
- /// <summary>
- /// Indicates a Little-endian.
- /// </summary>
- Little,
- /// <summary>
- /// Indicates a Big-endian.
- /// </summary>
- Big
- }
-}
diff --git a/SocketHttpListener.Portable/CloseEventArgs.cs b/SocketHttpListener.Portable/CloseEventArgs.cs
deleted file mode 100644
index b1bb4b196..000000000
--- a/SocketHttpListener.Portable/CloseEventArgs.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using System;
-using System.Text;
-
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the event data associated with a <see cref="WebSocket.OnClose"/> event.
- /// </summary>
- /// <remarks>
- /// A <see cref="WebSocket.OnClose"/> event occurs when the WebSocket connection has been closed.
- /// If you would like to get the reason for the close, you should access the <see cref="Code"/> or
- /// <see cref="Reason"/> property.
- /// </remarks>
- public class CloseEventArgs : EventArgs
- {
- #region Private Fields
-
- private bool _clean;
- private ushort _code;
- private string _reason;
-
- #endregion
-
- #region Internal Constructors
-
- internal CloseEventArgs (PayloadData payload)
- {
- var data = payload.ApplicationData;
- var len = data.Length;
- _code = len > 1
- ? data.SubArray (0, 2).ToUInt16 (ByteOrder.Big)
- : (ushort) CloseStatusCode.NoStatusCode;
-
- _reason = len > 2
- ? GetUtf8String(data.SubArray (2, len - 2))
- : String.Empty;
- }
-
- private string GetUtf8String(byte[] bytes)
- {
- return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the status code for the close.
- /// </summary>
- /// <value>
- /// A <see cref="ushort"/> that represents the status code for the close if any.
- /// </value>
- public ushort Code {
- get {
- return _code;
- }
- }
-
- /// <summary>
- /// Gets the reason for the close.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that represents the reason for the close if any.
- /// </value>
- public string Reason {
- get {
- return _reason;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether the WebSocket connection has been closed cleanly.
- /// </summary>
- /// <value>
- /// <c>true</c> if the WebSocket connection has been closed cleanly; otherwise, <c>false</c>.
- /// </value>
- public bool WasClean {
- get {
- return _clean;
- }
-
- internal set {
- _clean = value;
- }
- }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/CloseStatusCode.cs b/SocketHttpListener.Portable/CloseStatusCode.cs
deleted file mode 100644
index 62a268bce..000000000
--- a/SocketHttpListener.Portable/CloseStatusCode.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the values of the status code for the WebSocket connection close.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The values of the status code are defined in
- /// <see href="http://tools.ietf.org/html/rfc6455#section-7.4">Section 7.4</see>
- /// of RFC 6455.
- /// </para>
- /// <para>
- /// "Reserved value" must not be set as a status code in a close control frame
- /// by an endpoint. It's designated for use in applications expecting a status
- /// code to indicate that the connection was closed due to the system grounds.
- /// </para>
- /// </remarks>
- public enum CloseStatusCode : ushort
- {
- /// <summary>
- /// Equivalent to close status 1000.
- /// Indicates a normal close.
- /// </summary>
- Normal = 1000,
- /// <summary>
- /// Equivalent to close status 1001.
- /// Indicates that an endpoint is going away.
- /// </summary>
- Away = 1001,
- /// <summary>
- /// Equivalent to close status 1002.
- /// Indicates that an endpoint is terminating the connection due to a protocol error.
- /// </summary>
- ProtocolError = 1002,
- /// <summary>
- /// Equivalent to close status 1003.
- /// Indicates that an endpoint is terminating the connection because it has received
- /// an unacceptable type message.
- /// </summary>
- IncorrectData = 1003,
- /// <summary>
- /// Equivalent to close status 1004.
- /// Still undefined. Reserved value.
- /// </summary>
- Undefined = 1004,
- /// <summary>
- /// Equivalent to close status 1005.
- /// Indicates that no status code was actually present. Reserved value.
- /// </summary>
- NoStatusCode = 1005,
- /// <summary>
- /// Equivalent to close status 1006.
- /// Indicates that the connection was closed abnormally. Reserved value.
- /// </summary>
- Abnormal = 1006,
- /// <summary>
- /// Equivalent to close status 1007.
- /// Indicates that an endpoint is terminating the connection because it has received
- /// a message that contains a data that isn't consistent with the type of the message.
- /// </summary>
- InconsistentData = 1007,
- /// <summary>
- /// Equivalent to close status 1008.
- /// Indicates that an endpoint is terminating the connection because it has received
- /// a message that violates its policy.
- /// </summary>
- PolicyViolation = 1008,
- /// <summary>
- /// Equivalent to close status 1009.
- /// Indicates that an endpoint is terminating the connection because it has received
- /// a message that is too big to process.
- /// </summary>
- TooBig = 1009,
- /// <summary>
- /// Equivalent to close status 1010.
- /// Indicates that the client is terminating the connection because it has expected
- /// the server to negotiate one or more extension, but the server didn't return them
- /// in the handshake response.
- /// </summary>
- IgnoreExtension = 1010,
- /// <summary>
- /// Equivalent to close status 1011.
- /// Indicates that the server is terminating the connection because it has encountered
- /// an unexpected condition that prevented it from fulfilling the request.
- /// </summary>
- ServerError = 1011,
- /// <summary>
- /// Equivalent to close status 1015.
- /// Indicates that the connection was closed due to a failure to perform a TLS handshake.
- /// Reserved value.
- /// </summary>
- TlsHandshakeFailure = 1015
- }
-}
diff --git a/SocketHttpListener.Portable/CompressionMethod.cs b/SocketHttpListener.Portable/CompressionMethod.cs
deleted file mode 100644
index 36a48d94c..000000000
--- a/SocketHttpListener.Portable/CompressionMethod.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the values of the compression method used to compress the message on the WebSocket
- /// connection.
- /// </summary>
- /// <remarks>
- /// The values of the compression method are defined in
- /// <see href="http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-09">Compression
- /// Extensions for WebSocket</see>.
- /// </remarks>
- public enum CompressionMethod : byte
- {
- /// <summary>
- /// Indicates non compression.
- /// </summary>
- None,
- /// <summary>
- /// Indicates using DEFLATE.
- /// </summary>
- Deflate
- }
-}
diff --git a/SocketHttpListener.Portable/ErrorEventArgs.cs b/SocketHttpListener.Portable/ErrorEventArgs.cs
deleted file mode 100644
index bf1d6fc95..000000000
--- a/SocketHttpListener.Portable/ErrorEventArgs.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the event data associated with a <see cref="WebSocket.OnError"/> event.
- /// </summary>
- /// <remarks>
- /// A <see cref="WebSocket.OnError"/> event occurs when the <see cref="WebSocket"/> gets an error.
- /// If you would like to get the error message, you should access the <see cref="Message"/>
- /// property.
- /// </remarks>
- public class ErrorEventArgs : EventArgs
- {
- #region Private Fields
-
- private string _message;
-
- #endregion
-
- #region Internal Constructors
-
- internal ErrorEventArgs (string message)
- {
- _message = message;
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the error message.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that represents the error message.
- /// </value>
- public string Message {
- get {
- return _message;
- }
- }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/Ext.cs b/SocketHttpListener.Portable/Ext.cs
deleted file mode 100644
index 87f0887ed..000000000
--- a/SocketHttpListener.Portable/Ext.cs
+++ /dev/null
@@ -1,1083 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.IO.Compression;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-using SocketHttpListener.Net;
-using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
-using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
-
-namespace SocketHttpListener
-{
- /// <summary>
- /// Provides a set of static methods for the websocket-sharp.
- /// </summary>
- public static class Ext
- {
- #region Private Const Fields
-
- private const string _tspecials = "()<>@,;:\\\"/[]?={} \t";
-
- #endregion
-
- #region Private Methods
-
- private static MemoryStream compress(this Stream stream)
- {
- var output = new MemoryStream();
- if (stream.Length == 0)
- return output;
-
- stream.Position = 0;
- using (var ds = new DeflateStream(output, CompressionMode.Compress, true))
- {
- stream.CopyTo(ds);
- //ds.Close(); // "BFINAL" set to 1.
- output.Position = 0;
-
- return output;
- }
- }
-
- private static byte[] decompress(this byte[] value)
- {
- if (value.Length == 0)
- return value;
-
- using (var input = new MemoryStream(value))
- {
- return input.decompressToArray();
- }
- }
-
- private static MemoryStream decompress(this Stream stream)
- {
- var output = new MemoryStream();
- if (stream.Length == 0)
- return output;
-
- stream.Position = 0;
- using (var ds = new DeflateStream(stream, CompressionMode.Decompress, true))
- {
- ds.CopyTo(output, true);
- return output;
- }
- }
-
- private static byte[] decompressToArray(this Stream stream)
- {
- using (var decomp = stream.decompress())
- {
- return decomp.ToArray();
- }
- }
-
- private static byte[] readBytes(this Stream stream, byte[] buffer, int offset, int length)
- {
- var len = stream.Read(buffer, offset, length);
- if (len < 1)
- return buffer.SubArray(0, offset);
-
- var tmp = 0;
- while (len < length)
- {
- tmp = stream.Read(buffer, offset + len, length - len);
- if (tmp < 1)
- break;
-
- len += tmp;
- }
-
- return len < length
- ? buffer.SubArray(0, offset + len)
- : buffer;
- }
-
- private static bool readBytes(
- this Stream stream, byte[] buffer, int offset, int length, Stream dest)
- {
- var bytes = stream.readBytes(buffer, offset, length);
- var len = bytes.Length;
- dest.Write(bytes, 0, len);
-
- return len == offset + length;
- }
-
- #endregion
-
- #region Internal Methods
-
- internal static byte[] Append(this ushort code, string reason)
- {
- using (var buffer = new MemoryStream())
- {
- var tmp = code.ToByteArrayInternally(ByteOrder.Big);
- buffer.Write(tmp, 0, 2);
- if (reason != null && reason.Length > 0)
- {
- tmp = Encoding.UTF8.GetBytes(reason);
- buffer.Write(tmp, 0, tmp.Length);
- }
-
- return buffer.ToArray();
- }
- }
-
- internal static string CheckIfClosable(this WebSocketState state)
- {
- return state == WebSocketState.Closing
- ? "While closing the WebSocket connection."
- : state == WebSocketState.Closed
- ? "The WebSocket connection has already been closed."
- : null;
- }
-
- internal static string CheckIfOpen(this WebSocketState state)
- {
- return state == WebSocketState.Connecting
- ? "A WebSocket connection isn't established."
- : state == WebSocketState.Closing
- ? "While closing the WebSocket connection."
- : state == WebSocketState.Closed
- ? "The WebSocket connection has already been closed."
- : null;
- }
-
- internal static string CheckIfValidControlData(this byte[] data, string paramName)
- {
- return data.Length > 125
- ? String.Format("'{0}' length must be less.", paramName)
- : null;
- }
-
- internal static string CheckIfValidSendData(this byte[] data)
- {
- return data == null
- ? "'data' must not be null."
- : null;
- }
-
- internal static string CheckIfValidSendData(this string data)
- {
- return data == null
- ? "'data' must not be null."
- : null;
- }
-
- internal static Stream Compress(this Stream stream, CompressionMethod method)
- {
- return method == CompressionMethod.Deflate
- ? stream.compress()
- : stream;
- }
-
- internal static bool Contains<T>(this IEnumerable<T> source, Func<T, bool> condition)
- {
- foreach (T elm in source)
- if (condition(elm))
- return true;
-
- return false;
- }
-
- internal static void CopyTo(this Stream src, Stream dest, bool setDefaultPosition)
- {
- var readLen = 0;
- var bufferLen = 256;
- var buffer = new byte[bufferLen];
- while ((readLen = src.Read(buffer, 0, bufferLen)) > 0)
- {
- dest.Write(buffer, 0, readLen);
- }
-
- if (setDefaultPosition)
- dest.Position = 0;
- }
-
- internal static byte[] Decompress(this byte[] value, CompressionMethod method)
- {
- return method == CompressionMethod.Deflate
- ? value.decompress()
- : value;
- }
-
- internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method)
- {
- return method == CompressionMethod.Deflate
- ? stream.decompressToArray()
- : stream.ToByteArray();
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="int"/> equals the specified <see cref="char"/>,
- /// and invokes the specified Action&lt;int&gt; delegate at the same time.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="value"/> equals <paramref name="c"/>;
- /// otherwise, <c>false</c>.
- /// </returns>
- /// <param name="value">
- /// An <see cref="int"/> to compare.
- /// </param>
- /// <param name="c">
- /// A <see cref="char"/> to compare.
- /// </param>
- /// <param name="action">
- /// An Action&lt;int&gt; delegate that references the method(s) called at
- /// the same time as comparing. An <see cref="int"/> parameter to pass to
- /// the method(s) is <paramref name="value"/>.
- /// </param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="value"/> isn't between 0 and 255.
- /// </exception>
- internal static bool EqualsWith(this int value, char c, Action<int> action)
- {
- if (value < 0 || value > 255)
- throw new ArgumentOutOfRangeException("value");
-
- action(value);
- return value == c - 0;
- }
-
- internal static string GetMessage(this CloseStatusCode code)
- {
- return code == CloseStatusCode.ProtocolError
- ? "A WebSocket protocol error has occurred."
- : code == CloseStatusCode.IncorrectData
- ? "An incorrect data has been received."
- : code == CloseStatusCode.Abnormal
- ? "An exception has occurred."
- : code == CloseStatusCode.InconsistentData
- ? "An inconsistent data has been received."
- : code == CloseStatusCode.PolicyViolation
- ? "A policy violation has occurred."
- : code == CloseStatusCode.TooBig
- ? "A too big data has been received."
- : code == CloseStatusCode.IgnoreExtension
- ? "WebSocket client did not receive expected extension(s)."
- : code == CloseStatusCode.ServerError
- ? "WebSocket server got an internal error."
- : code == CloseStatusCode.TlsHandshakeFailure
- ? "An error has occurred while handshaking."
- : String.Empty;
- }
-
- internal static string GetNameInternal(this string nameAndValue, string separator)
- {
- var i = nameAndValue.IndexOf(separator);
- return i > 0
- ? nameAndValue.Substring(0, i).Trim()
- : null;
- }
-
- internal static string GetValueInternal(this string nameAndValue, string separator)
- {
- var i = nameAndValue.IndexOf(separator);
- return i >= 0 && i < nameAndValue.Length - 1
- ? nameAndValue.Substring(i + 1).Trim()
- : null;
- }
-
- internal static bool IsCompressionExtension(this string value, CompressionMethod method)
- {
- return value.StartsWith(method.ToExtensionString());
- }
-
- internal static bool IsPortNumber(this int value)
- {
- return value > 0 && value < 65536;
- }
-
- internal static bool IsReserved(this ushort code)
- {
- return code == (ushort)CloseStatusCode.Undefined ||
- code == (ushort)CloseStatusCode.NoStatusCode ||
- code == (ushort)CloseStatusCode.Abnormal ||
- code == (ushort)CloseStatusCode.TlsHandshakeFailure;
- }
-
- internal static bool IsReserved(this CloseStatusCode code)
- {
- return code == CloseStatusCode.Undefined ||
- code == CloseStatusCode.NoStatusCode ||
- code == CloseStatusCode.Abnormal ||
- code == CloseStatusCode.TlsHandshakeFailure;
- }
-
- internal static bool IsText(this string value)
- {
- var len = value.Length;
- for (var i = 0; i < len; i++)
- {
- char c = value[i];
- if (c < 0x20 && !"\r\n\t".Contains(c))
- return false;
-
- if (c == 0x7f)
- return false;
-
- if (c == '\n' && ++i < len)
- {
- c = value[i];
- if (!" \t".Contains(c))
- return false;
- }
- }
-
- return true;
- }
-
- internal static bool IsToken(this string value)
- {
- foreach (char c in value)
- if (c < 0x20 || c >= 0x7f || _tspecials.Contains(c))
- return false;
-
- return true;
- }
-
- internal static string Quote(this string value)
- {
- return value.IsToken()
- ? value
- : String.Format("\"{0}\"", value.Replace("\"", "\\\""));
- }
-
- internal static byte[] ReadBytes(this Stream stream, int length)
- {
- return stream.readBytes(new byte[length], 0, length);
- }
-
- internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength)
- {
- using (var result = new MemoryStream())
- {
- var count = length / bufferLength;
- var rem = (int)(length % bufferLength);
-
- var buffer = new byte[bufferLength];
- var end = false;
- for (long i = 0; i < count; i++)
- {
- if (!stream.readBytes(buffer, 0, bufferLength, result))
- {
- end = true;
- break;
- }
- }
-
- if (!end && rem > 0)
- stream.readBytes(new byte[rem], 0, rem, result);
-
- return result.ToArray();
- }
- }
-
- internal static async Task<byte[]> ReadBytesAsync(this Stream stream, int length)
- {
- var buffer = new byte[length];
-
- var len = await stream.ReadAsync(buffer, 0, length).ConfigureAwait(false);
- var bytes = len < 1
- ? new byte[0]
- : len < length
- ? stream.readBytes(buffer, len, length - len)
- : buffer;
-
- return bytes;
- }
-
- internal static string RemovePrefix(this string value, params string[] prefixes)
- {
- var i = 0;
- foreach (var prefix in prefixes)
- {
- if (value.StartsWith(prefix))
- {
- i = prefix.Length;
- break;
- }
- }
-
- return i > 0
- ? value.Substring(i)
- : value;
- }
-
- internal static T[] Reverse<T>(this T[] array)
- {
- var len = array.Length;
- T[] reverse = new T[len];
-
- var end = len - 1;
- for (var i = 0; i <= end; i++)
- reverse[i] = array[end - i];
-
- return reverse;
- }
-
- internal static IEnumerable<string> SplitHeaderValue(
- this string value, params char[] separator)
- {
- var len = value.Length;
- var separators = new string(separator);
-
- var buffer = new StringBuilder(32);
- var quoted = false;
- var escaped = false;
-
- char c;
- for (var i = 0; i < len; i++)
- {
- c = value[i];
- if (c == '"')
- {
- if (escaped)
- escaped = !escaped;
- else
- quoted = !quoted;
- }
- else if (c == '\\')
- {
- if (i < len - 1 && value[i + 1] == '"')
- escaped = true;
- }
- else if (separators.Contains(c))
- {
- if (!quoted)
- {
- yield return buffer.ToString();
- buffer.Length = 0;
-
- continue;
- }
- }
- else {
- }
-
- buffer.Append(c);
- }
-
- if (buffer.Length > 0)
- yield return buffer.ToString();
- }
-
- internal static byte[] ToByteArray(this Stream stream)
- {
- using (var output = new MemoryStream())
- {
- stream.Position = 0;
- stream.CopyTo(output);
-
- return output.ToArray();
- }
- }
-
- internal static byte[] ToByteArrayInternally(this ushort value, ByteOrder order)
- {
- var bytes = BitConverter.GetBytes(value);
- if (!order.IsHostOrder())
- Array.Reverse(bytes);
-
- return bytes;
- }
-
- internal static byte[] ToByteArrayInternally(this ulong value, ByteOrder order)
- {
- var bytes = BitConverter.GetBytes(value);
- if (!order.IsHostOrder())
- Array.Reverse(bytes);
-
- return bytes;
- }
-
- internal static string ToExtensionString(
- this CompressionMethod method, params string[] parameters)
- {
- if (method == CompressionMethod.None)
- return String.Empty;
-
- var m = String.Format("permessage-{0}", method.ToString().ToLower());
- if (parameters == null || parameters.Length == 0)
- return m;
-
- return String.Format("{0}; {1}", m, parameters.ToString("; "));
- }
-
- internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
- {
- return new List<TSource>(source);
- }
-
- internal static ushort ToUInt16(this byte[] src, ByteOrder srcOrder)
- {
- return BitConverter.ToUInt16(src.ToHostOrder(srcOrder), 0);
- }
-
- internal static ulong ToUInt64(this byte[] src, ByteOrder srcOrder)
- {
- return BitConverter.ToUInt64(src.ToHostOrder(srcOrder), 0);
- }
-
- internal static string TrimEndSlash(this string value)
- {
- value = value.TrimEnd('/');
- return value.Length > 0
- ? value
- : "/";
- }
-
- internal static string Unquote(this string value)
- {
- var start = value.IndexOf('\"');
- var end = value.LastIndexOf('\"');
- if (start < end)
- value = value.Substring(start + 1, end - start - 1).Replace("\\\"", "\"");
-
- return value.Trim();
- }
-
- internal static void WriteBytes(this Stream stream, byte[] value)
- {
- using (var src = new MemoryStream(value))
- {
- src.CopyTo(stream);
- }
- }
-
- #endregion
-
- #region Public Methods
-
- /// <summary>
- /// Determines whether the specified <see cref="string"/> contains any of characters
- /// in the specified array of <see cref="char"/>.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="value"/> contains any of <paramref name="chars"/>;
- /// otherwise, <c>false</c>.
- /// </returns>
- /// <param name="value">
- /// A <see cref="string"/> to test.
- /// </param>
- /// <param name="chars">
- /// An array of <see cref="char"/> that contains characters to find.
- /// </param>
- public static bool Contains(this string value, params char[] chars)
- {
- return chars == null || chars.Length == 0
- ? true
- : value == null || value.Length == 0
- ? false
- : value.IndexOfAny(chars) != -1;
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="QueryParamCollection"/> contains the entry
- /// with the specified <paramref name="name"/>.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="collection"/> contains the entry
- /// with <paramref name="name"/>; otherwise, <c>false</c>.
- /// </returns>
- /// <param name="collection">
- /// A <see cref="QueryParamCollection"/> to test.
- /// </param>
- /// <param name="name">
- /// A <see cref="string"/> that represents the key of the entry to find.
- /// </param>
- public static bool Contains(this QueryParamCollection collection, string name)
- {
- return collection == null || collection.Count == 0
- ? false
- : collection[name] != null;
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="QueryParamCollection"/> contains the entry
- /// with the specified both <paramref name="name"/> and <paramref name="value"/>.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="collection"/> contains the entry
- /// with both <paramref name="name"/> and <paramref name="value"/>;
- /// otherwise, <c>false</c>.
- /// </returns>
- /// <param name="collection">
- /// A <see cref="QueryParamCollection"/> to test.
- /// </param>
- /// <param name="name">
- /// A <see cref="string"/> that represents the key of the entry to find.
- /// </param>
- /// <param name="value">
- /// A <see cref="string"/> that represents the value of the entry to find.
- /// </param>
- public static bool Contains(this QueryParamCollection collection, string name, string value)
- {
- if (collection == null || collection.Count == 0)
- return false;
-
- var values = collection[name];
- if (values == null)
- return false;
-
- foreach (var v in values.Split(','))
- if (v.Trim().Equals(value, StringComparison.OrdinalIgnoreCase))
- return true;
-
- return false;
- }
-
- /// <summary>
- /// Emits the specified <see cref="EventHandler"/> delegate if it isn't <see langword="null"/>.
- /// </summary>
- /// <param name="eventHandler">
- /// A <see cref="EventHandler"/> to emit.
- /// </param>
- /// <param name="sender">
- /// An <see cref="object"/> from which emits this <paramref name="eventHandler"/>.
- /// </param>
- /// <param name="e">
- /// A <see cref="EventArgs"/> that contains no event data.
- /// </param>
- public static void Emit(this EventHandler eventHandler, object sender, EventArgs e)
- {
- if (eventHandler != null)
- eventHandler(sender, e);
- }
-
- /// <summary>
- /// Emits the specified <c>EventHandler&lt;TEventArgs&gt;</c> delegate
- /// if it isn't <see langword="null"/>.
- /// </summary>
- /// <param name="eventHandler">
- /// An <c>EventHandler&lt;TEventArgs&gt;</c> to emit.
- /// </param>
- /// <param name="sender">
- /// An <see cref="object"/> from which emits this <paramref name="eventHandler"/>.
- /// </param>
- /// <param name="e">
- /// A <c>TEventArgs</c> that represents the event data.
- /// </param>
- /// <typeparam name="TEventArgs">
- /// The type of the event data generated by the event.
- /// </typeparam>
- public static void Emit<TEventArgs>(
- this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e)
- where TEventArgs : EventArgs
- {
- if (eventHandler != null)
- eventHandler(sender, e);
- }
-
- /// <summary>
- /// Gets the collection of the HTTP cookies from the specified HTTP <paramref name="headers"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="CookieCollection"/> that receives a collection of the HTTP cookies.
- /// </returns>
- /// <param name="headers">
- /// A <see cref="QueryParamCollection"/> that contains a collection of the HTTP headers.
- /// </param>
- /// <param name="response">
- /// <c>true</c> if <paramref name="headers"/> is a collection of the response headers;
- /// otherwise, <c>false</c>.
- /// </param>
- public static CookieCollection GetCookies(this QueryParamCollection headers, bool response)
- {
- var name = response ? "Set-Cookie" : "Cookie";
- return headers == null || !headers.Contains(name)
- ? new CookieCollection()
- : CookieHelper.Parse(headers[name], response);
- }
-
- /// <summary>
- /// Gets the description of the specified HTTP status <paramref name="code"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> that represents the description of the HTTP status code.
- /// </returns>
- /// <param name="code">
- /// One of <see cref="HttpStatusCode"/> enum values, indicates the HTTP status codes.
- /// </param>
- public static string GetDescription(this HttpStatusCode code)
- {
- return ((int)code).GetStatusDescription();
- }
-
- /// <summary>
- /// Gets the name from the specified <see cref="string"/> that contains a pair of name and
- /// value separated by a separator string.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> that represents the name if any; otherwise, <c>null</c>.
- /// </returns>
- /// <param name="nameAndValue">
- /// A <see cref="string"/> that contains a pair of name and value separated by a separator
- /// string.
- /// </param>
- /// <param name="separator">
- /// A <see cref="string"/> that represents a separator string.
- /// </param>
- public static string GetName(this string nameAndValue, string separator)
- {
- return (nameAndValue != null && nameAndValue.Length > 0) &&
- (separator != null && separator.Length > 0)
- ? nameAndValue.GetNameInternal(separator)
- : null;
- }
-
- /// <summary>
- /// Gets the name and value from the specified <see cref="string"/> that contains a pair of
- /// name and value separated by a separator string.
- /// </summary>
- /// <returns>
- /// A <c>KeyValuePair&lt;string, string&gt;</c> that represents the name and value if any.
- /// </returns>
- /// <param name="nameAndValue">
- /// A <see cref="string"/> that contains a pair of name and value separated by a separator
- /// string.
- /// </param>
- /// <param name="separator">
- /// A <see cref="string"/> that represents a separator string.
- /// </param>
- public static KeyValuePair<string, string> GetNameAndValue(
- this string nameAndValue, string separator)
- {
- var name = nameAndValue.GetName(separator);
- var value = nameAndValue.GetValue(separator);
- return name != null
- ? new KeyValuePair<string, string>(name, value)
- : new KeyValuePair<string, string>(null, null);
- }
-
- /// <summary>
- /// Gets the description of the specified HTTP status <paramref name="code"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> that represents the description of the HTTP status code.
- /// </returns>
- /// <param name="code">
- /// An <see cref="int"/> that represents the HTTP status code.
- /// </param>
- public static string GetStatusDescription(this int code)
- {
- switch (code)
- {
- case 100: return "Continue";
- case 101: return "Switching Protocols";
- case 102: return "Processing";
- case 200: return "OK";
- case 201: return "Created";
- case 202: return "Accepted";
- case 203: return "Non-Authoritative Information";
- case 204: return "No Content";
- case 205: return "Reset Content";
- case 206: return "Partial Content";
- case 207: return "Multi-Status";
- case 300: return "Multiple Choices";
- case 301: return "Moved Permanently";
- case 302: return "Found";
- case 303: return "See Other";
- case 304: return "Not Modified";
- case 305: return "Use Proxy";
- case 307: return "Temporary Redirect";
- case 400: return "Bad Request";
- case 401: return "Unauthorized";
- case 402: return "Payment Required";
- case 403: return "Forbidden";
- case 404: return "Not Found";
- case 405: return "Method Not Allowed";
- case 406: return "Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Timeout";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Request Entity Too Large";
- case 414: return "Request-Uri Too Long";
- case 415: return "Unsupported Media Type";
- case 416: return "Requested Range Not Satisfiable";
- case 417: return "Expectation Failed";
- case 422: return "Unprocessable Entity";
- case 423: return "Locked";
- case 424: return "Failed Dependency";
- case 500: return "Internal Server Error";
- case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Timeout";
- case 505: return "Http Version Not Supported";
- case 507: return "Insufficient Storage";
- }
-
- return String.Empty;
- }
-
- /// <summary>
- /// Gets the value from the specified <see cref="string"/> that contains a pair of name and
- /// value separated by a separator string.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> that represents the value if any; otherwise, <c>null</c>.
- /// </returns>
- /// <param name="nameAndValue">
- /// A <see cref="string"/> that contains a pair of name and value separated by a separator
- /// string.
- /// </param>
- /// <param name="separator">
- /// A <see cref="string"/> that represents a separator string.
- /// </param>
- public static string GetValue(this string nameAndValue, string separator)
- {
- return (nameAndValue != null && nameAndValue.Length > 0) &&
- (separator != null && separator.Length > 0)
- ? nameAndValue.GetValueInternal(separator)
- : null;
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="ByteOrder"/> is host
- /// (this computer architecture) byte order.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="order"/> is host byte order;
- /// otherwise, <c>false</c>.
- /// </returns>
- /// <param name="order">
- /// One of the <see cref="ByteOrder"/> enum values, to test.
- /// </param>
- public static bool IsHostOrder(this ByteOrder order)
- {
- // true : !(true ^ true) or !(false ^ false)
- // false: !(true ^ false) or !(false ^ true)
- return !(BitConverter.IsLittleEndian ^ (order == ByteOrder.Little));
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="string"/> is a predefined scheme.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="value"/> is a predefined scheme; otherwise, <c>false</c>.
- /// </returns>
- /// <param name="value">
- /// A <see cref="string"/> to test.
- /// </param>
- public static bool IsPredefinedScheme(this string value)
- {
- if (value == null || value.Length < 2)
- return false;
-
- var c = value[0];
- if (c == 'h')
- return value == "http" || value == "https";
-
- if (c == 'w')
- return value == "ws" || value == "wss";
-
- if (c == 'f')
- return value == "file" || value == "ftp";
-
- if (c == 'n')
- {
- c = value[1];
- return c == 'e'
- ? value == "news" || value == "net.pipe" || value == "net.tcp"
- : value == "nntp";
- }
-
- return (c == 'g' && value == "gopher") || (c == 'm' && value == "mailto");
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="string"/> is a URI string.
- /// </summary>
- /// <returns>
- /// <c>true</c> if <paramref name="value"/> may be a URI string; otherwise, <c>false</c>.
- /// </returns>
- /// <param name="value">
- /// A <see cref="string"/> to test.
- /// </param>
- public static bool MaybeUri(this string value)
- {
- if (value == null || value.Length == 0)
- return false;
-
- var i = value.IndexOf(':');
- if (i == -1)
- return false;
-
- if (i >= 10)
- return false;
-
- return value.Substring(0, i).IsPredefinedScheme();
- }
-
- /// <summary>
- /// Retrieves a sub-array from the specified <paramref name="array"/>.
- /// A sub-array starts at the specified element position.
- /// </summary>
- /// <returns>
- /// An array of T that receives a sub-array, or an empty array of T if any problems
- /// with the parameters.
- /// </returns>
- /// <param name="array">
- /// An array of T that contains the data to retrieve a sub-array.
- /// </param>
- /// <param name="startIndex">
- /// An <see cref="int"/> that contains the zero-based starting position of a sub-array
- /// in <paramref name="array"/>.
- /// </param>
- /// <param name="length">
- /// An <see cref="int"/> that contains the number of elements to retrieve a sub-array.
- /// </param>
- /// <typeparam name="T">
- /// The type of elements in the <paramref name="array"/>.
- /// </typeparam>
- public static T[] SubArray<T>(this T[] array, int startIndex, int length)
- {
- if (array == null || array.Length == 0)
- return new T[0];
-
- if (startIndex < 0 || length <= 0)
- return new T[0];
-
- if (startIndex + length > array.Length)
- return new T[0];
-
- if (startIndex == 0 && array.Length == length)
- return array;
-
- T[] subArray = new T[length];
- Array.Copy(array, startIndex, subArray, 0, length);
-
- return subArray;
- }
-
- /// <summary>
- /// Converts the order of the specified array of <see cref="byte"/> to the host byte order.
- /// </summary>
- /// <returns>
- /// An array of <see cref="byte"/> converted from <paramref name="src"/>.
- /// </returns>
- /// <param name="src">
- /// An array of <see cref="byte"/> to convert.
- /// </param>
- /// <param name="srcOrder">
- /// One of the <see cref="ByteOrder"/> enum values, indicates the byte order of
- /// <paramref name="src"/>.
- /// </param>
- /// <exception cref="ArgumentNullException">
- /// <paramref name="src"/> is <see langword="null"/>.
- /// </exception>
- public static byte[] ToHostOrder(this byte[] src, ByteOrder srcOrder)
- {
- if (src == null)
- throw new ArgumentNullException("src");
-
- return src.Length > 1 && !srcOrder.IsHostOrder()
- ? src.Reverse()
- : src;
- }
-
- /// <summary>
- /// Converts the specified <paramref name="array"/> to a <see cref="string"/> that
- /// concatenates the each element of <paramref name="array"/> across the specified
- /// <paramref name="separator"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> converted from <paramref name="array"/>,
- /// or <see cref="String.Empty"/> if <paramref name="array"/> is empty.
- /// </returns>
- /// <param name="array">
- /// An array of T to convert.
- /// </param>
- /// <param name="separator">
- /// A <see cref="string"/> that represents the separator string.
- /// </param>
- /// <typeparam name="T">
- /// The type of elements in <paramref name="array"/>.
- /// </typeparam>
- /// <exception cref="ArgumentNullException">
- /// <paramref name="array"/> is <see langword="null"/>.
- /// </exception>
- public static string ToString<T>(this T[] array, string separator)
- {
- if (array == null)
- throw new ArgumentNullException("array");
-
- var len = array.Length;
- if (len == 0)
- return String.Empty;
-
- if (separator == null)
- separator = String.Empty;
-
- var buff = new StringBuilder(64);
- (len - 1).Times(i => buff.AppendFormat("{0}{1}", array[i].ToString(), separator));
-
- buff.Append(array[len - 1].ToString());
- return buff.ToString();
- }
-
- /// <summary>
- /// Executes the specified <c>Action&lt;int&gt;</c> delegate <paramref name="n"/> times.
- /// </summary>
- /// <param name="n">
- /// An <see cref="int"/> is the number of times to execute.
- /// </param>
- /// <param name="action">
- /// An <c>Action&lt;int&gt;</c> delegate that references the method(s) to execute.
- /// An <see cref="int"/> parameter to pass to the method(s) is the zero-based count of
- /// iteration.
- /// </param>
- public static void Times(this int n, Action<int> action)
- {
- if (n > 0 && action != null)
- for (int i = 0; i < n; i++)
- action(i);
- }
-
- /// <summary>
- /// Converts the specified <see cref="string"/> to a <see cref="Uri"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="Uri"/> converted from <paramref name="uriString"/>, or <see langword="null"/>
- /// if <paramref name="uriString"/> isn't successfully converted.
- /// </returns>
- /// <param name="uriString">
- /// A <see cref="string"/> to convert.
- /// </param>
- public static Uri ToUri(this string uriString)
- {
- Uri res;
- return Uri.TryCreate(
- uriString, uriString.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out res)
- ? res
- : null;
- }
-
- /// <summary>
- /// URL-decodes the specified <see cref="string"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> that receives the decoded string, or the <paramref name="value"/>
- /// if it's <see langword="null"/> or empty.
- /// </returns>
- /// <param name="value">
- /// A <see cref="string"/> to decode.
- /// </param>
- public static string UrlDecode(this string value)
- {
- return value == null || value.Length == 0
- ? value
- : WebUtility.UrlDecode(value);
- }
-
- #endregion
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/Fin.cs b/SocketHttpListener.Portable/Fin.cs
deleted file mode 100644
index f91401b99..000000000
--- a/SocketHttpListener.Portable/Fin.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace SocketHttpListener
-{
- internal enum Fin : byte
- {
- More = 0x0,
- Final = 0x1
- }
-}
diff --git a/SocketHttpListener.Portable/HttpBase.cs b/SocketHttpListener.Portable/HttpBase.cs
deleted file mode 100644
index 5172ba497..000000000
--- a/SocketHttpListener.Portable/HttpBase.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.Text;
-using System.Threading;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener
-{
- internal abstract class HttpBase
- {
- #region Private Fields
-
- private QueryParamCollection _headers;
- private Version _version;
-
- #endregion
-
- #region Internal Fields
-
- internal byte[] EntityBodyData;
-
- #endregion
-
- #region Protected Fields
-
- protected const string CrLf = "\r\n";
-
- #endregion
-
- #region Protected Constructors
-
- protected HttpBase(Version version, QueryParamCollection headers)
- {
- _version = version;
- _headers = headers;
- }
-
- #endregion
-
- #region Public Properties
-
- public string EntityBody
- {
- get
- {
- var data = EntityBodyData;
-
- return data != null && data.Length > 0
- ? getEncoding(_headers["Content-Type"]).GetString(data, 0, data.Length)
- : String.Empty;
- }
- }
-
- public QueryParamCollection Headers
- {
- get
- {
- return _headers;
- }
- }
-
- public Version ProtocolVersion
- {
- get
- {
- return _version;
- }
- }
-
- #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).TrimEnd();
-
- return Encoding.GetEncoding(charset.Trim('"'));
- }
-
- #endregion
-
- #region Public Methods
-
- public byte[] ToByteArray()
- {
- return Encoding.UTF8.GetBytes(ToString());
- }
-
- #endregion
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/HttpResponse.cs b/SocketHttpListener.Portable/HttpResponse.cs
deleted file mode 100644
index 5aca28c7c..000000000
--- a/SocketHttpListener.Portable/HttpResponse.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-using System;
-using System.Collections.Specialized;
-using System.IO;
-using System.Net;
-using System.Text;
-using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
-using HttpVersion = SocketHttpListener.Net.HttpVersion;
-using System.Linq;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener
-{
- internal class HttpResponse : HttpBase
- {
- #region Private Fields
-
- private string _code;
- private string _reason;
-
- #endregion
-
- #region Private Constructors
-
- private HttpResponse(string code, string reason, Version version, QueryParamCollection headers)
- : base(version, headers)
- {
- _code = code;
- _reason = reason;
- }
-
- #endregion
-
- #region Internal Constructors
-
- internal HttpResponse(HttpStatusCode code)
- : this(code, code.GetDescription())
- {
- }
-
- internal HttpResponse(HttpStatusCode code, string reason)
- : this(((int)code).ToString(), reason, HttpVersion.Version11, new QueryParamCollection())
- {
- Headers["Server"] = "websocket-sharp/1.0";
- }
-
- #endregion
-
- #region Public Properties
-
- public CookieCollection Cookies
- {
- get
- {
- return Headers.GetCookies(true);
- }
- }
-
- public bool IsProxyAuthenticationRequired
- {
- get
- {
- return _code == "407";
- }
- }
-
- public bool IsUnauthorized
- {
- get
- {
- return _code == "401";
- }
- }
-
- public bool IsWebSocketResponse
- {
- get
- {
- var headers = Headers;
- return ProtocolVersion > HttpVersion.Version10 &&
- _code == "101" &&
- headers.Contains("Upgrade", "websocket") &&
- headers.Contains("Connection", "Upgrade");
- }
- }
-
- public string Reason
- {
- get
- {
- return _reason;
- }
- }
-
- public string StatusCode
- {
- get
- {
- return _code;
- }
- }
-
- #endregion
-
- #region Internal Methods
-
- internal static HttpResponse CreateCloseResponse(HttpStatusCode code)
- {
- var res = new HttpResponse(code);
- res.Headers["Connection"] = "close";
-
- return res;
- }
-
- internal static HttpResponse CreateWebSocketResponse()
- {
- var res = new HttpResponse(HttpStatusCode.SwitchingProtocols);
-
- var headers = res.Headers;
- headers["Upgrade"] = "websocket";
- headers["Connection"] = "Upgrade";
-
- return res;
- }
-
- #endregion
-
- #region Public Methods
-
- public void SetCookies(CookieCollection cookies)
- {
- if (cookies == null || cookies.Count == 0)
- return;
-
- var headers = Headers;
- var sorted = cookies.OfType<Cookie>().OrderBy(i => i.Name).ToList();
-
- foreach (var cookie in sorted)
- headers.Add("Set-Cookie", cookie.ToString());
- }
-
- public override string ToString()
- {
- var output = new StringBuilder(64);
- output.AppendFormat("HTTP/{0} {1} {2}{3}", ProtocolVersion, _code, _reason, CrLf);
-
- var headers = Headers;
- foreach (var key in headers.Keys)
- output.AppendFormat("{0}: {1}{2}", key, headers[key], CrLf);
-
- output.Append(CrLf);
-
- var entity = EntityBody;
- if (entity.Length > 0)
- output.Append(entity);
-
- return output.ToString();
- }
-
- #endregion
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/Mask.cs b/SocketHttpListener.Portable/Mask.cs
deleted file mode 100644
index adc2f098e..000000000
--- a/SocketHttpListener.Portable/Mask.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace SocketHttpListener
-{
- internal enum Mask : byte
- {
- Unmask = 0x0,
- Mask = 0x1
- }
-}
diff --git a/SocketHttpListener.Portable/MessageEventArgs.cs b/SocketHttpListener.Portable/MessageEventArgs.cs
deleted file mode 100644
index 9dbadb9ab..000000000
--- a/SocketHttpListener.Portable/MessageEventArgs.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System;
-using System.Text;
-
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the event data associated with a <see cref="WebSocket.OnMessage"/> event.
- /// </summary>
- /// <remarks>
- /// A <see cref="WebSocket.OnMessage"/> event occurs when the <see cref="WebSocket"/> receives
- /// a text or binary data frame.
- /// If you want to get the received data, you access the <see cref="MessageEventArgs.Data"/> or
- /// <see cref="MessageEventArgs.RawData"/> property.
- /// </remarks>
- public class MessageEventArgs : EventArgs
- {
- #region Private Fields
-
- private string _data;
- private Opcode _opcode;
- private byte[] _rawData;
-
- #endregion
-
- #region Internal Constructors
-
- internal MessageEventArgs (Opcode opcode, byte[] data)
- {
- _opcode = opcode;
- _rawData = data;
- _data = convertToString (opcode, data);
- }
-
- internal MessageEventArgs (Opcode opcode, PayloadData payload)
- {
- _opcode = opcode;
- _rawData = payload.ApplicationData;
- _data = convertToString (opcode, _rawData);
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the received data as a <see cref="string"/>.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that contains the received data.
- /// </value>
- public string Data {
- get {
- return _data;
- }
- }
-
- /// <summary>
- /// Gets the received data as an array of <see cref="byte"/>.
- /// </summary>
- /// <value>
- /// An array of <see cref="byte"/> that contains the received data.
- /// </value>
- public byte [] RawData {
- get {
- return _rawData;
- }
- }
-
- /// <summary>
- /// Gets the type of the received data.
- /// </summary>
- /// <value>
- /// One of the <see cref="Opcode"/> values, indicates the type of the received data.
- /// </value>
- public Opcode Type {
- get {
- return _opcode;
- }
- }
-
- #endregion
-
- #region Private Methods
-
- private static string convertToString (Opcode opcode, byte [] data)
- {
- return data.Length == 0
- ? String.Empty
- : opcode == Opcode.Text
- ? Encoding.UTF8.GetString (data, 0, data.Length)
- : opcode.ToString ();
- }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/Net/AuthenticationSchemeSelector.cs b/SocketHttpListener.Portable/Net/AuthenticationSchemeSelector.cs
deleted file mode 100644
index c6e7e538e..000000000
--- a/SocketHttpListener.Portable/Net/AuthenticationSchemeSelector.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using System.Net;
-
-namespace SocketHttpListener.Net
-{
- public delegate AuthenticationSchemes AuthenticationSchemeSelector(HttpListenerRequest httpRequest);
-}
diff --git a/SocketHttpListener.Portable/Net/ChunkStream.cs b/SocketHttpListener.Portable/Net/ChunkStream.cs
deleted file mode 100644
index 3f3b4a667..000000000
--- a/SocketHttpListener.Portable/Net/ChunkStream.cs
+++ /dev/null
@@ -1,371 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-
-namespace SocketHttpListener.Net
-{
- class ChunkStream
- {
- enum State
- {
- None,
- PartialSize,
- Body,
- BodyFinished,
- Trailer
- }
-
- class Chunk
- {
- public byte[] Bytes;
- public int Offset;
-
- public Chunk(byte[] chunk)
- {
- this.Bytes = chunk;
- }
-
- public int Read(byte[] buffer, int offset, int size)
- {
- int nread = (size > Bytes.Length - Offset) ? Bytes.Length - Offset : size;
- Buffer.BlockCopy(Bytes, Offset, buffer, offset, nread);
- Offset += nread;
- return nread;
- }
- }
-
- internal WebHeaderCollection headers;
- int chunkSize;
- int chunkRead;
- int totalWritten;
- State state;
- //byte [] waitBuffer;
- StringBuilder saved;
- bool sawCR;
- bool gotit;
- int trailerState;
- List<Chunk> chunks;
-
- public ChunkStream(WebHeaderCollection headers)
- {
- this.headers = headers;
- saved = new StringBuilder();
- chunks = new List<Chunk>();
- chunkSize = -1;
- totalWritten = 0;
- }
-
- public void ResetBuffer()
- {
- chunkSize = -1;
- chunkRead = 0;
- totalWritten = 0;
- chunks.Clear();
- }
-
- public void WriteAndReadBack(byte[] buffer, int offset, int size, ref int read)
- {
- if (offset + read > 0)
- Write(buffer, offset, offset + read);
- read = Read(buffer, offset, size);
- }
-
- public int Read(byte[] buffer, int offset, int size)
- {
- return ReadFromChunks(buffer, offset, size);
- }
-
- int ReadFromChunks(byte[] buffer, int offset, int size)
- {
- int count = chunks.Count;
- int nread = 0;
-
- var chunksForRemoving = new List<Chunk>(count);
- for (int i = 0; i < count; i++)
- {
- Chunk chunk = (Chunk)chunks[i];
-
- if (chunk.Offset == chunk.Bytes.Length)
- {
- chunksForRemoving.Add(chunk);
- continue;
- }
-
- nread += chunk.Read(buffer, offset + nread, size - nread);
- if (nread == size)
- break;
- }
-
- foreach (var chunk in chunksForRemoving)
- chunks.Remove(chunk);
-
- return nread;
- }
-
- public void Write(byte[] buffer, int offset, int size)
- {
- if (offset < size)
- InternalWrite(buffer, ref offset, size);
- }
-
- void InternalWrite(byte[] buffer, ref int offset, int size)
- {
- if (state == State.None || state == State.PartialSize)
- {
- state = GetChunkSize(buffer, ref offset, size);
- if (state == State.PartialSize)
- return;
-
- saved.Length = 0;
- sawCR = false;
- gotit = false;
- }
-
- if (state == State.Body && offset < size)
- {
- state = ReadBody(buffer, ref offset, size);
- if (state == State.Body)
- return;
- }
-
- if (state == State.BodyFinished && offset < size)
- {
- state = ReadCRLF(buffer, ref offset, size);
- if (state == State.BodyFinished)
- return;
-
- sawCR = false;
- }
-
- if (state == State.Trailer && offset < size)
- {
- state = ReadTrailer(buffer, ref offset, size);
- if (state == State.Trailer)
- return;
-
- saved.Length = 0;
- sawCR = false;
- gotit = false;
- }
-
- if (offset < size)
- InternalWrite(buffer, ref offset, size);
- }
-
- public bool WantMore
- {
- get { return (chunkRead != chunkSize || chunkSize != 0 || state != State.None); }
- }
-
- public bool DataAvailable
- {
- get
- {
- int count = chunks.Count;
- for (int i = 0; i < count; i++)
- {
- Chunk ch = (Chunk)chunks[i];
- if (ch == null || ch.Bytes == null)
- continue;
- if (ch.Bytes.Length > 0 && ch.Offset < ch.Bytes.Length)
- return (state != State.Body);
- }
- return false;
- }
- }
-
- public int TotalDataSize
- {
- get { return totalWritten; }
- }
-
- public int ChunkLeft
- {
- get { return chunkSize - chunkRead; }
- }
-
- State ReadBody(byte[] buffer, ref int offset, int size)
- {
- if (chunkSize == 0)
- return State.BodyFinished;
-
- int diff = size - offset;
- if (diff + chunkRead > chunkSize)
- diff = chunkSize - chunkRead;
-
- byte[] chunk = new byte[diff];
- Buffer.BlockCopy(buffer, offset, chunk, 0, diff);
- chunks.Add(new Chunk(chunk));
- offset += diff;
- chunkRead += diff;
- totalWritten += diff;
- return (chunkRead == chunkSize) ? State.BodyFinished : State.Body;
-
- }
-
- State GetChunkSize(byte[] buffer, ref int offset, int size)
- {
- chunkRead = 0;
- chunkSize = 0;
- char c = '\0';
- while (offset < size)
- {
- c = (char)buffer[offset++];
- if (c == '\r')
- {
- if (sawCR)
- ThrowProtocolViolation("2 CR found");
-
- sawCR = true;
- continue;
- }
-
- if (sawCR && c == '\n')
- break;
-
- if (c == ' ')
- gotit = true;
-
- if (!gotit)
- saved.Append(c);
-
- if (saved.Length > 20)
- ThrowProtocolViolation("chunk size too long.");
- }
-
- if (!sawCR || c != '\n')
- {
- if (offset < size)
- ThrowProtocolViolation("Missing \\n");
-
- try
- {
- if (saved.Length > 0)
- {
- chunkSize = Int32.Parse(RemoveChunkExtension(saved.ToString()), NumberStyles.HexNumber);
- }
- }
- catch (Exception)
- {
- ThrowProtocolViolation("Cannot parse chunk size.");
- }
-
- return State.PartialSize;
- }
-
- chunkRead = 0;
- try
- {
- chunkSize = Int32.Parse(RemoveChunkExtension(saved.ToString()), NumberStyles.HexNumber);
- }
- catch (Exception)
- {
- ThrowProtocolViolation("Cannot parse chunk size.");
- }
-
- if (chunkSize == 0)
- {
- trailerState = 2;
- return State.Trailer;
- }
-
- return State.Body;
- }
-
- static string RemoveChunkExtension(string input)
- {
- int idx = input.IndexOf(';');
- if (idx == -1)
- return input;
- return input.Substring(0, idx);
- }
-
- State ReadCRLF(byte[] buffer, ref int offset, int size)
- {
- if (!sawCR)
- {
- if ((char)buffer[offset++] != '\r')
- ThrowProtocolViolation("Expecting \\r");
-
- sawCR = true;
- if (offset == size)
- return State.BodyFinished;
- }
-
- if (sawCR && (char)buffer[offset++] != '\n')
- ThrowProtocolViolation("Expecting \\n");
-
- return State.None;
- }
-
- State ReadTrailer(byte[] buffer, ref int offset, int size)
- {
- char c = '\0';
-
- // short path
- if (trailerState == 2 && (char)buffer[offset] == '\r' && saved.Length == 0)
- {
- offset++;
- if (offset < size && (char)buffer[offset] == '\n')
- {
- offset++;
- return State.None;
- }
- offset--;
- }
-
- int st = trailerState;
- string stString = "\r\n\r";
- while (offset < size && st < 4)
- {
- c = (char)buffer[offset++];
- if ((st == 0 || st == 2) && c == '\r')
- {
- st++;
- continue;
- }
-
- if ((st == 1 || st == 3) && c == '\n')
- {
- st++;
- continue;
- }
-
- if (st > 0)
- {
- saved.Append(stString.Substring(0, saved.Length == 0 ? st - 2 : st));
- st = 0;
- if (saved.Length > 4196)
- ThrowProtocolViolation("Error reading trailer (too long).");
- }
- }
-
- if (st < 4)
- {
- trailerState = st;
- if (offset < size)
- ThrowProtocolViolation("Error reading trailer.");
-
- return State.Trailer;
- }
-
- StringReader reader = new StringReader(saved.ToString());
- string line;
- while ((line = reader.ReadLine()) != null && line != "")
- headers.Add(line);
-
- return State.None;
- }
-
- static void ThrowProtocolViolation(string message)
- {
- WebException we = new WebException(message, null, WebExceptionStatus.UnknownError, null);
- //WebException we = new WebException(message, null, WebExceptionStatus.ServerProtocolViolation, null);
- throw we;
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/ChunkedInputStream.cs b/SocketHttpListener.Portable/Net/ChunkedInputStream.cs
deleted file mode 100644
index 6dfd8d8a1..000000000
--- a/SocketHttpListener.Portable/Net/ChunkedInputStream.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- class ChunkedInputStream : RequestStream
- {
- bool disposed;
- ChunkStream decoder;
- HttpListenerContext context;
- bool no_more_data;
-
- //class ReadBufferState
- //{
- // public byte[] Buffer;
- // public int Offset;
- // public int Count;
- // public int InitialCount;
- // public HttpStreamAsyncResult Ares;
- // public ReadBufferState(byte[] buffer, int offset, int count,
- // HttpStreamAsyncResult ares)
- // {
- // Buffer = buffer;
- // Offset = offset;
- // Count = count;
- // InitialCount = count;
- // Ares = ares;
- // }
- //}
-
- public ChunkedInputStream(HttpListenerContext context, Stream stream,
- byte[] buffer, int offset, int length)
- : base(stream, buffer, offset, length)
- {
- this.context = context;
- WebHeaderCollection coll = (WebHeaderCollection)context.Request.Headers;
- decoder = new ChunkStream(coll);
- }
-
- //public ChunkStream Decoder
- //{
- // get { return decoder; }
- // set { decoder = value; }
- //}
-
- //public override int Read([In, Out] byte[] buffer, int offset, int count)
- //{
- // IAsyncResult ares = BeginRead(buffer, offset, count, null, null);
- // return EndRead(ares);
- //}
-
- //public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
- // AsyncCallback cback, object state)
- //{
- // if (disposed)
- // throw new ObjectDisposedException(GetType().ToString());
-
- // if (buffer == null)
- // throw new ArgumentNullException("buffer");
-
- // int len = buffer.Length;
- // if (offset < 0 || offset > len)
- // throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
-
- // if (count < 0 || offset > len - count)
- // throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
-
- // HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
- // ares.Callback = cback;
- // ares.State = state;
- // if (no_more_data)
- // {
- // ares.Complete();
- // return ares;
- // }
- // int nread = decoder.Read(buffer, offset, count);
- // offset += nread;
- // count -= nread;
- // if (count == 0)
- // {
- // // got all we wanted, no need to bother the decoder yet
- // ares.Count = nread;
- // ares.Complete();
- // return ares;
- // }
- // if (!decoder.WantMore)
- // {
- // no_more_data = nread == 0;
- // ares.Count = nread;
- // ares.Complete();
- // return ares;
- // }
- // ares.Buffer = new byte[8192];
- // ares.Offset = 0;
- // ares.Count = 8192;
- // ReadBufferState rb = new ReadBufferState(buffer, offset, count, ares);
- // rb.InitialCount += nread;
- // base.BeginRead(ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
- // return ares;
- //}
-
- //void OnRead(IAsyncResult base_ares)
- //{
- // ReadBufferState rb = (ReadBufferState)base_ares.AsyncState;
- // HttpStreamAsyncResult ares = rb.Ares;
- // try
- // {
- // int nread = base.EndRead(base_ares);
- // decoder.Write(ares.Buffer, ares.Offset, nread);
- // nread = decoder.Read(rb.Buffer, rb.Offset, rb.Count);
- // rb.Offset += nread;
- // rb.Count -= nread;
- // if (rb.Count == 0 || !decoder.WantMore || nread == 0)
- // {
- // no_more_data = !decoder.WantMore && nread == 0;
- // ares.Count = rb.InitialCount - rb.Count;
- // ares.Complete();
- // return;
- // }
- // ares.Offset = 0;
- // ares.Count = Math.Min(8192, decoder.ChunkLeft + 6);
- // base.BeginRead(ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
- // }
- // catch (Exception e)
- // {
- // context.Connection.SendError(e.Message, 400);
- // ares.Complete(e);
- // }
- //}
-
- //public override int EndRead(IAsyncResult ares)
- //{
- // if (disposed)
- // throw new ObjectDisposedException(GetType().ToString());
-
- // HttpStreamAsyncResult my_ares = ares as HttpStreamAsyncResult;
- // if (ares == null)
- // throw new ArgumentException("Invalid IAsyncResult", "ares");
-
- // if (!ares.IsCompleted)
- // ares.AsyncWaitHandle.WaitOne();
-
- // if (my_ares.Error != null)
- // throw new HttpListenerException(400, "I/O operation aborted: " + my_ares.Error.Message);
-
- // return my_ares.Count;
- //}
-
- //protected override void Dispose(bool disposing)
- //{
- // if (!disposed)
- // {
- // disposed = true;
- // base.Dispose(disposing);
- // }
- //}
- }
-}
diff --git a/SocketHttpListener.Portable/Net/CookieHelper.cs b/SocketHttpListener.Portable/Net/CookieHelper.cs
deleted file mode 100644
index 470507d6b..000000000
--- a/SocketHttpListener.Portable/Net/CookieHelper.cs
+++ /dev/null
@@ -1,144 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Net
-{
- public static class CookieHelper
- {
- internal static CookieCollection Parse(string value, bool response)
- {
- return response
- ? parseResponse(value)
- : null;
- }
-
- private static string[] splitCookieHeaderValue(string value)
- {
- return new List<string>(value.SplitHeaderValue(',', ';')).ToArray();
- }
-
- private static CookieCollection parseResponse(string value)
- {
- var cookies = new CookieCollection();
-
- Cookie cookie = null;
- var pairs = splitCookieHeaderValue(value);
- for (int i = 0; i < pairs.Length; i++)
- {
- var pair = pairs[i].Trim();
- if (pair.Length == 0)
- continue;
-
- if (pair.StartsWith("version", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.Version = Int32.Parse(pair.GetValueInternal("=").Trim('"'));
- }
- else if (pair.StartsWith("expires", StringComparison.OrdinalIgnoreCase))
- {
- var buffer = new StringBuilder(pair.GetValueInternal("="), 32);
- if (i < pairs.Length - 1)
- buffer.AppendFormat(", {0}", pairs[++i].Trim());
-
- DateTime expires;
- if (!DateTime.TryParseExact(
- buffer.ToString(),
- new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" },
- new CultureInfo("en-US"),
- DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal,
- out expires))
- expires = DateTime.Now;
-
- if (cookie != null && cookie.Expires == DateTime.MinValue)
- cookie.Expires = expires.ToLocalTime();
- }
- else if (pair.StartsWith("max-age", StringComparison.OrdinalIgnoreCase))
- {
- var max = Int32.Parse(pair.GetValueInternal("=").Trim('"'));
- var expires = DateTime.Now.AddSeconds((double)max);
- if (cookie != null)
- cookie.Expires = expires;
- }
- else if (pair.StartsWith("path", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.Path = pair.GetValueInternal("=");
- }
- else if (pair.StartsWith("domain", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.Domain = pair.GetValueInternal("=");
- }
- else if (pair.StartsWith("port", StringComparison.OrdinalIgnoreCase))
- {
- var port = pair.Equals("port", StringComparison.OrdinalIgnoreCase)
- ? "\"\""
- : pair.GetValueInternal("=");
-
- if (cookie != null)
- cookie.Port = port;
- }
- else if (pair.StartsWith("comment", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.Comment = pair.GetValueInternal("=").UrlDecode();
- }
- else if (pair.StartsWith("commenturl", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.CommentUri = pair.GetValueInternal("=").Trim('"').ToUri();
- }
- else if (pair.StartsWith("discard", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.Discard = true;
- }
- else if (pair.StartsWith("secure", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.Secure = true;
- }
- else if (pair.StartsWith("httponly", StringComparison.OrdinalIgnoreCase))
- {
- if (cookie != null)
- cookie.HttpOnly = true;
- }
- else
- {
- if (cookie != null)
- cookies.Add(cookie);
-
- string name;
- string val = String.Empty;
-
- var pos = pair.IndexOf('=');
- if (pos == -1)
- {
- name = pair;
- }
- else if (pos == pair.Length - 1)
- {
- name = pair.Substring(0, pos).TrimEnd(' ');
- }
- else
- {
- name = pair.Substring(0, pos).TrimEnd(' ');
- val = pair.Substring(pos + 1).TrimStart(' ');
- }
-
- cookie = new Cookie(name, val);
- }
- }
-
- if (cookie != null)
- cookies.Add(cookie);
-
- return cookies;
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/EndPointListener.cs b/SocketHttpListener.Portable/Net/EndPointListener.cs
deleted file mode 100644
index 2106bbec5..000000000
--- a/SocketHttpListener.Portable/Net/EndPointListener.cs
+++ /dev/null
@@ -1,391 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Threading;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- sealed class EndPointListener
- {
- HttpListener listener;
- IpEndPointInfo endpoint;
- IAcceptSocket sock;
- Dictionary<ListenerPrefix,HttpListener> prefixes; // Dictionary <ListenerPrefix, HttpListener>
- List<ListenerPrefix> unhandled; // List<ListenerPrefix> unhandled; host = '*'
- List<ListenerPrefix> all; // List<ListenerPrefix> all; host = '+'
- ICertificate cert;
- bool secure;
- Dictionary<HttpConnection, HttpConnection> unregistered;
- private readonly ILogger _logger;
- private bool _closed;
- private bool _enableDualMode;
- private readonly ICryptoProvider _cryptoProvider;
- private readonly IStreamFactory _streamFactory;
- private readonly ISocketFactory _socketFactory;
- private readonly ITextEncoding _textEncoding;
- private readonly IMemoryStreamFactory _memoryStreamFactory;
- private readonly IFileSystem _fileSystem;
- private readonly IEnvironmentInfo _environment;
-
- public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
- {
- this.listener = listener;
- _logger = logger;
- _cryptoProvider = cryptoProvider;
- _streamFactory = streamFactory;
- _socketFactory = socketFactory;
- _memoryStreamFactory = memoryStreamFactory;
- _textEncoding = textEncoding;
- _fileSystem = fileSystem;
- _environment = environment;
-
- this.secure = secure;
- this.cert = cert;
-
- _enableDualMode = addr.Equals(IpAddressInfo.IPv6Any);
- endpoint = new IpEndPointInfo(addr, port);
-
- prefixes = new Dictionary<ListenerPrefix, HttpListener>();
- unregistered = new Dictionary<HttpConnection, HttpConnection>();
-
- CreateSocket();
- }
-
- internal HttpListener Listener
- {
- get
- {
- return listener;
- }
- }
-
- private void CreateSocket()
- {
- try
- {
- sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
- }
- catch (SocketCreateException ex)
- {
- if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) &&
- (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
- // mono on bsd is throwing this
- string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase)))
- {
- endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
- _enableDualMode = false;
- sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
- }
- else
- {
- throw;
- }
- }
-
- sock.Bind(endpoint);
-
- // This is the number TcpListener uses.
- sock.Listen(2147483647);
-
- sock.StartAccept(ProcessAccept, () => _closed);
- _closed = false;
- }
-
- private async void ProcessAccept(IAcceptSocket accepted)
- {
- try
- {
- var listener = this;
-
- if (listener.secure && listener.cert == null)
- {
- accepted.Close();
- return;
- }
-
- HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
-
- //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
- lock (listener.unregistered)
- {
- listener.unregistered[conn] = conn;
- }
- conn.BeginReadRequest();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ProcessAccept", ex);
- }
- }
-
- internal void RemoveConnection(HttpConnection conn)
- {
- lock (unregistered)
- {
- unregistered.Remove(conn);
- }
- }
-
- public bool BindContext(HttpListenerContext context)
- {
- HttpListenerRequest req = context.Request;
- ListenerPrefix prefix;
- HttpListener listener = SearchListener(req.Url, out prefix);
- if (listener == null)
- return false;
-
- context.Connection.Prefix = prefix;
- return true;
- }
-
- public void UnbindContext(HttpListenerContext context)
- {
- if (context == null || context.Request == null)
- return;
-
- listener.UnregisterContext(context);
- }
-
- HttpListener SearchListener(Uri uri, out ListenerPrefix prefix)
- {
- prefix = null;
- if (uri == null)
- return null;
-
- string host = uri.Host;
- int port = uri.Port;
- string path = WebUtility.UrlDecode(uri.AbsolutePath);
- string path_slash = path[path.Length - 1] == '/' ? path : path + "/";
-
- HttpListener best_match = null;
- int best_length = -1;
-
- if (host != null && host != "")
- {
- var p_ro = prefixes;
- foreach (ListenerPrefix p in p_ro.Keys)
- {
- string ppath = p.Path;
- if (ppath.Length < best_length)
- continue;
-
- if (p.Host != host || p.Port != port)
- continue;
-
- if (path.StartsWith(ppath) || path_slash.StartsWith(ppath))
- {
- best_length = ppath.Length;
- best_match = (HttpListener)p_ro[p];
- prefix = p;
- }
- }
- if (best_length != -1)
- return best_match;
- }
-
- List<ListenerPrefix> list = unhandled;
- best_match = MatchFromList(host, path, list, out prefix);
- if (path != path_slash && best_match == null)
- best_match = MatchFromList(host, path_slash, list, out prefix);
- if (best_match != null)
- return best_match;
-
- list = all;
- best_match = MatchFromList(host, path, list, out prefix);
- if (path != path_slash && best_match == null)
- best_match = MatchFromList(host, path_slash, list, out prefix);
- if (best_match != null)
- return best_match;
-
- return null;
- }
-
- HttpListener MatchFromList(string host, string path, List<ListenerPrefix> list, out ListenerPrefix prefix)
- {
- prefix = null;
- if (list == null)
- return null;
-
- HttpListener best_match = null;
- int best_length = -1;
-
- foreach (ListenerPrefix p in list)
- {
- string ppath = p.Path;
- if (ppath.Length < best_length)
- continue;
-
- if (path.StartsWith(ppath))
- {
- best_length = ppath.Length;
- best_match = p.Listener;
- prefix = p;
- }
- }
-
- return best_match;
- }
-
- void AddSpecial(List<ListenerPrefix> coll, ListenerPrefix prefix)
- {
- if (coll == null)
- return;
-
- foreach (ListenerPrefix p in coll)
- {
- if (p.Path == prefix.Path) //TODO: code
- throw new HttpListenerException(400, "Prefix already in use.");
- }
- coll.Add(prefix);
- }
-
- bool RemoveSpecial(List<ListenerPrefix> coll, ListenerPrefix prefix)
- {
- if (coll == null)
- return false;
-
- int c = coll.Count;
- for (int i = 0; i < c; i++)
- {
- ListenerPrefix p = (ListenerPrefix)coll[i];
- if (p.Path == prefix.Path)
- {
- coll.RemoveAt(i);
- return true;
- }
- }
- return false;
- }
-
- void CheckIfRemove()
- {
- if (prefixes.Count > 0)
- return;
-
- List<ListenerPrefix> list = unhandled;
- if (list != null && list.Count > 0)
- return;
-
- list = all;
- if (list != null && list.Count > 0)
- return;
-
- EndPointManager.RemoveEndPoint(this, endpoint);
- }
-
- public void Close()
- {
- _closed = true;
- sock.Close();
- lock (unregistered)
- {
- //
- // Clone the list because RemoveConnection can be called from Close
- //
- var connections = new List<HttpConnection>(unregistered.Keys);
-
- foreach (HttpConnection c in connections)
- c.Close(true);
- unregistered.Clear();
- }
- }
-
- public void AddPrefix(ListenerPrefix prefix, HttpListener listener)
- {
- List<ListenerPrefix> current;
- List<ListenerPrefix> future;
- if (prefix.Host == "*")
- {
- do
- {
- current = unhandled;
- future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
- prefix.Listener = listener;
- AddSpecial(future, prefix);
- } while (Interlocked.CompareExchange(ref unhandled, future, current) != current);
- return;
- }
-
- if (prefix.Host == "+")
- {
- do
- {
- current = all;
- future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
- prefix.Listener = listener;
- AddSpecial(future, prefix);
- } while (Interlocked.CompareExchange(ref all, future, current) != current);
- return;
- }
-
- Dictionary<ListenerPrefix, HttpListener> prefs;
- Dictionary<ListenerPrefix, HttpListener> p2;
- do
- {
- prefs = prefixes;
- if (prefs.ContainsKey(prefix))
- {
- HttpListener other = (HttpListener)prefs[prefix];
- if (other != listener) // TODO: code.
- throw new HttpListenerException(400, "There's another listener for " + prefix);
- return;
- }
- p2 = new Dictionary<ListenerPrefix, HttpListener>(prefs);
- p2[prefix] = listener;
- } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs);
- }
-
- public void RemovePrefix(ListenerPrefix prefix, HttpListener listener)
- {
- List<ListenerPrefix> current;
- List<ListenerPrefix> future;
- if (prefix.Host == "*")
- {
- do
- {
- current = unhandled;
- future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
- if (!RemoveSpecial(future, prefix))
- break; // Prefix not found
- } while (Interlocked.CompareExchange(ref unhandled, future, current) != current);
- CheckIfRemove();
- return;
- }
-
- if (prefix.Host == "+")
- {
- do
- {
- current = all;
- future = (current != null) ? current.ToList() : new List<ListenerPrefix>();
- if (!RemoveSpecial(future, prefix))
- break; // Prefix not found
- } while (Interlocked.CompareExchange(ref all, future, current) != current);
- CheckIfRemove();
- return;
- }
-
- Dictionary<ListenerPrefix, HttpListener> prefs;
- Dictionary<ListenerPrefix, HttpListener> p2;
- do
- {
- prefs = prefixes;
- if (!prefs.ContainsKey(prefix))
- break;
-
- p2 = new Dictionary<ListenerPrefix, HttpListener>(prefs);
- p2.Remove(prefix);
- } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs);
- CheckIfRemove();
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/EndPointManager.cs b/SocketHttpListener.Portable/Net/EndPointManager.cs
deleted file mode 100644
index 6a00ed360..000000000
--- a/SocketHttpListener.Portable/Net/EndPointManager.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Reflection;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- sealed class EndPointManager
- {
- // Dictionary<IPAddress, Dictionary<int, EndPointListener>>
- static Dictionary<string, Dictionary<int, EndPointListener>> ip_to_endpoints = new Dictionary<string, Dictionary<int, EndPointListener>>();
-
- private EndPointManager()
- {
- }
-
- public static void AddListener(ILogger logger, HttpListener listener)
- {
- List<string> added = new List<string>();
- try
- {
- lock (ip_to_endpoints)
- {
- foreach (string prefix in listener.Prefixes)
- {
- AddPrefixInternal(logger, prefix, listener);
- added.Add(prefix);
- }
- }
- }
- catch
- {
- foreach (string prefix in added)
- {
- RemovePrefix(logger, prefix, listener);
- }
- throw;
- }
- }
-
- public static void AddPrefix(ILogger logger, string prefix, HttpListener listener)
- {
- lock (ip_to_endpoints)
- {
- AddPrefixInternal(logger, prefix, listener);
- }
- }
-
- static void AddPrefixInternal(ILogger logger, string p, HttpListener listener)
- {
- ListenerPrefix lp = new ListenerPrefix(p);
- if (lp.Path.IndexOf('%') != -1)
- throw new HttpListenerException(400, "Invalid path.");
-
- if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) // TODO: Code?
- throw new HttpListenerException(400, "Invalid path.");
-
- // listens on all the interfaces if host name cannot be parsed by IPAddress.
- EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result;
- epl.AddPrefix(lp, listener);
- }
-
- private static IpAddressInfo GetIpAnyAddress(HttpListener listener)
- {
- return listener.EnableDualMode ? IpAddressInfo.IPv6Any : IpAddressInfo.Any;
- }
-
- static async Task<EndPointListener> GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure)
- {
- var networkManager = listener.NetworkManager;
-
- IpAddressInfo addr;
- if (host == "*" || host == "+")
- addr = GetIpAnyAddress(listener);
- else if (networkManager.TryParseIpAddress(host, out addr) == false)
- {
- try
- {
- addr = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false)).FirstOrDefault() ??
- GetIpAnyAddress(listener);
- }
- catch
- {
- addr = GetIpAnyAddress(listener);
- }
- }
-
- Dictionary<int, EndPointListener> p = null; // Dictionary<int, EndPointListener>
- if (!ip_to_endpoints.TryGetValue(addr.Address, out p))
- {
- p = new Dictionary<int, EndPointListener>();
- ip_to_endpoints[addr.Address] = p;
- }
-
- EndPointListener epl = null;
- if (p.ContainsKey(port))
- {
- epl = (EndPointListener)p[port];
- }
- else
- {
- epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
- p[port] = epl;
- }
-
- return epl;
- }
-
- public static void RemoveEndPoint(EndPointListener epl, IpEndPointInfo ep)
- {
- lock (ip_to_endpoints)
- {
- // Dictionary<int, EndPointListener> p
- Dictionary<int, EndPointListener> p;
- if (ip_to_endpoints.TryGetValue(ep.IpAddress.Address, out p))
- {
- p.Remove(ep.Port);
- if (p.Count == 0)
- {
- ip_to_endpoints.Remove(ep.IpAddress.Address);
- }
- }
- epl.Close();
- }
- }
-
- public static void RemoveListener(ILogger logger, HttpListener listener)
- {
- lock (ip_to_endpoints)
- {
- foreach (string prefix in listener.Prefixes)
- {
- RemovePrefixInternal(logger, prefix, listener);
- }
- }
- }
-
- public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener)
- {
- lock (ip_to_endpoints)
- {
- RemovePrefixInternal(logger, prefix, listener);
- }
- }
-
- static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener)
- {
- ListenerPrefix lp = new ListenerPrefix(prefix);
- if (lp.Path.IndexOf('%') != -1)
- return;
-
- if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
- return;
-
- EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result;
- epl.RemovePrefix(lp, listener);
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpConnection.cs b/SocketHttpListener.Portable/Net/HttpConnection.cs
deleted file mode 100644
index 65e7470f7..000000000
--- a/SocketHttpListener.Portable/Net/HttpConnection.cs
+++ /dev/null
@@ -1,558 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- sealed class HttpConnection
- {
- const int BufferSize = 8192;
- IAcceptSocket sock;
- Stream stream;
- EndPointListener epl;
- MemoryStream ms;
- byte[] buffer;
- HttpListenerContext context;
- StringBuilder current_line;
- ListenerPrefix prefix;
- RequestStream i_stream;
- Stream o_stream;
- bool chunked;
- int reuses;
- bool context_bound;
- bool secure;
- int s_timeout = 300000; // 90k ms for first request, 15k ms from then on
- IpEndPointInfo local_ep;
- HttpListener last_listener;
- int[] client_cert_errors;
- ICertificate cert;
- Stream ssl_stream;
-
- private readonly ILogger _logger;
- private readonly ICryptoProvider _cryptoProvider;
- private readonly IMemoryStreamFactory _memoryStreamFactory;
- private readonly ITextEncoding _textEncoding;
- private readonly IStreamFactory _streamFactory;
- private readonly IFileSystem _fileSystem;
- private readonly IEnvironmentInfo _environment;
-
- private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
- {
- _logger = logger;
- this.sock = sock;
- this.epl = epl;
- this.secure = secure;
- this.cert = cert;
- _cryptoProvider = cryptoProvider;
- _memoryStreamFactory = memoryStreamFactory;
- _textEncoding = textEncoding;
- _fileSystem = fileSystem;
- _environment = environment;
- _streamFactory = streamFactory;
- }
-
- private async Task InitStream()
- {
- if (secure == false)
- {
- stream = _streamFactory.CreateNetworkStream(sock, false);
- }
- else
- {
- //ssl_stream = epl.Listener.CreateSslStream(new NetworkStream(sock, false), false, (t, c, ch, e) =>
- //{
- // if (c == null)
- // return true;
- // var c2 = c as X509Certificate2;
- // if (c2 == null)
- // c2 = new X509Certificate2(c.GetRawCertData());
- // client_cert = c2;
- // client_cert_errors = new int[] { (int)e };
- // return true;
- //});
- //stream = ssl_stream.AuthenticatedStream;
-
- ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(sock, false), false);
- await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false);
- stream = ssl_stream;
- }
- Init();
- }
-
- public static async Task<HttpConnection> Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
- {
- var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment);
-
- await connection.InitStream().ConfigureAwait(false);
-
- return connection;
- }
-
- public Stream Stream
- {
- get
- {
- return stream;
- }
- }
-
- internal int[] ClientCertificateErrors
- {
- get { return client_cert_errors; }
- }
-
- void Init()
- {
- if (ssl_stream != null)
- {
- //ssl_stream.AuthenticateAsServer(client_cert, true, (SslProtocols)ServicePointManager.SecurityProtocol, false);
- //_streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert);
- }
-
- context_bound = false;
- i_stream = null;
- o_stream = null;
- prefix = null;
- chunked = false;
- ms = _memoryStreamFactory.CreateNew();
- position = 0;
- input_state = InputState.RequestLine;
- line_state = LineState.None;
- context = new HttpListenerContext(this, _logger, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem);
- }
-
- public bool IsClosed
- {
- get { return (sock == null); }
- }
-
- public int Reuses
- {
- get { return reuses; }
- }
-
- public IpEndPointInfo LocalEndPoint
- {
- get
- {
- if (local_ep != null)
- return local_ep;
-
- local_ep = (IpEndPointInfo)sock.LocalEndPoint;
- return local_ep;
- }
- }
-
- public IpEndPointInfo RemoteEndPoint
- {
- get { return (IpEndPointInfo)sock.RemoteEndPoint; }
- }
-
- public bool IsSecure
- {
- get { return secure; }
- }
-
- public ListenerPrefix Prefix
- {
- get { return prefix; }
- set { prefix = value; }
- }
-
- public async Task BeginReadRequest()
- {
- if (buffer == null)
- buffer = new byte[BufferSize];
-
- try
- {
- //if (reuses == 1)
- // s_timeout = 15000;
- var nRead = await stream.ReadAsync(buffer, 0, BufferSize).ConfigureAwait(false);
-
- OnReadInternal(nRead);
- }
- catch (Exception ex)
- {
- OnReadInternalException(ms, ex);
- }
- }
-
- public RequestStream GetRequestStream(bool chunked, long contentlength)
- {
- if (i_stream == null)
- {
- byte[] buffer;
- _memoryStreamFactory.TryGetBuffer(ms, out buffer);
-
- int length = (int)ms.Length;
- ms = null;
- if (chunked)
- {
- this.chunked = true;
- //context.Response.SendChunked = true;
- i_stream = new ChunkedInputStream(context, stream, buffer, position, length - position);
- }
- else
- {
- i_stream = new RequestStream(stream, buffer, position, length - position, contentlength);
- }
- }
- return i_stream;
- }
-
- public Stream GetResponseStream(bool isExpect100Continue = false)
- {
- // TODO: can we get this stream before reading the input?
- if (o_stream == null)
- {
- //context.Response.DetermineIfChunked();
-
- if (context.Response.SendChunked || isExpect100Continue || context.Request.IsWebSocketRequest || true)
- {
- var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure;
-
- o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment);
- }
- else
- {
- o_stream = stream;
- using (var headerStream = ResponseStream.GetHeaders(context.Response, _memoryStreamFactory, false))
- {
- headerStream.CopyTo(o_stream);
- }
- }
- }
- return o_stream;
- }
-
- void OnReadInternal(int nread)
- {
- ms.Write(buffer, 0, nread);
- if (ms.Length > 32768)
- {
- SendError("Bad request", 400);
- Close(true);
- return;
- }
-
- if (nread == 0)
- {
- //if (ms.Length > 0)
- // SendError (); // Why bother?
- CloseSocket();
- Unbind();
- return;
- }
-
- if (ProcessInput(ms))
- {
- if (!context.HaveError)
- context.Request.FinishInitialization();
-
- if (context.HaveError)
- {
- SendError();
- Close(true);
- return;
- }
-
- if (!epl.BindContext(context))
- {
- SendError("Invalid host", 400);
- Close(true);
- return;
- }
- HttpListener listener = epl.Listener;
- if (last_listener != listener)
- {
- RemoveConnection();
- listener.AddConnection(this);
- last_listener = listener;
- }
-
- context_bound = true;
- listener.RegisterContext(context);
- return;
- }
-
- BeginReadRequest();
- }
-
- private void OnReadInternalException(MemoryStream ms, Exception ex)
- {
- //_logger.ErrorException("Error in HttpConnection.OnReadInternal", ex);
-
- if (ms != null && ms.Length > 0)
- SendError();
- if (sock != null)
- {
- CloseSocket();
- Unbind();
- }
- }
-
- void RemoveConnection()
- {
- if (last_listener == null)
- epl.RemoveConnection(this);
- else
- last_listener.RemoveConnection(this);
- }
-
- enum InputState
- {
- RequestLine,
- Headers
- }
-
- enum LineState
- {
- None,
- CR,
- LF
- }
-
- InputState input_state = InputState.RequestLine;
- LineState line_state = LineState.None;
- int position;
-
- // true -> done processing
- // false -> need more input
- bool ProcessInput(MemoryStream ms)
- {
- byte[] buffer;
- _memoryStreamFactory.TryGetBuffer(ms, out buffer);
-
- int len = (int)ms.Length;
- int used = 0;
- string line;
-
- while (true)
- {
- if (context.HaveError)
- return true;
-
- if (position >= len)
- break;
-
- try
- {
- line = ReadLine(buffer, position, len - position, ref used);
- position += used;
- }
- catch
- {
- context.ErrorMessage = "Bad request";
- context.ErrorStatus = 400;
- return true;
- }
-
- if (line == null)
- break;
-
- if (line == "")
- {
- if (input_state == InputState.RequestLine)
- continue;
- current_line = null;
- ms = null;
- return true;
- }
-
- if (input_state == InputState.RequestLine)
- {
- context.Request.SetRequestLine(line);
- input_state = InputState.Headers;
- }
- else
- {
- try
- {
- context.Request.AddHeader(line);
- }
- catch (Exception e)
- {
- context.ErrorMessage = e.Message;
- context.ErrorStatus = 400;
- return true;
- }
- }
- }
-
- if (used == len)
- {
- ms.SetLength(0);
- position = 0;
- }
- return false;
- }
-
- string ReadLine(byte[] buffer, int offset, int len, ref int used)
- {
- if (current_line == null)
- current_line = new StringBuilder(128);
- int last = offset + len;
- used = 0;
-
- for (int i = offset; i < last && line_state != LineState.LF; i++)
- {
- used++;
- byte b = buffer[i];
- if (b == 13)
- {
- line_state = LineState.CR;
- }
- else if (b == 10)
- {
- line_state = LineState.LF;
- }
- else
- {
- current_line.Append((char)b);
- }
- }
-
- string result = null;
- if (line_state == LineState.LF)
- {
- line_state = LineState.None;
- result = current_line.ToString();
- current_line.Length = 0;
- }
-
- return result;
- }
-
- public void SendError(string msg, int status)
- {
- try
- {
- HttpListenerResponse response = context.Response;
- response.StatusCode = status;
- response.ContentType = "text/html";
- string description = HttpListenerResponse.GetStatusDescription(status);
- string str;
- if (msg != null)
- str = String.Format("<h1>{0} ({1})</h1>", description, msg);
- else
- str = String.Format("<h1>{0}</h1>", description);
-
- byte[] error = context.Response.ContentEncoding.GetBytes(str);
- response.ContentLength64 = error.Length;
- response.OutputStream.Write(error, 0, (int)error.Length);
- response.Close();
- }
- catch
- {
- // response was already closed
- }
- }
-
- public void SendError()
- {
- SendError(context.ErrorMessage, context.ErrorStatus);
- }
-
- void Unbind()
- {
- if (context_bound)
- {
- epl.UnbindContext(context);
- context_bound = false;
- }
- }
-
- public void Close()
- {
- Close(false);
- }
-
- private void CloseSocket()
- {
- if (sock == null)
- return;
-
- try
- {
- sock.Close();
- }
- catch
- {
- }
- finally
- {
- sock = null;
- }
- RemoveConnection();
- }
-
- internal void Close(bool force_close)
- {
- if (sock != null)
- {
- if (!context.Request.IsWebSocketRequest || force_close)
- {
- Stream st = GetResponseStream();
- if (st != null)
- {
- st.Dispose();
- }
-
- o_stream = null;
- }
- }
-
- if (sock != null)
- {
- force_close |= !context.Request.KeepAlive;
- if (!force_close)
- force_close = (string.Equals(context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase));
- /*
- if (!force_close) {
-// bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 ||
-// status_code == 413 || status_code == 414 || status_code == 500 ||
-// status_code == 503);
- force_close |= (context.Request.ProtocolVersion <= HttpVersion.Version10);
- }
- */
-
- if (!force_close && context.Request.FlushInput())
- {
- reuses++;
- Unbind();
- Init();
- BeginReadRequest();
- return;
- }
-
- IAcceptSocket s = sock;
- sock = null;
- try
- {
- if (s != null)
- s.Shutdown(true);
- }
- catch
- {
- }
- finally
- {
- if (s != null)
- s.Close();
- }
- Unbind();
- RemoveConnection();
- return;
- }
- }
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/Net/HttpListener.cs b/SocketHttpListener.Portable/Net/HttpListener.cs
deleted file mode 100644
index b3e01425c..000000000
--- a/SocketHttpListener.Portable/Net/HttpListener.cs
+++ /dev/null
@@ -1,293 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- public sealed class HttpListener : IDisposable
- {
- internal ICryptoProvider CryptoProvider { get; private set; }
- internal IStreamFactory StreamFactory { get; private set; }
- internal ISocketFactory SocketFactory { get; private set; }
- internal IFileSystem FileSystem { get; private set; }
- internal ITextEncoding TextEncoding { get; private set; }
- internal IMemoryStreamFactory MemoryStreamFactory { get; private set; }
- internal INetworkManager NetworkManager { get; private set; }
- internal IEnvironmentInfo EnvironmentInfo { get; private set; }
-
- public bool EnableDualMode { get; set; }
-
- AuthenticationSchemes auth_schemes;
- HttpListenerPrefixCollection prefixes;
- AuthenticationSchemeSelector auth_selector;
- string realm;
- bool unsafe_ntlm_auth;
- bool listening;
- bool disposed;
-
- Dictionary<HttpListenerContext, HttpListenerContext> registry; // Dictionary<HttpListenerContext,HttpListenerContext>
- Dictionary<HttpConnection, HttpConnection> connections;
- private ILogger _logger;
- private ICertificate _certificate;
-
- public Action<HttpListenerContext> OnContext { get; set; }
-
- public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
- {
- _logger = logger;
- CryptoProvider = cryptoProvider;
- StreamFactory = streamFactory;
- SocketFactory = socketFactory;
- NetworkManager = networkManager;
- TextEncoding = textEncoding;
- MemoryStreamFactory = memoryStreamFactory;
- FileSystem = fileSystem;
- EnvironmentInfo = environmentInfo;
- prefixes = new HttpListenerPrefixCollection(logger, this);
- registry = new Dictionary<HttpListenerContext, HttpListenerContext>();
- connections = new Dictionary<HttpConnection, HttpConnection>();
- auth_schemes = AuthenticationSchemes.Anonymous;
- }
-
- public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
- :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
- {
- }
-
- public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
- : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
- {
- _certificate = certificate;
- }
-
- public void LoadCert(ICertificate cert)
- {
- _certificate = cert;
- }
-
- // TODO: Digest, NTLM and Negotiate require ControlPrincipal
- public AuthenticationSchemes AuthenticationSchemes
- {
- get { return auth_schemes; }
- set
- {
- CheckDisposed();
- auth_schemes = value;
- }
- }
-
- public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate
- {
- get { return auth_selector; }
- set
- {
- CheckDisposed();
- auth_selector = value;
- }
- }
-
- public bool IsListening
- {
- get { return listening; }
- }
-
- public static bool IsSupported
- {
- get { return true; }
- }
-
- public HttpListenerPrefixCollection Prefixes
- {
- get
- {
- CheckDisposed();
- return prefixes;
- }
- }
-
- // TODO: use this
- public string Realm
- {
- get { return realm; }
- set
- {
- CheckDisposed();
- realm = value;
- }
- }
-
- public bool UnsafeConnectionNtlmAuthentication
- {
- get { return unsafe_ntlm_auth; }
- set
- {
- CheckDisposed();
- unsafe_ntlm_auth = value;
- }
- }
-
- //internal IMonoSslStream CreateSslStream(Stream innerStream, bool ownsStream, MSI.MonoRemoteCertificateValidationCallback callback)
- //{
- // lock (registry)
- // {
- // if (tlsProvider == null)
- // tlsProvider = MonoTlsProviderFactory.GetProviderInternal();
- // if (tlsSettings == null)
- // tlsSettings = MSI.MonoTlsSettings.CopyDefaultSettings();
- // if (tlsSettings.RemoteCertificateValidationCallback == null)
- // tlsSettings.RemoteCertificateValidationCallback = callback;
- // return tlsProvider.CreateSslStream(innerStream, ownsStream, tlsSettings);
- // }
- //}
-
- internal ICertificate Certificate
- {
- get { return _certificate; }
- }
-
- public void Abort()
- {
- if (disposed)
- return;
-
- if (!listening)
- {
- return;
- }
-
- Close(true);
- }
-
- public void Close()
- {
- if (disposed)
- return;
-
- if (!listening)
- {
- disposed = true;
- return;
- }
-
- Close(true);
- disposed = true;
- }
-
- void Close(bool force)
- {
- CheckDisposed();
- EndPointManager.RemoveListener(_logger, this);
- Cleanup(force);
- }
-
- void Cleanup(bool close_existing)
- {
- lock (registry)
- {
- if (close_existing)
- {
- // Need to copy this since closing will call UnregisterContext
- ICollection keys = registry.Keys;
- var all = new HttpListenerContext[keys.Count];
- keys.CopyTo(all, 0);
- registry.Clear();
- for (int i = all.Length - 1; i >= 0; i--)
- all[i].Connection.Close(true);
- }
-
- lock (connections)
- {
- ICollection keys = connections.Keys;
- var conns = new HttpConnection[keys.Count];
- keys.CopyTo(conns, 0);
- connections.Clear();
- for (int i = conns.Length - 1; i >= 0; i--)
- conns[i].Close(true);
- }
- }
- }
-
- internal AuthenticationSchemes SelectAuthenticationScheme(HttpListenerContext context)
- {
- if (AuthenticationSchemeSelectorDelegate != null)
- return AuthenticationSchemeSelectorDelegate(context.Request);
- else
- return auth_schemes;
- }
-
- public void Start()
- {
- CheckDisposed();
- if (listening)
- return;
-
- EndPointManager.AddListener(_logger, this);
- listening = true;
- }
-
- public void Stop()
- {
- CheckDisposed();
- listening = false;
- Close(false);
- }
-
- void IDisposable.Dispose()
- {
- if (disposed)
- return;
-
- Close(true); //TODO: Should we force here or not?
- disposed = true;
- }
-
- internal void CheckDisposed()
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
- }
-
- internal void RegisterContext(HttpListenerContext context)
- {
- if (OnContext != null && IsListening)
- {
- OnContext(context);
- }
-
- lock (registry)
- registry[context] = context;
- }
-
- internal void UnregisterContext(HttpListenerContext context)
- {
- lock (registry)
- registry.Remove(context);
- }
-
- internal void AddConnection(HttpConnection cnc)
- {
- lock (connections)
- {
- connections[cnc] = cnc;
- }
- }
-
- internal void RemoveConnection(HttpConnection cnc)
- {
- lock (connections)
- {
- connections.Remove(cnc);
- }
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpListenerBasicIdentity.cs b/SocketHttpListener.Portable/Net/HttpListenerBasicIdentity.cs
deleted file mode 100644
index faa26693d..000000000
--- a/SocketHttpListener.Portable/Net/HttpListenerBasicIdentity.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System.Security.Principal;
-
-namespace SocketHttpListener.Net
-{
- public class HttpListenerBasicIdentity : GenericIdentity
- {
- string password;
-
- public HttpListenerBasicIdentity(string username, string password)
- : base(username, "Basic")
- {
- this.password = password;
- }
-
- public virtual string Password
- {
- get { return password; }
- }
- }
-
- public class GenericIdentity : IIdentity
- {
- private string m_name;
- private string m_type;
-
- public GenericIdentity(string name)
- {
- if (name == null)
- throw new System.ArgumentNullException("name");
-
- m_name = name;
- m_type = "";
- }
-
- public GenericIdentity(string name, string type)
- {
- if (name == null)
- throw new System.ArgumentNullException("name");
- if (type == null)
- throw new System.ArgumentNullException("type");
-
- m_name = name;
- m_type = type;
- }
-
- public virtual string Name
- {
- get
- {
- return m_name;
- }
- }
-
- public virtual string AuthenticationType
- {
- get
- {
- return m_type;
- }
- }
-
- public virtual bool IsAuthenticated
- {
- get
- {
- return !m_name.Equals("");
- }
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpListenerContext.cs b/SocketHttpListener.Portable/Net/HttpListenerContext.cs
deleted file mode 100644
index 58d769f22..000000000
--- a/SocketHttpListener.Portable/Net/HttpListenerContext.cs
+++ /dev/null
@@ -1,198 +0,0 @@
-using System;
-using System.Net;
-using System.Security.Principal;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Net.WebSockets;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- public sealed class HttpListenerContext
- {
- HttpListenerRequest request;
- HttpListenerResponse response;
- IPrincipal user;
- HttpConnection cnc;
- string error;
- int err_status = 400;
- private readonly ICryptoProvider _cryptoProvider;
- private readonly IMemoryStreamFactory _memoryStreamFactory;
- private readonly ITextEncoding _textEncoding;
-
- internal HttpListenerContext(HttpConnection cnc, ILogger logger, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem)
- {
- this.cnc = cnc;
- _cryptoProvider = cryptoProvider;
- _memoryStreamFactory = memoryStreamFactory;
- _textEncoding = textEncoding;
- request = new HttpListenerRequest(this, _textEncoding);
- response = new HttpListenerResponse(this, logger, _textEncoding, fileSystem);
- }
-
- internal int ErrorStatus
- {
- get { return err_status; }
- set { err_status = value; }
- }
-
- internal string ErrorMessage
- {
- get { return error; }
- set { error = value; }
- }
-
- internal bool HaveError
- {
- get { return (error != null); }
- }
-
- internal HttpConnection Connection
- {
- get { return cnc; }
- }
-
- public HttpListenerRequest Request
- {
- get { return request; }
- }
-
- public HttpListenerResponse Response
- {
- get { return response; }
- }
-
- public IPrincipal User
- {
- get { return user; }
- }
-
- internal void ParseAuthentication(AuthenticationSchemes expectedSchemes)
- {
- if (expectedSchemes == AuthenticationSchemes.Anonymous)
- return;
-
- // TODO: Handle NTLM/Digest modes
- string header = request.Headers["Authorization"];
- if (header == null || header.Length < 2)
- return;
-
- string[] authenticationData = header.Split(new char[] { ' ' }, 2);
- if (string.Equals(authenticationData[0], "basic", StringComparison.OrdinalIgnoreCase))
- {
- user = ParseBasicAuthentication(authenticationData[1]);
- }
- // TODO: throw if malformed -> 400 bad request
- }
-
- internal IPrincipal ParseBasicAuthentication(string authData)
- {
- try
- {
- // Basic AUTH Data is a formatted Base64 String
- //string domain = null;
- string user = null;
- string password = null;
- int pos = -1;
- var authDataBytes = Convert.FromBase64String(authData);
- string authString = _textEncoding.GetDefaultEncoding().GetString(authDataBytes, 0, authDataBytes.Length);
-
- // The format is DOMAIN\username:password
- // Domain is optional
-
- pos = authString.IndexOf(':');
-
- // parse the password off the end
- password = authString.Substring(pos + 1);
-
- // discard the password
- authString = authString.Substring(0, pos);
-
- // check if there is a domain
- pos = authString.IndexOf('\\');
-
- if (pos > 0)
- {
- //domain = authString.Substring (0, pos);
- user = authString.Substring(pos);
- }
- else
- {
- user = authString;
- }
-
- HttpListenerBasicIdentity identity = new HttpListenerBasicIdentity(user, password);
- // TODO: What are the roles MS sets
- return new GenericPrincipal(identity, new string[0]);
- }
- catch (Exception)
- {
- // Invalid auth data is swallowed silently
- return null;
- }
- }
-
- public HttpListenerWebSocketContext AcceptWebSocket(string protocol)
- {
- if (protocol != null)
- {
- if (protocol.Length == 0)
- throw new ArgumentException("An empty string.", "protocol");
-
- if (!protocol.IsToken())
- throw new ArgumentException("Contains an invalid character.", "protocol");
- }
-
- return new HttpListenerWebSocketContext(this, protocol, _cryptoProvider, _memoryStreamFactory);
- }
- }
-
- public class GenericPrincipal : IPrincipal
- {
- private IIdentity m_identity;
- private string[] m_roles;
-
- public GenericPrincipal(IIdentity identity, string[] roles)
- {
- if (identity == null)
- throw new ArgumentNullException("identity");
-
- m_identity = identity;
- if (roles != null)
- {
- m_roles = new string[roles.Length];
- for (int i = 0; i < roles.Length; ++i)
- {
- m_roles[i] = roles[i];
- }
- }
- else
- {
- m_roles = null;
- }
- }
-
- public virtual IIdentity Identity
- {
- get
- {
- return m_identity;
- }
- }
-
- public virtual bool IsInRole(string role)
- {
- if (role == null || m_roles == null)
- return false;
-
- for (int i = 0; i < m_roles.Length; ++i)
- {
- if (m_roles[i] != null && String.Compare(m_roles[i], role, StringComparison.OrdinalIgnoreCase) == 0)
- return true;
- }
- return false;
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpListenerPrefixCollection.cs b/SocketHttpListener.Portable/Net/HttpListenerPrefixCollection.cs
deleted file mode 100644
index 0b05539ee..000000000
--- a/SocketHttpListener.Portable/Net/HttpListenerPrefixCollection.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using MediaBrowser.Model.Logging;
-
-namespace SocketHttpListener.Net
-{
- public class HttpListenerPrefixCollection : ICollection<string>, IEnumerable<string>, IEnumerable
- {
- List<string> prefixes = new List<string>();
- HttpListener listener;
-
- private ILogger _logger;
-
- internal HttpListenerPrefixCollection(ILogger logger, HttpListener listener)
- {
- _logger = logger;
- this.listener = listener;
- }
-
- public int Count
- {
- get { return prefixes.Count; }
- }
-
- public bool IsReadOnly
- {
- get { return false; }
- }
-
- public bool IsSynchronized
- {
- get { return false; }
- }
-
- public void Add(string uriPrefix)
- {
- listener.CheckDisposed();
- ListenerPrefix.CheckUri(uriPrefix);
- if (prefixes.Contains(uriPrefix))
- return;
-
- prefixes.Add(uriPrefix);
- if (listener.IsListening)
- EndPointManager.AddPrefix(_logger, uriPrefix, listener);
- }
-
- public void Clear()
- {
- listener.CheckDisposed();
- prefixes.Clear();
- if (listener.IsListening)
- EndPointManager.RemoveListener(_logger, listener);
- }
-
- public bool Contains(string uriPrefix)
- {
- listener.CheckDisposed();
- return prefixes.Contains(uriPrefix);
- }
-
- public void CopyTo(string[] array, int offset)
- {
- listener.CheckDisposed();
- prefixes.CopyTo(array, offset);
- }
-
- public void CopyTo(Array array, int offset)
- {
- listener.CheckDisposed();
- ((ICollection)prefixes).CopyTo(array, offset);
- }
-
- public IEnumerator<string> GetEnumerator()
- {
- return prefixes.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return prefixes.GetEnumerator();
- }
-
- public bool Remove(string uriPrefix)
- {
- listener.CheckDisposed();
- if (uriPrefix == null)
- throw new ArgumentNullException("uriPrefix");
-
- bool result = prefixes.Remove(uriPrefix);
- if (result && listener.IsListening)
- EndPointManager.RemovePrefix(_logger, uriPrefix, listener);
-
- return result;
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpListenerRequest.cs b/SocketHttpListener.Portable/Net/HttpListenerRequest.cs
deleted file mode 100644
index cfbd49203..000000000
--- a/SocketHttpListener.Portable/Net/HttpListenerRequest.cs
+++ /dev/null
@@ -1,654 +0,0 @@
-using System;
-using System.Collections.Specialized;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- public sealed class HttpListenerRequest
- {
- string[] accept_types;
- Encoding content_encoding;
- long content_length;
- bool cl_set;
- CookieCollection cookies;
- WebHeaderCollection headers;
- string method;
- Stream input_stream;
- Version version;
- QueryParamCollection query_string; // check if null is ok, check if read-only, check case-sensitiveness
- string raw_url;
- Uri url;
- Uri referrer;
- string[] user_languages;
- HttpListenerContext context;
- bool is_chunked;
- bool ka_set;
- bool keep_alive;
-
- private readonly ITextEncoding _textEncoding;
-
- internal HttpListenerRequest(HttpListenerContext context, ITextEncoding textEncoding)
- {
- this.context = context;
- _textEncoding = textEncoding;
- headers = new WebHeaderCollection();
- version = HttpVersion.Version10;
- }
-
- static char[] separators = new char[] { ' ' };
-
- internal void SetRequestLine(string req)
- {
- string[] parts = req.Split(separators, 3);
- if (parts.Length != 3)
- {
- context.ErrorMessage = "Invalid request line (parts).";
- return;
- }
-
- method = parts[0];
- foreach (char c in method)
- {
- int ic = (int)c;
-
- if ((ic >= 'A' && ic <= 'Z') ||
- (ic > 32 && c < 127 && c != '(' && c != ')' && c != '<' &&
- c != '<' && c != '>' && c != '@' && c != ',' && c != ';' &&
- c != ':' && c != '\\' && c != '"' && c != '/' && c != '[' &&
- c != ']' && c != '?' && c != '=' && c != '{' && c != '}'))
- continue;
-
- context.ErrorMessage = "(Invalid verb)";
- return;
- }
-
- raw_url = parts[1];
- if (parts[2].Length != 8 || !parts[2].StartsWith("HTTP/"))
- {
- context.ErrorMessage = "Invalid request line (version).";
- return;
- }
-
- try
- {
- version = new Version(parts[2].Substring(5));
- if (version.Major < 1)
- throw new Exception();
- }
- catch
- {
- context.ErrorMessage = "Invalid request line (version).";
- return;
- }
- }
-
- void CreateQueryString(string query)
- {
- if (query == null || query.Length == 0)
- {
- query_string = new QueryParamCollection();
- return;
- }
-
- query_string = new QueryParamCollection();
- if (query[0] == '?')
- query = query.Substring(1);
- string[] components = query.Split('&');
- foreach (string kv in components)
- {
- int pos = kv.IndexOf('=');
- if (pos == -1)
- {
- query_string.Add(null, WebUtility.UrlDecode(kv));
- }
- else
- {
- string key = WebUtility.UrlDecode(kv.Substring(0, pos));
- string val = WebUtility.UrlDecode(kv.Substring(pos + 1));
-
- query_string.Add(key, val);
- }
- }
- }
-
- internal void FinishInitialization()
- {
- string host = UserHostName;
- if (version > HttpVersion.Version10 && (host == null || host.Length == 0))
- {
- context.ErrorMessage = "Invalid host name";
- return;
- }
-
- string path;
- Uri raw_uri = null;
- if (MaybeUri(raw_url.ToLowerInvariant()) && Uri.TryCreate(raw_url, UriKind.Absolute, out raw_uri))
- path = raw_uri.PathAndQuery;
- else
- path = raw_url;
-
- if ((host == null || host.Length == 0))
- host = UserHostAddress;
-
- if (raw_uri != null)
- host = raw_uri.Host;
-
- int colon = host.LastIndexOf(':');
- if (colon >= 0)
- host = host.Substring(0, colon);
-
- string base_uri = String.Format("{0}://{1}:{2}",
- (IsSecureConnection) ? (IsWebSocketRequest ? "wss" : "https") : (IsWebSocketRequest ? "ws" : "http"),
- host, LocalEndPoint.Port);
-
- if (!Uri.TryCreate(base_uri + path, UriKind.Absolute, out url))
- {
- context.ErrorMessage = WebUtility.HtmlEncode("Invalid url: " + base_uri + path);
- return; return;
- }
-
- CreateQueryString(url.Query);
-
- if (version >= HttpVersion.Version11)
- {
- string t_encoding = Headers["Transfer-Encoding"];
- is_chunked = (t_encoding != null && String.Compare(t_encoding, "chunked", StringComparison.OrdinalIgnoreCase) == 0);
- // 'identity' is not valid!
- if (t_encoding != null && !is_chunked)
- {
- context.Connection.SendError(null, 501);
- return;
- }
- }
-
- if (!is_chunked && !cl_set)
- {
- if (String.Compare(method, "POST", StringComparison.OrdinalIgnoreCase) == 0 ||
- String.Compare(method, "PUT", StringComparison.OrdinalIgnoreCase) == 0)
- {
- context.Connection.SendError(null, 411);
- return;
- }
- }
-
- if (String.Compare(Headers["Expect"], "100-continue", StringComparison.OrdinalIgnoreCase) == 0)
- {
- var output = (ResponseStream)context.Connection.GetResponseStream(true);
-
- var _100continue = _textEncoding.GetASCIIEncoding().GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
-
- output.InternalWrite(_100continue, 0, _100continue.Length);
- }
- }
-
- static bool MaybeUri(string s)
- {
- int p = s.IndexOf(':');
- if (p == -1)
- return false;
-
- if (p >= 10)
- return false;
-
- return IsPredefinedScheme(s.Substring(0, p));
- }
-
- //
- // Using a simple block of if's is twice as slow as the compiler generated
- // switch statement. But using this tuned code is faster than the
- // compiler generated code, with a million loops on x86-64:
- //
- // With "http": .10 vs .51 (first check)
- // with "https": .16 vs .51 (second check)
- // with "foo": .22 vs .31 (never found)
- // with "mailto": .12 vs .51 (last check)
- //
- //
- static bool IsPredefinedScheme(string scheme)
- {
- if (scheme == null || scheme.Length < 3)
- return false;
-
- char c = scheme[0];
- if (c == 'h')
- return (scheme == "http" || scheme == "https");
- if (c == 'f')
- return (scheme == "file" || scheme == "ftp");
-
- if (c == 'n')
- {
- c = scheme[1];
- if (c == 'e')
- return (scheme == "news" || scheme == "net.pipe" || scheme == "net.tcp");
- if (scheme == "nntp")
- return true;
- return false;
- }
- if ((c == 'g' && scheme == "gopher") || (c == 'm' && scheme == "mailto"))
- return true;
-
- return false;
- }
-
- internal static string Unquote(String str)
- {
- int start = str.IndexOf('\"');
- int end = str.LastIndexOf('\"');
- if (start >= 0 && end >= 0)
- str = str.Substring(start + 1, end - 1);
- return str.Trim();
- }
-
- internal void AddHeader(string header)
- {
- int colon = header.IndexOf(':');
- if (colon == -1 || colon == 0)
- {
- context.ErrorMessage = "Bad Request";
- context.ErrorStatus = 400;
- return;
- }
-
- string name = header.Substring(0, colon).Trim();
- string val = header.Substring(colon + 1).Trim();
- string lower = name.ToLowerInvariant();
- headers.SetInternal(name, val);
- switch (lower)
- {
- case "accept-language":
- user_languages = val.Split(','); // yes, only split with a ','
- break;
- case "accept":
- accept_types = val.Split(','); // yes, only split with a ','
- break;
- case "content-length":
- try
- {
- //TODO: max. content_length?
- content_length = Int64.Parse(val.Trim());
- if (content_length < 0)
- context.ErrorMessage = "Invalid Content-Length.";
- cl_set = true;
- }
- catch
- {
- context.ErrorMessage = "Invalid Content-Length.";
- }
-
- break;
- case "content-type":
- {
- var contents = val.Split(';');
- foreach (var content in contents)
- {
- var tmp = content.Trim();
- if (tmp.StartsWith("charset"))
- {
- var charset = tmp.GetValue("=");
- if (charset != null && charset.Length > 0)
- {
- try
- {
-
- // Support upnp/dlna devices - CONTENT-TYPE: text/xml ; charset="utf-8"\r\n
- charset = charset.Trim('"');
- var index = charset.IndexOf('"');
- if (index != -1) charset = charset.Substring(0, index);
-
- content_encoding = Encoding.GetEncoding(charset);
- }
- catch
- {
- context.ErrorMessage = "Invalid Content-Type header: " + charset;
- }
- }
-
- break;
- }
- }
- }
- break;
- case "referer":
- try
- {
- referrer = new Uri(val);
- }
- catch
- {
- referrer = new Uri("http://someone.is.screwing.with.the.headers.com/");
- }
- break;
- case "cookie":
- if (cookies == null)
- cookies = new CookieCollection();
-
- string[] cookieStrings = val.Split(new char[] { ',', ';' });
- Cookie current = null;
- int version = 0;
- foreach (string cookieString in cookieStrings)
- {
- string str = cookieString.Trim();
- if (str.Length == 0)
- continue;
- if (str.StartsWith("$Version"))
- {
- version = Int32.Parse(Unquote(str.Substring(str.IndexOf('=') + 1)));
- }
- else if (str.StartsWith("$Path"))
- {
- if (current != null)
- current.Path = str.Substring(str.IndexOf('=') + 1).Trim();
- }
- else if (str.StartsWith("$Domain"))
- {
- if (current != null)
- current.Domain = str.Substring(str.IndexOf('=') + 1).Trim();
- }
- else if (str.StartsWith("$Port"))
- {
- if (current != null)
- current.Port = str.Substring(str.IndexOf('=') + 1).Trim();
- }
- else
- {
- if (current != null)
- {
- cookies.Add(current);
- }
- current = new Cookie();
- int idx = str.IndexOf('=');
- if (idx > 0)
- {
- current.Name = str.Substring(0, idx).Trim();
- current.Value = str.Substring(idx + 1).Trim();
- }
- else
- {
- current.Name = str.Trim();
- current.Value = String.Empty;
- }
- current.Version = version;
- }
- }
- if (current != null)
- {
- cookies.Add(current);
- }
- break;
- }
- }
-
- // returns true is the stream could be reused.
- internal bool FlushInput()
- {
- if (!HasEntityBody)
- return true;
-
- int length = 2048;
- if (content_length > 0)
- length = (int)Math.Min(content_length, (long)length);
-
- byte[] bytes = new byte[length];
- while (true)
- {
- // TODO: test if MS has a timeout when doing this
- try
- {
- var task = InputStream.ReadAsync(bytes, 0, length);
- var result = Task.WaitAll(new [] { task }, 1000);
- if (!result)
- {
- return false;
- }
- if (task.Result <= 0)
- {
- return true;
- }
- }
- catch (ObjectDisposedException e)
- {
- input_stream = null;
- return true;
- }
- catch
- {
- return false;
- }
- }
- }
-
- public string[] AcceptTypes
- {
- get { return accept_types; }
- }
-
- public int ClientCertificateError
- {
- get
- {
- HttpConnection cnc = context.Connection;
- //if (cnc.ClientCertificate == null)
- // throw new InvalidOperationException("No client certificate");
- //int[] errors = cnc.ClientCertificateErrors;
- //if (errors != null && errors.Length > 0)
- // return errors[0];
- return 0;
- }
- }
-
- public Encoding ContentEncoding
- {
- get
- {
- if (content_encoding == null)
- content_encoding = _textEncoding.GetDefaultEncoding();
- return content_encoding;
- }
- }
-
- public long ContentLength64
- {
- get { return is_chunked ? -1 : content_length; }
- }
-
- public string ContentType
- {
- get { return headers["content-type"]; }
- }
-
- public CookieCollection Cookies
- {
- get
- {
- // TODO: check if the collection is read-only
- if (cookies == null)
- cookies = new CookieCollection();
- return cookies;
- }
- }
-
- public bool HasEntityBody
- {
- get { return (content_length > 0 || is_chunked); }
- }
-
- public QueryParamCollection Headers
- {
- get { return headers; }
- }
-
- public string HttpMethod
- {
- get { return method; }
- }
-
- public Stream InputStream
- {
- get
- {
- if (input_stream == null)
- {
- if (is_chunked || content_length > 0)
- input_stream = context.Connection.GetRequestStream(is_chunked, content_length);
- else
- input_stream = Stream.Null;
- }
-
- return input_stream;
- }
- }
-
- public bool IsAuthenticated
- {
- get { return false; }
- }
-
- public bool IsLocal
- {
- get { return RemoteEndPoint.IpAddress.Equals(IpAddressInfo.Loopback) || RemoteEndPoint.IpAddress.Equals(IpAddressInfo.IPv6Loopback) || LocalEndPoint.IpAddress.Equals(RemoteEndPoint.IpAddress); }
- }
-
- public bool IsSecureConnection
- {
- get { return context.Connection.IsSecure; }
- }
-
- public bool KeepAlive
- {
- get
- {
- if (ka_set)
- return keep_alive;
-
- ka_set = true;
- // 1. Connection header
- // 2. Protocol (1.1 == keep-alive by default)
- // 3. Keep-Alive header
- string cnc = headers["Connection"];
- if (!String.IsNullOrEmpty(cnc))
- {
- keep_alive = (0 == String.Compare(cnc, "keep-alive", StringComparison.OrdinalIgnoreCase));
- }
- else if (version == HttpVersion.Version11)
- {
- keep_alive = true;
- }
- else
- {
- cnc = headers["keep-alive"];
- if (!String.IsNullOrEmpty(cnc))
- keep_alive = (0 != String.Compare(cnc, "closed", StringComparison.OrdinalIgnoreCase));
- }
- return keep_alive;
- }
- }
-
- public IpEndPointInfo LocalEndPoint
- {
- get { return context.Connection.LocalEndPoint; }
- }
-
- public Version ProtocolVersion
- {
- get { return version; }
- }
-
- public QueryParamCollection QueryString
- {
- get { return query_string; }
- }
-
- public string RawUrl
- {
- get { return raw_url; }
- }
-
- public IpEndPointInfo RemoteEndPoint
- {
- get { return context.Connection.RemoteEndPoint; }
- }
-
- public Guid RequestTraceIdentifier
- {
- get { return Guid.Empty; }
- }
-
- public Uri Url
- {
- get { return url; }
- }
-
- public Uri UrlReferrer
- {
- get { return referrer; }
- }
-
- public string UserAgent
- {
- get { return headers["user-agent"]; }
- }
-
- public string UserHostAddress
- {
- get { return LocalEndPoint.ToString(); }
- }
-
- public string UserHostName
- {
- get { return headers["host"]; }
- }
-
- public string[] UserLanguages
- {
- get { return user_languages; }
- }
-
- public string ServiceName
- {
- get
- {
- return null;
- }
- }
-
- private bool _websocketRequestWasSet;
- private bool _websocketRequest;
-
- /// <summary>
- /// Gets a value indicating whether the request is a WebSocket connection request.
- /// </summary>
- /// <value>
- /// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
- /// </value>
- public bool IsWebSocketRequest
- {
- get
- {
- if (!_websocketRequestWasSet)
- {
- _websocketRequest = method == "GET" &&
- version > HttpVersion.Version10 &&
- headers.Contains("Upgrade", "websocket") &&
- headers.Contains("Connection", "Upgrade");
-
- _websocketRequestWasSet = true;
- }
-
- return _websocketRequest;
- }
- }
-
- public Task<ICertificate> GetClientCertificateAsync()
- {
- return Task.FromResult<ICertificate>(null);
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs b/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
deleted file mode 100644
index 3cb6a0d75..000000000
--- a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
+++ /dev/null
@@ -1,525 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- public sealed class HttpListenerResponse : IDisposable
- {
- bool disposed;
- Encoding content_encoding;
- long content_length;
- bool cl_set;
- string content_type;
- CookieCollection cookies;
- WebHeaderCollection headers = new WebHeaderCollection();
- bool keep_alive = true;
- Stream output_stream;
- Version version = HttpVersion.Version11;
- string location;
- int status_code = 200;
- string status_description = "OK";
- bool chunked;
- HttpListenerContext context;
-
- internal bool HeadersSent;
- internal object headers_lock = new object();
-
- private readonly ILogger _logger;
- private readonly ITextEncoding _textEncoding;
- private readonly IFileSystem _fileSystem;
-
- internal HttpListenerResponse(HttpListenerContext context, ILogger logger, ITextEncoding textEncoding, IFileSystem fileSystem)
- {
- this.context = context;
- _logger = logger;
- _textEncoding = textEncoding;
- _fileSystem = fileSystem;
- }
-
- internal bool CloseConnection
- {
- get
- {
- return headers["Connection"] == "close";
- }
- }
-
- public Encoding ContentEncoding
- {
- get
- {
- if (content_encoding == null)
- content_encoding = _textEncoding.GetDefaultEncoding();
- return content_encoding;
- }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- content_encoding = value;
- }
- }
-
- public long ContentLength64
- {
- get { return content_length; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (HeadersSent)
- throw new InvalidOperationException("Cannot be changed after headers are sent.");
-
- if (value < 0)
- throw new ArgumentOutOfRangeException("Must be >= 0", "value");
-
- cl_set = true;
- content_length = value;
- }
- }
-
- public string ContentType
- {
- get { return content_type; }
- set
- {
- // TODO: is null ok?
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- content_type = value;
- }
- }
-
- // RFC 2109, 2965 + the netscape specification at http://wp.netscape.com/newsref/std/cookie_spec.html
- public CookieCollection Cookies
- {
- get
- {
- if (cookies == null)
- cookies = new CookieCollection();
- return cookies;
- }
- set { cookies = value; } // null allowed?
- }
-
- public WebHeaderCollection Headers
- {
- get { return headers; }
- set
- {
- /**
- * "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, or
- * WWW-Authenticate header using the Headers property, an exception will be
- * thrown. Use the KeepAlive or ContentLength64 properties to set these headers.
- * You cannot set the Transfer-Encoding or WWW-Authenticate headers manually."
- */
- // TODO: check if this is marked readonly after headers are sent.
- headers = value;
- }
- }
-
- public bool KeepAlive
- {
- get { return keep_alive; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- keep_alive = value;
- }
- }
-
- public Stream OutputStream
- {
- get
- {
- if (output_stream == null)
- output_stream = context.Connection.GetResponseStream();
- return output_stream;
- }
- }
-
- public Version ProtocolVersion
- {
- get { return version; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (value == null)
- throw new ArgumentNullException("value");
-
- if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
- throw new ArgumentException("Must be 1.0 or 1.1", "value");
-
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- version = value;
- }
- }
-
- public string RedirectLocation
- {
- get { return location; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- location = value;
- }
- }
-
- public bool SendChunked
- {
- get { return chunked; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- chunked = value;
- }
- }
-
- public int StatusCode
- {
- get { return status_code; }
- set
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (value < 100 || value > 999)
- throw new ProtocolViolationException("StatusCode must be between 100 and 999.");
- status_code = value;
- status_description = GetStatusDescription(value);
- }
- }
-
- internal static string GetStatusDescription(int code)
- {
- switch (code)
- {
- case 100: return "Continue";
- case 101: return "Switching Protocols";
- case 102: return "Processing";
- case 200: return "OK";
- case 201: return "Created";
- case 202: return "Accepted";
- case 203: return "Non-Authoritative Information";
- case 204: return "No Content";
- case 205: return "Reset Content";
- case 206: return "Partial Content";
- case 207: return "Multi-Status";
- case 300: return "Multiple Choices";
- case 301: return "Moved Permanently";
- case 302: return "Found";
- case 303: return "See Other";
- case 304: return "Not Modified";
- case 305: return "Use Proxy";
- case 307: return "Temporary Redirect";
- case 400: return "Bad Request";
- case 401: return "Unauthorized";
- case 402: return "Payment Required";
- case 403: return "Forbidden";
- case 404: return "Not Found";
- case 405: return "Method Not Allowed";
- case 406: return "Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Timeout";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Request Entity Too Large";
- case 414: return "Request-Uri Too Long";
- case 415: return "Unsupported Media Type";
- case 416: return "Requested Range Not Satisfiable";
- case 417: return "Expectation Failed";
- case 422: return "Unprocessable Entity";
- case 423: return "Locked";
- case 424: return "Failed Dependency";
- case 500: return "Internal Server Error";
- case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Timeout";
- case 505: return "Http Version Not Supported";
- case 507: return "Insufficient Storage";
- }
- return "";
- }
-
- public string StatusDescription
- {
- get { return status_description; }
- set
- {
- status_description = value;
- }
- }
-
- void IDisposable.Dispose()
- {
- Close(true); //TODO: Abort or Close?
- }
-
- public void Abort()
- {
- if (disposed)
- return;
-
- Close(true);
- }
-
- public void AddHeader(string name, string value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
-
- if (name == "")
- throw new ArgumentException("'name' cannot be empty", "name");
-
- //TODO: check for forbidden headers and invalid characters
- if (value.Length > 65535)
- throw new ArgumentOutOfRangeException("value");
-
- headers.Set(name, value);
- }
-
- public void AppendCookie(Cookie cookie)
- {
- if (cookie == null)
- throw new ArgumentNullException("cookie");
-
- Cookies.Add(cookie);
- }
-
- public void AppendHeader(string name, string value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
-
- if (name == "")
- throw new ArgumentException("'name' cannot be empty", "name");
-
- if (value.Length > 65535)
- throw new ArgumentOutOfRangeException("value");
-
- headers.Add(name, value);
- }
-
- private void Close(bool force)
- {
- if (force)
- {
- _logger.Debug("HttpListenerResponse force closing HttpConnection");
- }
- disposed = true;
- context.Connection.Close(force);
- }
-
- public void Close()
- {
- if (disposed)
- return;
-
- Close(false);
- }
-
- public void Redirect(string url)
- {
- StatusCode = 302; // Found
- location = url;
- }
-
- bool FindCookie(Cookie cookie)
- {
- string name = cookie.Name;
- string domain = cookie.Domain;
- string path = cookie.Path;
- foreach (Cookie c in cookies)
- {
- if (name != c.Name)
- continue;
- if (domain != c.Domain)
- continue;
- if (path == c.Path)
- return true;
- }
-
- return false;
- }
-
- public void DetermineIfChunked()
- {
- if (chunked)
- {
- return;
- }
-
- Version v = context.Request.ProtocolVersion;
- if (!cl_set && !chunked && v >= HttpVersion.Version11)
- chunked = true;
- if (!chunked && string.Equals(headers["Transfer-Encoding"], "chunked"))
- {
- chunked = true;
- }
- }
-
- internal void SendHeaders(bool closing, MemoryStream ms)
- {
- Encoding encoding = content_encoding;
- if (encoding == null)
- encoding = _textEncoding.GetDefaultEncoding();
-
- if (content_type != null)
- {
- if (content_encoding != null && content_type.IndexOf("charset=", StringComparison.OrdinalIgnoreCase) == -1)
- {
- string enc_name = content_encoding.WebName;
- headers.SetInternal("Content-Type", content_type + "; charset=" + enc_name);
- }
- else
- {
- headers.SetInternal("Content-Type", content_type);
- }
- }
-
- if (headers["Server"] == null)
- headers.SetInternal("Server", "Mono-HTTPAPI/1.0");
-
- CultureInfo inv = CultureInfo.InvariantCulture;
- if (headers["Date"] == null)
- headers.SetInternal("Date", DateTime.UtcNow.ToString("r", inv));
-
- if (!chunked)
- {
- if (!cl_set && closing)
- {
- cl_set = true;
- content_length = 0;
- }
-
- if (cl_set)
- headers.SetInternal("Content-Length", content_length.ToString(inv));
- }
-
- Version v = context.Request.ProtocolVersion;
- if (!cl_set && !chunked && v >= HttpVersion.Version11)
- chunked = true;
-
- /* Apache forces closing the connection for these status codes:
- * HttpStatusCode.BadRequest 400
- * HttpStatusCode.RequestTimeout 408
- * HttpStatusCode.LengthRequired 411
- * HttpStatusCode.RequestEntityTooLarge 413
- * HttpStatusCode.RequestUriTooLong 414
- * HttpStatusCode.InternalServerError 500
- * HttpStatusCode.ServiceUnavailable 503
- */
- bool conn_close = status_code == 400 || status_code == 408 || status_code == 411 ||
- status_code == 413 || status_code == 414 ||
- status_code == 500 ||
- status_code == 503;
-
- if (conn_close == false)
- conn_close = !context.Request.KeepAlive;
-
- // They sent both KeepAlive: true and Connection: close!?
- if (!keep_alive || conn_close)
- {
- headers.SetInternal("Connection", "close");
- conn_close = true;
- }
-
- if (chunked)
- headers.SetInternal("Transfer-Encoding", "chunked");
-
- //int reuses = context.Connection.Reuses;
- //if (reuses >= 100)
- //{
- // _logger.Debug("HttpListenerResponse - keep alive has exceeded 100 uses and will be closed.");
-
- // force_close_chunked = true;
- // if (!conn_close)
- // {
- // headers.SetInternal("Connection", "close");
- // conn_close = true;
- // }
- //}
-
- if (!conn_close)
- {
- if (context.Request.ProtocolVersion <= HttpVersion.Version10)
- headers.SetInternal("Connection", "keep-alive");
- }
-
- if (location != null)
- headers.SetInternal("Location", location);
-
- if (cookies != null)
- {
- foreach (Cookie cookie in cookies)
- headers.SetInternal("Set-Cookie", cookie.ToString());
- }
-
- headers.SetInternal("Status", status_code.ToString(CultureInfo.InvariantCulture));
-
- using (StreamWriter writer = new StreamWriter(ms, encoding, 256, true))
- {
- writer.Write("HTTP/{0} {1} {2}\r\n", version, status_code, status_description);
- string headers_str = headers.ToStringMultiValue();
- writer.Write(headers_str);
- writer.Flush();
- }
-
- int preamble = encoding.GetPreamble().Length;
- if (output_stream == null)
- output_stream = context.Connection.GetResponseStream();
-
- /* Assumes that the ms was at position 0 */
- ms.Position = preamble;
- HeadersSent = true;
- }
-
- public void SetCookie(Cookie cookie)
- {
- if (cookie == null)
- throw new ArgumentNullException("cookie");
-
- if (cookies != null)
- {
- if (FindCookie(cookie))
- throw new ArgumentException("The cookie already exists.");
- }
- else
- {
- cookies = new CookieCollection();
- }
-
- cookies.Add(cookie);
- }
-
- public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken);
- }
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/Net/HttpStatusCode.cs b/SocketHttpListener.Portable/Net/HttpStatusCode.cs
deleted file mode 100644
index 93da82ba0..000000000
--- a/SocketHttpListener.Portable/Net/HttpStatusCode.cs
+++ /dev/null
@@ -1,321 +0,0 @@
-namespace SocketHttpListener.Net
-{
- /// <summary>
- /// Contains the values of the HTTP status codes.
- /// </summary>
- /// <remarks>
- /// The HttpStatusCode enumeration contains the values of the HTTP status codes defined in
- /// <see href="http://tools.ietf.org/html/rfc2616#section-10">RFC 2616</see> for HTTP 1.1.
- /// </remarks>
- public enum HttpStatusCode
- {
- /// <summary>
- /// Equivalent to status code 100.
- /// Indicates that the client should continue with its request.
- /// </summary>
- Continue = 100,
- /// <summary>
- /// Equivalent to status code 101.
- /// Indicates that the server is switching the HTTP version or protocol on the connection.
- /// </summary>
- SwitchingProtocols = 101,
- /// <summary>
- /// Equivalent to status code 200.
- /// Indicates that the client's request has succeeded.
- /// </summary>
- OK = 200,
- /// <summary>
- /// Equivalent to status code 201.
- /// Indicates that the client's request has been fulfilled and resulted in a new resource being
- /// created.
- /// </summary>
- Created = 201,
- /// <summary>
- /// Equivalent to status code 202.
- /// Indicates that the client's request has been accepted for processing, but the processing
- /// hasn't been completed.
- /// </summary>
- Accepted = 202,
- /// <summary>
- /// Equivalent to status code 203.
- /// Indicates that the returned metainformation is from a local or a third-party copy instead of
- /// the origin server.
- /// </summary>
- NonAuthoritativeInformation = 203,
- /// <summary>
- /// Equivalent to status code 204.
- /// Indicates that the server has fulfilled the client's request but doesn't need to return
- /// an entity-body.
- /// </summary>
- NoContent = 204,
- /// <summary>
- /// Equivalent to status code 205.
- /// Indicates that the server has fulfilled the client's request, and the user agent should
- /// reset the document view which caused the request to be sent.
- /// </summary>
- ResetContent = 205,
- /// <summary>
- /// Equivalent to status code 206.
- /// Indicates that the server has fulfilled the partial GET request for the resource.
- /// </summary>
- PartialContent = 206,
- /// <summary>
- /// <para>
- /// Equivalent to status code 300.
- /// Indicates that the requested resource corresponds to any of multiple representations.
- /// </para>
- /// <para>
- /// MultipleChoices is a synonym for Ambiguous.
- /// </para>
- /// </summary>
- MultipleChoices = 300,
- /// <summary>
- /// <para>
- /// Equivalent to status code 300.
- /// Indicates that the requested resource corresponds to any of multiple representations.
- /// </para>
- /// <para>
- /// Ambiguous is a synonym for MultipleChoices.
- /// </para>
- /// </summary>
- Ambiguous = 300,
- /// <summary>
- /// <para>
- /// Equivalent to status code 301.
- /// Indicates that the requested resource has been assigned a new permanent URI and
- /// any future references to this resource should use one of the returned URIs.
- /// </para>
- /// <para>
- /// MovedPermanently is a synonym for Moved.
- /// </para>
- /// </summary>
- MovedPermanently = 301,
- /// <summary>
- /// <para>
- /// Equivalent to status code 301.
- /// Indicates that the requested resource has been assigned a new permanent URI and
- /// any future references to this resource should use one of the returned URIs.
- /// </para>
- /// <para>
- /// Moved is a synonym for MovedPermanently.
- /// </para>
- /// </summary>
- Moved = 301,
- /// <summary>
- /// <para>
- /// Equivalent to status code 302.
- /// Indicates that the requested resource is located temporarily under a different URI.
- /// </para>
- /// <para>
- /// Found is a synonym for Redirect.
- /// </para>
- /// </summary>
- Found = 302,
- /// <summary>
- /// <para>
- /// Equivalent to status code 302.
- /// Indicates that the requested resource is located temporarily under a different URI.
- /// </para>
- /// <para>
- /// Redirect is a synonym for Found.
- /// </para>
- /// </summary>
- Redirect = 302,
- /// <summary>
- /// <para>
- /// Equivalent to status code 303.
- /// Indicates that the response to the request can be found under a different URI and
- /// should be retrieved using a GET method on that resource.
- /// </para>
- /// <para>
- /// SeeOther is a synonym for RedirectMethod.
- /// </para>
- /// </summary>
- SeeOther = 303,
- /// <summary>
- /// <para>
- /// Equivalent to status code 303.
- /// Indicates that the response to the request can be found under a different URI and
- /// should be retrieved using a GET method on that resource.
- /// </para>
- /// <para>
- /// RedirectMethod is a synonym for SeeOther.
- /// </para>
- /// </summary>
- RedirectMethod = 303,
- /// <summary>
- /// Equivalent to status code 304.
- /// Indicates that the client has performed a conditional GET request and access is allowed,
- /// but the document hasn't been modified.
- /// </summary>
- NotModified = 304,
- /// <summary>
- /// Equivalent to status code 305.
- /// Indicates that the requested resource must be accessed through the proxy given by
- /// the Location field.
- /// </summary>
- UseProxy = 305,
- /// <summary>
- /// Equivalent to status code 306.
- /// This status code was used in a previous version of the specification, is no longer used,
- /// and is reserved for future use.
- /// </summary>
- Unused = 306,
- /// <summary>
- /// <para>
- /// Equivalent to status code 307.
- /// Indicates that the requested resource is located temporarily under a different URI.
- /// </para>
- /// <para>
- /// TemporaryRedirect is a synonym for RedirectKeepVerb.
- /// </para>
- /// </summary>
- TemporaryRedirect = 307,
- /// <summary>
- /// <para>
- /// Equivalent to status code 307.
- /// Indicates that the requested resource is located temporarily under a different URI.
- /// </para>
- /// <para>
- /// RedirectKeepVerb is a synonym for TemporaryRedirect.
- /// </para>
- /// </summary>
- RedirectKeepVerb = 307,
- /// <summary>
- /// Equivalent to status code 400.
- /// Indicates that the client's request couldn't be understood by the server due to
- /// malformed syntax.
- /// </summary>
- BadRequest = 400,
- /// <summary>
- /// Equivalent to status code 401.
- /// Indicates that the client's request requires user authentication.
- /// </summary>
- Unauthorized = 401,
- /// <summary>
- /// Equivalent to status code 402.
- /// This status code is reserved for future use.
- /// </summary>
- PaymentRequired = 402,
- /// <summary>
- /// Equivalent to status code 403.
- /// Indicates that the server understood the client's request but is refusing to fulfill it.
- /// </summary>
- Forbidden = 403,
- /// <summary>
- /// Equivalent to status code 404.
- /// Indicates that the server hasn't found anything matching the request URI.
- /// </summary>
- NotFound = 404,
- /// <summary>
- /// Equivalent to status code 405.
- /// Indicates that the method specified in the request line isn't allowed for the resource
- /// identified by the request URI.
- /// </summary>
- MethodNotAllowed = 405,
- /// <summary>
- /// Equivalent to status code 406.
- /// Indicates that the server doesn't have the appropriate resource to respond to the Accept
- /// headers in the client's request.
- /// </summary>
- NotAcceptable = 406,
- /// <summary>
- /// Equivalent to status code 407.
- /// Indicates that the client must first authenticate itself with the proxy.
- /// </summary>
- ProxyAuthenticationRequired = 407,
- /// <summary>
- /// Equivalent to status code 408.
- /// Indicates that the client didn't produce a request within the time that the server was
- /// prepared to wait.
- /// </summary>
- RequestTimeout = 408,
- /// <summary>
- /// Equivalent to status code 409.
- /// Indicates that the client's request couldn't be completed due to a conflict on the server.
- /// </summary>
- Conflict = 409,
- /// <summary>
- /// Equivalent to status code 410.
- /// Indicates that the requested resource is no longer available at the server and
- /// no forwarding address is known.
- /// </summary>
- Gone = 410,
- /// <summary>
- /// Equivalent to status code 411.
- /// Indicates that the server refuses to accept the client's request without a defined
- /// Content-Length.
- /// </summary>
- LengthRequired = 411,
- /// <summary>
- /// Equivalent to status code 412.
- /// Indicates that the precondition given in one or more of the request headers evaluated to
- /// false when it was tested on the server.
- /// </summary>
- PreconditionFailed = 412,
- /// <summary>
- /// Equivalent to status code 413.
- /// Indicates that the entity of the client's request is larger than the server is willing or
- /// able to process.
- /// </summary>
- RequestEntityTooLarge = 413,
- /// <summary>
- /// Equivalent to status code 414.
- /// Indicates that the request URI is longer than the server is willing to interpret.
- /// </summary>
- RequestUriTooLong = 414,
- /// <summary>
- /// Equivalent to status code 415.
- /// Indicates that the entity of the client's request is in a format not supported by
- /// the requested resource for the requested method.
- /// </summary>
- UnsupportedMediaType = 415,
- /// <summary>
- /// Equivalent to status code 416.
- /// Indicates that none of the range specifier values in a Range request header overlap
- /// the current extent of the selected resource.
- /// </summary>
- RequestedRangeNotSatisfiable = 416,
- /// <summary>
- /// Equivalent to status code 417.
- /// Indicates that the expectation given in an Expect request header couldn't be met by
- /// the server.
- /// </summary>
- ExpectationFailed = 417,
- /// <summary>
- /// Equivalent to status code 500.
- /// Indicates that the server encountered an unexpected condition which prevented it from
- /// fulfilling the client's request.
- /// </summary>
- InternalServerError = 500,
- /// <summary>
- /// Equivalent to status code 501.
- /// Indicates that the server doesn't support the functionality required to fulfill the client's
- /// request.
- /// </summary>
- NotImplemented = 501,
- /// <summary>
- /// Equivalent to status code 502.
- /// Indicates that a gateway or proxy server received an invalid response from the upstream
- /// server.
- /// </summary>
- BadGateway = 502,
- /// <summary>
- /// Equivalent to status code 503.
- /// Indicates that the server is currently unable to handle the client's request due to
- /// a temporary overloading or maintenance of the server.
- /// </summary>
- ServiceUnavailable = 503,
- /// <summary>
- /// Equivalent to status code 504.
- /// Indicates that a gateway or proxy server didn't receive a timely response from the upstream
- /// server or some other auxiliary server.
- /// </summary>
- GatewayTimeout = 504,
- /// <summary>
- /// Equivalent to status code 505.
- /// Indicates that the server doesn't support the HTTP version used in the client's request.
- /// </summary>
- HttpVersionNotSupported = 505,
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpStreamAsyncResult.cs b/SocketHttpListener.Portable/Net/HttpStreamAsyncResult.cs
deleted file mode 100644
index 518c45acb..000000000
--- a/SocketHttpListener.Portable/Net/HttpStreamAsyncResult.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Threading;
-
-namespace SocketHttpListener.Net
-{
- class HttpStreamAsyncResult : IAsyncResult
- {
- object locker = new object();
- ManualResetEvent handle;
- bool completed;
-
- internal byte[] Buffer;
- internal int Offset;
- internal int Count;
- internal AsyncCallback Callback;
- internal object State;
- internal int SynchRead;
- internal Exception Error;
-
- public void Complete(Exception e)
- {
- Error = e;
- Complete();
- }
-
- public void Complete()
- {
- lock (locker)
- {
- if (completed)
- return;
-
- completed = true;
- if (handle != null)
- handle.Set();
-
- if (Callback != null)
- Callback.BeginInvoke(this, null, null);
- }
- }
-
- public object AsyncState
- {
- get { return State; }
- }
-
- public WaitHandle AsyncWaitHandle
- {
- get
- {
- lock (locker)
- {
- if (handle == null)
- handle = new ManualResetEvent(completed);
- }
-
- return handle;
- }
- }
-
- public bool CompletedSynchronously
- {
- get { return (SynchRead == Count); }
- }
-
- public bool IsCompleted
- {
- get
- {
- lock (locker)
- {
- return completed;
- }
- }
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/HttpVersion.cs b/SocketHttpListener.Portable/Net/HttpVersion.cs
deleted file mode 100644
index c0839b46d..000000000
--- a/SocketHttpListener.Portable/Net/HttpVersion.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-
-namespace SocketHttpListener.Net
-{
- // <remarks>
- // </remarks>
- public class HttpVersion
- {
-
- public static readonly Version Version10 = new Version(1, 0);
- public static readonly Version Version11 = new Version(1, 1);
-
- // pretty useless..
- public HttpVersion() { }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/ListenerPrefix.cs b/SocketHttpListener.Portable/Net/ListenerPrefix.cs
deleted file mode 100644
index 2c314da50..000000000
--- a/SocketHttpListener.Portable/Net/ListenerPrefix.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using System;
-using System.Net;
-using MediaBrowser.Model.Net;
-
-namespace SocketHttpListener.Net
-{
- sealed class ListenerPrefix
- {
- string original;
- string host;
- ushort port;
- string path;
- bool secure;
- IpAddressInfo[] addresses;
- public HttpListener Listener;
-
- public ListenerPrefix(string prefix)
- {
- this.original = prefix;
- Parse(prefix);
- }
-
- public override string ToString()
- {
- return original;
- }
-
- public IpAddressInfo[] Addresses
- {
- get { return addresses; }
- set { addresses = value; }
- }
- public bool Secure
- {
- get { return secure; }
- }
-
- public string Host
- {
- get { return host; }
- }
-
- public int Port
- {
- get { return (int)port; }
- }
-
- public string Path
- {
- get { return path; }
- }
-
- // Equals and GetHashCode are required to detect duplicates in HttpListenerPrefixCollection.
- public override bool Equals(object o)
- {
- ListenerPrefix other = o as ListenerPrefix;
- if (other == null)
- return false;
-
- return (original == other.original);
- }
-
- public override int GetHashCode()
- {
- return original.GetHashCode();
- }
-
- void Parse(string uri)
- {
- ushort default_port = 80;
- if (uri.StartsWith("https://"))
- {
- default_port = 443;
- secure = true;
- }
-
- int length = uri.Length;
- int start_host = uri.IndexOf(':') + 3;
- if (start_host >= length)
- throw new ArgumentException("No host specified.");
-
- int colon = uri.IndexOf(':', start_host, length - start_host);
- int root;
- if (colon > 0)
- {
- host = uri.Substring(start_host, colon - start_host);
- root = uri.IndexOf('/', colon, length - colon);
- port = (ushort)Int32.Parse(uri.Substring(colon + 1, root - colon - 1));
- path = uri.Substring(root);
- }
- else
- {
- root = uri.IndexOf('/', start_host, length - start_host);
- host = uri.Substring(start_host, root - start_host);
- port = default_port;
- path = uri.Substring(root);
- }
- if (path.Length != 1)
- path = path.Substring(0, path.Length - 1);
- }
-
- public static void CheckUri(string uri)
- {
- if (uri == null)
- throw new ArgumentNullException("uriPrefix");
-
- if (!uri.StartsWith("http://") && !uri.StartsWith("https://"))
- throw new ArgumentException("Only 'http' and 'https' schemes are supported.");
-
- int length = uri.Length;
- int start_host = uri.IndexOf(':') + 3;
- if (start_host >= length)
- throw new ArgumentException("No host specified.");
-
- int colon = uri.IndexOf(':', start_host, length - start_host);
- if (start_host == colon)
- throw new ArgumentException("No host specified.");
-
- int root;
- if (colon > 0)
- {
- root = uri.IndexOf('/', colon, length - colon);
- if (root == -1)
- throw new ArgumentException("No path specified.");
-
- try
- {
- int p = Int32.Parse(uri.Substring(colon + 1, root - colon - 1));
- if (p <= 0 || p >= 65536)
- throw new Exception();
- }
- catch
- {
- throw new ArgumentException("Invalid port.");
- }
- }
- else
- {
- root = uri.IndexOf('/', start_host, length - start_host);
- if (root == -1)
- throw new ArgumentException("No path specified.");
- }
-
- if (uri[uri.Length - 1] != '/')
- throw new ArgumentException("The prefix must end with '/'");
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/RequestStream.cs b/SocketHttpListener.Portable/Net/RequestStream.cs
deleted file mode 100644
index 58030500d..000000000
--- a/SocketHttpListener.Portable/Net/RequestStream.cs
+++ /dev/null
@@ -1,231 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Net
-{
- class RequestStream : Stream
- {
- byte[] buffer;
- int offset;
- int length;
- long remaining_body;
- bool disposed;
- Stream stream;
-
- internal RequestStream(Stream stream, byte[] buffer, int offset, int length)
- : this(stream, buffer, offset, length, -1)
- {
- }
-
- internal RequestStream(Stream stream, byte[] buffer, int offset, int length, long contentlength)
- {
- this.stream = stream;
- this.buffer = buffer;
- this.offset = offset;
- this.length = length;
- this.remaining_body = contentlength;
- }
-
- public override bool CanRead
- {
- get { return true; }
- }
-
- public override bool CanSeek
- {
- get { return false; }
- }
-
- public override bool CanWrite
- {
- get { return false; }
- }
-
- public override long Length
- {
- get { throw new NotSupportedException(); }
- }
-
- public override long Position
- {
- get { throw new NotSupportedException(); }
- set { throw new NotSupportedException(); }
- }
-
-
- protected override void Dispose(bool disposing)
- {
- disposed = true;
- }
-
- public override void Flush()
- {
- }
-
-
- // Returns 0 if we can keep reading from the base stream,
- // > 0 if we read something from the buffer.
- // -1 if we had a content length set and we finished reading that many bytes.
- int FillFromBuffer(byte[] buffer, int off, int count)
- {
- if (buffer == null)
- throw new ArgumentNullException("buffer");
- if (off < 0)
- throw new ArgumentOutOfRangeException("offset", "< 0");
- if (count < 0)
- throw new ArgumentOutOfRangeException("count", "< 0");
- int len = buffer.Length;
- if (off > len)
- throw new ArgumentException("destination offset is beyond array size");
- if (off > len - count)
- throw new ArgumentException("Reading would overrun buffer");
-
- if (this.remaining_body == 0)
- return -1;
-
- if (this.length == 0)
- return 0;
-
- int size = Math.Min(this.length, count);
- if (this.remaining_body > 0)
- size = (int)Math.Min(size, this.remaining_body);
-
- if (this.offset > this.buffer.Length - size)
- {
- size = Math.Min(size, this.buffer.Length - this.offset);
- }
- if (size == 0)
- return 0;
-
- Buffer.BlockCopy(this.buffer, this.offset, buffer, off, size);
- this.offset += size;
- this.length -= size;
- if (this.remaining_body > 0)
- remaining_body -= size;
- return size;
- }
-
- public override int Read([In, Out] byte[] buffer, int offset, int count)
- {
- if (disposed)
- throw new ObjectDisposedException(typeof(RequestStream).ToString());
-
- // Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
- int nread = FillFromBuffer(buffer, offset, count);
- if (nread == -1)
- { // No more bytes available (Content-Length)
- return 0;
- }
- else if (nread > 0)
- {
- return nread;
- }
-
- nread = stream.Read(buffer, offset, count);
- if (nread > 0 && remaining_body > 0)
- remaining_body -= nread;
- return nread;
- }
-
- public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- if (disposed)
- throw new ObjectDisposedException(typeof(RequestStream).ToString());
-
- int nread = FillFromBuffer(buffer, offset, count);
- if (nread > 0 || nread == -1)
- {
- return Math.Max(0, nread);
- }
-
- // Avoid reading past the end of the request to allow
- // for HTTP pipelining
- if (remaining_body >= 0 && count > remaining_body)
- count = (int)Math.Min(Int32.MaxValue, remaining_body);
-
- nread = await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
- if (remaining_body > 0 && nread > 0)
- remaining_body -= nread;
- return nread;
- }
-
- //public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
- // AsyncCallback cback, object state)
- //{
- // if (disposed)
- // throw new ObjectDisposedException(typeof(RequestStream).ToString());
-
- // int nread = FillFromBuffer(buffer, offset, count);
- // if (nread > 0 || nread == -1)
- // {
- // HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
- // ares.Buffer = buffer;
- // ares.Offset = offset;
- // ares.Count = count;
- // ares.Callback = cback;
- // ares.State = state;
- // ares.SynchRead = Math.Max(0, nread);
- // ares.Complete();
- // return ares;
- // }
-
- // // Avoid reading past the end of the request to allow
- // // for HTTP pipelining
- // if (remaining_body >= 0 && count > remaining_body)
- // count = (int)Math.Min(Int32.MaxValue, remaining_body);
- // return stream.BeginRead(buffer, offset, count, cback, state);
- //}
-
- //public override int EndRead(IAsyncResult ares)
- //{
- // if (disposed)
- // throw new ObjectDisposedException(typeof(RequestStream).ToString());
-
- // if (ares == null)
- // throw new ArgumentNullException("async_result");
-
- // if (ares is HttpStreamAsyncResult)
- // {
- // HttpStreamAsyncResult r = (HttpStreamAsyncResult)ares;
- // if (!ares.IsCompleted)
- // ares.AsyncWaitHandle.WaitOne();
- // return r.SynchRead;
- // }
-
- // // Close on exception?
- // int nread = stream.EndRead(ares);
- // if (remaining_body > 0 && nread > 0)
- // remaining_body -= nread;
- // return nread;
- //}
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException();
- }
-
- //public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
- // AsyncCallback cback, object state)
- //{
- // throw new NotSupportedException();
- //}
-
- //public override void EndWrite(IAsyncResult async_result)
- //{
- // throw new NotSupportedException();
- //}
- }
-}
diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs
deleted file mode 100644
index 9552fe8ca..000000000
--- a/SocketHttpListener.Portable/Net/ResponseStream.cs
+++ /dev/null
@@ -1,453 +0,0 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Text;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net
-{
- // FIXME: Does this buffer the response until Close?
- // Update: we send a single packet for the first non-chunked Write
- // What happens when we set content-length to X and write X-1 bytes then close?
- // what if we don't set content-length at all?
- public class ResponseStream : Stream
- {
- HttpListenerResponse response;
- bool disposed;
- bool trailer_sent;
- Stream stream;
- private readonly IMemoryStreamFactory _memoryStreamFactory;
- private readonly ITextEncoding _textEncoding;
- private readonly IFileSystem _fileSystem;
- private readonly IAcceptSocket _socket;
- private readonly bool _supportsDirectSocketAccess;
- private readonly ILogger _logger;
- private readonly IEnvironmentInfo _environment;
-
- internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger, IEnvironmentInfo environment)
- {
- this.response = response;
- _memoryStreamFactory = memoryStreamFactory;
- _textEncoding = textEncoding;
- _fileSystem = fileSystem;
- _socket = socket;
- _supportsDirectSocketAccess = supportsDirectSocketAccess;
- _logger = logger;
- _environment = environment;
- this.stream = stream;
- }
-
- public override bool CanRead
- {
- get { return false; }
- }
-
- public override bool CanSeek
- {
- get { return false; }
- }
-
- public override bool CanWrite
- {
- get { return true; }
- }
-
- public override long Length
- {
- get { throw new NotSupportedException(); }
- }
-
- public override long Position
- {
- get { throw new NotSupportedException(); }
- set { throw new NotSupportedException(); }
- }
-
-
- protected override void Dispose(bool disposing)
- {
- if (disposed == false)
- {
- disposed = true;
- byte[] bytes = null;
- MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
- bool chunked = response.SendChunked;
- if (stream.CanWrite)
- {
- try
- {
- if (ms != null)
- {
- long start = ms.Position;
- if (chunked && !trailer_sent)
- {
- bytes = GetChunkSizeBytes(0, true);
- ms.Position = ms.Length;
- ms.Write(bytes, 0, bytes.Length);
- }
- byte[] msBuffer;
- _memoryStreamFactory.TryGetBuffer(ms, out msBuffer);
- InternalWrite(msBuffer, (int)start, (int)(ms.Length - start));
- trailer_sent = true;
- }
- else if (chunked && !trailer_sent)
- {
- bytes = GetChunkSizeBytes(0, true);
- InternalWrite(bytes, 0, bytes.Length);
- trailer_sent = true;
- }
- }
- catch (IOException ex)
- {
- // Ignore error due to connection reset by peer
- }
- }
- response.Close();
- }
-
- base.Dispose(disposing);
- }
-
- internal static MemoryStream GetHeaders(HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, bool closing)
- {
- // SendHeaders works on shared headers
- lock (response.headers_lock)
- {
- if (response.HeadersSent)
- return null;
- MemoryStream ms = memoryStreamFactory.CreateNew();
- response.SendHeaders(closing, ms);
- return ms;
- }
- }
-
- public override void Flush()
- {
- }
-
- static byte[] crlf = new byte[] { 13, 10 };
- byte[] GetChunkSizeBytes(int size, bool final)
- {
- string str = String.Format("{0:x}\r\n{1}", size, final ? "\r\n" : "");
- return _textEncoding.GetASCIIEncoding().GetBytes(str);
- }
-
- internal void InternalWrite(byte[] buffer, int offset, int count)
- {
- stream.Write(buffer, offset, count);
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (count == 0)
- {
- //return;
- }
-
- byte[] bytes = null;
- MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
- bool chunked = response.SendChunked;
- if (ms != null)
- {
- long start = ms.Position; // After the possible preamble for the encoding
- ms.Position = ms.Length;
- if (chunked)
- {
- bytes = GetChunkSizeBytes(count, false);
- ms.Write(bytes, 0, bytes.Length);
- }
-
- int new_count = Math.Min(count, 16384 - (int)ms.Position + (int)start);
- ms.Write(buffer, offset, new_count);
- count -= new_count;
- offset += new_count;
- byte[] msBuffer;
- _memoryStreamFactory.TryGetBuffer(ms, out msBuffer);
- InternalWrite(msBuffer, (int)start, (int)(ms.Length - start));
- ms.SetLength(0);
- ms.Capacity = 0; // 'dispose' the buffer in ms.
- }
- else if (chunked)
- {
- bytes = GetChunkSizeBytes(count, false);
- InternalWrite(bytes, 0, bytes.Length);
- }
-
- if (count > 0)
- InternalWrite(buffer, offset, count);
- if (chunked)
- InternalWrite(crlf, 0, 2);
- }
-
- public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- if (disposed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (count == 0)
- {
- //return;
- }
-
- byte[] bytes = null;
- MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
- bool chunked = response.SendChunked;
- if (ms != null)
- {
- long start = ms.Position;
- ms.Position = ms.Length;
- if (chunked)
- {
- bytes = GetChunkSizeBytes(count, false);
- ms.Write(bytes, 0, bytes.Length);
- }
- ms.Write(buffer, offset, count);
- byte[] msBuffer;
- _memoryStreamFactory.TryGetBuffer(ms, out msBuffer);
- buffer = msBuffer;
- offset = (int)start;
- count = (int)(ms.Position - start);
- }
- else if (chunked)
- {
- bytes = GetChunkSizeBytes(count, false);
- InternalWrite(bytes, 0, bytes.Length);
- }
-
- if (count > 0)
- {
- await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
- }
-
- if (chunked)
- stream.Write(crlf, 0, 2);
- }
-
- //public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
- // AsyncCallback cback, object state)
- //{
- // if (disposed)
- // throw new ObjectDisposedException(GetType().ToString());
-
- // byte[] bytes = null;
- // MemoryStream ms = GetHeaders(false);
- // bool chunked = response.SendChunked;
- // if (ms != null)
- // {
- // long start = ms.Position;
- // ms.Position = ms.Length;
- // if (chunked)
- // {
- // bytes = GetChunkSizeBytes(count, false);
- // ms.Write(bytes, 0, bytes.Length);
- // }
- // ms.Write(buffer, offset, count);
- // buffer = ms.ToArray();
- // offset = (int)start;
- // count = (int)(ms.Position - start);
- // }
- // else if (chunked)
- // {
- // bytes = GetChunkSizeBytes(count, false);
- // InternalWrite(bytes, 0, bytes.Length);
- // }
-
- // return stream.BeginWrite(buffer, offset, count, cback, state);
- //}
-
- //public override void EndWrite(IAsyncResult ares)
- //{
- // if (disposed)
- // throw new ObjectDisposedException(GetType().ToString());
-
- // if (ignore_errors)
- // {
- // try
- // {
- // stream.EndWrite(ares);
- // if (response.SendChunked)
- // stream.Write(crlf, 0, 2);
- // }
- // catch { }
- // }
- // else {
- // stream.EndWrite(ares);
- // if (response.SendChunked)
- // stream.Write(crlf, 0, 2);
- // }
- //}
-
- public override int Read([In, Out] byte[] buffer, int offset, int count)
- {
- throw new NotSupportedException();
- }
-
- //public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
- // AsyncCallback cback, object state)
- //{
- // throw new NotSupportedException();
- //}
-
- //public override int EndRead(IAsyncResult ares)
- //{
- // throw new NotSupportedException();
- //}
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotSupportedException();
- }
-
- public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked && response.ContentLength64 > 8192)
- //{
- // return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken);
- //}
- return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
- }
-
- private readonly byte[] _emptyBuffer = new byte[] { };
- private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
-
- byte[] buffer;
- if (ms != null)
- {
- using (var msCopy = new MemoryStream())
- {
- ms.CopyTo(msCopy);
- buffer = msCopy.ToArray();
- }
- }
- else
- {
- return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
- }
-
- _logger.Info("Socket sending file {0} {1}", path, response.ContentLength64);
- return _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken);
- }
-
- private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- var allowAsync = _environment.OperatingSystem != OperatingSystem.Windows;
-
- var fileOpenOptions = offset > 0
- ? FileOpenOptions.RandomAccess
- : FileOpenOptions.SequentialScan;
-
- if (allowAsync)
- {
- fileOpenOptions |= FileOpenOptions.Asynchronous;
- }
-
- // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
-
- using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
- {
- if (offset > 0)
- {
- fs.Position = offset;
- }
-
- var targetStream = this;
-
- if (count > 0)
- {
- if (allowAsync)
- {
- await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
- }
- }
- else
- {
- if (allowAsync)
- {
- await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- fs.CopyTo(targetStream, 81920);
- }
- }
- }
- }
-
- private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
- {
- var array = new byte[81920];
- int bytesRead;
-
- while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
- {
- if (bytesRead == 0)
- {
- break;
- }
-
- var bytesToWrite = Math.Min(bytesRead, copyLength);
-
- if (bytesToWrite > 0)
- {
- await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
- }
-
- copyLength -= bytesToWrite;
-
- if (copyLength <= 0)
- {
- break;
- }
- }
- }
-
- private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
- {
- var array = new byte[81920];
- int bytesRead;
-
- while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
- {
- if (bytesRead == 0)
- {
- break;
- }
-
- var bytesToWrite = Math.Min(bytesRead, copyLength);
-
- if (bytesToWrite > 0)
- {
- await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
- }
-
- copyLength -= bytesToWrite;
-
- if (copyLength <= 0)
- {
- break;
- }
- }
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/WebHeaderCollection.cs b/SocketHttpListener.Portable/Net/WebHeaderCollection.cs
deleted file mode 100644
index d20f99b9b..000000000
--- a/SocketHttpListener.Portable/Net/WebHeaderCollection.cs
+++ /dev/null
@@ -1,391 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Net;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
-using System.Text;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener.Net
-{
- [ComVisible(true)]
- public class WebHeaderCollection : QueryParamCollection
- {
- [Flags]
- internal enum HeaderInfo
- {
- Request = 1,
- Response = 1 << 1,
- MultiValue = 1 << 10
- }
-
- static readonly bool[] allowed_chars = {
- false, false, false, false, false, false, false, false, false, false, false, false, false, false,
- false, false, false, false, false, false, false, false, false, false, false, false, false, false,
- false, false, false, false, false, true, false, true, true, true, true, false, false, false, true,
- true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, false,
- false, false, false, false, false, false, true, true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
- false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
- false, true, false
- };
-
- static readonly Dictionary<string, HeaderInfo> headers;
- HeaderInfo? headerRestriction;
- HeaderInfo? headerConsistency;
-
- static WebHeaderCollection()
- {
- headers = new Dictionary<string, HeaderInfo>(StringComparer.OrdinalIgnoreCase) {
- { "Allow", HeaderInfo.MultiValue },
- { "Accept", HeaderInfo.Request | HeaderInfo.MultiValue },
- { "Accept-Charset", HeaderInfo.MultiValue },
- { "Accept-Encoding", HeaderInfo.MultiValue },
- { "Accept-Language", HeaderInfo.MultiValue },
- { "Accept-Ranges", HeaderInfo.MultiValue },
- { "Age", HeaderInfo.Response },
- { "Authorization", HeaderInfo.MultiValue },
- { "Cache-Control", HeaderInfo.MultiValue },
- { "Cookie", HeaderInfo.MultiValue },
- { "Connection", HeaderInfo.Request | HeaderInfo.MultiValue },
- { "Content-Encoding", HeaderInfo.MultiValue },
- { "Content-Length", HeaderInfo.Request | HeaderInfo.Response },
- { "Content-Type", HeaderInfo.Request },
- { "Content-Language", HeaderInfo.MultiValue },
- { "Date", HeaderInfo.Request },
- { "Expect", HeaderInfo.Request | HeaderInfo.MultiValue},
- { "Host", HeaderInfo.Request },
- { "If-Match", HeaderInfo.MultiValue },
- { "If-Modified-Since", HeaderInfo.Request },
- { "If-None-Match", HeaderInfo.MultiValue },
- { "Keep-Alive", HeaderInfo.Response },
- { "Pragma", HeaderInfo.MultiValue },
- { "Proxy-Authenticate", HeaderInfo.MultiValue },
- { "Proxy-Authorization", HeaderInfo.MultiValue },
- { "Proxy-Connection", HeaderInfo.Request | HeaderInfo.MultiValue },
- { "Range", HeaderInfo.Request | HeaderInfo.MultiValue },
- { "Referer", HeaderInfo.Request },
- { "Set-Cookie", HeaderInfo.MultiValue },
- { "Set-Cookie2", HeaderInfo.MultiValue },
- { "Server", HeaderInfo.Response },
- { "TE", HeaderInfo.MultiValue },
- { "Trailer", HeaderInfo.MultiValue },
- { "Transfer-Encoding", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo.MultiValue },
- { "Translate", HeaderInfo.Request | HeaderInfo.Response },
- { "Upgrade", HeaderInfo.MultiValue },
- { "User-Agent", HeaderInfo.Request },
- { "Vary", HeaderInfo.MultiValue },
- { "Via", HeaderInfo.MultiValue },
- { "Warning", HeaderInfo.MultiValue },
- { "WWW-Authenticate", HeaderInfo.Response | HeaderInfo. MultiValue },
- { "SecWebSocketAccept", HeaderInfo.Response },
- { "SecWebSocketExtensions", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo. MultiValue },
- { "SecWebSocketKey", HeaderInfo.Request },
- { "Sec-WebSocket-Protocol", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo. MultiValue },
- { "SecWebSocketVersion", HeaderInfo.Response | HeaderInfo. MultiValue }
- };
- }
-
- // Methods
-
- public void Add(string header)
- {
- if (header == null)
- throw new ArgumentNullException("header");
- int pos = header.IndexOf(':');
- if (pos == -1)
- throw new ArgumentException("no colon found", "header");
-
- this.Add(header.Substring(0, pos), header.Substring(pos + 1));
- }
-
- public override void Add(string name, string value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
-
- ThrowIfRestricted(name);
- this.AddWithoutValidate(name, value);
- }
-
- protected void AddWithoutValidate(string headerName, string headerValue)
- {
- if (!IsHeaderName(headerName))
- throw new ArgumentException("invalid header name: " + headerName, "headerName");
- if (headerValue == null)
- headerValue = String.Empty;
- else
- headerValue = headerValue.Trim();
- if (!IsHeaderValue(headerValue))
- throw new ArgumentException("invalid header value: " + headerValue, "headerValue");
-
- AddValue(headerName, headerValue);
- }
-
- internal void AddValue(string headerName, string headerValue)
- {
- base.Add(headerName, headerValue);
- }
-
- internal string[] GetValues_internal(string header, bool split)
- {
- if (header == null)
- throw new ArgumentNullException("header");
-
- string[] values = base.GetValues(header);
- if (values == null || values.Length == 0)
- return null;
-
- if (split && IsMultiValue(header))
- {
- List<string> separated = null;
- foreach (var value in values)
- {
- if (value.IndexOf(',') < 0)
- {
- if (separated != null)
- separated.Add(value);
-
- continue;
- }
-
- if (separated == null)
- {
- separated = new List<string>(values.Length + 1);
- foreach (var v in values)
- {
- if (v == value)
- break;
-
- separated.Add(v);
- }
- }
-
- var slices = value.Split(',');
- var slices_length = slices.Length;
- if (value[value.Length - 1] == ',')
- --slices_length;
-
- for (int i = 0; i < slices_length; ++i)
- {
- separated.Add(slices[i].Trim());
- }
- }
-
- if (separated != null)
- return separated.ToArray();
- }
-
- return values;
- }
-
- public override string[] GetValues(string header)
- {
- return GetValues_internal(header, true);
- }
-
- public override string[] GetValues(int index)
- {
- string[] values = base.GetValues(index);
-
- if (values == null || values.Length == 0)
- {
- return null;
- }
-
- return values;
- }
-
- public static bool IsRestricted(string headerName)
- {
- return IsRestricted(headerName, false);
- }
-
- public static bool IsRestricted(string headerName, bool response)
- {
- if (headerName == null)
- throw new ArgumentNullException("headerName");
-
- if (headerName.Length == 0)
- throw new ArgumentException("empty string", "headerName");
-
- if (!IsHeaderName(headerName))
- throw new ArgumentException("Invalid character in header");
-
- HeaderInfo info;
- if (!headers.TryGetValue(headerName, out info))
- return false;
-
- var flag = response ? HeaderInfo.Response : HeaderInfo.Request;
- return (info & flag) != 0;
- }
-
- public override void Set(string name, string value)
- {
- if (name == null)
- throw new ArgumentNullException("name");
- if (!IsHeaderName(name))
- throw new ArgumentException("invalid header name");
- if (value == null)
- value = String.Empty;
- else
- value = value.Trim();
- if (!IsHeaderValue(value))
- throw new ArgumentException("invalid header value");
-
- ThrowIfRestricted(name);
- base.Set(name, value);
- }
-
- internal string ToStringMultiValue()
- {
- StringBuilder sb = new StringBuilder();
-
- int count = base.Count;
- for (int i = 0; i < count; i++)
- {
- string key = GetKey(i);
- if (IsMultiValue(key))
- {
- foreach (string v in GetValues(i))
- {
- sb.Append(key)
- .Append(": ")
- .Append(v)
- .Append("\r\n");
- }
- }
- else
- {
- sb.Append(key)
- .Append(": ")
- .Append(Get(i))
- .Append("\r\n");
- }
- }
- return sb.Append("\r\n").ToString();
- }
-
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder();
-
- int count = base.Count;
- for (int i = 0; i < count; i++)
- sb.Append(GetKey(i))
- .Append(": ")
- .Append(Get(i))
- .Append("\r\n");
-
- return sb.Append("\r\n").ToString();
- }
-
-
- // Internal Methods
-
- // With this we don't check for invalid characters in header. See bug #55994.
- internal void SetInternal(string header)
- {
- int pos = header.IndexOf(':');
- if (pos == -1)
- throw new ArgumentException("no colon found", "header");
-
- SetInternal(header.Substring(0, pos), header.Substring(pos + 1));
- }
-
- internal void SetInternal(string name, string value)
- {
- if (value == null)
- value = String.Empty;
- else
- value = value.Trim();
- if (!IsHeaderValue(value))
- throw new ArgumentException("invalid header value");
-
- if (IsMultiValue(name))
- {
- base.Add(name, value);
- }
- else
- {
- base.Remove(name);
- base.Set(name, value);
- }
- }
-
- // Private Methods
-
- public override int Remove(string name)
- {
- ThrowIfRestricted(name);
- return base.Remove(name);
- }
-
- protected void ThrowIfRestricted(string headerName)
- {
- if (!headerRestriction.HasValue)
- return;
-
- HeaderInfo info;
- if (!headers.TryGetValue(headerName, out info))
- return;
-
- if ((info & headerRestriction.Value) != 0)
- throw new ArgumentException("This header must be modified with the appropriate property.");
- }
-
- internal static bool IsMultiValue(string headerName)
- {
- if (headerName == null)
- return false;
-
- HeaderInfo info;
- return headers.TryGetValue(headerName, out info) && (info & HeaderInfo.MultiValue) != 0;
- }
-
- internal static bool IsHeaderValue(string value)
- {
- // TEXT any 8 bit value except CTL's (0-31 and 127)
- // but including \r\n space and \t
- // after a newline at least one space or \t must follow
- // certain header fields allow comments ()
-
- int len = value.Length;
- for (int i = 0; i < len; i++)
- {
- char c = value[i];
- if (c == 127)
- return false;
- if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
- return false;
- if (c == '\n' && ++i < len)
- {
- c = value[i];
- if (c != ' ' && c != '\t')
- return false;
- }
- }
-
- return true;
- }
-
- internal static bool IsHeaderName(string name)
- {
- if (name == null || name.Length == 0)
- return false;
-
- int len = name.Length;
- for (int i = 0; i < len; i++)
- {
- char c = name[i];
- if (c > 126 || !allowed_chars[c])
- return false;
- }
-
- return true;
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs
deleted file mode 100644
index 034ac17d2..000000000
--- a/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs
+++ /dev/null
@@ -1,348 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.Net;
-using System.Security.Principal;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Services;
-using SocketHttpListener.Primitives;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- /// <summary>
- /// Provides the properties used to access the information in a WebSocket connection request
- /// received by the <see cref="HttpListener"/>.
- /// </summary>
- /// <remarks>
- /// </remarks>
- public class HttpListenerWebSocketContext : WebSocketContext
- {
- #region Private Fields
-
- private HttpListenerContext _context;
- private WebSocket _websocket;
-
- #endregion
-
- #region Internal Constructors
-
- internal HttpListenerWebSocketContext(
- HttpListenerContext context, string protocol, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory)
- {
- _context = context;
- _websocket = new WebSocket(this, protocol, cryptoProvider, memoryStreamFactory);
- }
-
- #endregion
-
- #region Internal Properties
-
- internal Stream Stream
- {
- get
- {
- return _context.Connection.Stream;
- }
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the HTTP cookies included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="System.Net.CookieCollection"/> that contains the cookies.
- /// </value>
- public override CookieCollection CookieCollection
- {
- get
- {
- return _context.Request.Cookies;
- }
- }
-
- /// <summary>
- /// Gets the HTTP headers included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="QueryParamCollection"/> that contains the headers.
- /// </value>
- public override QueryParamCollection Headers
- {
- get
- {
- return _context.Request.Headers;
- }
- }
-
- /// <summary>
- /// Gets the value of the Host header included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Host header.
- /// </value>
- public override string Host
- {
- get
- {
- return _context.Request.Headers["Host"];
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether the client is authenticated.
- /// </summary>
- /// <value>
- /// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
- /// </value>
- public override bool IsAuthenticated
- {
- get
- {
- return _context.Request.IsAuthenticated;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether the client connected from the local computer.
- /// </summary>
- /// <value>
- /// <c>true</c> if the client connected from the local computer; otherwise, <c>false</c>.
- /// </value>
- public override bool IsLocal
- {
- get
- {
- return _context.Request.IsLocal;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether the WebSocket connection is secured.
- /// </summary>
- /// <value>
- /// <c>true</c> if the connection is secured; otherwise, <c>false</c>.
- /// </value>
- public override bool IsSecureConnection
- {
- get
- {
- return _context.Connection.IsSecure;
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether the request is a WebSocket connection request.
- /// </summary>
- /// <value>
- /// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
- /// </value>
- public override bool IsWebSocketRequest
- {
- get
- {
- return _context.Request.IsWebSocketRequest;
- }
- }
-
- /// <summary>
- /// Gets the value of the Origin header included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Origin header.
- /// </value>
- public override string Origin
- {
- get
- {
- return _context.Request.Headers["Origin"];
- }
- }
-
- /// <summary>
- /// Gets the query string included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="QueryParamCollection"/> that contains the query string parameters.
- /// </value>
- public override QueryParamCollection QueryString
- {
- get
- {
- return _context.Request.QueryString;
- }
- }
-
- /// <summary>
- /// Gets the URI requested by the client.
- /// </summary>
- /// <value>
- /// A <see cref="Uri"/> that represents the requested URI.
- /// </value>
- public override Uri RequestUri
- {
- get
- {
- return _context.Request.Url;
- }
- }
-
- /// <summary>
- /// Gets the value of the Sec-WebSocket-Key header included in the request.
- /// </summary>
- /// <remarks>
- /// This property provides a part of the information used by the server to prove that it
- /// received a valid WebSocket connection request.
- /// </remarks>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Sec-WebSocket-Key header.
- /// </value>
- public override string SecWebSocketKey
- {
- get
- {
- return _context.Request.Headers["Sec-WebSocket-Key"];
- }
- }
-
- /// <summary>
- /// Gets the values of the Sec-WebSocket-Protocol header included in the request.
- /// </summary>
- /// <remarks>
- /// This property represents the subprotocols requested by the client.
- /// </remarks>
- /// <value>
- /// An <see cref="T:System.Collections.Generic.IEnumerable{string}"/> instance that provides
- /// an enumerator which supports the iteration over the values of the Sec-WebSocket-Protocol
- /// header.
- /// </value>
- public override IEnumerable<string> SecWebSocketProtocols
- {
- get
- {
- var protocols = _context.Request.Headers["Sec-WebSocket-Protocol"];
- if (protocols != null)
- foreach (var protocol in protocols.Split(','))
- yield return protocol.Trim();
- }
- }
-
- /// <summary>
- /// Gets the value of the Sec-WebSocket-Version header included in the request.
- /// </summary>
- /// <remarks>
- /// This property represents the WebSocket protocol version.
- /// </remarks>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Sec-WebSocket-Version header.
- /// </value>
- public override string SecWebSocketVersion
- {
- get
- {
- return _context.Request.Headers["Sec-WebSocket-Version"];
- }
- }
-
- /// <summary>
- /// Gets the server endpoint as an IP address and a port number.
- /// </summary>
- /// <value>
- /// </value>
- public override IpEndPointInfo ServerEndPoint
- {
- get
- {
- return _context.Connection.LocalEndPoint;
- }
- }
-
- /// <summary>
- /// Gets the client information (identity, authentication, and security roles).
- /// </summary>
- /// <value>
- /// A <see cref="IPrincipal"/> that represents the client information.
- /// </value>
- public override IPrincipal User
- {
- get
- {
- return _context.User;
- }
- }
-
- /// <summary>
- /// Gets the client endpoint as an IP address and a port number.
- /// </summary>
- /// <value>
- /// </value>
- public override IpEndPointInfo UserEndPoint
- {
- get
- {
- return _context.Connection.RemoteEndPoint;
- }
- }
-
- /// <summary>
- /// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication
- /// between client and server.
- /// </summary>
- /// <value>
- /// A <see cref="SocketHttpListener.WebSocket"/>.
- /// </value>
- public override WebSocket WebSocket
- {
- get
- {
- return _websocket;
- }
- }
-
- #endregion
-
- #region Internal Methods
-
- internal void Close()
- {
- try
- {
- _context.Connection.Close(true);
- }
- catch
- {
- // catch errors sending the closing handshake
- }
- }
-
- internal void Close(HttpStatusCode code)
- {
- _context.Response.StatusCode = (int)code;
- _context.Response.OutputStream.Dispose();
- }
-
- #endregion
-
- #region Public Methods
-
- /// <summary>
- /// Returns a <see cref="string"/> that represents the current
- /// <see cref="HttpListenerWebSocketContext"/>.
- /// </summary>
- /// <returns>
- /// A <see cref="string"/> that represents the current
- /// <see cref="HttpListenerWebSocketContext"/>.
- /// </returns>
- public override string ToString()
- {
- return _context.Request.ToString();
- }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/Net/WebSockets/WebSocketContext.cs b/SocketHttpListener.Portable/Net/WebSockets/WebSocketContext.cs
deleted file mode 100644
index 3ffa6e639..000000000
--- a/SocketHttpListener.Portable/Net/WebSockets/WebSocketContext.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Net;
-using System.Security.Principal;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- /// <summary>
- /// Exposes the properties used to access the information in a WebSocket connection request.
- /// </summary>
- /// <remarks>
- /// The WebSocketContext class is an abstract class.
- /// </remarks>
- public abstract class WebSocketContext
- {
- #region Protected Constructors
-
- /// <summary>
- /// Initializes a new instance of the <see cref="WebSocketContext"/> class.
- /// </summary>
- protected WebSocketContext()
- {
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the HTTP cookies included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="System.Net.CookieCollection"/> that contains the cookies.
- /// </value>
- public abstract CookieCollection CookieCollection { get; }
-
- /// <summary>
- /// Gets the HTTP headers included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="QueryParamCollection"/> that contains the headers.
- /// </value>
- public abstract QueryParamCollection Headers { get; }
-
- /// <summary>
- /// Gets the value of the Host header included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Host header.
- /// </value>
- public abstract string Host { get; }
-
- /// <summary>
- /// Gets a value indicating whether the client is authenticated.
- /// </summary>
- /// <value>
- /// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
- /// </value>
- public abstract bool IsAuthenticated { get; }
-
- /// <summary>
- /// Gets a value indicating whether the client connected from the local computer.
- /// </summary>
- /// <value>
- /// <c>true</c> if the client connected from the local computer; otherwise, <c>false</c>.
- /// </value>
- public abstract bool IsLocal { get; }
-
- /// <summary>
- /// Gets a value indicating whether the WebSocket connection is secured.
- /// </summary>
- /// <value>
- /// <c>true</c> if the connection is secured; otherwise, <c>false</c>.
- /// </value>
- public abstract bool IsSecureConnection { get; }
-
- /// <summary>
- /// Gets a value indicating whether the request is a WebSocket connection request.
- /// </summary>
- /// <value>
- /// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
- /// </value>
- public abstract bool IsWebSocketRequest { get; }
-
- /// <summary>
- /// Gets the value of the Origin header included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Origin header.
- /// </value>
- public abstract string Origin { get; }
-
- /// <summary>
- /// Gets the query string included in the request.
- /// </summary>
- /// <value>
- /// A <see cref="QueryParamCollection"/> that contains the query string parameters.
- /// </value>
- public abstract QueryParamCollection QueryString { get; }
-
- /// <summary>
- /// Gets the URI requested by the client.
- /// </summary>
- /// <value>
- /// A <see cref="Uri"/> that represents the requested URI.
- /// </value>
- public abstract Uri RequestUri { get; }
-
- /// <summary>
- /// Gets the value of the Sec-WebSocket-Key header included in the request.
- /// </summary>
- /// <remarks>
- /// This property provides a part of the information used by the server to prove that it
- /// received a valid WebSocket connection request.
- /// </remarks>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Sec-WebSocket-Key header.
- /// </value>
- public abstract string SecWebSocketKey { get; }
-
- /// <summary>
- /// Gets the values of the Sec-WebSocket-Protocol header included in the request.
- /// </summary>
- /// <remarks>
- /// This property represents the subprotocols requested by the client.
- /// </remarks>
- /// <value>
- /// An <see cref="T:System.Collections.Generic.IEnumerable{string}"/> instance that provides
- /// an enumerator which supports the iteration over the values of the Sec-WebSocket-Protocol
- /// header.
- /// </value>
- public abstract IEnumerable<string> SecWebSocketProtocols { get; }
-
- /// <summary>
- /// Gets the value of the Sec-WebSocket-Version header included in the request.
- /// </summary>
- /// <remarks>
- /// This property represents the WebSocket protocol version.
- /// </remarks>
- /// <value>
- /// A <see cref="string"/> that represents the value of the Sec-WebSocket-Version header.
- /// </value>
- public abstract string SecWebSocketVersion { get; }
-
- /// <summary>
- /// Gets the server endpoint as an IP address and a port number.
- /// </summary>
- /// <value>
- /// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint.
- /// </value>
- public abstract IpEndPointInfo ServerEndPoint { get; }
-
- /// <summary>
- /// Gets the client information (identity, authentication, and security roles).
- /// </summary>
- /// <value>
- /// A <see cref="IPrincipal"/> that represents the client information.
- /// </value>
- public abstract IPrincipal User { get; }
-
- /// <summary>
- /// Gets the client endpoint as an IP address and a port number.
- /// </summary>
- /// <value>
- /// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint.
- /// </value>
- public abstract IpEndPointInfo UserEndPoint { get; }
-
- /// <summary>
- /// Gets the <see cref="SocketHttpListener.WebSocket"/> instance used for two-way communication
- /// between client and server.
- /// </summary>
- /// <value>
- /// A <see cref="SocketHttpListener.WebSocket"/>.
- /// </value>
- public abstract WebSocket WebSocket { get; }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/Opcode.cs b/SocketHttpListener.Portable/Opcode.cs
deleted file mode 100644
index 62b7d8585..000000000
--- a/SocketHttpListener.Portable/Opcode.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the values of the opcode that indicates the type of a WebSocket frame.
- /// </summary>
- /// <remarks>
- /// The values of the opcode are defined in
- /// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2</see> of RFC 6455.
- /// </remarks>
- public enum Opcode : byte
- {
- /// <summary>
- /// Equivalent to numeric value 0.
- /// Indicates a continuation frame.
- /// </summary>
- Cont = 0x0,
- /// <summary>
- /// Equivalent to numeric value 1.
- /// Indicates a text frame.
- /// </summary>
- Text = 0x1,
- /// <summary>
- /// Equivalent to numeric value 2.
- /// Indicates a binary frame.
- /// </summary>
- Binary = 0x2,
- /// <summary>
- /// Equivalent to numeric value 8.
- /// Indicates a connection close frame.
- /// </summary>
- Close = 0x8,
- /// <summary>
- /// Equivalent to numeric value 9.
- /// Indicates a ping frame.
- /// </summary>
- Ping = 0x9,
- /// <summary>
- /// Equivalent to numeric value 10.
- /// Indicates a pong frame.
- /// </summary>
- Pong = 0xa
- }
-}
diff --git a/SocketHttpListener.Portable/PayloadData.cs b/SocketHttpListener.Portable/PayloadData.cs
deleted file mode 100644
index a6318da2b..000000000
--- a/SocketHttpListener.Portable/PayloadData.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
-
-namespace SocketHttpListener
-{
- internal class PayloadData : IEnumerable<byte>
- {
- #region Private Fields
-
- private byte [] _applicationData;
- private byte [] _extensionData;
- private bool _masked;
-
- #endregion
-
- #region Public Const Fields
-
- public const ulong MaxLength = long.MaxValue;
-
- #endregion
-
- #region Public Constructors
-
- public PayloadData ()
- : this (new byte [0], new byte [0], false)
- {
- }
-
- public PayloadData (byte [] applicationData)
- : this (new byte [0], applicationData, false)
- {
- }
-
- public PayloadData (string applicationData)
- : this (new byte [0], Encoding.UTF8.GetBytes (applicationData), false)
- {
- }
-
- public PayloadData (byte [] applicationData, bool masked)
- : this (new byte [0], applicationData, masked)
- {
- }
-
- public PayloadData (byte [] extensionData, byte [] applicationData, bool masked)
- {
- _extensionData = extensionData;
- _applicationData = applicationData;
- _masked = masked;
- }
-
- #endregion
-
- #region Internal Properties
-
- internal bool ContainsReservedCloseStatusCode {
- get {
- return _applicationData.Length > 1 &&
- _applicationData.SubArray (0, 2).ToUInt16 (ByteOrder.Big).IsReserved ();
- }
- }
-
- #endregion
-
- #region Public Properties
-
- public byte [] ApplicationData {
- get {
- return _applicationData;
- }
- }
-
- public byte [] ExtensionData {
- get {
- return _extensionData;
- }
- }
-
- public bool IsMasked {
- get {
- return _masked;
- }
- }
-
- public ulong Length {
- get {
- return (ulong) (_extensionData.Length + _applicationData.Length);
- }
- }
-
- #endregion
-
- #region Private Methods
-
- private static void mask (byte [] src, byte [] key)
- {
- for (long i = 0; i < src.Length; i++)
- src [i] = (byte) (src [i] ^ key [i % 4]);
- }
-
- #endregion
-
- #region Public Methods
-
- public IEnumerator<byte> GetEnumerator ()
- {
- foreach (byte b in _extensionData)
- yield return b;
-
- foreach (byte b in _applicationData)
- yield return b;
- }
-
- public void Mask (byte [] maskingKey)
- {
- if (_extensionData.Length > 0)
- mask (_extensionData, maskingKey);
-
- if (_applicationData.Length > 0)
- mask (_applicationData, maskingKey);
-
- _masked = !_masked;
- }
-
- public byte [] ToByteArray ()
- {
- return _extensionData.Length > 0
- ? new List<byte> (this).ToArray ()
- : _applicationData;
- }
-
- public override string ToString ()
- {
- return BitConverter.ToString (ToByteArray ());
- }
-
- #endregion
-
- #region Explicitly Implemented Interface Members
-
- IEnumerator IEnumerable.GetEnumerator ()
- {
- return GetEnumerator ();
- }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/Primitives/HttpListenerException.cs b/SocketHttpListener.Portable/Primitives/HttpListenerException.cs
deleted file mode 100644
index 7b383fd23..000000000
--- a/SocketHttpListener.Portable/Primitives/HttpListenerException.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Primitives
-{
- public class HttpListenerException : Exception
- {
- public HttpListenerException(int statusCode, string message)
- : base(message)
- {
-
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Primitives/ICertificate.cs b/SocketHttpListener.Portable/Primitives/ICertificate.cs
deleted file mode 100644
index 1289da13d..000000000
--- a/SocketHttpListener.Portable/Primitives/ICertificate.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Primitives
-{
- public interface ICertificate
- {
- }
-}
diff --git a/SocketHttpListener.Portable/Primitives/IStreamFactory.cs b/SocketHttpListener.Portable/Primitives/IStreamFactory.cs
deleted file mode 100644
index 57e21e31b..000000000
--- a/SocketHttpListener.Portable/Primitives/IStreamFactory.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
-
-namespace SocketHttpListener.Primitives
-{
- public interface IStreamFactory
- {
- Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket);
- Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen);
-
- Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate);
- }
-}
diff --git a/SocketHttpListener.Portable/Primitives/ITextEncoding.cs b/SocketHttpListener.Portable/Primitives/ITextEncoding.cs
deleted file mode 100644
index b10145687..000000000
--- a/SocketHttpListener.Portable/Primitives/ITextEncoding.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Text;
-
-namespace SocketHttpListener.Primitives
-{
- public static class TextEncodingExtensions
- {
- public static Encoding GetDefaultEncoding(this ITextEncoding encoding)
- {
- return Encoding.UTF8;
- }
- }
-}
diff --git a/SocketHttpListener.Portable/Properties/AssemblyInfo.cs b/SocketHttpListener.Portable/Properties/AssemblyInfo.cs
deleted file mode 100644
index 870426460..000000000
--- a/SocketHttpListener.Portable/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.Resources;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("SocketHttpListener.Portable")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("SocketHttpListener.Portable")]
-[assembly: AssemblyCopyright("Copyright © 2016")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: NeutralResourcesLanguage("en")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/SocketHttpListener.Portable/Rsv.cs b/SocketHttpListener.Portable/Rsv.cs
deleted file mode 100644
index 668059b8a..000000000
--- a/SocketHttpListener.Portable/Rsv.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace SocketHttpListener
-{
- internal enum Rsv : byte
- {
- Off = 0x0,
- On = 0x1
- }
-}
diff --git a/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj b/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj
deleted file mode 100644
index ee902462b..000000000
--- a/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
- <PropertyGroup>
- <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>SocketHttpListener.Portable</RootNamespace>
- <AssemblyName>SocketHttpListener.Portable</AssemblyName>
- <DefaultLanguage>en-US</DefaultLanguage>
- <FileAlignment>512</FileAlignment>
- <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
- <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
- <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Compile Include="ByteOrder.cs" />
- <Compile Include="CloseEventArgs.cs" />
- <Compile Include="CloseStatusCode.cs" />
- <Compile Include="CompressionMethod.cs" />
- <Compile Include="ErrorEventArgs.cs" />
- <Compile Include="Ext.cs" />
- <Compile Include="Fin.cs" />
- <Compile Include="HttpBase.cs" />
- <Compile Include="HttpResponse.cs" />
- <Compile Include="Mask.cs" />
- <Compile Include="MessageEventArgs.cs" />
- <Compile Include="Net\AuthenticationSchemeSelector.cs" />
- <Compile Include="Net\ChunkedInputStream.cs" />
- <Compile Include="Net\ChunkStream.cs" />
- <Compile Include="Net\CookieHelper.cs" />
- <Compile Include="Net\EndPointListener.cs" />
- <Compile Include="Net\EndPointManager.cs" />
- <Compile Include="Net\HttpConnection.cs" />
- <Compile Include="Net\HttpListener.cs" />
- <Compile Include="Net\HttpListenerBasicIdentity.cs" />
- <Compile Include="Net\HttpListenerContext.cs" />
- <Compile Include="Net\HttpListenerPrefixCollection.cs" />
- <Compile Include="Net\HttpListenerRequest.cs" />
- <Compile Include="Net\HttpListenerResponse.cs" />
- <Compile Include="Net\HttpStatusCode.cs" />
- <Compile Include="Net\HttpStreamAsyncResult.cs" />
- <Compile Include="Net\HttpVersion.cs" />
- <Compile Include="Net\ListenerPrefix.cs" />
- <Compile Include="Net\RequestStream.cs" />
- <Compile Include="Net\ResponseStream.cs" />
- <Compile Include="Net\WebHeaderCollection.cs" />
- <Compile Include="Net\WebSockets\HttpListenerWebSocketContext.cs" />
- <Compile Include="Net\WebSockets\WebSocketContext.cs" />
- <Compile Include="Opcode.cs" />
- <Compile Include="PayloadData.cs" />
- <Compile Include="Primitives\HttpListenerException.cs" />
- <Compile Include="Primitives\ICertificate.cs" />
- <Compile Include="Primitives\IStreamFactory.cs" />
- <Compile Include="Primitives\ITextEncoding.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Rsv.cs" />
- <Compile Include="WebSocket.cs" />
- <Compile Include="WebSocketException.cs" />
- <Compile Include="WebSocketFrame.cs" />
- <Compile Include="WebSocketState.cs" />
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
- <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
- <Name>MediaBrowser.Common</Name>
- </ProjectReference>
- <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
- <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
- <Name>MediaBrowser.Model</Name>
- </ProjectReference>
- </ItemGroup>
- <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
- <PropertyGroup>
- <PostBuildEvent>
- </PostBuildEvent>
- </PropertyGroup>
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
-</Project> \ No newline at end of file
diff --git a/SocketHttpListener.Portable/SocketHttpListener.Portable.nuget.targets b/SocketHttpListener.Portable/SocketHttpListener.Portable.nuget.targets
deleted file mode 100644
index e69ce0e64..000000000
--- a/SocketHttpListener.Portable/SocketHttpListener.Portable.nuget.targets
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
-<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Target Name="EmitMSBuildWarning" BeforeTargets="Build">
- <Warning Text="Packages containing MSBuild targets and props files cannot be fully installed in projects targeting multiple frameworks. The MSBuild targets and props files have been ignored." />
- </Target>
-</Project> \ No newline at end of file
diff --git a/SocketHttpListener.Portable/WebSocket.cs b/SocketHttpListener.Portable/WebSocket.cs
deleted file mode 100644
index 9966d3fcf..000000000
--- a/SocketHttpListener.Portable/WebSocket.cs
+++ /dev/null
@@ -1,887 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using SocketHttpListener.Net.WebSockets;
-using SocketHttpListener.Primitives;
-using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
-
-namespace SocketHttpListener
-{
- /// <summary>
- /// Implements the WebSocket interface.
- /// </summary>
- /// <remarks>
- /// The WebSocket class provides a set of methods and properties for two-way communication using
- /// the WebSocket protocol (<see href="http://tools.ietf.org/html/rfc6455">RFC 6455</see>).
- /// </remarks>
- public class WebSocket : IDisposable
- {
- #region Private Fields
-
- private string _base64Key;
- private Action _closeContext;
- private CompressionMethod _compression;
- private WebSocketContext _context;
- private CookieCollection _cookies;
- private string _extensions;
- private AutoResetEvent _exitReceiving;
- private object _forConn;
- private object _forEvent;
- private object _forMessageEventQueue;
- private object _forSend;
- private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- private Func<WebSocketContext, string>
- _handshakeRequestChecker;
- private Queue<MessageEventArgs> _messageEventQueue;
- private uint _nonceCount;
- private string _origin;
- private bool _preAuth;
- private string _protocol;
- private string[] _protocols;
- private Uri _proxyUri;
- private volatile WebSocketState _readyState;
- private AutoResetEvent _receivePong;
- private bool _secure;
- private Stream _stream;
- private Uri _uri;
- private const string _version = "13";
- private readonly IMemoryStreamFactory _memoryStreamFactory;
-
- private readonly ICryptoProvider _cryptoProvider;
-
- #endregion
-
- #region Internal Fields
-
- internal const int FragmentLength = 1016; // Max value is int.MaxValue - 14.
-
- #endregion
-
- #region Internal Constructors
-
- // As server
- internal WebSocket(HttpListenerWebSocketContext context, string protocol, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory)
- {
- _context = context;
- _protocol = protocol;
- _cryptoProvider = cryptoProvider;
- _memoryStreamFactory = memoryStreamFactory;
-
- _closeContext = context.Close;
- _secure = context.IsSecureConnection;
- _stream = context.Stream;
-
- init();
- }
-
- #endregion
-
- // As server
- internal Func<WebSocketContext, string> CustomHandshakeRequestChecker
- {
- get
- {
- return _handshakeRequestChecker ?? (context => null);
- }
-
- set
- {
- _handshakeRequestChecker = value;
- }
- }
-
- internal bool IsConnected
- {
- get
- {
- return _readyState == WebSocketState.Open || _readyState == WebSocketState.Closing;
- }
- }
-
- /// <summary>
- /// Gets the state of the WebSocket connection.
- /// </summary>
- /// <value>
- /// One of the <see cref="WebSocketState"/> enum values, indicates the state of the WebSocket
- /// connection. The default value is <see cref="WebSocketState.Connecting"/>.
- /// </value>
- public WebSocketState ReadyState
- {
- get
- {
- return _readyState;
- }
- }
-
- #region Public Events
-
- /// <summary>
- /// Occurs when the WebSocket connection has been closed.
- /// </summary>
- public event EventHandler<CloseEventArgs> OnClose;
-
- /// <summary>
- /// Occurs when the <see cref="WebSocket"/> gets an error.
- /// </summary>
- public event EventHandler<ErrorEventArgs> OnError;
-
- /// <summary>
- /// Occurs when the <see cref="WebSocket"/> receives a message.
- /// </summary>
- public event EventHandler<MessageEventArgs> OnMessage;
-
- /// <summary>
- /// Occurs when the WebSocket connection has been established.
- /// </summary>
- public event EventHandler OnOpen;
-
- #endregion
-
- #region Private Methods
-
- // As server
- private bool acceptHandshake()
- {
- var msg = checkIfValidHandshakeRequest(_context);
- if (msg != null)
- {
- error("An error has occurred while connecting: " + msg);
- Close(HttpStatusCode.BadRequest);
-
- return false;
- }
-
- if (_protocol != null &&
- !_context.SecWebSocketProtocols.Contains(protocol => protocol == _protocol))
- _protocol = null;
-
- ////var extensions = _context.Headers["Sec-WebSocket-Extensions"];
- ////if (extensions != null && extensions.Length > 0)
- //// processSecWebSocketExtensionsHeader(extensions);
-
- return sendHttpResponse(createHandshakeResponse());
- }
-
- // As server
- private string checkIfValidHandshakeRequest(WebSocketContext context)
- {
- var headers = context.Headers;
- return context.RequestUri == null
- ? "Invalid request url."
- : !context.IsWebSocketRequest
- ? "Not WebSocket connection request."
- : !validateSecWebSocketKeyHeader(headers["Sec-WebSocket-Key"])
- ? "Invalid Sec-WebSocket-Key header."
- : !validateSecWebSocketVersionClientHeader(headers["Sec-WebSocket-Version"])
- ? "Invalid Sec-WebSocket-Version header."
- : CustomHandshakeRequestChecker(context);
- }
-
- private void close(CloseStatusCode code, string reason, bool wait)
- {
- close(new PayloadData(((ushort)code).Append(reason)), !code.IsReserved(), wait);
- }
-
- private void close(PayloadData payload, bool send, bool wait)
- {
- lock (_forConn)
- {
- if (_readyState == WebSocketState.Closing || _readyState == WebSocketState.Closed)
- {
- return;
- }
-
- _readyState = WebSocketState.Closing;
- }
-
- var e = new CloseEventArgs(payload);
- e.WasClean =
- closeHandshake(
- send ? WebSocketFrame.CreateCloseFrame(Mask.Unmask, payload).ToByteArray() : null,
- wait ? 1000 : 0,
- closeServerResources);
-
- _readyState = WebSocketState.Closed;
- try
- {
- OnClose.Emit(this, e);
- }
- catch (Exception ex)
- {
- error("An exception has occurred while OnClose.", ex);
- }
- }
-
- private bool closeHandshake(byte[] frameAsBytes, int millisecondsTimeout, Action release)
- {
- var sent = frameAsBytes != null && writeBytes(frameAsBytes);
- var received =
- millisecondsTimeout == 0 ||
- (sent && _exitReceiving != null && _exitReceiving.WaitOne(millisecondsTimeout));
-
- release();
- if (_receivePong != null)
- {
- _receivePong.Dispose();
- _receivePong = null;
- }
-
- if (_exitReceiving != null)
- {
- _exitReceiving.Dispose();
- _exitReceiving = null;
- }
-
- var result = sent && received;
-
- return result;
- }
-
- // As server
- private void closeServerResources()
- {
- if (_closeContext == null)
- return;
-
- _closeContext();
- _closeContext = null;
- _stream = null;
- _context = null;
- }
-
- private bool concatenateFragmentsInto(Stream dest)
- {
- while (true)
- {
- var frame = WebSocketFrame.Read(_stream, true);
- if (frame.IsFinal)
- {
- /* FINAL */
-
- // CONT
- if (frame.IsContinuation)
- {
- dest.WriteBytes(frame.PayloadData.ApplicationData);
- break;
- }
-
- // PING
- if (frame.IsPing)
- {
- processPingFrame(frame);
- continue;
- }
-
- // PONG
- if (frame.IsPong)
- {
- processPongFrame(frame);
- continue;
- }
-
- // CLOSE
- if (frame.IsClose)
- return processCloseFrame(frame);
- }
- else
- {
- /* MORE */
-
- // CONT
- if (frame.IsContinuation)
- {
- dest.WriteBytes(frame.PayloadData.ApplicationData);
- continue;
- }
- }
-
- // ?
- return processUnsupportedFrame(
- frame,
- CloseStatusCode.IncorrectData,
- "An incorrect data has been received while receiving fragmented data.");
- }
-
- return true;
- }
-
- // As server
- private HttpResponse createHandshakeCloseResponse(HttpStatusCode code)
- {
- var res = HttpResponse.CreateCloseResponse(code);
- res.Headers["Sec-WebSocket-Version"] = _version;
-
- return res;
- }
-
- // As server
- private HttpResponse createHandshakeResponse()
- {
- var res = HttpResponse.CreateWebSocketResponse();
-
- var headers = res.Headers;
- headers["Sec-WebSocket-Accept"] = CreateResponseKey(_base64Key);
-
- if (_protocol != null)
- headers["Sec-WebSocket-Protocol"] = _protocol;
-
- if (_extensions != null)
- headers["Sec-WebSocket-Extensions"] = _extensions;
-
- if (_cookies.Count > 0)
- res.SetCookies(_cookies);
-
- return res;
- }
-
- private MessageEventArgs dequeueFromMessageEventQueue()
- {
- lock (_forMessageEventQueue)
- return _messageEventQueue.Count > 0
- ? _messageEventQueue.Dequeue()
- : null;
- }
-
- private void enqueueToMessageEventQueue(MessageEventArgs e)
- {
- lock (_forMessageEventQueue)
- _messageEventQueue.Enqueue(e);
- }
-
- private void error(string message, Exception exception)
- {
- try
- {
- if (exception != null)
- {
- message += ". Exception.Message: " + exception.Message;
- }
- OnError.Emit(this, new ErrorEventArgs(message));
- }
- catch (Exception ex)
- {
- }
- }
-
- private void error(string message)
- {
- try
- {
- OnError.Emit(this, new ErrorEventArgs(message));
- }
- catch (Exception ex)
- {
- }
- }
-
- private void init()
- {
- _compression = CompressionMethod.None;
- _cookies = new CookieCollection();
- _forConn = new object();
- _forEvent = new object();
- _forSend = new object();
- _messageEventQueue = new Queue<MessageEventArgs>();
- _forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot;
- _readyState = WebSocketState.Connecting;
- }
-
- private void open()
- {
- try
- {
- startReceiving();
-
- lock (_forEvent)
- {
- try
- {
- OnOpen.Emit(this, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- processException(ex, "An exception has occurred while OnOpen.");
- }
- }
- }
- catch (Exception ex)
- {
- processException(ex, "An exception has occurred while opening.");
- }
- }
-
- private bool processCloseFrame(WebSocketFrame frame)
- {
- var payload = frame.PayloadData;
- close(payload, !payload.ContainsReservedCloseStatusCode, false);
-
- return false;
- }
-
- private bool processDataFrame(WebSocketFrame frame)
- {
- var e = frame.IsCompressed
- ? new MessageEventArgs(
- frame.Opcode, frame.PayloadData.ApplicationData.Decompress(_compression))
- : new MessageEventArgs(frame.Opcode, frame.PayloadData);
-
- enqueueToMessageEventQueue(e);
- return true;
- }
-
- private void processException(Exception exception, string message)
- {
- var code = CloseStatusCode.Abnormal;
- var reason = message;
- if (exception is WebSocketException)
- {
- var wsex = (WebSocketException)exception;
- code = wsex.Code;
- reason = wsex.Message;
- }
-
- error(message ?? code.GetMessage(), exception);
- if (_readyState == WebSocketState.Connecting)
- Close(HttpStatusCode.BadRequest);
- else
- close(code, reason ?? code.GetMessage(), false);
- }
-
- private bool processFragmentedFrame(WebSocketFrame frame)
- {
- return frame.IsContinuation // Not first fragment
- ? true
- : processFragments(frame);
- }
-
- private bool processFragments(WebSocketFrame first)
- {
- using (var buff = _memoryStreamFactory.CreateNew())
- {
- buff.WriteBytes(first.PayloadData.ApplicationData);
- if (!concatenateFragmentsInto(buff))
- return false;
-
- byte[] data;
- if (_compression != CompressionMethod.None)
- {
- data = buff.DecompressToArray(_compression);
- }
- else
- {
- data = buff.ToArray();
- }
-
- enqueueToMessageEventQueue(new MessageEventArgs(first.Opcode, data));
- return true;
- }
- }
-
- private bool processPingFrame(WebSocketFrame frame)
- {
- var mask = Mask.Unmask;
-
- return true;
- }
-
- private bool processPongFrame(WebSocketFrame frame)
- {
- _receivePong.Set();
-
- return true;
- }
-
- private bool processUnsupportedFrame(WebSocketFrame frame, CloseStatusCode code, string reason)
- {
- processException(new WebSocketException(code, reason), null);
-
- return false;
- }
-
- private bool processWebSocketFrame(WebSocketFrame frame)
- {
- return frame.IsCompressed && _compression == CompressionMethod.None
- ? processUnsupportedFrame(
- frame,
- CloseStatusCode.IncorrectData,
- "A compressed data has been received without available decompression method.")
- : frame.IsFragmented
- ? processFragmentedFrame(frame)
- : frame.IsData
- ? processDataFrame(frame)
- : frame.IsPing
- ? processPingFrame(frame)
- : frame.IsPong
- ? processPongFrame(frame)
- : frame.IsClose
- ? processCloseFrame(frame)
- : processUnsupportedFrame(frame, CloseStatusCode.PolicyViolation, null);
- }
-
- private bool send(Opcode opcode, Stream stream)
- {
- lock (_forSend)
- {
- var src = stream;
- var compressed = false;
- var sent = false;
- try
- {
- if (_compression != CompressionMethod.None)
- {
- stream = stream.Compress(_compression);
- compressed = true;
- }
-
- sent = send(opcode, Mask.Unmask, stream, compressed);
- if (!sent)
- error("Sending a data has been interrupted.");
- }
- catch (Exception ex)
- {
- error("An exception has occurred while sending a data.", ex);
- }
- finally
- {
- if (compressed)
- stream.Dispose();
-
- src.Dispose();
- }
-
- return sent;
- }
- }
-
- private bool send(Opcode opcode, Mask mask, Stream stream, bool compressed)
- {
- var len = stream.Length;
-
- /* Not fragmented */
-
- if (len == 0)
- return send(Fin.Final, opcode, mask, new byte[0], compressed);
-
- var quo = len / FragmentLength;
- var rem = (int)(len % FragmentLength);
-
- byte[] buff = null;
- if (quo == 0)
- {
- buff = new byte[rem];
- return stream.Read(buff, 0, rem) == rem &&
- send(Fin.Final, opcode, mask, buff, compressed);
- }
-
- buff = new byte[FragmentLength];
- if (quo == 1 && rem == 0)
- return stream.Read(buff, 0, FragmentLength) == FragmentLength &&
- send(Fin.Final, opcode, mask, buff, compressed);
-
- /* Send fragmented */
-
- // Begin
- if (stream.Read(buff, 0, FragmentLength) != FragmentLength ||
- !send(Fin.More, opcode, mask, buff, compressed))
- return false;
-
- var n = rem == 0 ? quo - 2 : quo - 1;
- for (long i = 0; i < n; i++)
- if (stream.Read(buff, 0, FragmentLength) != FragmentLength ||
- !send(Fin.More, Opcode.Cont, mask, buff, compressed))
- return false;
-
- // End
- if (rem == 0)
- rem = FragmentLength;
- else
- buff = new byte[rem];
-
- return stream.Read(buff, 0, rem) == rem &&
- send(Fin.Final, Opcode.Cont, mask, buff, compressed);
- }
-
- private bool send(Fin fin, Opcode opcode, Mask mask, byte[] data, bool compressed)
- {
- lock (_forConn)
- {
- if (_readyState != WebSocketState.Open)
- {
- return false;
- }
-
- return writeBytes(
- WebSocketFrame.CreateWebSocketFrame(fin, opcode, mask, data, compressed).ToByteArray());
- }
- }
-
- private Task sendAsync(Opcode opcode, Stream stream)
- {
- var completionSource = new TaskCompletionSource<bool>();
- Task.Run(() =>
- {
- try
- {
- send(opcode, stream);
- completionSource.TrySetResult(true);
- }
- catch (Exception ex)
- {
- completionSource.TrySetException(ex);
- }
- });
- return completionSource.Task;
- }
-
- // As server
- private bool sendHttpResponse(HttpResponse response)
- {
- return writeBytes(response.ToByteArray());
- }
-
- private void startReceiving()
- {
- if (_messageEventQueue.Count > 0)
- _messageEventQueue.Clear();
-
- _exitReceiving = new AutoResetEvent(false);
- _receivePong = new AutoResetEvent(false);
-
- Action receive = null;
- receive = () => WebSocketFrame.ReadAsync(
- _stream,
- true,
- frame =>
- {
- if (processWebSocketFrame(frame) && _readyState != WebSocketState.Closed)
- {
- receive();
-
- if (!frame.IsData)
- return;
-
- lock (_forEvent)
- {
- try
- {
- var e = dequeueFromMessageEventQueue();
- if (e != null && _readyState == WebSocketState.Open)
- OnMessage.Emit(this, e);
- }
- catch (Exception ex)
- {
- processException(ex, "An exception has occurred while OnMessage.");
- }
- }
- }
- else if (_exitReceiving != null)
- {
- _exitReceiving.Set();
- }
- },
- ex => processException(ex, "An exception has occurred while receiving a message."));
-
- receive();
- }
-
- // As server
- private bool validateSecWebSocketKeyHeader(string value)
- {
- if (value == null || value.Length == 0)
- return false;
-
- _base64Key = value;
- return true;
- }
-
- // As server
- private bool validateSecWebSocketVersionClientHeader(string value)
- {
- return true;
- //return value != null && value == _version;
- }
-
- private bool writeBytes(byte[] data)
- {
- try
- {
- _stream.Write(data, 0, data.Length);
- return true;
- }
- catch (Exception ex)
- {
- return false;
- }
- }
-
- #endregion
-
- #region Internal Methods
-
- // As server
- internal void Close(HttpResponse response)
- {
- _readyState = WebSocketState.Closing;
-
- sendHttpResponse(response);
- closeServerResources();
-
- _readyState = WebSocketState.Closed;
- }
-
- // As server
- internal void Close(HttpStatusCode code)
- {
- Close(createHandshakeCloseResponse(code));
- }
-
- // As server
- public void ConnectAsServer()
- {
- try
- {
- if (acceptHandshake())
- {
- _readyState = WebSocketState.Open;
- open();
- }
- }
- catch (Exception ex)
- {
- processException(ex, "An exception has occurred while connecting.");
- }
- }
-
- private string CreateResponseKey(string base64Key)
- {
- var buff = new StringBuilder(base64Key, 64);
- buff.Append(_guid);
- var src = _cryptoProvider.ComputeSHA1(Encoding.UTF8.GetBytes(buff.ToString()));
-
- return Convert.ToBase64String(src);
- }
-
- #endregion
-
- #region Public Methods
-
- /// <summary>
- /// Closes the WebSocket connection, and releases all associated resources.
- /// </summary>
- public void Close()
- {
- var msg = _readyState.CheckIfClosable();
- if (msg != null)
- {
- error(msg);
-
- return;
- }
-
- var send = _readyState == WebSocketState.Open;
- close(new PayloadData(), send, send);
- }
-
- /// <summary>
- /// Closes the WebSocket connection with the specified <see cref="CloseStatusCode"/>
- /// and <see cref="string"/>, and releases all associated resources.
- /// </summary>
- /// <remarks>
- /// This method emits a <see cref="OnError"/> event if the size
- /// of <paramref name="reason"/> is greater than 123 bytes.
- /// </remarks>
- /// <param name="code">
- /// One of the <see cref="CloseStatusCode"/> enum values, represents the status code
- /// indicating the reason for the close.
- /// </param>
- /// <param name="reason">
- /// A <see cref="string"/> that represents the reason for the close.
- /// </param>
- public void Close(CloseStatusCode code, string reason)
- {
- byte[] data = null;
- var msg = _readyState.CheckIfClosable() ??
- (data = ((ushort)code).Append(reason)).CheckIfValidControlData("reason");
-
- if (msg != null)
- {
- error(msg);
-
- return;
- }
-
- var send = _readyState == WebSocketState.Open && !code.IsReserved();
- close(new PayloadData(data), send, send);
- }
-
- /// <summary>
- /// Sends a binary <paramref name="data"/> asynchronously using the WebSocket connection.
- /// </summary>
- /// <remarks>
- /// This method doesn't wait for the send to be complete.
- /// </remarks>
- /// <param name="data">
- /// An array of <see cref="byte"/> that represents the binary data to send.
- /// </param>
- /// An Action&lt;bool&gt; delegate that references the method(s) called when the send is
- /// complete. A <see cref="bool"/> passed to this delegate is <c>true</c> if the send is
- /// complete successfully; otherwise, <c>false</c>.
- public Task SendAsync(byte[] data)
- {
- var msg = _readyState.CheckIfOpen() ?? data.CheckIfValidSendData();
- if (msg != null)
- {
- throw new Exception(msg);
- }
-
- return sendAsync(Opcode.Binary, _memoryStreamFactory.CreateNew(data));
- }
-
- /// <summary>
- /// Sends a text <paramref name="data"/> asynchronously using the WebSocket connection.
- /// </summary>
- /// <remarks>
- /// This method doesn't wait for the send to be complete.
- /// </remarks>
- /// <param name="data">
- /// A <see cref="string"/> that represents the text data to send.
- /// </param>
- /// An Action&lt;bool&gt; delegate that references the method(s) called when the send is
- /// complete. A <see cref="bool"/> passed to this delegate is <c>true</c> if the send is
- /// complete successfully; otherwise, <c>false</c>.
- public Task SendAsync(string data)
- {
- var msg = _readyState.CheckIfOpen() ?? data.CheckIfValidSendData();
- if (msg != null)
- {
- throw new Exception(msg);
- }
-
- return sendAsync(Opcode.Text, _memoryStreamFactory.CreateNew(Encoding.UTF8.GetBytes(data)));
- }
-
- #endregion
-
- #region Explicit Interface Implementation
-
- /// <summary>
- /// Closes the WebSocket connection, and releases all associated resources.
- /// </summary>
- /// <remarks>
- /// This method closes the WebSocket connection with <see cref="CloseStatusCode.Away"/>.
- /// </remarks>
- void IDisposable.Dispose()
- {
- Close(CloseStatusCode.Away, null);
- }
-
- #endregion
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/WebSocketException.cs b/SocketHttpListener.Portable/WebSocketException.cs
deleted file mode 100644
index 260721317..000000000
--- a/SocketHttpListener.Portable/WebSocketException.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-
-namespace SocketHttpListener
-{
- /// <summary>
- /// The exception that is thrown when a <see cref="WebSocket"/> gets a fatal error.
- /// </summary>
- public class WebSocketException : Exception
- {
- #region Internal Constructors
-
- internal WebSocketException ()
- : this (CloseStatusCode.Abnormal, null, null)
- {
- }
-
- internal WebSocketException (string message)
- : this (CloseStatusCode.Abnormal, message, null)
- {
- }
-
- internal WebSocketException (CloseStatusCode code)
- : this (code, null, null)
- {
- }
-
- internal WebSocketException (string message, Exception innerException)
- : this (CloseStatusCode.Abnormal, message, innerException)
- {
- }
-
- internal WebSocketException (CloseStatusCode code, string message)
- : this (code, message, null)
- {
- }
-
- internal WebSocketException (CloseStatusCode code, string message, Exception innerException)
- : base (message ?? code.GetMessage (), innerException)
- {
- Code = code;
- }
-
- #endregion
-
- #region Public Properties
-
- /// <summary>
- /// Gets the status code indicating the cause for the exception.
- /// </summary>
- /// <value>
- /// One of the <see cref="CloseStatusCode"/> enum values, represents the status code indicating
- /// the cause for the exception.
- /// </value>
- public CloseStatusCode Code {
- get; private set;
- }
-
- #endregion
- }
-}
diff --git a/SocketHttpListener.Portable/WebSocketFrame.cs b/SocketHttpListener.Portable/WebSocketFrame.cs
deleted file mode 100644
index 44fa4a5dc..000000000
--- a/SocketHttpListener.Portable/WebSocketFrame.cs
+++ /dev/null
@@ -1,578 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
-namespace SocketHttpListener
-{
- internal class WebSocketFrame : IEnumerable<byte>
- {
- #region Private Fields
-
- private byte[] _extPayloadLength;
- private Fin _fin;
- private Mask _mask;
- private byte[] _maskingKey;
- private Opcode _opcode;
- private PayloadData _payloadData;
- private byte _payloadLength;
- private Rsv _rsv1;
- private Rsv _rsv2;
- private Rsv _rsv3;
-
- #endregion
-
- #region Internal Fields
-
- internal static readonly byte[] EmptyUnmaskPingData;
-
- #endregion
-
- #region Static Constructor
-
- static WebSocketFrame()
- {
- EmptyUnmaskPingData = CreatePingFrame(Mask.Unmask).ToByteArray();
- }
-
- #endregion
-
- #region Private Constructors
-
- private WebSocketFrame()
- {
- }
-
- #endregion
-
- #region Internal Constructors
-
- internal WebSocketFrame(Opcode opcode, PayloadData payload)
- : this(Fin.Final, opcode, Mask.Mask, payload, false)
- {
- }
-
- internal WebSocketFrame(Opcode opcode, Mask mask, PayloadData payload)
- : this(Fin.Final, opcode, mask, payload, false)
- {
- }
-
- internal WebSocketFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payload)
- : this(fin, opcode, mask, payload, false)
- {
- }
-
- internal WebSocketFrame(
- Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
- {
- _fin = fin;
- _rsv1 = isData(opcode) && compressed ? Rsv.On : Rsv.Off;
- _rsv2 = Rsv.Off;
- _rsv3 = Rsv.Off;
- _opcode = opcode;
- _mask = mask;
-
- var len = payload.Length;
- if (len < 126)
- {
- _payloadLength = (byte)len;
- _extPayloadLength = new byte[0];
- }
- else if (len < 0x010000)
- {
- _payloadLength = (byte)126;
- _extPayloadLength = ((ushort)len).ToByteArrayInternally(ByteOrder.Big);
- }
- else
- {
- _payloadLength = (byte)127;
- _extPayloadLength = len.ToByteArrayInternally(ByteOrder.Big);
- }
-
- if (mask == Mask.Mask)
- {
- _maskingKey = createMaskingKey();
- payload.Mask(_maskingKey);
- }
- else
- {
- _maskingKey = new byte[0];
- }
-
- _payloadData = payload;
- }
-
- #endregion
-
- #region Public Properties
-
- public byte[] ExtendedPayloadLength
- {
- get
- {
- return _extPayloadLength;
- }
- }
-
- public Fin Fin
- {
- get
- {
- return _fin;
- }
- }
-
- public bool IsBinary
- {
- get
- {
- return _opcode == Opcode.Binary;
- }
- }
-
- public bool IsClose
- {
- get
- {
- return _opcode == Opcode.Close;
- }
- }
-
- public bool IsCompressed
- {
- get
- {
- return _rsv1 == Rsv.On;
- }
- }
-
- public bool IsContinuation
- {
- get
- {
- return _opcode == Opcode.Cont;
- }
- }
-
- public bool IsControl
- {
- get
- {
- return _opcode == Opcode.Close || _opcode == Opcode.Ping || _opcode == Opcode.Pong;
- }
- }
-
- public bool IsData
- {
- get
- {
- return _opcode == Opcode.Binary || _opcode == Opcode.Text;
- }
- }
-
- public bool IsFinal
- {
- get
- {
- return _fin == Fin.Final;
- }
- }
-
- public bool IsFragmented
- {
- get
- {
- return _fin == Fin.More || _opcode == Opcode.Cont;
- }
- }
-
- public bool IsMasked
- {
- get
- {
- return _mask == Mask.Mask;
- }
- }
-
- public bool IsPerMessageCompressed
- {
- get
- {
- return (_opcode == Opcode.Binary || _opcode == Opcode.Text) && _rsv1 == Rsv.On;
- }
- }
-
- public bool IsPing
- {
- get
- {
- return _opcode == Opcode.Ping;
- }
- }
-
- public bool IsPong
- {
- get
- {
- return _opcode == Opcode.Pong;
- }
- }
-
- public bool IsText
- {
- get
- {
- return _opcode == Opcode.Text;
- }
- }
-
- public ulong Length
- {
- get
- {
- return 2 + (ulong)(_extPayloadLength.Length + _maskingKey.Length) + _payloadData.Length;
- }
- }
-
- public Mask Mask
- {
- get
- {
- return _mask;
- }
- }
-
- public byte[] MaskingKey
- {
- get
- {
- return _maskingKey;
- }
- }
-
- public Opcode Opcode
- {
- get
- {
- return _opcode;
- }
- }
-
- public PayloadData PayloadData
- {
- get
- {
- return _payloadData;
- }
- }
-
- public byte PayloadLength
- {
- get
- {
- return _payloadLength;
- }
- }
-
- public Rsv Rsv1
- {
- get
- {
- return _rsv1;
- }
- }
-
- public Rsv Rsv2
- {
- get
- {
- return _rsv2;
- }
- }
-
- public Rsv Rsv3
- {
- get
- {
- return _rsv3;
- }
- }
-
- #endregion
-
- #region Private Methods
-
- private byte[] createMaskingKey()
- {
- var key = new byte[4];
- var rand = new Random();
- rand.NextBytes(key);
-
- return key;
- }
-
- private static bool isControl(Opcode opcode)
- {
- return opcode == Opcode.Close || opcode == Opcode.Ping || opcode == Opcode.Pong;
- }
-
- private static bool isData(Opcode opcode)
- {
- return opcode == Opcode.Text || opcode == Opcode.Binary;
- }
-
- private static WebSocketFrame read(byte[] header, Stream stream, bool unmask)
- {
- /* Header */
-
- // FIN
- var fin = (header[0] & 0x80) == 0x80 ? Fin.Final : Fin.More;
- // RSV1
- var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
- // RSV2
- var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
- // RSV3
- var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off;
- // Opcode
- var opcode = (Opcode)(header[0] & 0x0f);
- // MASK
- var mask = (header[1] & 0x80) == 0x80 ? Mask.Mask : Mask.Unmask;
- // Payload Length
- var payloadLen = (byte)(header[1] & 0x7f);
-
- // Check if correct frame.
- var incorrect = isControl(opcode) && fin == Fin.More
- ? "A control frame is fragmented."
- : !isData(opcode) && rsv1 == Rsv.On
- ? "A non data frame is compressed."
- : null;
-
- if (incorrect != null)
- throw new WebSocketException(CloseStatusCode.IncorrectData, incorrect);
-
- // Check if consistent frame.
- if (isControl(opcode) && payloadLen > 125)
- throw new WebSocketException(
- CloseStatusCode.InconsistentData,
- "The length of payload data of a control frame is greater than 125 bytes.");
-
- var frame = new WebSocketFrame();
- frame._fin = fin;
- frame._rsv1 = rsv1;
- frame._rsv2 = rsv2;
- frame._rsv3 = rsv3;
- frame._opcode = opcode;
- frame._mask = mask;
- frame._payloadLength = payloadLen;
-
- /* Extended Payload Length */
-
- var size = payloadLen < 126
- ? 0
- : payloadLen == 126
- ? 2
- : 8;
-
- var extPayloadLen = size > 0 ? stream.ReadBytes(size) : new byte[0];
- if (size > 0 && extPayloadLen.Length != size)
- throw new WebSocketException(
- "The 'Extended Payload Length' of a frame cannot be read from the data source.");
-
- frame._extPayloadLength = extPayloadLen;
-
- /* Masking Key */
-
- var masked = mask == Mask.Mask;
- var maskingKey = masked ? stream.ReadBytes(4) : new byte[0];
- if (masked && maskingKey.Length != 4)
- throw new WebSocketException(
- "The 'Masking Key' of a frame cannot be read from the data source.");
-
- frame._maskingKey = maskingKey;
-
- /* Payload Data */
-
- ulong len = payloadLen < 126
- ? payloadLen
- : payloadLen == 126
- ? extPayloadLen.ToUInt16(ByteOrder.Big)
- : extPayloadLen.ToUInt64(ByteOrder.Big);
-
- byte[] data = null;
- if (len > 0)
- {
- // Check if allowable payload data length.
- if (payloadLen > 126 && len > PayloadData.MaxLength)
- throw new WebSocketException(
- CloseStatusCode.TooBig,
- "The length of 'Payload Data' of a frame is greater than the allowable length.");
-
- data = payloadLen > 126
- ? stream.ReadBytes((long)len, 1024)
- : stream.ReadBytes((int)len);
-
- //if (data.LongLength != (long)len)
- // throw new WebSocketException(
- // "The 'Payload Data' of a frame cannot be read from the data source.");
- }
- else
- {
- data = new byte[0];
- }
-
- var payload = new PayloadData(data, masked);
- if (masked && unmask)
- {
- payload.Mask(maskingKey);
- frame._mask = Mask.Unmask;
- frame._maskingKey = new byte[0];
- }
-
- frame._payloadData = payload;
- return frame;
- }
-
- #endregion
-
- #region Internal Methods
-
- internal static WebSocketFrame CreateCloseFrame(Mask mask, byte[] data)
- {
- return new WebSocketFrame(Opcode.Close, mask, new PayloadData(data));
- }
-
- internal static WebSocketFrame CreateCloseFrame(Mask mask, PayloadData payload)
- {
- return new WebSocketFrame(Opcode.Close, mask, payload);
- }
-
- internal static WebSocketFrame CreateCloseFrame(Mask mask, CloseStatusCode code, string reason)
- {
- return new WebSocketFrame(
- Opcode.Close, mask, new PayloadData(((ushort)code).Append(reason)));
- }
-
- internal static WebSocketFrame CreatePingFrame(Mask mask)
- {
- return new WebSocketFrame(Opcode.Ping, mask, new PayloadData());
- }
-
- internal static WebSocketFrame CreatePingFrame(Mask mask, byte[] data)
- {
- return new WebSocketFrame(Opcode.Ping, mask, new PayloadData(data));
- }
-
- internal static WebSocketFrame CreatePongFrame(Mask mask, PayloadData payload)
- {
- return new WebSocketFrame(Opcode.Pong, mask, payload);
- }
-
- internal static WebSocketFrame CreateWebSocketFrame(
- Fin fin, Opcode opcode, Mask mask, byte[] data, bool compressed)
- {
- return new WebSocketFrame(fin, opcode, mask, new PayloadData(data), compressed);
- }
-
- internal static WebSocketFrame Read(Stream stream)
- {
- return Read(stream, true);
- }
-
- internal static WebSocketFrame Read(Stream stream, bool unmask)
- {
- var header = stream.ReadBytes(2);
- if (header.Length != 2)
- throw new WebSocketException(
- "The header part of a frame cannot be read from the data source.");
-
- return read(header, stream, unmask);
- }
-
- internal static async void ReadAsync(
- Stream stream, bool unmask, Action<WebSocketFrame> completed, Action<Exception> error)
- {
- try
- {
- var header = await stream.ReadBytesAsync(2).ConfigureAwait(false);
- if (header.Length != 2)
- throw new WebSocketException(
- "The header part of a frame cannot be read from the data source.");
-
- var frame = read(header, stream, unmask);
- if (completed != null)
- completed(frame);
- }
- catch (Exception ex)
- {
- if (error != null)
- {
- error(ex);
- }
- }
- }
-
- #endregion
-
- #region Public Methods
-
- public IEnumerator<byte> GetEnumerator()
- {
- foreach (var b in ToByteArray())
- yield return b;
- }
-
- public void Print(bool dumped)
- {
- //Console.WriteLine(dumped ? dump(this) : print(this));
- }
-
- public byte[] ToByteArray()
- {
- using (var buff = new MemoryStream())
- {
- var header = (int)_fin;
- header = (header << 1) + (int)_rsv1;
- header = (header << 1) + (int)_rsv2;
- header = (header << 1) + (int)_rsv3;
- header = (header << 4) + (int)_opcode;
- header = (header << 1) + (int)_mask;
- header = (header << 7) + (int)_payloadLength;
- buff.Write(((ushort)header).ToByteArrayInternally(ByteOrder.Big), 0, 2);
-
- if (_payloadLength > 125)
- buff.Write(_extPayloadLength, 0, _extPayloadLength.Length);
-
- if (_mask == Mask.Mask)
- buff.Write(_maskingKey, 0, _maskingKey.Length);
-
- if (_payloadLength > 0)
- {
- var payload = _payloadData.ToByteArray();
- if (_payloadLength < 127)
- buff.Write(payload, 0, payload.Length);
- else
- buff.WriteBytes(payload);
- }
-
- return buff.ToArray();
- }
- }
-
- public override string ToString()
- {
- return BitConverter.ToString(ToByteArray());
- }
-
- #endregion
-
- #region Explicitly Implemented Interface Members
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- #endregion
- }
-} \ No newline at end of file
diff --git a/SocketHttpListener.Portable/WebSocketState.cs b/SocketHttpListener.Portable/WebSocketState.cs
deleted file mode 100644
index 73b3a49dd..000000000
--- a/SocketHttpListener.Portable/WebSocketState.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-namespace SocketHttpListener
-{
- /// <summary>
- /// Contains the values of the state of the WebSocket connection.
- /// </summary>
- /// <remarks>
- /// The values of the state are defined in
- /// <see href="http://www.w3.org/TR/websockets/#dom-websocket-readystate">The WebSocket
- /// API</see>.
- /// </remarks>
- public enum WebSocketState : ushort
- {
- /// <summary>
- /// Equivalent to numeric value 0.
- /// Indicates that the connection has not yet been established.
- /// </summary>
- Connecting = 0,
- /// <summary>
- /// Equivalent to numeric value 1.
- /// Indicates that the connection is established and the communication is possible.
- /// </summary>
- Open = 1,
- /// <summary>
- /// Equivalent to numeric value 2.
- /// Indicates that the connection is going through the closing handshake or
- /// the <c>WebSocket.Close</c> method has been invoked.
- /// </summary>
- Closing = 2,
- /// <summary>
- /// Equivalent to numeric value 3.
- /// Indicates that the connection has been closed or couldn't be opened.
- /// </summary>
- Closed = 3
- }
-}
diff --git a/SocketHttpListener.Portable/packages.config b/SocketHttpListener.Portable/packages.config
deleted file mode 100644
index 2aae715b5..000000000
--- a/SocketHttpListener.Portable/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
- <package id="MediaBrowser.Common" version="3.0.689" targetFramework="portable45-net45+win8" />
- <package id="Patterns.Logging" version="1.0.0.6" targetFramework="portable45-net45+win8" />
-</packages> \ No newline at end of file
diff --git a/SocketHttpListener.Portable/project.json b/SocketHttpListener.Portable/project.json
deleted file mode 100644
index fbbe9eaf3..000000000
--- a/SocketHttpListener.Portable/project.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "frameworks":{
- "netstandard1.6":{
- "dependencies":{
- "NETStandard.Library":"1.6.0",
- }
- },
- ".NETPortable,Version=v4.5,Profile=Profile7":{
- "buildOptions": {
- "define": [ ]
- },
- "frameworkAssemblies":{
-
- }
- }
- }
-} \ No newline at end of file