aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaus Vium <clausvium@gmail.com>2019-02-21 10:07:21 +0100
committerClaus Vium <clausvium@gmail.com>2019-02-26 22:11:21 +0100
commit4db31acff940dc9cabbd39649103faf4dc2e2c47 (patch)
tree4472b2330124f2bfea3f9dcdfcd5508cedd84570
parent968e282c907f57d7998b6435cadae2f0a5ec832c (diff)
Begin removing System.Net sources
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs16
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/ResponseFilter.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/StreamWriter.cs4
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs54
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs3
-rw-r--r--Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs46
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs18
-rw-r--r--MediaBrowser.Model/Services/IRequest.cs2
-rw-r--r--MediaBrowser.Model/Services/QueryParamCollection.cs31
-rw-r--r--SocketHttpListener/Ext.cs1
-rw-r--r--SocketHttpListener/HttpResponse.cs243
-rw-r--r--SocketHttpListener/Net/AuthenticationSchemeSelector.cs6
-rw-r--r--SocketHttpListener/Net/AuthenticationTypes.cs9
-rw-r--r--SocketHttpListener/Net/BoundaryType.cs11
-rw-r--r--SocketHttpListener/Net/ChunkStream.cs385
-rw-r--r--SocketHttpListener/Net/ChunkedInputStream.cs178
-rw-r--r--SocketHttpListener/Net/EntitySendFormat.cs8
-rw-r--r--SocketHttpListener/Net/HttpConnection.cs528
-rw-r--r--SocketHttpListener/Net/HttpEndPointListener.cs526
-rw-r--r--SocketHttpListener/Net/HttpEndPointManager.cs192
-rw-r--r--SocketHttpListener/Net/HttpKnownHeaderNames.cs91
-rw-r--r--SocketHttpListener/Net/HttpListener.cs284
-rw-r--r--SocketHttpListener/Net/HttpListenerBasicIdentity.cs49
-rw-r--r--SocketHttpListener/Net/HttpListenerContext.Managed.cs99
-rw-r--r--SocketHttpListener/Net/HttpListenerContext.cs74
-rw-r--r--SocketHttpListener/Net/HttpListenerPrefixCollection.cs117
-rw-r--r--SocketHttpListener/Net/HttpListenerRequest.Managed.cs325
-rw-r--r--SocketHttpListener/Net/HttpListenerRequest.cs537
-rw-r--r--SocketHttpListener/Net/HttpListenerRequestUriBuilder.cs443
-rw-r--r--SocketHttpListener/Net/HttpListenerResponse.Managed.cs333
-rw-r--r--SocketHttpListener/Net/HttpListenerResponse.cs294
-rw-r--r--SocketHttpListener/Net/HttpRequestStream.Managed.cs210
-rw-r--r--SocketHttpListener/Net/HttpRequestStream.cs129
-rw-r--r--SocketHttpListener/Net/HttpResponseStream.Managed.cs329
-rw-r--r--SocketHttpListener/Net/HttpResponseStream.cs124
-rw-r--r--SocketHttpListener/Net/HttpStatusCode.cs321
-rw-r--r--SocketHttpListener/Net/HttpStatusDescription.cs69
-rw-r--r--SocketHttpListener/Net/HttpStreamAsyncResult.cs79
-rw-r--r--SocketHttpListener/Net/HttpVersion.cs16
-rw-r--r--SocketHttpListener/Net/ListenerPrefix.cs89
-rw-r--r--SocketHttpListener/Net/UriScheme.cs20
-rw-r--r--SocketHttpListener/Net/WebHeaderCollection.cs360
-rw-r--r--SocketHttpListener/Net/WebHeaderEncoding.cs84
-rw-r--r--SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs92
-rw-r--r--SocketHttpListener/Net/WebSockets/HttpWebSocket.Managed.cs81
-rw-r--r--SocketHttpListener/Net/WebSockets/HttpWebSocket.cs159
-rw-r--r--SocketHttpListener/Net/WebSockets/WebSocketCloseStatus.cs27
-rw-r--r--SocketHttpListener/Net/WebSockets/WebSocketContext.cs24
-rw-r--r--SocketHttpListener/Net/WebSockets/WebSocketValidate.cs141
-rw-r--r--SocketHttpListener/WebSocket.cs3
54 files changed, 263 insertions, 7012 deletions
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index 2e0728136..834a494f8 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -327,7 +327,7 @@ namespace Emby.Server.Implementations.HttpClientManager
}
httpWebRequest.ContentType = contentType;
- httpWebRequest.ContentLength = bytes.Length;
+ // httpWebRequest.ContentLength = bytes.Length;
(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length);
}
catch (Exception ex)
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index 7aedba9b3..835c6f52e 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Server.Implementations.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
@@ -14,6 +15,7 @@ namespace Emby.Server.Implementations.HttpServer
public class FileWriter : IHttpResult
{
private ILogger Logger { get; set; }
+ public IFileSystem FileSystem { get; }
private string RangeHeader { get; set; }
private bool IsHeadRequest { get; set; }
@@ -51,6 +53,7 @@ namespace Emby.Server.Implementations.HttpServer
Path = path;
Logger = logger;
+ FileSystem = fileSystem;
RangeHeader = rangeHeader;
Headers["Content-Type"] = contentType;
@@ -60,7 +63,8 @@ namespace Emby.Server.Implementations.HttpServer
if (string.IsNullOrWhiteSpace(rangeHeader))
{
- Headers["Content-Length"] = TotalContentLength.ToString(UsCulture);
+ // TODO
+ //Headers["Content-Length"] = TotalContentLength.ToString(UsCulture);
StatusCode = HttpStatusCode.OK;
}
else
@@ -95,7 +99,7 @@ namespace Emby.Server.Implementations.HttpServer
// Content-Length is the length of what we're serving, not the original content
var lengthString = RangeLength.ToString(UsCulture);
- Headers["Content-Length"] = lengthString;
+ // TODO Headers["Content-Length"] = lengthString;
var rangeString = string.Format("bytes {0}-{1}/{2}", RangeStart, RangeEnd, TotalContentLength);
Headers["Content-Range"] = rangeString;
@@ -174,12 +178,12 @@ namespace Emby.Server.Implementations.HttpServer
}
//var count = FileShare == FileShareMode.ReadWrite ? TotalContentLength : 0;
-
- await response.TransmitFile(path, 0, 0, FileShare, cancellationToken).ConfigureAwait(false);
+ // TODO not DI friendly lol
+ await response.TransmitFile(path, 0, 0, FileShare, FileSystem, new StreamHelper(), cancellationToken).ConfigureAwait(false);
return;
}
-
- await response.TransmitFile(path, RangeStart, RangeLength, FileShare, cancellationToken).ConfigureAwait(false);
+ // TODO not DI friendly lol
+ await response.TransmitFile(path, RangeStart, RangeLength, FileShare, FileSystem, new StreamHelper(), cancellationToken).ConfigureAwait(false);
}
finally
{
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index ee746c669..fb42460f1 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -644,6 +644,9 @@ namespace Emby.Server.Implementations.HttpServer
{
var bOutput = Encoding.UTF8.GetBytes(text);
response.SetContentLength(bOutput.Length);
+ // TODO
+ response.Headers.Remove("Content-Length"); // DO NOT SET THIS, IT'S DONE AUTOMATICALLY BECAUSE MS ARE NOT STUPID
+ response.SendChunked = true;
return response.OutputStream.WriteAsync(bOutput, 0, bOutput.Length);
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 070717d48..5e9d2b4c3 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -592,7 +592,7 @@ namespace Emby.Server.Implementations.HttpServer
{
if (totalContentLength.HasValue)
{
- responseHeaders["Content-Length"] = totalContentLength.Value.ToString(UsCulture);
+ // TODO responseHeaders["Content-Length"] = totalContentLength.Value.ToString(UsCulture);
}
if (isHeadRequest)
diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
index 891a76ec2..9c8ab8d91 100644
--- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -96,7 +96,7 @@ namespace Emby.Server.Implementations.HttpServer
RangeLength = 1 + RangeEnd - RangeStart;
// Content-Length is the length of what we're serving, not the original content
- Headers["Content-Length"] = RangeLength.ToString(UsCulture);
+ // TODO Headers["Content-Length"] = RangeLength.ToString(UsCulture);
Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", RangeStart, RangeEnd, TotalContentLength);
if (RangeStart > 0 && SourceStream.CanSeek)
diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
index da2bf983a..dbce3250d 100644
--- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
+++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.HttpServer
public void FilterResponse(IRequest req, IResponse res, object dto)
{
// Try to prevent compatibility view
- res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
+ res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
res.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
res.AddHeader("Access-Control-Allow-Origin", "*");
diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
index cb2e3580b..750b0f795 100644
--- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
@@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.HttpServer
if (source.CanSeek)
{
- Headers["Content-Length"] = source.Length.ToString(UsCulture);
+ // TODO Headers["Content-Length"] = source.Length.ToString(UsCulture);
}
}
@@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.HttpServer
Headers["Content-Type"] = contentType;
- Headers["Content-Length"] = contentLength.ToString(UsCulture);
+ // TODO Headers["Content-Length"] = contentLength.ToString(UsCulture);
}
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
index 693c2328c..64856f04a 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Security.Cryptography.X509Certificates;
+ using System.Net;
+ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
@@ -13,9 +14,8 @@ using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
-using SocketHttpListener.Net;
-namespace Jellyfin.Server.SocketSharp
+ namespace Jellyfin.Server.SocketSharp
{
public class WebSocketSharpListener : IHttpListener
{
@@ -67,24 +67,44 @@ namespace Jellyfin.Server.SocketSharp
public void Start(IEnumerable<string> urlPrefixes)
{
- if (_listener == null)
- {
- _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _streamHelper, _fileSystem, _environment);
- }
+ // TODO
+ //if (_listener == null)
+ //{
+ // _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _streamHelper, _fileSystem, _environment);
+ //}
+
+ //_listener.EnableDualMode = _enableDualMode;
+
+ //if (_certificate != null)
+ //{
+ // _listener.LoadCert(_certificate);
+ //}
- _listener.EnableDualMode = _enableDualMode;
+ //_logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes);
+ //_listener.Prefixes.AddRange(urlPrefixes);
- if (_certificate != null)
+ //_listener.OnContext = async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false);
+
+ //_listener.Start();
+
+ if (_listener == null)
{
- _listener.LoadCert(_certificate);
+ _listener = new HttpListener();
}
-
+
_logger.LogInformation("Adding HttpListener prefixes {Prefixes}", urlPrefixes);
- _listener.Prefixes.AddRange(urlPrefixes);
- _listener.OnContext = async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false);
+ //foreach (var urlPrefix in urlPrefixes)
+ //{
+ // _listener.Prefixes.Add(urlPrefix);
+ //}
+ _listener.Prefixes.Add("http://localhost:8096/");
_listener.Start();
+
+ // TODO how to do this in netcore?
+ _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false),
+ null);
}
private static void LogRequest(ILogger logger, HttpListenerRequest request)
@@ -98,8 +118,10 @@ namespace Jellyfin.Server.SocketSharp
request.UserAgent ?? string.Empty);
}
- private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
+ private Task InitTask(IAsyncResult asyncResult, CancellationToken cancellationToken)
{
+ var context = _listener.EndGetContext(asyncResult);
+ _listener.BeginGetContext(async c => await InitTask(c, _disposeCancellationToken).ConfigureAwait(false), null);
IHttpRequest httpReq = null;
var request = context.Request;
@@ -134,7 +156,7 @@ namespace Jellyfin.Server.SocketSharp
var endpoint = ctx.Request.RemoteEndPoint.ToString();
var url = ctx.Request.RawUrl;
- var queryString = ctx.Request.QueryString;
+ var queryString = new QueryParamCollection(ctx.Request.QueryString);
var connectingArgs = new WebSocketConnectingEventArgs
{
@@ -153,7 +175,7 @@ namespace Jellyfin.Server.SocketSharp
if (WebSocketConnected != null)
{
- var socket = new SharpWebSocket(webSocketContext.WebSocket, _logger);
+ SharpWebSocket socket = null; //new SharpWebSocket(webSocketContext.WebSocket, _logger);
await socket.ConnectAsServerAsync().ConfigureAwait(false);
WebSocketConnected(new WebSocketConnectEventArgs
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
index 6458707d9..6a00e283c 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Net;
using System.Text;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Services;
@@ -438,7 +439,7 @@ namespace Jellyfin.Server.SocketSharp
public string UserAgent => request.UserAgent;
- public QueryParamCollection Headers => request.Headers;
+ public QueryParamCollection Headers => new QueryParamCollection(request.Headers);
private QueryParamCollection queryString;
public QueryParamCollection QueryString => queryString ?? (queryString = MyHttpUtility.ParseQueryString(request.Url.Query));
diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs
index cf5aee5d4..552ae1754 100644
--- a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs
+++ b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs
@@ -3,13 +3,14 @@ using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
+using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Server.Implementations;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
-using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
using IRequest = MediaBrowser.Model.Services.IRequest;
@@ -53,7 +54,7 @@ namespace Jellyfin.Server.SocketSharp
set => _response.ContentType = value;
}
- public QueryParamCollection Headers => _response.Headers;
+ public QueryParamCollection Headers => new QueryParamCollection(_response.Headers);
private static string AsHeaderValue(Cookie cookie)
{
@@ -152,7 +153,7 @@ namespace Jellyfin.Server.SocketSharp
// you can happily set the Content-Length header in Asp.Net
// but HttpListener will complain if you do - you have to set ContentLength64 on the response.
// workaround: HttpListener throws "The parameter is incorrect" exceptions when we try to set the Content-Length header
- _response.ContentLength64 = contentLength;
+ //_response.ContentLength64 = contentLength;
}
public void SetCookie(Cookie cookie)
@@ -172,10 +173,43 @@ namespace Jellyfin.Server.SocketSharp
public void ClearCookies()
{
}
-
- public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ const int StreamCopyToBufferSize = 81920;
+ public async Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken)
{
- return _response.TransmitFile(path, offset, count, fileShareMode, cancellationToken);
+ // TODO
+ // return _response.TransmitFile(path, offset, count, fileShareMode, cancellationToken);
+ var allowAsync = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+
+ //if (count <= 0)
+ //{
+ // allowAsync = true;
+ //}
+
+ var fileOpenOptions = 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;
+ }
+
+ if (count > 0)
+ {
+ await streamHelper.CopyToAsync(fs, OutputStream, count, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await fs.CopyToAsync(OutputStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false);
+ }
+ }
}
}
}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 6a98c5e8a..3e74d59db 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -324,7 +324,8 @@ namespace MediaBrowser.Api.Playback.Progressive
// Seeing cases of -1 here
if (response.ContentLength.HasValue && response.ContentLength.Value >= 0)
{
- responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture);
+ // TODO
+ //responseHeaders["Content-Length"] = response.ContentLength.Value.ToString(UsCulture);
}
if (isHeadRequest)
@@ -382,17 +383,18 @@ namespace MediaBrowser.Api.Playback.Progressive
var hasHeaders = streamResult as IHasHeaders;
if (hasHeaders != null)
{
- if (contentLength.HasValue)
- {
- hasHeaders.Headers["Content-Length"] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
- }
- else
- {
+ // TODO
+ //if (contentLength.HasValue)
+ //{
+ // hasHeaders.Headers["Content-Length"] = contentLength.Value.ToString(CultureInfo.InvariantCulture);
+ //}
+ //else
+ //{
if (hasHeaders.Headers.ContainsKey("Content-Length"))
{
hasHeaders.Headers.Remove("Content-Length");
}
- }
+ //}
}
return streamResult;
diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs
index ac9b981b9..909cebce3 100644
--- a/MediaBrowser.Model/Services/IRequest.cs
+++ b/MediaBrowser.Model/Services/IRequest.cs
@@ -152,7 +152,7 @@ namespace MediaBrowser.Model.Services
QueryParamCollection Headers { get; }
- Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken);
+ Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken);
bool SendChunked { get; set; }
}
diff --git a/MediaBrowser.Model/Services/QueryParamCollection.cs b/MediaBrowser.Model/Services/QueryParamCollection.cs
index 4297b97c6..0e0ebf848 100644
--- a/MediaBrowser.Model/Services/QueryParamCollection.cs
+++ b/MediaBrowser.Model/Services/QueryParamCollection.cs
@@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
using System.Linq;
+using System.Net;
using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.Services
{
+ // Remove this garbage class, it's just a bastard copy of NameValueCollection
public class QueryParamCollection : List<NameValuePair>
{
public QueryParamCollection()
@@ -20,6 +23,30 @@ namespace MediaBrowser.Model.Services
}
}
+ // TODO remove this shit
+ public QueryParamCollection(WebHeaderCollection webHeaderCollection)
+ {
+ foreach (var key in webHeaderCollection.AllKeys)
+ {
+ foreach (var value in webHeaderCollection.GetValues(key) ?? Array.Empty<string>())
+ {
+ Add(key, value);
+ }
+ }
+ }
+
+ // TODO remove this shit
+ public QueryParamCollection(NameValueCollection nameValueCollection)
+ {
+ foreach (var key in nameValueCollection.AllKeys)
+ {
+ foreach (var value in nameValueCollection.GetValues(key) ?? Array.Empty<string>())
+ {
+ Add(key, value);
+ }
+ }
+ }
+
private static StringComparison GetStringComparison()
{
return StringComparison.OrdinalIgnoreCase;
@@ -50,6 +77,10 @@ namespace MediaBrowser.Model.Services
/// </summary>
public virtual void Add(string key, string value)
{
+ if (string.Equals(key, "content-length", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
Add(new NameValuePair(key, value));
}
diff --git a/SocketHttpListener/Ext.cs b/SocketHttpListener/Ext.cs
index 2b3c67071..697c5d5b7 100644
--- a/SocketHttpListener/Ext.cs
+++ b/SocketHttpListener/Ext.cs
@@ -6,7 +6,6 @@ using System.Net;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
-using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
using WebSocketState = System.Net.WebSockets.WebSocketState;
namespace SocketHttpListener
diff --git a/SocketHttpListener/HttpResponse.cs b/SocketHttpListener/HttpResponse.cs
index d5d9b4a1c..a33b94295 100644
--- a/SocketHttpListener/HttpResponse.cs
+++ b/SocketHttpListener/HttpResponse.cs
@@ -1,123 +1,122 @@
-using System;
-using System.Linq;
-using System.Net;
-using System.Text;
-using MediaBrowser.Model.Services;
-using SocketHttpListener.Net;
-using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
-using HttpVersion = SocketHttpListener.Net.HttpVersion;
-
-namespace SocketHttpListener
+using System;
+using System.Linq;
+using System.Net;
+using System.Text;
+using MediaBrowser.Model.Services;
+using SocketHttpListener.Net;
+
+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 => GetCookies(Headers, true);
-
- private static CookieCollection GetCookies(QueryParamCollection headers, bool response)
- {
- var name = response ? "Set-Cookie" : "Cookie";
- return headers == null || !headers.Contains(name)
- ? new CookieCollection()
- : CookieHelper.Parse(headers[name], response);
- }
-
- public bool IsProxyAuthenticationRequired => _code == "407";
-
- public bool IsUnauthorized => _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 => _reason;
-
- public string StatusCode => _code;
-
- #endregion
-
- #region Internal Methods
-
- internal static HttpResponse CreateCloseResponse(HttpStatusCode code)
- {
- var res = new HttpResponse(code);
- res.Headers["Connection"] = "close";
-
- 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);
-
- return output.ToString();
- }
-
- #endregion
- }
-}
+ // TODO what is the point of this class?
+ 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 => GetCookies(Headers, true);
+
+ private static CookieCollection GetCookies(QueryParamCollection headers, bool response)
+ {
+ var name = response ? "Set-Cookie" : "Cookie";
+ return headers == null || !headers.Contains(name)
+ ? new CookieCollection()
+ : CookieHelper.Parse(headers[name], response);
+ }
+
+ public bool IsProxyAuthenticationRequired => _code == "407";
+
+ public bool IsUnauthorized => _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 => _reason;
+
+ public string StatusCode => _code;
+
+ #endregion
+
+ #region Internal Methods
+
+ internal static HttpResponse CreateCloseResponse(HttpStatusCode code)
+ {
+ var res = new HttpResponse(code);
+ res.Headers["Connection"] = "close";
+
+ 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);
+
+ return output.ToString();
+ }
+
+ #endregion
+ }
+}
diff --git a/SocketHttpListener/Net/AuthenticationSchemeSelector.cs b/SocketHttpListener/Net/AuthenticationSchemeSelector.cs
deleted file mode 100644
index 77e6d0b8a..000000000
--- a/SocketHttpListener/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/Net/AuthenticationTypes.cs b/SocketHttpListener/Net/AuthenticationTypes.cs
deleted file mode 100644
index a3dbe9dff..000000000
--- a/SocketHttpListener/Net/AuthenticationTypes.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace SocketHttpListener.Net
-{
- internal class AuthenticationTypes
- {
- internal const string NTLM = "NTLM";
- internal const string Negotiate = "Negotiate";
- internal const string Basic = "Basic";
- }
-}
diff --git a/SocketHttpListener/Net/BoundaryType.cs b/SocketHttpListener/Net/BoundaryType.cs
deleted file mode 100644
index da0b22910..000000000
--- a/SocketHttpListener/Net/BoundaryType.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace SocketHttpListener.Net
-{
- internal enum BoundaryType
- {
- ContentLength = 0, // Content-Length: XXX
- Chunked = 1, // Transfer-Encoding: chunked
- Multipart = 3,
- None = 4,
- Invalid = 5,
- }
-}
diff --git a/SocketHttpListener/Net/ChunkStream.cs b/SocketHttpListener/Net/ChunkStream.cs
deleted file mode 100644
index 3836947d4..000000000
--- a/SocketHttpListener/Net/ChunkStream.cs
+++ /dev/null
@@ -1,385 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-
-namespace SocketHttpListener.Net
-{
- // Licensed to the .NET Foundation under one or more agreements.
- // See the LICENSE file in the project root for more information.
- //
- // System.Net.ResponseStream
- //
- // Author:
- // Gonzalo Paniagua Javier (gonzalo@novell.com)
- //
- // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
-
- internal sealed class ChunkStream
- {
- private enum State
- {
- None,
- PartialSize,
- Body,
- BodyFinished,
- Trailer
- }
-
- private class Chunk
- {
- public byte[] Bytes;
- public int Offset;
-
- public Chunk(byte[] chunk)
- {
- 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;
- private int _chunkSize;
- private int _chunkRead;
- private int _totalWritten;
- private State _state;
- private StringBuilder _saved;
- private bool _sawCR;
- private bool _gotit;
- private int _trailerState;
- private List<Chunk> _chunks;
-
- public ChunkStream(WebHeaderCollection headers)
- {
- _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 int Read(byte[] buffer, int offset, int size)
- {
- return ReadFromChunks(buffer, offset, size);
- }
-
- private 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++)
- {
- var 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)
- {
- // Note, the logic here only works when offset is 0 here.
- // Otherwise, it would treat "size" as the end offset instead of an actual byte count from offset.
-
- if (offset < size)
- InternalWrite(buffer, ref offset, size);
- }
-
- private 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 => (_chunkRead != _chunkSize || _chunkSize != 0 || _state != State.None);
-
- public bool DataAvailable
- {
- get
- {
- int count = _chunks.Count;
- for (int i = 0; i < count; i++)
- {
- var ch = _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 => _totalWritten;
-
- public int ChunkLeft => _chunkSize - _chunkRead;
-
- private 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;
- }
-
- private 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 = int.Parse(RemoveChunkExtension(_saved.ToString()), NumberStyles.HexNumber);
- }
- }
- catch (Exception)
- {
- ThrowProtocolViolation("Cannot parse chunk size.");
- }
-
- return State.PartialSize;
- }
-
- _chunkRead = 0;
- try
- {
- _chunkSize = int.Parse(RemoveChunkExtension(_saved.ToString()), NumberStyles.HexNumber);
- }
- catch (Exception)
- {
- ThrowProtocolViolation("Cannot parse chunk size.");
- }
-
- if (_chunkSize == 0)
- {
- _trailerState = 2;
- return State.Trailer;
- }
-
- return State.Body;
- }
-
- private static string RemoveChunkExtension(string input)
- {
- int idx = input.IndexOf(';');
- if (idx == -1)
- return input;
- return input.Substring(0, idx);
- }
-
- private 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;
- }
-
- private 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;
- }
-
- var reader = new StringReader(_saved.ToString());
- string line;
- while ((line = reader.ReadLine()) != null && line != "")
- _headers.Add(line);
-
- return State.None;
- }
-
- private static void ThrowProtocolViolation(string message)
- {
- var we = new WebException(message, null, WebExceptionStatus.ServerProtocolViolation, null);
- throw we;
- }
- }
-}
diff --git a/SocketHttpListener/Net/ChunkedInputStream.cs b/SocketHttpListener/Net/ChunkedInputStream.cs
deleted file mode 100644
index 7aa8529e3..000000000
--- a/SocketHttpListener/Net/ChunkedInputStream.cs
+++ /dev/null
@@ -1,178 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-
-namespace SocketHttpListener.Net
-{
- // Licensed to the .NET Foundation under one or more agreements.
- // See the LICENSE file in the project root for more information.
- //
- // System.Net.ResponseStream
- //
- // Author:
- // Gonzalo Paniagua Javier (gonzalo@novell.com)
- //
- // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
-
- internal sealed class ChunkedInputStream : HttpRequestStream
- {
- private ChunkStream _decoder;
- private readonly HttpListenerContext _context;
- private bool _no_more_data;
-
- private 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)
- {
- _context = context;
- var coll = (WebHeaderCollection)context.Request.Headers;
- _decoder = new ChunkStream(coll);
- }
-
- public ChunkStream Decoder
- {
- get => _decoder;
- set => _decoder = value;
- }
-
- protected override int ReadCore(byte[] buffer, int offset, int count)
- {
- IAsyncResult ares = BeginReadCore(buffer, offset, count, null, null);
- return EndRead(ares);
- }
-
- protected override IAsyncResult BeginReadCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state)
- {
- var ares = new HttpStreamAsyncResult(this);
- ares._callback = cback;
- ares._state = state;
- if (_no_more_data || size == 0 || _closed)
- {
- ares.Complete();
- return ares;
- }
- int nread = _decoder.Read(buffer, offset, size);
- offset += nread;
- size -= nread;
- if (size == 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;
- var rb = new ReadBufferState(buffer, offset, size, ares);
- rb.InitialCount += nread;
- base.BeginReadCore(ares._buffer, ares._offset, ares._count, OnRead, rb);
- return ares;
- }
-
- private void OnRead(IAsyncResult base_ares)
- {
- ReadBufferState rb = (ReadBufferState)base_ares.AsyncState;
- var ares = rb.Ares;
- try
- {
- int nread = base.EndRead(base_ares);
- if (nread == 0)
- {
- _no_more_data = true;
- ares._count = rb.InitialCount - rb.Count;
- ares.Complete();
- return;
- }
-
- _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)
- {
- _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.BeginReadCore(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 asyncResult)
- {
- if (asyncResult == null)
- throw new ArgumentNullException(nameof(asyncResult));
-
- var ares = asyncResult as HttpStreamAsyncResult;
- if (ares == null || !ReferenceEquals(this, ares._parent))
- {
- throw new ArgumentException("Invalid async result");
- }
- if (ares._endCalled)
- {
- throw new InvalidOperationException("Invalid end call");
- }
- ares._endCalled = true;
-
- if (!asyncResult.IsCompleted)
- asyncResult.AsyncWaitHandle.WaitOne();
-
- if (ares._error != null)
- throw new HttpListenerException((int)HttpStatusCode.BadRequest, "Operation aborted");
-
- return ares._count;
- }
- }
-}
diff --git a/SocketHttpListener/Net/EntitySendFormat.cs b/SocketHttpListener/Net/EntitySendFormat.cs
deleted file mode 100644
index 3ed981084..000000000
--- a/SocketHttpListener/Net/EntitySendFormat.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace SocketHttpListener.Net
-{
- internal enum EntitySendFormat
- {
- ContentLength = 0, // Content-Length: XXX
- Chunked = 1, // Transfer-Encoding: chunked
- }
-}
diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs
deleted file mode 100644
index e89f4ed9b..000000000
--- a/SocketHttpListener/Net/HttpConnection.cs
+++ /dev/null
@@ -1,528 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Security;
-using System.Net.Sockets;
-using System.Security.Authentication;
-using System.Security.Cryptography.X509Certificates;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.System;
-using Microsoft.Extensions.Logging;
-namespace SocketHttpListener.Net
-{
- sealed class HttpConnection
- {
- private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead);
- const int BufferSize = 8192;
- Socket _socket;
- Stream _stream;
- HttpEndPointListener _epl;
- MemoryStream _memoryStream;
- byte[] _buffer;
- HttpListenerContext _context;
- StringBuilder _currentLine;
- ListenerPrefix _prefix;
- HttpRequestStream _requestStream;
- HttpResponseStream _responseStream;
- bool _chunked;
- int _reuses;
- bool _contextBound;
- bool secure;
- IPEndPoint local_ep;
- HttpListener _lastListener;
- X509Certificate cert;
- SslStream ssl_stream;
-
- private readonly ILogger _logger;
- private readonly ICryptoProvider _cryptoProvider;
- private readonly IStreamHelper _streamHelper;
- private readonly IFileSystem _fileSystem;
- private readonly IEnvironmentInfo _environment;
-
- public HttpConnection(ILogger logger, Socket socket, HttpEndPointListener epl, bool secure,
- X509Certificate cert, ICryptoProvider cryptoProvider, IStreamHelper streamHelper, IFileSystem fileSystem,
- IEnvironmentInfo environment)
- {
- _logger = logger;
- this._socket = socket;
- this._epl = epl;
- this.secure = secure;
- this.cert = cert;
- _cryptoProvider = cryptoProvider;
- _streamHelper = streamHelper;
- _fileSystem = fileSystem;
- _environment = environment;
-
- if (secure == false)
- {
- _stream = new SocketStream(_socket, false);
- }
- else
- {
- ssl_stream = new SslStream(new SocketStream(_socket, false), false, (t, c, ch, e) =>
- {
- if (c == null)
- {
- return true;
- }
-
- //var c2 = c as X509Certificate2;
- //if (c2 == null)
- //{
- // c2 = new X509Certificate2(c.GetRawCertData());
- //}
-
- //_clientCert = c2;
- //_clientCertErrors = new int[] { (int)e };
- return true;
- });
-
- _stream = ssl_stream;
- }
- }
-
- public Stream Stream => _stream;
-
- public async Task Init()
- {
- if (ssl_stream != null)
- {
- var enableAsync = true;
- if (enableAsync)
- {
- await ssl_stream.AuthenticateAsServerAsync(cert, false, (SslProtocols)ServicePointManager.SecurityProtocol, false).ConfigureAwait(false);
- }
- else
- {
- ssl_stream.AuthenticateAsServer(cert, false, (SslProtocols)ServicePointManager.SecurityProtocol, false);
- }
- }
-
- InitInternal();
- }
-
- private void InitInternal()
- {
- _contextBound = false;
- _requestStream = null;
- _responseStream = null;
- _prefix = null;
- _chunked = false;
- _memoryStream = new MemoryStream();
- _position = 0;
- _inputState = InputState.RequestLine;
- _lineState = LineState.None;
- _context = new HttpListenerContext(this);
- }
-
- public bool IsClosed => (_socket == null);
-
- public int Reuses => _reuses;
-
- public IPEndPoint LocalEndPoint
- {
- get
- {
- if (local_ep != null)
- return local_ep;
-
- local_ep = (IPEndPoint)_socket.LocalEndPoint;
- return local_ep;
- }
- }
-
- public IPEndPoint RemoteEndPoint => _socket.RemoteEndPoint as IPEndPoint;
-
- public bool IsSecure => secure;
-
- public ListenerPrefix Prefix
- {
- get => _prefix;
- set => _prefix = value;
- }
-
- private void OnTimeout(object unused)
- {
- //_logger.LogInformation("HttpConnection timer fired");
- CloseSocket();
- Unbind();
- }
-
- public void BeginReadRequest()
- {
- if (_buffer == null)
- _buffer = new byte[BufferSize];
- try
- {
- _stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this);
- }
- catch
- {
- CloseSocket();
- Unbind();
- }
- }
-
- public HttpRequestStream GetRequestStream(bool chunked, long contentlength)
- {
- if (_requestStream == null)
- {
- byte[] buffer = _memoryStream.GetBuffer();
- int length = (int)_memoryStream.Length;
- _memoryStream = null;
- if (chunked)
- {
- _chunked = true;
- //_context.Response.SendChunked = true;
- _requestStream = new ChunkedInputStream(_context, _stream, buffer, _position, length - _position);
- }
- else
- {
- _requestStream = new HttpRequestStream(_stream, buffer, _position, length - _position, contentlength);
- }
- }
- return _requestStream;
- }
-
- public HttpResponseStream GetResponseStream(bool isExpect100Continue = false)
- {
- // TODO: can we get this _stream before reading the input?
- if (_responseStream == null)
- {
- var supportsDirectSocketAccess = !_context.Response.SendChunked && !isExpect100Continue && !secure;
-
- _responseStream = new HttpResponseStream(_stream, _context.Response, false, _streamHelper, _socket, supportsDirectSocketAccess, _environment, _fileSystem, _logger);
- }
- return _responseStream;
- }
-
- private static void OnRead(IAsyncResult ares)
- {
- var cnc = (HttpConnection)ares.AsyncState;
- cnc.OnReadInternal(ares);
- }
-
- private void OnReadInternal(IAsyncResult ares)
- {
- int nread = -1;
- try
- {
- nread = _stream.EndRead(ares);
- _memoryStream.Write(_buffer, 0, nread);
- if (_memoryStream.Length > 32768)
- {
- SendError("Bad Request", 400);
- Close(true);
- return;
- }
- }
- catch
- {
- if (_memoryStream != null && _memoryStream.Length > 0)
- SendError();
- if (_socket != null)
- {
- CloseSocket();
- Unbind();
- }
- return;
- }
-
- if (nread == 0)
- {
- CloseSocket();
- Unbind();
- return;
- }
-
- if (ProcessInput(_memoryStream))
- {
- if (!_context.HaveError)
- _context.Request.FinishInitialization();
-
- if (_context.HaveError)
- {
- SendError();
- Close(true);
- return;
- }
-
- if (!_epl.BindContext(_context))
- {
- const int NotFoundErrorCode = 404;
- SendError(HttpStatusDescription.Get(NotFoundErrorCode), NotFoundErrorCode);
- Close(true);
- return;
- }
- HttpListener listener = _epl.Listener;
- if (_lastListener != listener)
- {
- RemoveConnection();
- listener.AddConnection(this);
- _lastListener = listener;
- }
-
- _contextBound = true;
- listener.RegisterContext(_context);
- return;
- }
- _stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this);
- }
-
- private void RemoveConnection()
- {
- if (_lastListener == null)
- _epl.RemoveConnection(this);
- else
- _lastListener.RemoveConnection(this);
- }
-
- private enum InputState
- {
- RequestLine,
- Headers
- }
-
- private enum LineState
- {
- None,
- CR,
- LF
- }
-
- InputState _inputState = InputState.RequestLine;
- LineState _lineState = LineState.None;
- int _position;
-
- // true -> done processing
- // false -> need more input
- private bool ProcessInput(MemoryStream ms)
- {
- byte[] buffer = ms.GetBuffer();
- 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 (_inputState == InputState.RequestLine)
- continue;
- _currentLine = null;
- ms = null;
- return true;
- }
-
- if (_inputState == InputState.RequestLine)
- {
- _context.Request.SetRequestLine(line);
- _inputState = 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;
- }
-
- private string ReadLine(byte[] buffer, int offset, int len, ref int used)
- {
- if (_currentLine == null)
- _currentLine = new StringBuilder(128);
- int last = offset + len;
- used = 0;
- for (int i = offset; i < last && _lineState != LineState.LF; i++)
- {
- used++;
- byte b = buffer[i];
- if (b == 13)
- {
- _lineState = LineState.CR;
- }
- else if (b == 10)
- {
- _lineState = LineState.LF;
- }
- else
- {
- _currentLine.Append((char)b);
- }
- }
-
- string result = null;
- if (_lineState == LineState.LF)
- {
- _lineState = LineState.None;
- result = _currentLine.ToString();
- _currentLine.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 = HttpStatusDescription.Get(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 = Encoding.UTF8.GetBytes(str);
- response.Close(error, false);
- }
- catch
- {
- // response was already closed
- }
- }
-
- public void SendError()
- {
- SendError(_context.ErrorMessage, _context.ErrorStatus);
- }
-
- private void Unbind()
- {
- if (_contextBound)
- {
- _epl.UnbindContext(_context);
- _contextBound = false;
- }
- }
-
- public void Close()
- {
- Close(false);
- }
-
- private void CloseSocket()
- {
- if (_socket == null)
- return;
-
- try
- {
- _socket.Close();
- }
- catch { }
- finally
- {
- _socket = null;
- }
-
- RemoveConnection();
- }
-
- internal void Close(bool force)
- {
- if (_socket != null)
- {
- Stream st = GetResponseStream();
- if (st != null)
- st.Close();
-
- _responseStream = null;
- }
-
- if (_socket != null)
- {
- force |= !_context.Request.KeepAlive;
- if (!force)
- force = (string.Equals(_context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase));
-
- if (!force && _context.Request.FlushInput())
- {
- if (_chunked && _context.Response.ForceCloseChunked == false)
- {
- // Don't close. Keep working.
- _reuses++;
- Unbind();
- InitInternal();
- BeginReadRequest();
- return;
- }
-
- _reuses++;
- Unbind();
- InitInternal();
- BeginReadRequest();
- return;
- }
-
- Socket s = _socket;
- _socket = null;
- try
- {
- if (s != null)
- s.Shutdown(SocketShutdown.Both);
- }
- catch
- {
- }
- finally
- {
- if (s != null)
- {
- try
- {
- s.Close();
- }
- catch { }
- }
- }
- Unbind();
- RemoveConnection();
- return;
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpEndPointListener.cs b/SocketHttpListener/Net/HttpEndPointListener.cs
deleted file mode 100644
index 35d1af648..000000000
--- a/SocketHttpListener/Net/HttpEndPointListener.cs
+++ /dev/null
@@ -1,526 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Net;
-using System.Net.Sockets;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using Microsoft.Extensions.Logging;
-
-namespace SocketHttpListener.Net
-{
- internal sealed class HttpEndPointListener
- {
- private HttpListener _listener;
- private IPEndPoint _endpoint;
- private Socket _socket;
- private Dictionary<ListenerPrefix, HttpListener> _prefixes;
- private List<ListenerPrefix> _unhandledPrefixes; // host = '*'
- private List<ListenerPrefix> _allPrefixes; // host = '+'
- private X509Certificate _cert;
- private bool _secure;
- private Dictionary<HttpConnection, HttpConnection> _unregisteredConnections;
-
- private readonly ILogger _logger;
- private bool _closed;
- private bool _enableDualMode;
- private readonly ICryptoProvider _cryptoProvider;
- private readonly ISocketFactory _socketFactory;
- private readonly IStreamHelper _streamHelper;
- private readonly IFileSystem _fileSystem;
- private readonly IEnvironmentInfo _environment;
-
- public HttpEndPointListener(HttpListener listener, IPAddress addr, int port, bool secure, X509Certificate cert,
- ILogger logger, ICryptoProvider cryptoProvider, ISocketFactory socketFactory, IStreamHelper streamHelper,
- IFileSystem fileSystem, IEnvironmentInfo environment)
- {
- this._listener = listener;
- _logger = logger;
- _cryptoProvider = cryptoProvider;
- _socketFactory = socketFactory;
- _streamHelper = streamHelper;
- _fileSystem = fileSystem;
- _environment = environment;
-
- this._secure = secure;
- this._cert = cert;
-
- _enableDualMode = addr.Equals(IPAddress.IPv6Any);
- _endpoint = new IPEndPoint(addr, port);
-
- _prefixes = new Dictionary<ListenerPrefix, HttpListener>();
- _unregisteredConnections = new Dictionary<HttpConnection, HttpConnection>();
-
- CreateSocket();
- }
-
- internal HttpListener Listener => _listener;
-
- private void CreateSocket()
- {
- try
- {
- _socket = CreateSocket(_endpoint.Address.AddressFamily, _enableDualMode);
- }
- catch (SocketCreateException ex)
- {
- if (_enableDualMode && _endpoint.Address.Equals(IPAddress.IPv6Any) &&
- (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) ||
- // mono 4.8.1 and lower on bsd is throwing this
- string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase) ||
- // mono 5.2 on bsd is throwing this
- string.Equals(ex.ErrorCode, "OperationNotSupported", StringComparison.OrdinalIgnoreCase)))
- {
- _endpoint = new IPEndPoint(IPAddress.Any, _endpoint.Port);
- _enableDualMode = false;
- _socket = CreateSocket(_endpoint.Address.AddressFamily, _enableDualMode);
- }
- else
- {
- throw;
- }
- }
-
- try
- {
- _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
- }
- catch (SocketException)
- {
- // This is not supported on all operating systems (qnap)
- }
-
- _socket.Bind(_endpoint);
-
- // This is the number TcpListener uses.
- _socket.Listen(2147483647);
-
- Accept();
-
- _closed = false;
- }
-
- private void Accept()
- {
- var acceptEventArg = new SocketAsyncEventArgs();
- acceptEventArg.UserToken = this;
- acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnAccept);
-
- Accept(acceptEventArg);
- }
-
- private static void TryCloseAndDispose(Socket socket)
- {
- try
- {
- using (socket)
- {
- socket.Close();
- }
- }
- catch
- {
-
- }
- }
-
- private static void TryClose(Socket socket)
- {
- try
- {
- socket.Close();
- }
- catch
- {
-
- }
- }
-
- private void Accept(SocketAsyncEventArgs acceptEventArg)
- {
- // acceptSocket must be cleared since the context object is being reused
- acceptEventArg.AcceptSocket = null;
-
- try
- {
- bool willRaiseEvent = _socket.AcceptAsync(acceptEventArg);
-
- if (!willRaiseEvent)
- {
- ProcessAccept(acceptEventArg);
- }
- }
- catch (ObjectDisposedException)
- {
- // TODO Investigate or properly fix.
- }
- catch (Exception ex)
- {
- var epl = (HttpEndPointListener)acceptEventArg.UserToken;
-
- epl._logger.LogError(ex, "Error in socket.AcceptAsync");
- }
- }
-
- // This method is the callback method associated with Socket.AcceptAsync
- // operations and is invoked when an accept operation is complete
- //
- private static void OnAccept(object sender, SocketAsyncEventArgs e)
- {
- ProcessAccept(e);
- }
-
- private static async void ProcessAccept(SocketAsyncEventArgs args)
- {
- var epl = (HttpEndPointListener)args.UserToken;
-
- if (epl._closed)
- {
- return;
- }
-
- // http://msdn.microsoft.com/en-us/library/system.net.sockets.acceptSocket.acceptasync%28v=vs.110%29.aspx
- // Under certain conditions ConnectionReset can occur
- // Need to attept to re-accept
- var socketError = args.SocketError;
- var accepted = args.AcceptSocket;
-
- epl.Accept(args);
-
- if (socketError == SocketError.ConnectionReset)
- {
- epl._logger.LogError("SocketError.ConnectionReset reported. Attempting to re-accept.");
- return;
- }
-
- if (accepted == null)
- {
- return;
- }
-
- if (epl._secure && epl._cert == null)
- {
- TryClose(accepted);
- return;
- }
-
- try
- {
- var remoteEndPointString = accepted.RemoteEndPoint == null ? string.Empty : accepted.RemoteEndPoint.ToString();
- var localEndPointString = accepted.LocalEndPoint == null ? string.Empty : accepted.LocalEndPoint.ToString();
- //_logger.LogInformation("HttpEndPointListener Accepting connection from {0} to {1} secure connection requested: {2}", remoteEndPointString, localEndPointString, _secure);
-
- var conn = new HttpConnection(epl._logger, accepted, epl, epl._secure, epl._cert, epl._cryptoProvider, epl._streamHelper, epl._fileSystem, epl._environment);
-
- await conn.Init().ConfigureAwait(false);
-
- //_logger.LogDebug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
- lock (epl._unregisteredConnections)
- {
- epl._unregisteredConnections[conn] = conn;
- }
- conn.BeginReadRequest();
- }
- catch (Exception ex)
- {
- epl._logger.LogError(ex, "Error in ProcessAccept");
-
- TryClose(accepted);
- epl.Accept();
- return;
- }
- }
-
- private Socket CreateSocket(AddressFamily addressFamily, bool dualMode)
- {
- try
- {
- var socket = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
-
- if (dualMode)
- {
- socket.DualMode = true;
- }
-
- return socket;
- }
- catch (SocketException ex)
- {
- throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
- }
- catch (ArgumentException ex)
- {
- if (dualMode)
- {
- // Mono for BSD incorrectly throws ArgumentException instead of SocketException
- throw new SocketCreateException("AddressFamilyNotSupported", ex);
- }
- else
- {
- throw;
- }
- }
- }
-
- internal void RemoveConnection(HttpConnection conn)
- {
- lock (_unregisteredConnections)
- {
- _unregisteredConnections.Remove(conn);
- }
- }
-
- public bool BindContext(HttpListenerContext context)
- {
- var req = context.Request;
- HttpListener listener = SearchListener(req.Url, out var 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);
- }
-
- private 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 pathSlash = path[path.Length - 1] == '/' ? path : path + "/";
-
- HttpListener bestMatch = null;
- int bestLength = -1;
-
- if (host != null && host != "")
- {
- Dictionary<ListenerPrefix, HttpListener> localPrefixes = _prefixes;
- foreach (var p in localPrefixes.Keys)
- {
- string ppath = p.Path;
- if (ppath.Length < bestLength)
- continue;
-
- if (p.Host != host || p.Port != port)
- continue;
-
- if (path.StartsWith(ppath) || pathSlash.StartsWith(ppath))
- {
- bestLength = ppath.Length;
- bestMatch = localPrefixes[p];
- prefix = p;
- }
- }
- if (bestLength != -1)
- return bestMatch;
- }
-
- List<ListenerPrefix> list = _unhandledPrefixes;
- bestMatch = MatchFromList(host, path, list, out prefix);
-
- if (path != pathSlash && bestMatch == null)
- bestMatch = MatchFromList(host, pathSlash, list, out prefix);
-
- if (bestMatch != null)
- return bestMatch;
-
- list = _allPrefixes;
- bestMatch = MatchFromList(host, path, list, out prefix);
-
- if (path != pathSlash && bestMatch == null)
- bestMatch = MatchFromList(host, pathSlash, list, out prefix);
-
- if (bestMatch != null)
- return bestMatch;
-
- return null;
- }
-
- private HttpListener MatchFromList(string host, string path, List<ListenerPrefix> list, out ListenerPrefix prefix)
- {
- prefix = null;
- if (list == null)
- return null;
-
- HttpListener bestMatch = null;
- int bestLength = -1;
-
- foreach (ListenerPrefix p in list)
- {
- string ppath = p.Path;
- if (ppath.Length < bestLength)
- continue;
-
- if (path.StartsWith(ppath))
- {
- bestLength = ppath.Length;
- bestMatch = p._listener;
- prefix = p;
- }
- }
-
- return bestMatch;
- }
-
- private void AddSpecial(List<ListenerPrefix> list, ListenerPrefix prefix)
- {
- if (list == null)
- return;
-
- foreach (ListenerPrefix p in list)
- {
- if (p.Path == prefix.Path)
- throw new Exception("net_listener_already");
- }
- list.Add(prefix);
- }
-
- private bool RemoveSpecial(List<ListenerPrefix> list, ListenerPrefix prefix)
- {
- if (list == null)
- return false;
-
- int c = list.Count;
- for (int i = 0; i < c; i++)
- {
- ListenerPrefix p = list[i];
- if (p.Path == prefix.Path)
- {
- list.RemoveAt(i);
- return true;
- }
- }
- return false;
- }
-
- private void CheckIfRemove()
- {
- if (_prefixes.Count > 0)
- return;
-
- List<ListenerPrefix> list = _unhandledPrefixes;
- if (list != null && list.Count > 0)
- return;
-
- list = _allPrefixes;
- if (list != null && list.Count > 0)
- return;
-
- HttpEndPointManager.RemoveEndPoint(this, _endpoint);
- }
-
- public void Close()
- {
- _closed = true;
- _socket.Close();
- lock (_unregisteredConnections)
- {
- // Clone the list because RemoveConnection can be called from Close
- var connections = new List<HttpConnection>(_unregisteredConnections.Keys);
-
- foreach (HttpConnection c in connections)
- c.Close(true);
- _unregisteredConnections.Clear();
- }
- }
-
- public void AddPrefix(ListenerPrefix prefix, HttpListener listener)
- {
- List<ListenerPrefix> current;
- List<ListenerPrefix> future;
- if (prefix.Host == "*")
- {
- do
- {
- current = _unhandledPrefixes;
- future = current != null ? new List<ListenerPrefix>(current) : new List<ListenerPrefix>();
- prefix._listener = listener;
- AddSpecial(future, prefix);
- } while (Interlocked.CompareExchange(ref _unhandledPrefixes, future, current) != current);
- return;
- }
-
- if (prefix.Host == "+")
- {
- do
- {
- current = _allPrefixes;
- future = current != null ? new List<ListenerPrefix>(current) : new List<ListenerPrefix>();
- prefix._listener = listener;
- AddSpecial(future, prefix);
- } while (Interlocked.CompareExchange(ref _allPrefixes, future, current) != current);
- return;
- }
-
- Dictionary<ListenerPrefix, HttpListener> prefs, p2;
- do
- {
- prefs = _prefixes;
- if (prefs.ContainsKey(prefix))
- {
- throw new Exception("net_listener_already");
- }
- 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 = _unhandledPrefixes;
- future = current != null ? new List<ListenerPrefix>(current) : new List<ListenerPrefix>();
- if (!RemoveSpecial(future, prefix))
- break; // Prefix not found
- } while (Interlocked.CompareExchange(ref _unhandledPrefixes, future, current) != current);
-
- CheckIfRemove();
- return;
- }
-
- if (prefix.Host == "+")
- {
- do
- {
- current = _allPrefixes;
- future = current != null ? new List<ListenerPrefix>(current) : new List<ListenerPrefix>();
- if (!RemoveSpecial(future, prefix))
- break; // Prefix not found
- } while (Interlocked.CompareExchange(ref _allPrefixes, future, current) != current);
- CheckIfRemove();
- return;
- }
-
- Dictionary<ListenerPrefix, HttpListener> prefs, 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/Net/HttpEndPointManager.cs b/SocketHttpListener/Net/HttpEndPointManager.cs
deleted file mode 100644
index 27b4244a6..000000000
--- a/SocketHttpListener/Net/HttpEndPointManager.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Net;
-using System.Net.Sockets;
-using Microsoft.Extensions.Logging;
-
-namespace SocketHttpListener.Net
-{
- internal sealed class HttpEndPointManager
- {
- private static Dictionary<IPAddress, Dictionary<int, HttpEndPointListener>> s_ipEndPoints = new Dictionary<IPAddress, Dictionary<int, HttpEndPointListener>>();
-
- private HttpEndPointManager()
- {
- }
-
- public static void AddListener(ILogger logger, HttpListener listener)
- {
- var added = new List<string>();
- try
- {
- lock ((s_ipEndPoints as ICollection).SyncRoot)
- {
- 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 ((s_ipEndPoints as ICollection).SyncRoot)
- {
- AddPrefixInternal(logger, prefix, listener);
- }
- }
-
- private static void AddPrefixInternal(ILogger logger, string p, HttpListener listener)
- {
- int start = p.IndexOf(':') + 3;
- int colon = p.IndexOf(':', start);
- if (colon != -1)
- {
- // root can't be -1 here, since we've already checked for ending '/' in ListenerPrefix.
- int root = p.IndexOf('/', colon, p.Length - colon);
- string portString = p.Substring(colon + 1, root - colon - 1);
-
- if (!int.TryParse(portString, out var port) || port <= 0 || port >= 65536)
- {
- throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_port");
- }
- }
-
- var lp = new ListenerPrefix(p);
- if (lp.Host != "*" && lp.Host != "+" && Uri.CheckHostName(lp.Host) == UriHostNameType.Unknown)
- throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_listener_host");
-
- if (lp.Path.IndexOf('%') != -1)
- throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_path");
-
- if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
- throw new HttpListenerException((int)HttpStatusCode.BadRequest, "net_invalid_path");
-
- // listens on all the interfaces if host name cannot be parsed by IPAddress.
- HttpEndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure);
- epl.AddPrefix(lp, listener);
- }
-
- private static IPAddress GetIpAnyAddress(HttpListener listener)
- {
- return listener.EnableDualMode ? IPAddress.IPv6Any : IPAddress.Any;
- }
-
- private static HttpEndPointListener GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure)
- {
- IPAddress addr;
- if (host == "*" || host == "+")
- {
- addr = GetIpAnyAddress(listener);
- }
- else
- {
- const int NotSupportedErrorCode = 50;
- try
- {
- addr = Dns.GetHostAddresses(host)[0];
- }
- catch
- {
- // Throw same error code as windows, request is not supported.
- throw new HttpListenerException(NotSupportedErrorCode, "net_listener_not_supported");
- }
-
- if (IPAddress.Any.Equals(addr))
- {
- // Don't support listening to 0.0.0.0, match windows behavior.
- throw new HttpListenerException(NotSupportedErrorCode, "net_listener_not_supported");
- }
- }
-
- Dictionary<int, HttpEndPointListener> p = null;
- if (s_ipEndPoints.ContainsKey(addr))
- {
- p = s_ipEndPoints[addr];
- }
- else
- {
- p = new Dictionary<int, HttpEndPointListener>();
- s_ipEndPoints[addr] = p;
- }
-
- HttpEndPointListener epl = null;
- if (p.ContainsKey(port))
- {
- epl = p[port];
- }
- else
- {
- try
- {
- epl = new HttpEndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.SocketFactory, listener.StreamHelper, listener.FileSystem, listener.EnvironmentInfo);
- }
- catch (SocketException ex)
- {
- throw new HttpListenerException(ex.ErrorCode, ex.Message);
- }
- p[port] = epl;
- }
-
- return epl;
- }
-
- public static void RemoveEndPoint(HttpEndPointListener epl, IPEndPoint ep)
- {
- lock ((s_ipEndPoints as ICollection).SyncRoot)
- {
- Dictionary<int, HttpEndPointListener> p = null;
- p = s_ipEndPoints[ep.Address];
- p.Remove(ep.Port);
- if (p.Count == 0)
- {
- s_ipEndPoints.Remove(ep.Address);
- }
- epl.Close();
- }
- }
-
- public static void RemoveListener(ILogger logger, HttpListener listener)
- {
- lock ((s_ipEndPoints as ICollection).SyncRoot)
- {
- foreach (string prefix in listener.Prefixes)
- {
- RemovePrefixInternal(logger, prefix, listener);
- }
- }
- }
-
- public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener)
- {
- lock ((s_ipEndPoints as ICollection).SyncRoot)
- {
- RemovePrefixInternal(logger, prefix, listener);
- }
- }
-
- private static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener)
- {
- var lp = new ListenerPrefix(prefix);
- if (lp.Path.IndexOf('%') != -1)
- return;
-
- if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1)
- return;
-
- HttpEndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure);
- epl.RemovePrefix(lp, listener);
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpKnownHeaderNames.cs b/SocketHttpListener/Net/HttpKnownHeaderNames.cs
deleted file mode 100644
index dc6f2ce41..000000000
--- a/SocketHttpListener/Net/HttpKnownHeaderNames.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-namespace SocketHttpListener.Net
-{
- internal static partial class HttpKnownHeaderNames
- {
- // When adding a new constant, add it to HttpKnownHeaderNames.TryGetHeaderName.cs as well.
-
- public const string Accept = "Accept";
- public const string AcceptCharset = "Accept-Charset";
- public const string AcceptEncoding = "Accept-Encoding";
- public const string AcceptLanguage = "Accept-Language";
- public const string AcceptPatch = "Accept-Patch";
- public const string AcceptRanges = "Accept-Ranges";
- public const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
- public const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
- public const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
- public const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
- public const string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
- public const string AccessControlMaxAge = "Access-Control-Max-Age";
- public const string Age = "Age";
- public const string Allow = "Allow";
- public const string AltSvc = "Alt-Svc";
- public const string Authorization = "Authorization";
- public const string CacheControl = "Cache-Control";
- public const string Connection = "Connection";
- public const string ContentDisposition = "Content-Disposition";
- public const string ContentEncoding = "Content-Encoding";
- public const string ContentLanguage = "Content-Language";
- public const string ContentLength = "Content-Length";
- public const string ContentLocation = "Content-Location";
- public const string ContentMD5 = "Content-MD5";
- public const string ContentRange = "Content-Range";
- public const string ContentSecurityPolicy = "Content-Security-Policy";
- public const string ContentType = "Content-Type";
- public const string Cookie = "Cookie";
- public const string Cookie2 = "Cookie2";
- public const string Date = "Date";
- public const string ETag = "ETag";
- public const string Expect = "Expect";
- public const string Expires = "Expires";
- public const string From = "From";
- public const string Host = "Host";
- public const string IfMatch = "If-Match";
- public const string IfModifiedSince = "If-Modified-Since";
- public const string IfNoneMatch = "If-None-Match";
- public const string IfRange = "If-Range";
- public const string IfUnmodifiedSince = "If-Unmodified-Since";
- public const string KeepAlive = "Keep-Alive";
- public const string LastModified = "Last-Modified";
- public const string Link = "Link";
- public const string Location = "Location";
- public const string MaxForwards = "Max-Forwards";
- public const string Origin = "Origin";
- public const string P3P = "P3P";
- public const string Pragma = "Pragma";
- public const string ProxyAuthenticate = "Proxy-Authenticate";
- public const string ProxyAuthorization = "Proxy-Authorization";
- public const string ProxyConnection = "Proxy-Connection";
- public const string PublicKeyPins = "Public-Key-Pins";
- public const string Range = "Range";
- public const string Referer = "Referer"; // NB: The spelling-mistake "Referer" for "Referrer" must be matched.
- public const string RetryAfter = "Retry-After";
- public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
- public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
- public const string SecWebSocketKey = "Sec-WebSocket-Key";
- public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
- public const string SecWebSocketVersion = "Sec-WebSocket-Version";
- public const string Server = "Server";
- public const string SetCookie = "Set-Cookie";
- public const string SetCookie2 = "Set-Cookie2";
- public const string StrictTransportSecurity = "Strict-Transport-Security";
- public const string TE = "TE";
- public const string TSV = "TSV";
- public const string Trailer = "Trailer";
- public const string TransferEncoding = "Transfer-Encoding";
- public const string Upgrade = "Upgrade";
- public const string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
- public const string UserAgent = "User-Agent";
- public const string Vary = "Vary";
- public const string Via = "Via";
- public const string WWWAuthenticate = "WWW-Authenticate";
- public const string Warning = "Warning";
- public const string XAspNetVersion = "X-AspNet-Version";
- public const string XContentDuration = "X-Content-Duration";
- public const string XContentTypeOptions = "X-Content-Type-Options";
- public const string XFrameOptions = "X-Frame-Options";
- public const string XMSEdgeRef = "X-MSEdge-Ref";
- public const string XPoweredBy = "X-Powered-By";
- public const string XRequestID = "X-Request-ID";
- public const string XUACompatible = "X-UA-Compatible";
- }
-}
diff --git a/SocketHttpListener/Net/HttpListener.cs b/SocketHttpListener/Net/HttpListener.cs
deleted file mode 100644
index f17036a21..000000000
--- a/SocketHttpListener/Net/HttpListener.cs
+++ /dev/null
@@ -1,284 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Net;
-using System.Security.Cryptography.X509Certificates;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using Microsoft.Extensions.Logging;
-
-namespace SocketHttpListener.Net
-{
- public sealed class HttpListener : IDisposable
- {
- internal ICryptoProvider CryptoProvider { get; private set; }
- internal ISocketFactory SocketFactory { get; private set; }
- internal IFileSystem FileSystem { get; private set; }
- internal IStreamHelper StreamHelper { get; private set; }
- internal IEnvironmentInfo EnvironmentInfo { get; private set; }
-
- public bool EnableDualMode { get; set; }
-
- private AuthenticationSchemes auth_schemes;
- private HttpListenerPrefixCollection prefixes;
- private AuthenticationSchemeSelector auth_selector;
- private string realm;
- private bool unsafe_ntlm_auth;
- private bool listening;
- private bool disposed;
-
- private Dictionary<HttpListenerContext, HttpListenerContext> registry;
- private Dictionary<HttpConnection, HttpConnection> connections;
- private ILogger _logger;
- private X509Certificate _certificate;
-
- public Action<HttpListenerContext> OnContext { get; set; }
-
- public HttpListener(
- ILogger logger,
- ICryptoProvider cryptoProvider,
- ISocketFactory socketFactory,
- IStreamHelper streamHelper,
- IFileSystem fileSystem,
- IEnvironmentInfo environmentInfo)
- {
- _logger = logger;
- CryptoProvider = cryptoProvider;
- SocketFactory = socketFactory;
- StreamHelper = streamHelper;
- 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(
- ILogger logger,
- X509Certificate certificate,
- ICryptoProvider cryptoProvider,
- ISocketFactory socketFactory,
- IStreamHelper streamHelper,
- IFileSystem fileSystem,
- IEnvironmentInfo environmentInfo)
- : this(logger, cryptoProvider, socketFactory, streamHelper, fileSystem, environmentInfo)
- {
- _certificate = certificate;
- }
-
- public void LoadCert(X509Certificate cert)
- {
- _certificate = cert;
- }
-
- // TODO: Digest, NTLM and Negotiate require ControlPrincipal
- public AuthenticationSchemes AuthenticationSchemes
- {
- get => auth_schemes;
- set
- {
- CheckDisposed();
- auth_schemes = value;
- }
- }
-
- public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate
- {
- get => auth_selector;
- set
- {
- CheckDisposed();
- auth_selector = value;
- }
- }
-
- public bool IsListening => listening;
-
- public static bool IsSupported => true;
-
- public HttpListenerPrefixCollection Prefixes
- {
- get
- {
- CheckDisposed();
- return prefixes;
- }
- }
-
- // TODO: use this
- public string Realm
- {
- get => realm;
- set
- {
- CheckDisposed();
- realm = value;
- }
- }
-
- public bool UnsafeConnectionNtlmAuthentication
- {
- get => 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 X509Certificate Certificate => _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();
- HttpEndPointManager.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;
-
- HttpEndPointManager.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().Name);
- }
-
- 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/Net/HttpListenerBasicIdentity.cs b/SocketHttpListener/Net/HttpListenerBasicIdentity.cs
deleted file mode 100644
index 5f6ec44b9..000000000
--- a/SocketHttpListener/Net/HttpListenerBasicIdentity.cs
+++ /dev/null
@@ -1,49 +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 => password;
- }
-
- public class GenericIdentity : IIdentity
- {
- private string m_name;
- private string m_type;
-
- public GenericIdentity(string name)
- {
- if (name == null)
- throw new System.ArgumentNullException(nameof(name));
-
- m_name = name;
- m_type = "";
- }
-
- public GenericIdentity(string name, string type)
- {
- if (name == null)
- throw new System.ArgumentNullException(nameof(name));
- if (type == null)
- throw new System.ArgumentNullException(nameof(type));
-
- m_name = name;
- m_type = type;
- }
-
- public virtual string Name => m_name;
-
- public virtual string AuthenticationType => m_type;
-
- public virtual bool IsAuthenticated => !m_name.Equals("");
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerContext.Managed.cs b/SocketHttpListener/Net/HttpListenerContext.Managed.cs
deleted file mode 100644
index 79742bf37..000000000
--- a/SocketHttpListener/Net/HttpListenerContext.Managed.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Security.Principal;
-using System.Text;
-using System.Threading.Tasks;
-using SocketHttpListener.Net.WebSockets;
-
-namespace SocketHttpListener.Net
-{
- public sealed partial class HttpListenerContext
- {
- private HttpConnection _connection;
-
- internal HttpListenerContext(HttpConnection connection)
- {
- _connection = connection;
- _response = new HttpListenerResponse(this);
- Request = new HttpListenerRequest(this);
- ErrorStatus = 400;
- }
-
- internal int ErrorStatus { get; set; }
-
- internal string ErrorMessage { get; set; }
-
- internal bool HaveError => ErrorMessage != null;
-
- internal HttpConnection Connection => _connection;
-
- internal void ParseAuthentication(System.Net.AuthenticationSchemes expectedSchemes)
- {
- if (expectedSchemes == System.Net.AuthenticationSchemes.Anonymous)
- return;
-
- string header = Request.Headers["Authorization"];
- if (string.IsNullOrEmpty(header))
- return;
-
- if (IsBasicHeader(header))
- {
- _user = ParseBasicAuthentication(header.Substring(AuthenticationTypes.Basic.Length + 1));
- }
- }
-
- internal IPrincipal ParseBasicAuthentication(string authData) =>
- TryParseBasicAuth(authData, out HttpStatusCode errorCode, out string username, out string password) ?
- new GenericPrincipal(new HttpListenerBasicIdentity(username, password), Array.Empty<string>()) :
- null;
-
- internal static bool IsBasicHeader(string header) =>
- header.Length >= 6 &&
- header[5] == ' ' &&
- string.Compare(header, 0, AuthenticationTypes.Basic, 0, 5, StringComparison.OrdinalIgnoreCase) == 0;
-
- internal static bool TryParseBasicAuth(string headerValue, out HttpStatusCode errorCode, out string username, out string password)
- {
- errorCode = HttpStatusCode.OK;
- username = password = null;
- try
- {
- if (string.IsNullOrWhiteSpace(headerValue))
- {
- return false;
- }
-
- string authString = Encoding.UTF8.GetString(Convert.FromBase64String(headerValue));
- int colonPos = authString.IndexOf(':');
- if (colonPos < 0)
- {
- // username must be at least 1 char
- errorCode = HttpStatusCode.BadRequest;
- return false;
- }
-
- username = authString.Substring(0, colonPos);
- password = authString.Substring(colonPos + 1);
- return true;
- }
- catch
- {
- errorCode = HttpStatusCode.InternalServerError;
- return false;
- }
- }
-
- public Task<HttpListenerWebSocketContext> AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval)
- {
- return HttpWebSocket.AcceptWebSocketAsyncCore(this, subProtocol, receiveBufferSize, keepAliveInterval);
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public Task<HttpListenerWebSocketContext> AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, ArraySegment<byte> internalBuffer)
- {
- WebSocketValidate.ValidateArraySegment(internalBuffer, nameof(internalBuffer));
- HttpWebSocket.ValidateOptions(subProtocol, receiveBufferSize, HttpWebSocket.MinSendBufferSize, keepAliveInterval);
- return HttpWebSocket.AcceptWebSocketAsyncCore(this, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer);
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerContext.cs b/SocketHttpListener/Net/HttpListenerContext.cs
deleted file mode 100644
index d84e2d1aa..000000000
--- a/SocketHttpListener/Net/HttpListenerContext.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Net;
-using System.Security.Principal;
-using System.Threading.Tasks;
-using SocketHttpListener.Net.WebSockets;
-
-namespace SocketHttpListener.Net
-{
- public sealed partial class HttpListenerContext
- {
- private HttpListenerResponse _response;
- private IPrincipal _user;
-
- public HttpListenerRequest Request { get; }
-
- public IPrincipal User => _user;
-
- // This can be used to cache the results of HttpListener.AuthenticationSchemeSelectorDelegate.
- internal AuthenticationSchemes AuthenticationSchemes { get; set; }
-
- public HttpListenerResponse Response => _response;
-
- public Task<HttpListenerWebSocketContext> AcceptWebSocketAsync(string subProtocol)
- {
- return AcceptWebSocketAsync(subProtocol, HttpWebSocket.DefaultReceiveBufferSize, WebSocket.DefaultKeepAliveInterval);
- }
-
- public Task<HttpListenerWebSocketContext> AcceptWebSocketAsync(string subProtocol, TimeSpan keepAliveInterval)
- {
- return AcceptWebSocketAsync(subProtocol, HttpWebSocket.DefaultReceiveBufferSize, keepAliveInterval);
- }
- }
-
- public class GenericPrincipal : IPrincipal
- {
- private IIdentity m_identity;
- private string[] m_roles;
-
- public GenericPrincipal(IIdentity identity, string[] roles)
- {
- if (identity == null)
- throw new ArgumentNullException(nameof(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 => 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/Net/HttpListenerPrefixCollection.cs b/SocketHttpListener/Net/HttpListenerPrefixCollection.cs
deleted file mode 100644
index 400a1adb6..000000000
--- a/SocketHttpListener/Net/HttpListenerPrefixCollection.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using Microsoft.Extensions.Logging;
-
-namespace SocketHttpListener.Net
-{
- public class HttpListenerPrefixCollection : ICollection<string>, IEnumerable<string>, IEnumerable
- {
- private List<string> _prefixes = new List<string>();
- private HttpListener _listener;
-
- private ILogger _logger;
-
- internal HttpListenerPrefixCollection(ILogger logger, HttpListener listener)
- {
- _logger = logger;
- _listener = listener;
- }
-
- public int Count => _prefixes.Count;
-
- public bool IsReadOnly => false;
-
- public bool IsSynchronized => false;
-
- public void Add(string uriPrefix)
- {
- _listener.CheckDisposed();
- //ListenerPrefix.CheckUri(uriPrefix);
- if (_prefixes.Contains(uriPrefix))
- {
- return;
- }
-
- _prefixes.Add(uriPrefix);
- if (_listener.IsListening)
- {
- HttpEndPointManager.AddPrefix(_logger, uriPrefix, _listener);
- }
- }
-
- public void AddRange(IEnumerable<string> uriPrefixes)
- {
- _listener.CheckDisposed();
-
- foreach (var uriPrefix in uriPrefixes)
- {
- if (_prefixes.Contains(uriPrefix))
- {
- continue;
- }
-
- _prefixes.Add(uriPrefix);
- if (_listener.IsListening)
- {
- HttpEndPointManager.AddPrefix(_logger, uriPrefix, _listener);
- }
- }
- }
-
- public void Clear()
- {
- _listener.CheckDisposed();
- _prefixes.Clear();
- if (_listener.IsListening)
- {
- HttpEndPointManager.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(nameof(uriPrefix));
- }
-
- bool result = _prefixes.Remove(uriPrefix);
- if (result && _listener.IsListening)
- {
- HttpEndPointManager.RemovePrefix(_logger, uriPrefix, _listener);
- }
-
- return result;
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerRequest.Managed.cs b/SocketHttpListener/Net/HttpListenerRequest.Managed.cs
deleted file mode 100644
index 3f9e32f08..000000000
--- a/SocketHttpListener/Net/HttpListenerRequest.Managed.cs
+++ /dev/null
@@ -1,325 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener.Net
-{
- public sealed partial class HttpListenerRequest
- {
- private long _contentLength;
- private bool _clSet;
- private WebHeaderCollection _headers;
- private string _method;
- private Stream _inputStream;
- private HttpListenerContext _context;
- private bool _isChunked;
-
- private static byte[] s_100continue = Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
-
- internal HttpListenerRequest(HttpListenerContext context)
- {
- _context = context;
- _headers = new WebHeaderCollection();
- _version = HttpVersion.Version10;
- }
-
- private static readonly char[] s_separators = new char[] { ' ' };
-
- internal void SetRequestLine(string req)
- {
- string[] parts = req.Split(s_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;
- }
-
- _rawUrl = 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));
- }
- catch
- {
- _context.ErrorMessage = "Invalid request line (version).";
- return;
- }
-
- if (_version.Major < 1)
- {
- _context.ErrorMessage = "Invalid request line (version).";
- return;
- }
- if (_version.Major > 1)
- {
- _context.ErrorStatus = (int)HttpStatusCode.HttpVersionNotSupported;
- _context.ErrorMessage = HttpStatusDescription.Get(HttpStatusCode.HttpVersionNotSupported);
- return;
- }
- }
-
- private 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));
- }
-
- private static bool IsPredefinedScheme(string scheme)
- {
- if (scheme == null || scheme.Length < 3)
- return false;
-
- char c = scheme[0];
- if (c == 'h')
- return (scheme == UriScheme.Http || scheme == UriScheme.Https);
- if (c == 'f')
- return (scheme == UriScheme.File || scheme == UriScheme.Ftp);
-
- if (c == 'n')
- {
- c = scheme[1];
- if (c == 'e')
- return (scheme == UriScheme.News || scheme == UriScheme.NetPipe || scheme == UriScheme.NetTcp);
- if (scheme == UriScheme.Nntp)
- return true;
- return false;
- }
- if ((c == 'g' && scheme == UriScheme.Gopher) || (c == 'm' && scheme == UriScheme.Mailto))
- return true;
-
- return false;
- }
-
- 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(_rawUrl.ToLowerInvariant()) && Uri.TryCreate(_rawUrl, UriKind.Absolute, out raw_uri))
- path = raw_uri.PathAndQuery;
- else
- path = _rawUrl;
-
- if ((host == null || host.Length == 0))
- host = UserHostAddress;
-
- if (raw_uri != null)
- host = raw_uri.Host;
-
- int colon = host.IndexOf(']') == -1 ? host.IndexOf(':') : host.LastIndexOf(':');
- if (colon >= 0)
- host = host.Substring(0, colon);
-
- string base_uri = string.Format("{0}://{1}:{2}", RequestScheme, host, LocalEndPoint.Port);
-
- if (!Uri.TryCreate(base_uri + path, UriKind.Absolute, out _requestUri))
- {
- _context.ErrorMessage = System.Net.WebUtility.HtmlEncode("Invalid url: " + base_uri + path);
- return;
- }
-
- _requestUri = HttpListenerRequestUriBuilder.GetRequestUri(_rawUrl, _requestUri.Scheme,
- _requestUri.Authority, _requestUri.LocalPath, _requestUri.Query);
-
- if (_version >= HttpVersion.Version11)
- {
- string t_encoding = Headers[HttpKnownHeaderNames.TransferEncoding];
- _isChunked = (t_encoding != null && string.Equals(t_encoding, "chunked", StringComparison.OrdinalIgnoreCase));
- // 'identity' is not valid!
- if (t_encoding != null && !_isChunked)
- {
- _context.Connection.SendError(null, 501);
- return;
- }
- }
-
- if (!_isChunked && !_clSet)
- {
- if (string.Equals(_method, "POST", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(_method, "PUT", StringComparison.OrdinalIgnoreCase))
- {
- _context.Connection.SendError(null, 411);
- return;
- }
- }
-
- if (string.Compare(Headers[HttpKnownHeaderNames.Expect], "100-continue", StringComparison.OrdinalIgnoreCase) == 0)
- {
- HttpResponseStream output = _context.Connection.GetResponseStream();
- output.InternalWrite(s_100continue, 0, s_100continue.Length);
- }
- }
-
- 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 = HttpStatusDescription.Get(400);
- _context.ErrorStatus = 400;
- return;
- }
-
- string name = header.Substring(0, colon).Trim();
- string val = header.Substring(colon + 1).Trim();
- if (name.Equals("content-length", StringComparison.OrdinalIgnoreCase))
- {
- // To match Windows behavior:
- // Content lengths >= 0 and <= long.MaxValue are accepted as is.
- // Content lengths > long.MaxValue and <= ulong.MaxValue are treated as 0.
- // Content lengths < 0 cause the requests to fail.
- // Other input is a failure, too.
- long parsedContentLength =
- ulong.TryParse(val, out ulong parsedUlongContentLength) ? (parsedUlongContentLength <= long.MaxValue ? (long)parsedUlongContentLength : 0) :
- long.Parse(val);
- if (parsedContentLength < 0 || (_clSet && parsedContentLength != _contentLength))
- {
- _context.ErrorMessage = "Invalid Content-Length.";
- }
- else
- {
- _contentLength = parsedContentLength;
- _clSet = true;
- }
- }
- else if (name.Equals("transfer-encoding", StringComparison.OrdinalIgnoreCase))
- {
- if (Headers[HttpKnownHeaderNames.TransferEncoding] != null)
- {
- _context.ErrorStatus = (int)HttpStatusCode.NotImplemented;
- _context.ErrorMessage = HttpStatusDescription.Get(HttpStatusCode.NotImplemented);
- }
- }
-
- if (_context.ErrorMessage == null)
- {
- _headers.Set(name, val);
- }
- }
-
- // returns true is the stream could be reused.
- internal bool FlushInput()
- {
- if (!HasEntityBody)
- return true;
-
- int length = 2048;
- if (_contentLength > 0)
- length = (int)Math.Min(_contentLength, (long)length);
-
- byte[] bytes = new byte[length];
- while (true)
- {
- try
- {
- IAsyncResult ares = InputStream.BeginRead(bytes, 0, length, null, null);
- if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne(1000))
- return false;
- if (InputStream.EndRead(ares) <= 0)
- return true;
- }
- catch (ObjectDisposedException)
- {
- _inputStream = null;
- return true;
- }
- catch
- {
- return false;
- }
- }
- }
-
- public long ContentLength64
- {
- get
- {
- if (_isChunked)
- _contentLength = -1;
-
- return _contentLength;
- }
- }
-
- public bool HasEntityBody => (_contentLength > 0 || _isChunked);
-
- public QueryParamCollection Headers => _headers;
-
- public string HttpMethod => _method;
-
- public Stream InputStream
- {
- get
- {
- if (_inputStream == null)
- {
- if (_isChunked || _contentLength > 0)
- _inputStream = _context.Connection.GetRequestStream(_isChunked, _contentLength);
- else
- _inputStream = Stream.Null;
- }
-
- return _inputStream;
- }
- }
-
- public bool IsAuthenticated => false;
-
- public bool IsSecureConnection => _context.Connection.IsSecure;
-
- public System.Net.IPEndPoint LocalEndPoint => _context.Connection.LocalEndPoint;
-
- public System.Net.IPEndPoint RemoteEndPoint => _context.Connection.RemoteEndPoint;
-
- public Guid RequestTraceIdentifier { get; } = Guid.NewGuid();
-
- public string ServiceName => null;
-
- private Uri RequestUri => _requestUri;
- private bool SupportsWebSockets => true;
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs
deleted file mode 100644
index 667d58ea7..000000000
--- a/SocketHttpListener/Net/HttpListenerRequest.cs
+++ /dev/null
@@ -1,537 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Net;
-using System.Text;
-using MediaBrowser.Model.Services;
-using SocketHttpListener.Net.WebSockets;
-
-namespace SocketHttpListener.Net
-{
- public sealed partial class HttpListenerRequest
- {
- private CookieCollection _cookies;
- private bool? _keepAlive;
- private string _rawUrl;
- private Uri _requestUri;
- private Version _version;
-
- public string[] AcceptTypes => Helpers.ParseMultivalueHeader(Headers[HttpKnownHeaderNames.Accept]);
-
- public string[] UserLanguages => Helpers.ParseMultivalueHeader(Headers[HttpKnownHeaderNames.AcceptLanguage]);
-
- private static CookieCollection ParseCookies(Uri uri, string setCookieHeader)
- {
- var cookies = new CookieCollection();
- return cookies;
- }
-
- public CookieCollection Cookies
- {
- get
- {
- if (_cookies == null)
- {
- string cookieString = Headers[HttpKnownHeaderNames.Cookie];
- if (!string.IsNullOrEmpty(cookieString))
- {
- _cookies = ParseCookies(RequestUri, cookieString);
- }
- if (_cookies == null)
- {
- _cookies = new CookieCollection();
- }
- }
- return _cookies;
- }
- }
-
- public Encoding ContentEncoding
- {
- get
- {
- if (UserAgent != null && CultureInfo.InvariantCulture.CompareInfo.IsPrefix(UserAgent, "UP"))
- {
- string postDataCharset = Headers["x-up-devcap-post-charset"];
- if (postDataCharset != null && postDataCharset.Length > 0)
- {
- try
- {
- return Encoding.GetEncoding(postDataCharset);
- }
- catch (ArgumentException)
- {
- }
- }
- }
- if (HasEntityBody)
- {
- if (ContentType != null)
- {
- string charSet = Helpers.GetCharSetValueFromHeader(ContentType);
- if (charSet != null)
- {
- try
- {
- return Encoding.GetEncoding(charSet);
- }
- catch (ArgumentException)
- {
- }
- }
- }
- }
- return Encoding.UTF8;
- }
- }
-
- public string ContentType => Headers[HttpKnownHeaderNames.ContentType];
-
- public bool IsLocal => LocalEndPoint.Address.Equals(RemoteEndPoint.Address);
-
- public bool IsWebSocketRequest
- {
- get
- {
- if (!SupportsWebSockets)
- {
- return false;
- }
-
- bool foundConnectionUpgradeHeader = false;
- if (string.IsNullOrEmpty(Headers[HttpKnownHeaderNames.Connection]) || string.IsNullOrEmpty(Headers[HttpKnownHeaderNames.Upgrade]))
- {
- return false;
- }
-
- foreach (string connection in Headers.GetValues(HttpKnownHeaderNames.Connection))
- {
- if (string.Equals(connection, HttpKnownHeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase))
- {
- foundConnectionUpgradeHeader = true;
- break;
- }
- }
-
- if (!foundConnectionUpgradeHeader)
- {
- return false;
- }
-
- foreach (string upgrade in Headers.GetValues(HttpKnownHeaderNames.Upgrade))
- {
- if (string.Equals(upgrade, HttpWebSocket.WebSocketUpgradeToken, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- }
- }
-
- public bool KeepAlive
- {
- get
- {
- if (!_keepAlive.HasValue)
- {
- string header = Headers[HttpKnownHeaderNames.ProxyConnection];
- if (string.IsNullOrEmpty(header))
- {
- header = Headers[HttpKnownHeaderNames.Connection];
- }
- if (string.IsNullOrEmpty(header))
- {
- if (ProtocolVersion >= HttpVersion.Version11)
- {
- _keepAlive = true;
- }
- else
- {
- header = Headers[HttpKnownHeaderNames.KeepAlive];
- _keepAlive = !string.IsNullOrEmpty(header);
- }
- }
- else
- {
- header = header.ToLowerInvariant();
- _keepAlive =
- header.IndexOf("close", StringComparison.OrdinalIgnoreCase) < 0 ||
- header.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) >= 0;
- }
- }
-
- return _keepAlive.Value;
- }
- }
-
- public QueryParamCollection QueryString
- {
- get
- {
- var queryString = new QueryParamCollection();
- Helpers.FillFromString(queryString, Url.Query, true, ContentEncoding);
- return queryString;
- }
- }
-
- public string RawUrl => _rawUrl;
-
- private string RequestScheme => IsSecureConnection ? UriScheme.Https : UriScheme.Http;
-
- public string UserAgent => Headers[HttpKnownHeaderNames.UserAgent];
-
- public string UserHostAddress => LocalEndPoint.ToString();
-
- public string UserHostName => Headers[HttpKnownHeaderNames.Host];
-
- public Uri UrlReferrer
- {
- get
- {
- string referrer = Headers[HttpKnownHeaderNames.Referer];
- if (referrer == null)
- {
- return null;
- }
-
- bool success = Uri.TryCreate(referrer, UriKind.RelativeOrAbsolute, out var urlReferrer);
- return success ? urlReferrer : null;
- }
- }
-
- public Uri Url => RequestUri;
-
- public Version ProtocolVersion => _version;
-
- private static class Helpers
- {
- //
- // Get attribute off header value
- //
- internal static string GetCharSetValueFromHeader(string headerValue)
- {
- const string AttrName = "charset";
-
- if (headerValue == null)
- return null;
-
- int l = headerValue.Length;
- int k = AttrName.Length;
-
- // find properly separated attribute name
- int i = 1; // start searching from 1
-
- while (i < l)
- {
- i = CultureInfo.InvariantCulture.CompareInfo.IndexOf(headerValue, AttrName, i, CompareOptions.IgnoreCase);
- if (i < 0)
- break;
- if (i + k >= l)
- break;
-
- char chPrev = headerValue[i - 1];
- char chNext = headerValue[i + k];
- if ((chPrev == ';' || chPrev == ',' || char.IsWhiteSpace(chPrev)) && (chNext == '=' || char.IsWhiteSpace(chNext)))
- break;
-
- i += k;
- }
-
- if (i < 0 || i >= l)
- return null;
-
- // skip to '=' and the following whitespace
- i += k;
- while (i < l && char.IsWhiteSpace(headerValue[i]))
- i++;
- if (i >= l || headerValue[i] != '=')
- return null;
- i++;
- while (i < l && char.IsWhiteSpace(headerValue[i]))
- i++;
- if (i >= l)
- return null;
-
- // parse the value
- string attrValue = null;
-
- int j;
-
- if (i < l && headerValue[i] == '"')
- {
- if (i == l - 1)
- return null;
- j = headerValue.IndexOf('"', i + 1);
- if (j < 0 || j == i + 1)
- return null;
-
- attrValue = headerValue.Substring(i + 1, j - i - 1).Trim();
- }
- else
- {
- for (j = i; j < l; j++)
- {
- if (headerValue[j] == ';')
- break;
- }
-
- if (j == i)
- return null;
-
- attrValue = headerValue.Substring(i, j - i).Trim();
- }
-
- return attrValue;
- }
-
- internal static string[] ParseMultivalueHeader(string s)
- {
- if (s == null)
- return null;
-
- int l = s.Length;
-
- // collect comma-separated values into list
-
- var values = new List<string>();
- int i = 0;
-
- while (i < l)
- {
- // find next ,
- int ci = s.IndexOf(',', i);
- if (ci < 0)
- ci = l;
-
- // append corresponding server value
- values.Add(s.Substring(i, ci - i));
-
- // move to next
- i = ci + 1;
-
- // skip leading space
- if (i < l && s[i] == ' ')
- i++;
- }
-
- // return list as array of strings
-
- int n = values.Count;
- string[] strings;
-
- // if n is 0 that means s was empty string
-
- if (n == 0)
- {
- strings = new string[1];
- strings[0] = string.Empty;
- }
- else
- {
- strings = new string[n];
- values.CopyTo(0, strings, 0, n);
- }
- return strings;
- }
-
-
- private static string UrlDecodeStringFromStringInternal(string s, Encoding e)
- {
- int count = s.Length;
- var helper = new UrlDecoder(count, e);
-
- // go through the string's chars collapsing %XX and %uXXXX and
- // appending each char as char, with exception of %XX constructs
- // that are appended as bytes
-
- for (int pos = 0; pos < count; pos++)
- {
- char ch = s[pos];
-
- if (ch == '+')
- {
- ch = ' ';
- }
- else if (ch == '%' && pos < count - 2)
- {
- if (s[pos + 1] == 'u' && pos < count - 5)
- {
- int h1 = HexToInt(s[pos + 2]);
- int h2 = HexToInt(s[pos + 3]);
- int h3 = HexToInt(s[pos + 4]);
- int h4 = HexToInt(s[pos + 5]);
-
- if (h1 >= 0 && h2 >= 0 && h3 >= 0 && h4 >= 0)
- { // valid 4 hex chars
- ch = (char)((h1 << 12) | (h2 << 8) | (h3 << 4) | h4);
- pos += 5;
-
- // only add as char
- helper.AddChar(ch);
- continue;
- }
- }
- else
- {
- int h1 = HexToInt(s[pos + 1]);
- int h2 = HexToInt(s[pos + 2]);
-
- if (h1 >= 0 && h2 >= 0)
- { // valid 2 hex chars
- byte b = (byte)((h1 << 4) | h2);
- pos += 2;
-
- // don't add as char
- helper.AddByte(b);
- continue;
- }
- }
- }
-
- if ((ch & 0xFF80) == 0)
- helper.AddByte((byte)ch); // 7 bit have to go as bytes because of Unicode
- else
- helper.AddChar(ch);
- }
-
- return helper.GetString();
- }
-
- private static int HexToInt(char h)
- {
- return (h >= '0' && h <= '9') ? h - '0' :
- (h >= 'a' && h <= 'f') ? h - 'a' + 10 :
- (h >= 'A' && h <= 'F') ? h - 'A' + 10 :
- -1;
- }
-
- private class UrlDecoder
- {
- private int _bufferSize;
-
- // Accumulate characters in a special array
- private int _numChars;
- private char[] _charBuffer;
-
- // Accumulate bytes for decoding into characters in a special array
- private int _numBytes;
- private byte[] _byteBuffer;
-
- // Encoding to convert chars to bytes
- private Encoding _encoding;
-
- private void FlushBytes()
- {
- if (_numBytes > 0)
- {
- _numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars);
- _numBytes = 0;
- }
- }
-
- internal UrlDecoder(int bufferSize, Encoding encoding)
- {
- _bufferSize = bufferSize;
- _encoding = encoding;
-
- _charBuffer = new char[bufferSize];
- // byte buffer created on demand
- }
-
- internal void AddChar(char ch)
- {
- if (_numBytes > 0)
- FlushBytes();
-
- _charBuffer[_numChars++] = ch;
- }
-
- internal void AddByte(byte b)
- {
- {
- if (_byteBuffer == null)
- _byteBuffer = new byte[_bufferSize];
-
- _byteBuffer[_numBytes++] = b;
- }
- }
-
- internal string GetString()
- {
- if (_numBytes > 0)
- FlushBytes();
-
- if (_numChars > 0)
- return new string(_charBuffer, 0, _numChars);
- else
- return string.Empty;
- }
- }
-
-
- internal static void FillFromString(QueryParamCollection nvc, string s, bool urlencoded, Encoding encoding)
- {
- int l = (s != null) ? s.Length : 0;
- int i = (s.Length > 0 && s[0] == '?') ? 1 : 0;
-
- while (i < l)
- {
- // find next & while noting first = on the way (and if there are more)
-
- int si = i;
- int ti = -1;
-
- while (i < l)
- {
- char ch = s[i];
-
- if (ch == '=')
- {
- if (ti < 0)
- ti = i;
- }
- else if (ch == '&')
- {
- break;
- }
-
- i++;
- }
-
- // extract the name / value pair
-
- string name = null;
- string value = null;
-
- if (ti >= 0)
- {
- name = s.Substring(si, ti - si);
- value = s.Substring(ti + 1, i - ti - 1);
- }
- else
- {
- value = s.Substring(si, i - si);
- }
-
- // add name / value pair to the collection
-
- if (urlencoded)
- nvc.Add(
- name == null ? null : UrlDecodeStringFromStringInternal(name, encoding),
- UrlDecodeStringFromStringInternal(value, encoding));
- else
- nvc.Add(name, value);
-
- // trailing '&'
-
- if (i == l - 1 && s[i] == '&')
- nvc.Add(null, "");
-
- i++;
- }
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerRequestUriBuilder.cs b/SocketHttpListener/Net/HttpListenerRequestUriBuilder.cs
deleted file mode 100644
index 7b4b619e6..000000000
--- a/SocketHttpListener/Net/HttpListenerRequestUriBuilder.cs
+++ /dev/null
@@ -1,443 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.Text;
-
-namespace SocketHttpListener.Net
-{
- // We don't use the cooked URL because http.sys unescapes all percent-encoded values. However,
- // we also can't just use the raw Uri, since http.sys supports not only Utf-8, but also ANSI/DBCS and
- // Unicode code points. System.Uri only supports Utf-8.
- // The purpose of this class is to convert all ANSI, DBCS, and Unicode code points into percent encoded
- // Utf-8 characters.
- internal sealed class HttpListenerRequestUriBuilder
- {
- private static readonly Encoding s_utf8Encoding = new UTF8Encoding(false, true);
- private static readonly Encoding s_ansiEncoding = Encoding.GetEncoding(0, new EncoderExceptionFallback(), new DecoderExceptionFallback());
-
- private readonly string _rawUri;
- private readonly string _cookedUriScheme;
- private readonly string _cookedUriHost;
- private readonly string _cookedUriPath;
- private readonly string _cookedUriQuery;
-
- // This field is used to build the final request Uri string from the Uri parts passed to the ctor.
- private StringBuilder _requestUriString;
-
- // The raw path is parsed by looping through all characters from left to right. 'rawOctets'
- // is used to store consecutive percent encoded octets as actual byte values: e.g. for path /pa%C3%84th%2F/
- // rawOctets will be set to { 0xC3, 0x84 } when we reach character 't' and it will be { 0x2F } when
- // we reach the final '/'. I.e. after a sequence of percent encoded octets ends, we use rawOctets as
- // input to the encoding and percent encode the resulting string into UTF-8 octets.
- //
- // When parsing ANSI (Latin 1) encoded path '/pa%C4th/', %C4 will be added to rawOctets and when
- // we reach 't', the content of rawOctets { 0xC4 } will be fed into the ANSI encoding. The resulting
- // string 'Ä' will be percent encoded into UTF-8 octets and appended to requestUriString. The final
- // path will be '/pa%C3%84th/', where '%C3%84' is the UTF-8 percent encoded character 'Ä'.
- private List<byte> _rawOctets;
- private string _rawPath;
-
- // Holds the final request Uri.
- private Uri _requestUri;
-
- private HttpListenerRequestUriBuilder(string rawUri, string cookedUriScheme, string cookedUriHost,
- string cookedUriPath, string cookedUriQuery)
- {
- _rawUri = rawUri;
- _cookedUriScheme = cookedUriScheme;
- _cookedUriHost = cookedUriHost;
- _cookedUriPath = AddSlashToAsteriskOnlyPath(cookedUriPath);
- _cookedUriQuery = cookedUriQuery ?? string.Empty;
- }
-
- public static Uri GetRequestUri(string rawUri, string cookedUriScheme, string cookedUriHost,
- string cookedUriPath, string cookedUriQuery)
- {
- var builder = new HttpListenerRequestUriBuilder(rawUri,
- cookedUriScheme, cookedUriHost, cookedUriPath, cookedUriQuery);
-
- return builder.Build();
- }
-
- private Uri Build()
- {
- BuildRequestUriUsingRawPath();
-
- if (_requestUri == null)
- {
- BuildRequestUriUsingCookedPath();
- }
-
- return _requestUri;
- }
-
- private void BuildRequestUriUsingCookedPath()
- {
- bool isValid = Uri.TryCreate(_cookedUriScheme + Uri.SchemeDelimiter + _cookedUriHost + _cookedUriPath +
- _cookedUriQuery, UriKind.Absolute, out _requestUri);
-
- // Creating a Uri from the cooked Uri should really always work: If not, we log at least.
- if (!isValid)
- {
- //if (NetEventSource.IsEnabled)
- // NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_create_uri, _cookedUriScheme, _cookedUriHost, _cookedUriPath, _cookedUriQuery));
- }
- }
-
- private void BuildRequestUriUsingRawPath()
- {
- bool isValid = false;
-
- // Initialize 'rawPath' only if really needed; i.e. if we build the request Uri from the raw Uri.
- _rawPath = GetPath(_rawUri);
-
- // Try to check the raw path using first the primary encoding (according to http.sys settings);
- // if it fails try the secondary encoding.
- ParsingResult result = BuildRequestUriUsingRawPath(GetEncoding(EncodingType.Primary));
- if (result == ParsingResult.EncodingError)
- {
- Encoding secondaryEncoding = GetEncoding(EncodingType.Secondary);
- result = BuildRequestUriUsingRawPath(secondaryEncoding);
- }
- isValid = (result == ParsingResult.Success) ? true : false;
-
- // Log that we weren't able to create a Uri from the raw string.
- if (!isValid)
- {
- //if (NetEventSource.IsEnabled)
- // NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_create_uri, _cookedUriScheme, _cookedUriHost, _rawPath, _cookedUriQuery));
- }
- }
-
- private static Encoding GetEncoding(EncodingType type)
- {
- Debug.Assert((type == EncodingType.Primary) || (type == EncodingType.Secondary),
- "Unknown 'EncodingType' value: " + type.ToString());
-
- if (type == EncodingType.Secondary)
- {
- return s_ansiEncoding;
- }
- else
- {
- return s_utf8Encoding;
- }
- }
-
- private ParsingResult BuildRequestUriUsingRawPath(Encoding encoding)
- {
- Debug.Assert(encoding != null, "'encoding' must be assigned.");
- Debug.Assert(!string.IsNullOrEmpty(_rawPath), "'rawPath' must have at least one character.");
-
- _rawOctets = new List<byte>();
- _requestUriString = new StringBuilder();
- _requestUriString.Append(_cookedUriScheme);
- _requestUriString.Append(Uri.SchemeDelimiter);
- _requestUriString.Append(_cookedUriHost);
-
- ParsingResult result = ParseRawPath(encoding);
- if (result == ParsingResult.Success)
- {
- _requestUriString.Append(_cookedUriQuery);
-
- Debug.Assert(_rawOctets.Count == 0,
- "Still raw octets left. They must be added to the result path.");
-
- if (!Uri.TryCreate(_requestUriString.ToString(), UriKind.Absolute, out _requestUri))
- {
- // If we can't create a Uri from the string, this is an invalid string and it doesn't make
- // sense to try another encoding.
- result = ParsingResult.InvalidString;
- }
- }
-
- if (result != ParsingResult.Success)
- {
- //if (NetEventSource.IsEnabled)
- // NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_raw_path, _rawPath, encoding.EncodingName));
- }
-
- return result;
- }
-
- private ParsingResult ParseRawPath(Encoding encoding)
- {
- Debug.Assert(encoding != null, "'encoding' must be assigned.");
-
- int index = 0;
- char current = '\0';
- while (index < _rawPath.Length)
- {
- current = _rawPath[index];
- if (current == '%')
- {
- // Assert is enough, since http.sys accepted the request string already. This should never happen.
- Debug.Assert(index + 2 < _rawPath.Length, "Expected >=2 characters after '%' (e.g. %2F)");
-
- index++;
- current = _rawPath[index];
- if (current == 'u' || current == 'U')
- {
- // We found "%u" which means, we have a Unicode code point of the form "%uXXXX".
- Debug.Assert(index + 4 < _rawPath.Length, "Expected >=4 characters after '%u' (e.g. %u0062)");
-
- // Decode the content of rawOctets into percent encoded UTF-8 characters and append them
- // to requestUriString.
- if (!EmptyDecodeAndAppendRawOctetsList(encoding))
- {
- return ParsingResult.EncodingError;
- }
- if (!AppendUnicodeCodePointValuePercentEncoded(_rawPath.Substring(index + 1, 4)))
- {
- return ParsingResult.InvalidString;
- }
- index += 5;
- }
- else
- {
- // We found '%', but not followed by 'u', i.e. we have a percent encoded octed: %XX
- if (!AddPercentEncodedOctetToRawOctetsList(encoding, _rawPath.Substring(index, 2)))
- {
- return ParsingResult.InvalidString;
- }
- index += 2;
- }
- }
- else
- {
- // We found a non-'%' character: decode the content of rawOctets into percent encoded
- // UTF-8 characters and append it to the result.
- if (!EmptyDecodeAndAppendRawOctetsList(encoding))
- {
- return ParsingResult.EncodingError;
- }
- // Append the current character to the result.
- _requestUriString.Append(current);
- index++;
- }
- }
-
- // if the raw path ends with a sequence of percent encoded octets, make sure those get added to the
- // result (requestUriString).
- if (!EmptyDecodeAndAppendRawOctetsList(encoding))
- {
- return ParsingResult.EncodingError;
- }
-
- return ParsingResult.Success;
- }
-
- private bool AppendUnicodeCodePointValuePercentEncoded(string codePoint)
- {
- // http.sys only supports %uXXXX (4 hex-digits), even though unicode code points could have up to
- // 6 hex digits. Therefore we parse always 4 characters after %u and convert them to an int.
- if (!int.TryParse(codePoint, NumberStyles.HexNumber, null, out var codePointValue))
- {
- //if (NetEventSource.IsEnabled)
- // NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_percent_value, codePoint));
- return false;
- }
-
- string unicodeString = null;
- try
- {
- unicodeString = char.ConvertFromUtf32(codePointValue);
- AppendOctetsPercentEncoded(_requestUriString, s_utf8Encoding.GetBytes(unicodeString));
-
- return true;
- }
- catch (ArgumentOutOfRangeException)
- {
- //if (NetEventSource.IsEnabled)
- // NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_percent_value, codePoint));
- }
- catch (EncoderFallbackException)
- {
- // If utf8Encoding.GetBytes() fails
- //if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_to_utf8, unicodeString, e.Message));
- }
-
- return false;
- }
-
- private bool AddPercentEncodedOctetToRawOctetsList(Encoding encoding, string escapedCharacter)
- {
- if (!byte.TryParse(escapedCharacter, NumberStyles.HexNumber, null, out byte encodedValue))
- {
- //if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_percent_value, escapedCharacter));
- return false;
- }
-
- _rawOctets.Add(encodedValue);
-
- return true;
- }
-
- private bool EmptyDecodeAndAppendRawOctetsList(Encoding encoding)
- {
- if (_rawOctets.Count == 0)
- {
- return true;
- }
-
- string decodedString = null;
- try
- {
- // If the encoding can get a string out of the byte array, this is a valid string in the
- // 'encoding' encoding.
- decodedString = encoding.GetString(_rawOctets.ToArray());
-
- if (encoding == s_utf8Encoding)
- {
- AppendOctetsPercentEncoded(_requestUriString, _rawOctets.ToArray());
- }
- else
- {
- AppendOctetsPercentEncoded(_requestUriString, s_utf8Encoding.GetBytes(decodedString));
- }
-
- _rawOctets.Clear();
-
- return true;
- }
- catch (DecoderFallbackException)
- {
- //if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_bytes, GetOctetsAsString(_rawOctets), e.Message));
- }
- catch (EncoderFallbackException)
- {
- // If utf8Encoding.GetBytes() fails
- //if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_cant_convert_to_utf8, decodedString, e.Message));
- }
-
- return false;
- }
-
- private static void AppendOctetsPercentEncoded(StringBuilder target, IEnumerable<byte> octets)
- {
- foreach (byte octet in octets)
- {
- target.Append('%');
- target.Append(octet.ToString("X2", CultureInfo.InvariantCulture));
- }
- }
-
- private static string GetOctetsAsString(IEnumerable<byte> octets)
- {
- var octetString = new StringBuilder();
-
- bool first = true;
- foreach (byte octet in octets)
- {
- if (first)
- {
- first = false;
- }
- else
- {
- octetString.Append(' ');
- }
- octetString.Append(octet.ToString("X2", CultureInfo.InvariantCulture));
- }
-
- return octetString.ToString();
- }
-
- private static string GetPath(string uriString)
- {
- Debug.Assert(uriString != null, "uriString must not be null");
- Debug.Assert(uriString.Length > 0, "uriString must not be empty");
-
- int pathStartIndex = 0;
-
- // Perf. improvement: nearly all strings are relative Uris. So just look if the
- // string starts with '/'. If so, we have a relative Uri and the path starts at position 0.
- // (http.sys already trimmed leading whitespaces)
- if (uriString[0] != '/')
- {
- // We can't check against cookedUriScheme, since http.sys allows for request http://myserver/ to
- // use a request line 'GET https://myserver/' (note http vs. https). Therefore check if the
- // Uri starts with either http:// or https://.
- int authorityStartIndex = 0;
- if (uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
- {
- authorityStartIndex = 7;
- }
- else if (uriString.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
- {
- authorityStartIndex = 8;
- }
-
- if (authorityStartIndex > 0)
- {
- // we have an absolute Uri. Find out where the authority ends and the path begins.
- // Note that Uris like "http://server?query=value/1/2" are invalid according to RFC2616
- // and http.sys behavior: If the Uri contains a query, there must be at least one '/'
- // between the authority and the '?' character: It's safe to just look for the first
- // '/' after the authority to determine the beginning of the path.
- pathStartIndex = uriString.IndexOf('/', authorityStartIndex);
- if (pathStartIndex == -1)
- {
- // e.g. for request lines like: 'GET http://myserver' (no final '/')
- pathStartIndex = uriString.Length;
- }
- }
- else
- {
- // RFC2616: Request-URI = "*" | absoluteURI | abs_path | authority
- // 'authority' can only be used with CONNECT which is never received by HttpListener.
- // I.e. if we don't have an absolute path (must start with '/') and we don't have
- // an absolute Uri (must start with http:// or https://), then 'uriString' must be '*'.
- Debug.Assert((uriString.Length == 1) && (uriString[0] == '*'), "Unknown request Uri string format",
- "Request Uri string is not an absolute Uri, absolute path, or '*': {0}", uriString);
-
- // Should we ever get here, be consistent with 2.0/3.5 behavior: just add an initial
- // slash to the string and treat it as a path:
- uriString = "/" + uriString;
- }
- }
-
- // Find end of path: The path is terminated by
- // - the first '?' character
- // - the first '#' character: This is never the case here, since http.sys won't accept
- // Uris containing fragments. Also, RFC2616 doesn't allow fragments in request Uris.
- // - end of Uri string
- int queryIndex = uriString.IndexOf('?');
- if (queryIndex == -1)
- {
- queryIndex = uriString.Length;
- }
-
- // will always return a != null string.
- return AddSlashToAsteriskOnlyPath(uriString.Substring(pathStartIndex, queryIndex - pathStartIndex));
- }
-
- private static string AddSlashToAsteriskOnlyPath(string path)
- {
- Debug.Assert(path != null, "'path' must not be null");
-
- // If a request like "OPTIONS * HTTP/1.1" is sent to the listener, then the request Uri
- // should be "http[s]://server[:port]/*" to be compatible with pre-4.0 behavior.
- if ((path.Length == 1) && (path[0] == '*'))
- {
- return "/*";
- }
-
- return path;
- }
-
- private enum ParsingResult
- {
- Success,
- InvalidString,
- EncodingError
- }
-
- private enum EncodingType
- {
- Primary,
- Secondary
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerResponse.Managed.cs b/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
deleted file mode 100644
index f595fce7c..000000000
--- a/SocketHttpListener/Net/HttpListenerResponse.Managed.cs
+++ /dev/null
@@ -1,333 +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;
-
-namespace SocketHttpListener.Net
-{
- public sealed partial class HttpListenerResponse : IDisposable
- {
- private long _contentLength;
- private Version _version = HttpVersion.Version11;
- private int _statusCode = 200;
- internal object _headersLock = new object();
- private bool _forceCloseChunked;
-
- internal HttpListenerResponse(HttpListenerContext context)
- {
- _httpContext = context;
- }
-
- internal bool ForceCloseChunked => _forceCloseChunked;
-
- private void EnsureResponseStream()
- {
- if (_responseStream == null)
- {
- _responseStream = _httpContext.Connection.GetResponseStream();
- }
- }
-
- public Version ProtocolVersion
- {
- get => _version;
- set
- {
- CheckDisposed();
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
- if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
- {
- throw new ArgumentException("Wrong version");
- }
-
- _version = new Version(value.Major, value.Minor); // match Windows behavior, trimming to just Major.Minor
- }
- }
-
- public int StatusCode
- {
- get => _statusCode;
- set
- {
- CheckDisposed();
-
- if (value < 100 || value > 999)
- throw new ProtocolViolationException("Invalid status");
-
- _statusCode = value;
- }
- }
-
- private void Dispose()
- {
- Close(true);
- }
-
- public void Close()
- {
- if (Disposed)
- return;
-
- Close(false);
- }
-
- public void Abort()
- {
- if (Disposed)
- return;
-
- Close(true);
- }
-
- private void Close(bool force)
- {
- Disposed = true;
- _httpContext.Connection.Close(force);
- }
-
- public void Close(byte[] responseEntity, bool willBlock)
- {
- CheckDisposed();
-
- if (responseEntity == null)
- {
- throw new ArgumentNullException(nameof(responseEntity));
- }
-
- if (!SentHeaders && _boundaryType != BoundaryType.Chunked)
- {
- ContentLength64 = responseEntity.Length;
- }
-
- if (willBlock)
- {
- try
- {
- OutputStream.Write(responseEntity, 0, responseEntity.Length);
- }
- finally
- {
- Close(false);
- }
- }
- else
- {
- OutputStream.BeginWrite(responseEntity, 0, responseEntity.Length, iar =>
- {
- var thisRef = (HttpListenerResponse)iar.AsyncState;
- try
- {
- try
- {
- thisRef.OutputStream.EndWrite(iar);
- }
- finally
- {
- thisRef.Close(false);
- }
- }
- catch (Exception)
- {
- // In case response was disposed during this time
- }
- }, this);
- }
- }
-
- public void CopyFrom(HttpListenerResponse templateResponse)
- {
- _webHeaders.Clear();
- //_webHeaders.Add(templateResponse._webHeaders);
- _contentLength = templateResponse._contentLength;
- _statusCode = templateResponse._statusCode;
- _statusDescription = templateResponse._statusDescription;
- _keepAlive = templateResponse._keepAlive;
- _version = templateResponse._version;
- }
-
- internal void SendHeaders(bool closing, MemoryStream ms, bool isWebSocketHandshake = false)
- {
- if (!isWebSocketHandshake)
- {
- if (_webHeaders["Server"] == null)
- {
- _webHeaders.Set("Server", "Microsoft-NetCore/2.0");
- }
-
- if (_webHeaders["Date"] == null)
- {
- _webHeaders.Set("Date", DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture));
- }
-
- if (_boundaryType == BoundaryType.None)
- {
- if (HttpListenerRequest.ProtocolVersion <= HttpVersion.Version10)
- {
- _keepAlive = false;
- }
- else
- {
- _boundaryType = BoundaryType.Chunked;
- }
-
- if (CanSendResponseBody(_httpContext.Response.StatusCode))
- {
- _contentLength = -1;
- }
- else
- {
- _boundaryType = BoundaryType.ContentLength;
- _contentLength = 0;
- }
- }
-
- if (_boundaryType != BoundaryType.Chunked)
- {
- if (_boundaryType != BoundaryType.ContentLength && closing)
- {
- _contentLength = CanSendResponseBody(_httpContext.Response.StatusCode) ? -1 : 0;
- }
-
- if (_boundaryType == BoundaryType.ContentLength)
- {
- _webHeaders.Set("Content-Length", _contentLength.ToString("D", CultureInfo.InvariantCulture));
- }
- }
-
- /* 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 = (_statusCode == (int)HttpStatusCode.BadRequest || _statusCode == (int)HttpStatusCode.RequestTimeout
- || _statusCode == (int)HttpStatusCode.LengthRequired || _statusCode == (int)HttpStatusCode.RequestEntityTooLarge
- || _statusCode == (int)HttpStatusCode.RequestUriTooLong || _statusCode == (int)HttpStatusCode.InternalServerError
- || _statusCode == (int)HttpStatusCode.ServiceUnavailable);
-
- if (!conn_close)
- {
- conn_close = !_httpContext.Request.KeepAlive;
- }
-
- // They sent both KeepAlive: true and Connection: close
- if (!_keepAlive || conn_close)
- {
- _webHeaders.Set("Connection", "Close");
- conn_close = true;
- }
-
- if (SendChunked)
- {
- _webHeaders.Set("Transfer-Encoding", "Chunked");
- }
-
- int reuses = _httpContext.Connection.Reuses;
- if (reuses >= 100)
- {
- _forceCloseChunked = true;
- if (!conn_close)
- {
- _webHeaders.Set("Connection", "Close");
- conn_close = true;
- }
- }
-
- if (HttpListenerRequest.ProtocolVersion <= HttpVersion.Version10)
- {
- if (_keepAlive)
- {
- Headers["Keep-Alive"] = "true";
- }
-
- if (!conn_close)
- {
- _webHeaders.Set("Connection", "Keep-Alive");
- }
- }
-
- ComputeCookies();
- }
-
- var encoding = Encoding.UTF8;
- var writer = new StreamWriter(ms, encoding, 256);
- writer.Write("HTTP/1.1 {0} ", _statusCode); // "1.1" matches Windows implementation, which ignores the response version
- writer.Flush();
- byte[] statusDescriptionBytes = WebHeaderEncoding.GetBytes(StatusDescription);
- ms.Write(statusDescriptionBytes, 0, statusDescriptionBytes.Length);
- writer.Write("\r\n");
-
- writer.Write(FormatHeaders(_webHeaders));
- writer.Flush();
- int preamble = encoding.GetPreamble().Length;
- EnsureResponseStream();
-
- /* Assumes that the ms was at position 0 */
- ms.Position = preamble;
- SentHeaders = !isWebSocketHandshake;
- }
-
- private static bool HeaderCanHaveEmptyValue(string name) =>
- !string.Equals(name, "Location", StringComparison.OrdinalIgnoreCase);
-
- private static string FormatHeaders(WebHeaderCollection headers)
- {
- var sb = new StringBuilder();
-
- for (int i = 0; i < headers.Count; i++)
- {
- string key = headers.GetKey(i);
- string[] values = headers.GetValues(i);
-
- int startingLength = sb.Length;
-
- sb.Append(key).Append(": ");
- bool anyValues = false;
- for (int j = 0; j < values.Length; j++)
- {
- string value = values[j];
- if (!string.IsNullOrWhiteSpace(value))
- {
- if (anyValues)
- {
- sb.Append(", ");
- }
- sb.Append(value);
- anyValues = true;
- }
- }
-
- if (anyValues || HeaderCanHaveEmptyValue(key))
- {
- // Complete the header
- sb.Append("\r\n");
- }
- else
- {
- // Empty header; remove it.
- sb.Length = startingLength;
- }
- }
-
- return sb.Append("\r\n").ToString();
- }
-
- private bool Disposed { get; set; }
- internal bool SentHeaders { get; set; }
-
- public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- return ((HttpResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken);
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpListenerResponse.cs b/SocketHttpListener/Net/HttpListenerResponse.cs
deleted file mode 100644
index 66ef88564..000000000
--- a/SocketHttpListener/Net/HttpListenerResponse.cs
+++ /dev/null
@@ -1,294 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Text;
-
-namespace SocketHttpListener.Net
-{
- public sealed partial class HttpListenerResponse : IDisposable
- {
- private BoundaryType _boundaryType = BoundaryType.None;
- private CookieCollection _cookies;
- private HttpListenerContext _httpContext;
- private bool _keepAlive = true;
- private HttpResponseStream _responseStream;
- private string _statusDescription;
- private WebHeaderCollection _webHeaders = new WebHeaderCollection();
-
- public WebHeaderCollection Headers => _webHeaders;
-
- public Encoding ContentEncoding { get; set; }
-
- public string ContentType
- {
- get => Headers["Content-Type"];
- set
- {
- CheckDisposed();
- if (string.IsNullOrEmpty(value))
- {
- Headers.Remove("Content-Type");
- }
- else
- {
- Headers.Set("Content-Type", value);
- }
- }
- }
-
- private HttpListenerContext HttpListenerContext => _httpContext;
-
- private HttpListenerRequest HttpListenerRequest => HttpListenerContext.Request;
-
- internal EntitySendFormat EntitySendFormat
- {
- get => (EntitySendFormat)_boundaryType;
- set
- {
- CheckDisposed();
- CheckSentHeaders();
- if (value == EntitySendFormat.Chunked && HttpListenerRequest.ProtocolVersion.Minor == 0)
- {
- throw new ProtocolViolationException("net_nochunkuploadonhttp10");
- }
- _boundaryType = (BoundaryType)value;
- if (value != EntitySendFormat.ContentLength)
- {
- _contentLength = -1;
- }
- }
- }
-
- public bool SendChunked
- {
- get => EntitySendFormat == EntitySendFormat.Chunked;
- set => EntitySendFormat = value ? EntitySendFormat.Chunked : EntitySendFormat.ContentLength;
- }
-
- // We MUST NOT send message-body when we send responses with these Status codes
- private static readonly int[] s_noResponseBody = { 100, 101, 204, 205, 304 };
-
- private static bool CanSendResponseBody(int responseCode)
- {
- for (int i = 0; i < s_noResponseBody.Length; i++)
- {
- if (responseCode == s_noResponseBody[i])
- {
- return false;
- }
- }
- return true;
- }
-
- public long ContentLength64
- {
- get => _contentLength;
- set
- {
- CheckDisposed();
- CheckSentHeaders();
- if (value >= 0)
- {
- _contentLength = value;
- _boundaryType = BoundaryType.ContentLength;
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(value));
- }
- }
- }
-
- public CookieCollection Cookies
- {
- get => _cookies ?? (_cookies = new CookieCollection());
- set => _cookies = value;
- }
-
- public bool KeepAlive
- {
- get => _keepAlive;
- set
- {
- CheckDisposed();
- _keepAlive = value;
- }
- }
-
- public Stream OutputStream
- {
- get
- {
- CheckDisposed();
- EnsureResponseStream();
- return _responseStream;
- }
- }
-
- public string RedirectLocation
- {
- get => Headers["Location"];
- set
- {
- // note that this doesn't set the status code to a redirect one
- CheckDisposed();
- if (string.IsNullOrEmpty(value))
- {
- Headers.Remove("Location");
- }
- else
- {
- Headers.Set("Location", value);
- }
- }
- }
-
- public string StatusDescription
- {
- get
- {
- if (_statusDescription == null)
- {
- // if the user hasn't set this, generated on the fly, if possible.
- // We know this one is safe, no need to verify it as in the setter.
- _statusDescription = HttpStatusDescription.Get(StatusCode);
- }
- if (_statusDescription == null)
- {
- _statusDescription = string.Empty;
- }
- return _statusDescription;
- }
- set
- {
- CheckDisposed();
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
-
- // Need to verify the status description doesn't contain any control characters except HT. We mask off the high
- // byte since that's how it's encoded.
- for (int i = 0; i < value.Length; i++)
- {
- char c = (char)(0x000000ff & (uint)value[i]);
- if ((c <= 31 && c != (byte)'\t') || c == 127)
- {
- throw new ArgumentException("net_WebHeaderInvalidControlChars");
- }
- }
-
- _statusDescription = value;
- }
- }
-
- public void AddHeader(string name, string value)
- {
- Headers.Set(name, value);
- }
-
- public void AppendHeader(string name, string value)
- {
- Headers.Add(name, value);
- }
-
- public void AppendCookie(Cookie cookie)
- {
- if (cookie == null)
- {
- throw new ArgumentNullException(nameof(cookie));
- }
- Cookies.Add(cookie);
- }
-
- private void ComputeCookies()
- {
- if (_cookies != null)
- {
- // now go through the collection, and concatenate all the cookies in per-variant strings
- //string setCookie2 = null, setCookie = null;
- //for (int index = 0; index < _cookies.Count; index++)
- //{
- // Cookie cookie = _cookies[index];
- // string cookieString = cookie.ToServerString();
- // if (cookieString == null || cookieString.Length == 0)
- // {
- // continue;
- // }
-
- // if (cookie.IsRfc2965Variant())
- // {
- // setCookie2 = setCookie2 == null ? cookieString : setCookie2 + ", " + cookieString;
- // }
- // else
- // {
- // setCookie = setCookie == null ? cookieString : setCookie + ", " + cookieString;
- // }
- //}
-
- //if (!string.IsNullOrEmpty(setCookie))
- //{
- // Headers.Set(HttpKnownHeaderNames.SetCookie, setCookie);
- // if (string.IsNullOrEmpty(setCookie2))
- // {
- // Headers.Remove(HttpKnownHeaderNames.SetCookie2);
- // }
- //}
-
- //if (!string.IsNullOrEmpty(setCookie2))
- //{
- // Headers.Set(HttpKnownHeaderNames.SetCookie2, setCookie2);
- // if (string.IsNullOrEmpty(setCookie))
- // {
- // Headers.Remove(HttpKnownHeaderNames.SetCookie);
- // }
- //}
- }
- }
-
- public void Redirect(string url)
- {
- Headers["Location"] = url;
- StatusCode = (int)HttpStatusCode.Redirect;
- StatusDescription = "Found";
- }
-
- public void SetCookie(Cookie cookie)
- {
- if (cookie == null)
- {
- throw new ArgumentNullException(nameof(cookie));
- }
-
- //Cookie newCookie = cookie.Clone();
- //int added = Cookies.InternalAdd(newCookie, true);
-
- //if (added != 1)
- //{
- // // The Cookie already existed and couldn't be replaced.
- // throw new ArgumentException("Cookie exists");
- //}
- }
-
- void IDisposable.Dispose()
- {
- Dispose();
- }
-
- private void CheckDisposed()
- {
- if (Disposed)
- {
- throw new ObjectDisposedException(GetType().FullName);
- }
- }
-
- private void CheckSentHeaders()
- {
- if (SentHeaders)
- {
- throw new InvalidOperationException();
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpRequestStream.Managed.cs b/SocketHttpListener/Net/HttpRequestStream.Managed.cs
deleted file mode 100644
index 42fc4d97c..000000000
--- a/SocketHttpListener/Net/HttpRequestStream.Managed.cs
+++ /dev/null
@@ -1,210 +0,0 @@
-using System;
-using System.IO;
-
-namespace SocketHttpListener.Net
-{
- // Licensed to the .NET Foundation under one or more agreements.
- // See the LICENSE file in the project root for more information.
- //
- // System.Net.ResponseStream
- //
- // Author:
- // Gonzalo Paniagua Javier (gonzalo@novell.com)
- //
- // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
-
- internal partial class HttpRequestStream : Stream
- {
- private byte[] _buffer;
- private int _offset;
- private int _length;
- private long _remainingBody;
- protected bool _closed;
- private Stream _stream;
-
- internal HttpRequestStream(Stream stream, byte[] buffer, int offset, int length)
- : this(stream, buffer, offset, length, -1)
- {
- }
-
- internal HttpRequestStream(Stream stream, byte[] buffer, int offset, int length, long contentlength)
- {
- _stream = stream;
- _buffer = buffer;
- _offset = offset;
- _length = length;
- _remainingBody = contentlength;
- }
-
- // 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.
- private int FillFromBuffer(byte[] buffer, int offset, int count)
- {
- if (_remainingBody == 0)
- return -1;
-
- if (_length == 0)
- return 0;
-
- int size = Math.Min(_length, count);
- if (_remainingBody > 0)
- size = (int)Math.Min(size, _remainingBody);
-
- if (_offset > _buffer.Length - size)
- {
- size = Math.Min(size, _buffer.Length - _offset);
- }
- if (size == 0)
- return 0;
-
- Buffer.BlockCopy(_buffer, _offset, buffer, offset, size);
- _offset += size;
- _length -= size;
- if (_remainingBody > 0)
- _remainingBody -= size;
- return size;
- }
-
- protected virtual int ReadCore(byte[] buffer, int offset, int size)
- {
- // Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
- int nread = FillFromBuffer(buffer, offset, size);
- if (nread == -1)
- { // No more bytes available (Content-Length)
- return 0;
- }
- else if (nread > 0)
- {
- return nread;
- }
-
- if (_remainingBody > 0)
- {
- size = (int)Math.Min(_remainingBody, (long)size);
- }
-
- nread = _stream.Read(buffer, offset, size);
-
- if (_remainingBody > 0)
- {
- if (nread == 0)
- {
- throw new Exception("Bad request");
- }
-
- //Debug.Assert(nread <= _remainingBody);
- _remainingBody -= nread;
- }
-
- return nread;
- }
-
- protected virtual IAsyncResult BeginReadCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state)
- {
- if (size == 0 || _closed)
- {
- var ares = new HttpStreamAsyncResult(this);
- ares._callback = cback;
- ares._state = state;
- ares.Complete();
- return ares;
- }
-
- int nread = FillFromBuffer(buffer, offset, size);
- if (nread > 0 || nread == -1)
- {
- var ares = new HttpStreamAsyncResult(this);
- ares._buffer = buffer;
- ares._offset = offset;
- ares._count = size;
- 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 (_remainingBody >= 0 && size > _remainingBody)
- {
- size = (int)Math.Min(_remainingBody, (long)size);
- }
-
- return _stream.BeginRead(buffer, offset, size, cback, state);
- }
-
- public override int EndRead(IAsyncResult asyncResult)
- {
- if (asyncResult == null)
- throw new ArgumentNullException(nameof(asyncResult));
-
- var r = asyncResult as HttpStreamAsyncResult;
- if (r != null)
- {
- if (!ReferenceEquals(this, r._parent))
- {
- throw new ArgumentException("Invalid async result");
- }
- if (r._endCalled)
- {
- throw new InvalidOperationException("invalid end call");
- }
- r._endCalled = true;
-
- if (!asyncResult.IsCompleted)
- {
- asyncResult.AsyncWaitHandle.WaitOne();
- }
-
- return r._synchRead;
- }
-
- if (_closed)
- return 0;
-
- int nread = 0;
- try
- {
- nread = _stream.EndRead(asyncResult);
- }
- catch (IOException e) when (e.InnerException is ArgumentException || e.InnerException is InvalidOperationException)
- {
- throw e.InnerException;
- }
-
- if (_remainingBody > 0)
- {
- if (nread == 0)
- {
- throw new Exception("Bad request");
- }
-
- _remainingBody -= nread;
- }
-
- return nread;
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpRequestStream.cs b/SocketHttpListener/Net/HttpRequestStream.cs
deleted file mode 100644
index 1c554df20..000000000
--- a/SocketHttpListener/Net/HttpRequestStream.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Net
-{
- // Licensed to the .NET Foundation under one or more agreements.
- // See the LICENSE file in the project root for more information.
- //
- // System.Net.ResponseStream
- //
- // Author:
- // Gonzalo Paniagua Javier (gonzalo@novell.com)
- //
- // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
-
- internal partial class HttpRequestStream : Stream
- {
- public override bool CanSeek => false;
- public override bool CanWrite => false;
- public override bool CanRead => true;
-
- public override int Read(byte[] buffer, int offset, int size)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
- if (offset < 0 || offset > buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
- if (size < 0 || size > buffer.Length - offset)
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- if (size == 0 || _closed)
- {
- return 0;
- }
-
- return ReadCore(buffer, offset, size);
- }
-
- public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
- if (offset < 0 || offset > buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
- if (size < 0 || size > buffer.Length - offset)
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
-
- return BeginReadCore(buffer, offset, size, callback, state);
- }
-
- public override void Flush() { }
- public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
-
- public override long Length => throw new NotImplementedException();
-
- public override long Position
- {
- get => throw new NotImplementedException();
-
- set => throw new NotImplementedException();
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
-
- public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
- {
- return base.BeginWrite(buffer, offset, count, callback, state);
- }
-
- public override void EndWrite(IAsyncResult asyncResult)
- {
- base.EndWrite(asyncResult);
- }
-
- internal bool Closed => _closed;
-
- protected override void Dispose(bool disposing)
- {
- _closed = true;
- base.Dispose(disposing);
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs
deleted file mode 100644
index 5d02a9c95..000000000
--- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs
+++ /dev/null
@@ -1,329 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.System;
-using Microsoft.Extensions.Logging;
-
-namespace SocketHttpListener.Net
-{
- // Licensed to the .NET Foundation under one or more agreements.
- // See the LICENSE file in the project root for more information.
- //
- // System.Net.ResponseStream
- //
- // Author:
- // Gonzalo Paniagua Javier (gonzalo@novell.com)
- //
- // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
-
- internal partial class HttpResponseStream : Stream
- {
- private HttpListenerResponse _response;
- private bool _ignore_errors;
- private bool _trailer_sent;
- private Stream _stream;
- private readonly IStreamHelper _streamHelper;
- private readonly Socket _socket;
- private readonly bool _supportsDirectSocketAccess;
- private readonly IEnvironmentInfo _environment;
- private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
-
- internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IStreamHelper streamHelper, Socket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger)
- {
- _response = response;
- _ignore_errors = ignore_errors;
- _streamHelper = streamHelper;
- _socket = socket;
- _supportsDirectSocketAccess = supportsDirectSocketAccess;
- _environment = environment;
- _fileSystem = fileSystem;
- _logger = logger;
- _stream = stream;
- }
-
- private void DisposeCore()
- {
- byte[] bytes = null;
- MemoryStream ms = GetHeaders(true);
- 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);
- }
- InternalWrite(ms.GetBuffer(), (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 (HttpListenerException)
- {
- // Ignore error due to connection reset by peer
- }
- }
- _response.Close();
- }
-
- internal async Task WriteWebSocketHandshakeHeadersAsync()
- {
- if (_closed)
- throw new ObjectDisposedException(GetType().ToString());
-
- if (_stream.CanWrite)
- {
- MemoryStream ms = GetHeaders(closing: false, isWebSocketHandshake: true);
- bool chunked = _response.SendChunked;
-
- long start = ms.Position;
- if (chunked)
- {
- byte[] bytes = GetChunkSizeBytes(0, true);
- ms.Position = ms.Length;
- ms.Write(bytes, 0, bytes.Length);
- }
-
- await InternalWriteAsync(ms.GetBuffer(), (int)start, (int)(ms.Length - start)).ConfigureAwait(false);
- await _stream.FlushAsync().ConfigureAwait(false);
- }
- }
-
- private MemoryStream GetHeaders(bool closing, bool isWebSocketHandshake = false)
- {
- //// SendHeaders works on shared headers
- //lock (_response.headers_lock)
- //{
- // if (_response.HeadersSent)
- // return null;
- // var ms = CreateNew();
- // _response.SendHeaders(closing, ms);
- // return ms;
- //}
-
- // SendHeaders works on shared headers
- lock (_response._headersLock)
- {
- if (_response.SentHeaders)
- {
- return null;
- }
-
- MemoryStream ms = new MemoryStream();
- _response.SendHeaders(closing, ms, isWebSocketHandshake);
- return ms;
- }
- }
-
- private static byte[] s_crlf = new byte[] { 13, 10 };
- private static byte[] GetChunkSizeBytes(int size, bool final)
- {
- string str = string.Format("{0:x}\r\n{1}", size, final ? "\r\n" : "");
- return Encoding.ASCII.GetBytes(str);
- }
-
- internal void InternalWrite(byte[] buffer, int offset, int count)
- {
- if (_ignore_errors)
- {
- try
- {
- _stream.Write(buffer, offset, count);
- }
- catch { }
- }
- else
- {
- _stream.Write(buffer, offset, count);
- }
- }
-
- internal Task InternalWriteAsync(byte[] buffer, int offset, int count) =>
- _ignore_errors ? InternalWriteIgnoreErrorsAsync(buffer, offset, count) : _stream.WriteAsync(buffer, offset, count);
-
- private async Task InternalWriteIgnoreErrorsAsync(byte[] buffer, int offset, int count)
- {
- try { await _stream.WriteAsync(buffer, offset, count).ConfigureAwait(false); }
- catch { }
- }
-
- private void WriteCore(byte[] buffer, int offset, int size)
- {
- if (size == 0)
- return;
-
- byte[] bytes = null;
- MemoryStream ms = GetHeaders(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(size, false);
- ms.Write(bytes, 0, bytes.Length);
- }
-
- int new_count = Math.Min(size, 16384 - (int)ms.Position + (int)start);
- ms.Write(buffer, offset, new_count);
- size -= new_count;
- offset += new_count;
- InternalWrite(ms.GetBuffer(), (int)start, (int)(ms.Length - start));
- ms.SetLength(0);
- ms.Capacity = 0; // 'dispose' the buffer in ms.
- }
- else if (chunked)
- {
- bytes = GetChunkSizeBytes(size, false);
- InternalWrite(bytes, 0, bytes.Length);
- }
-
- if (size > 0)
- InternalWrite(buffer, offset, size);
- if (chunked)
- InternalWrite(s_crlf, 0, 2);
- }
-
- private IAsyncResult BeginWriteCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state)
- {
- if (_closed)
- {
- var ares = new HttpStreamAsyncResult(this);
- ares._callback = cback;
- ares._state = state;
- ares.Complete();
- return ares;
- }
-
- 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(size, false);
- ms.Write(bytes, 0, bytes.Length);
- }
- ms.Write(buffer, offset, size);
- buffer = ms.GetBuffer();
- offset = (int)start;
- size = (int)(ms.Position - start);
- }
- else if (chunked)
- {
- bytes = GetChunkSizeBytes(size, false);
- InternalWrite(bytes, 0, bytes.Length);
- }
-
- return _stream.BeginWrite(buffer, offset, size, cback, state);
- }
-
- private void EndWriteCore(IAsyncResult asyncResult)
- {
- if (_closed)
- return;
-
- if (_ignore_errors)
- {
- try
- {
- _stream.EndWrite(asyncResult);
- if (_response.SendChunked)
- _stream.Write(s_crlf, 0, 2);
- }
- catch { }
- }
- else
- {
- _stream.EndWrite(asyncResult);
- if (_response.SendChunked)
- _stream.Write(s_crlf, 0, 2);
- }
- }
-
- public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
- }
-
- const int StreamCopyToBufferSize = 81920;
- private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
- {
- var allowAsync = _environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows;
-
- //if (count <= 0)
- //{
- // allowAsync = true;
- //}
-
- var fileOpenOptions = 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)
- {
- await _streamHelper.CopyToAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- await fs.CopyToAsync(targetStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false);
- }
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpResponseStream.cs b/SocketHttpListener/Net/HttpResponseStream.cs
deleted file mode 100644
index 085c2ad0c..000000000
--- a/SocketHttpListener/Net/HttpResponseStream.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Net
-{
- internal sealed partial class HttpResponseStream : Stream
- {
- private bool _closed;
- internal bool Closed => _closed;
-
- public override bool CanRead => false;
- public override bool CanSeek => false;
- public override bool CanWrite => true;
-
- public override void Flush() { }
- public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
-
- public override long Length => throw new NotImplementedException();
-
- public override long Position
- {
- get => throw new NotImplementedException();
-
- set => throw new NotImplementedException();
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
-
- public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
- {
- return base.BeginRead(buffer, offset, count, callback, state);
- }
-
- public override int EndRead(IAsyncResult asyncResult)
- {
- return base.EndRead(asyncResult);
- }
-
- public override void Write(byte[] buffer, int offset, int size)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
- if (offset < 0 || offset > buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
- if (size < 0 || size > buffer.Length - offset)
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- if (_closed)
- {
- return;
- }
-
- WriteCore(buffer, offset, size);
- }
-
- public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
- if (offset < 0 || offset > buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
- if (size < 0 || size > buffer.Length - offset)
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
-
- return BeginWriteCore(buffer, offset, size, callback, state);
- }
-
- public override void EndWrite(IAsyncResult asyncResult)
- {
- if (asyncResult == null)
- {
- throw new ArgumentNullException(nameof(asyncResult));
- }
-
- EndWriteCore(asyncResult);
- }
-
- protected override void Dispose(bool disposing)
- {
- try
- {
- if (disposing)
- {
- if (_closed)
- {
- return;
- }
- _closed = true;
- DisposeCore();
- }
- }
- finally
- {
- base.Dispose(disposing);
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpStatusCode.cs b/SocketHttpListener/Net/HttpStatusCode.cs
deleted file mode 100644
index d4bb61b8a..000000000
--- a/SocketHttpListener/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/Net/HttpStatusDescription.cs b/SocketHttpListener/Net/HttpStatusDescription.cs
deleted file mode 100644
index a4e42560b..000000000
--- a/SocketHttpListener/Net/HttpStatusDescription.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-namespace SocketHttpListener.Net
-{
- internal static class HttpStatusDescription
- {
- internal static string Get(HttpStatusCode code)
- {
- return Get((int)code);
- }
-
- internal static string Get(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 426: return "Upgrade Required"; // RFC 2817
-
- 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 null;
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpStreamAsyncResult.cs b/SocketHttpListener/Net/HttpStreamAsyncResult.cs
deleted file mode 100644
index 46944c624..000000000
--- a/SocketHttpListener/Net/HttpStreamAsyncResult.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Net
-{
- internal class HttpStreamAsyncResult : IAsyncResult
- {
- private object _locker = new object();
- private ManualResetEvent _handle;
- private bool _completed;
-
- internal readonly object _parent;
- internal byte[] _buffer;
- internal int _offset;
- internal int _count;
- internal AsyncCallback _callback;
- internal object _state;
- internal int _synchRead;
- internal Exception _error;
- internal bool _endCalled;
-
- internal HttpStreamAsyncResult(object parent)
- {
- _parent = parent;
- }
-
- 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)
- Task.Run(() => _callback(this));
- }
- }
-
- public object AsyncState => _state;
-
- public WaitHandle AsyncWaitHandle
- {
- get
- {
- lock (_locker)
- {
- if (_handle == null)
- _handle = new ManualResetEvent(_completed);
- }
-
- return _handle;
- }
- }
-
- public bool CompletedSynchronously => false;
-
- public bool IsCompleted
- {
- get
- {
- lock (_locker)
- {
- return _completed;
- }
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/HttpVersion.cs b/SocketHttpListener/Net/HttpVersion.cs
deleted file mode 100644
index c0839b46d..000000000
--- a/SocketHttpListener/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/Net/ListenerPrefix.cs b/SocketHttpListener/Net/ListenerPrefix.cs
deleted file mode 100644
index edfcb8904..000000000
--- a/SocketHttpListener/Net/ListenerPrefix.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using System;
-using System.Net;
-
-namespace SocketHttpListener.Net
-{
- internal sealed class ListenerPrefix
- {
- private string _original;
- private string _host;
- private ushort _port;
- private string _path;
- private bool _secure;
- private IPAddress[] _addresses;
- internal HttpListener _listener;
-
- public ListenerPrefix(string prefix)
- {
- _original = prefix;
- Parse(prefix);
- }
-
- public override string ToString()
- {
- return _original;
- }
-
- public IPAddress[] Addresses
- {
- get => _addresses;
- set => _addresses = value;
- }
- public bool Secure => _secure;
-
- public string Host => _host;
-
- public int Port => _port;
-
- public string Path => _path;
-
- // Equals and GetHashCode are required to detect duplicates in HttpListenerPrefixCollection.
- public override bool Equals(object o)
- {
- var other = o as ListenerPrefix;
- if (other == null)
- return false;
-
- return (_original == other._original);
- }
-
- public override int GetHashCode()
- {
- return _original.GetHashCode();
- }
-
- private 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("net_listener_host");
-
- 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)int.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);
- }
- }
-}
diff --git a/SocketHttpListener/Net/UriScheme.cs b/SocketHttpListener/Net/UriScheme.cs
deleted file mode 100644
index 33d1f09db..000000000
--- a/SocketHttpListener/Net/UriScheme.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace SocketHttpListener.Net
-{
- internal static class UriScheme
- {
- public const string File = "file";
- public const string Ftp = "ftp";
- public const string Gopher = "gopher";
- public const string Http = "http";
- public const string Https = "https";
- public const string News = "news";
- public const string NetPipe = "net.pipe";
- public const string NetTcp = "net.tcp";
- public const string Nntp = "nntp";
- public const string Mailto = "mailto";
- public const string Ws = "ws";
- public const string Wss = "wss";
-
- public const string SchemeDelimiter = "://";
- }
-}
diff --git a/SocketHttpListener/Net/WebHeaderCollection.cs b/SocketHttpListener/Net/WebHeaderCollection.cs
deleted file mode 100644
index 34fca808b..000000000
--- a/SocketHttpListener/Net/WebHeaderCollection.cs
+++ /dev/null
@@ -1,360 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-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;
-
- 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(nameof(header));
- int pos = header.IndexOf(':');
- if (pos == -1)
- throw new ArgumentException("no colon found", nameof(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(nameof(name));
-
- this.AddWithoutValidate(name, value);
- }
-
- protected void AddWithoutValidate(string headerName, string headerValue)
- {
- if (!IsHeaderName(headerName))
- throw new ArgumentException("invalid header name: " + headerName, nameof(headerName));
- if (headerValue == null)
- headerValue = string.Empty;
- else
- headerValue = headerValue.Trim();
- if (!IsHeaderValue(headerValue))
- throw new ArgumentException("invalid header value: " + headerValue, nameof(headerValue));
-
- AddValue(headerName, headerValue);
- }
-
- internal void AddValue(string headerName, string headerValue)
- {
- base.Add(headerName, headerValue);
- }
-
- internal List<string> GetValues_internal(string header, bool split)
- {
- if (header == null)
- throw new ArgumentNullException(nameof(header));
-
- var values = base.GetValues(header);
- if (values == null || values.Count == 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.Count + 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;
- }
-
- return values;
- }
-
- public override List<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(nameof(headerName));
-
- if (headerName.Length == 0)
- throw new ArgumentException("empty string", nameof(headerName));
-
- if (!IsHeaderName(headerName))
- throw new ArgumentException("Invalid character in header");
-
- if (!headers.TryGetValue(headerName, out HeaderInfo 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(nameof(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");
-
- base.Set(name, value);
- }
-
- internal string ToStringMultiValue()
- {
- var 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()
- {
- var 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", nameof(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);
- }
- }
-
- internal static bool IsMultiValue(string headerName)
- {
- if (headerName == null)
- return false;
-
- return headers.TryGetValue(headerName, out HeaderInfo 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/Net/WebHeaderEncoding.cs b/SocketHttpListener/Net/WebHeaderEncoding.cs
deleted file mode 100644
index 96e0cc85d..000000000
--- a/SocketHttpListener/Net/WebHeaderEncoding.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System.Text;
-
-namespace SocketHttpListener.Net
-{
- // we use this static class as a helper class to encode/decode HTTP headers.
- // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF
- // and a byte in the range 0x00-0xFF (which is the range that can hit the network).
- // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow.
- // It doesn't work for string -> byte[] because of best-fit-mapping problems.
- internal static class WebHeaderEncoding
- {
- // We don't want '?' replacement characters, just fail.
- private static readonly Encoding s_utf8Decoder = Encoding.GetEncoding("utf-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
-
- internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount)
- {
- fixed (byte* pBytes = bytes)
- return GetString(pBytes + byteIndex, byteCount);
- }
-
- internal static unsafe string GetString(byte* pBytes, int byteCount)
- {
- if (byteCount < 1)
- return "";
-
- string s = new string('\0', byteCount);
-
- fixed (char* pStr = s)
- {
- char* pString = pStr;
- while (byteCount >= 8)
- {
- pString[0] = (char)pBytes[0];
- pString[1] = (char)pBytes[1];
- pString[2] = (char)pBytes[2];
- pString[3] = (char)pBytes[3];
- pString[4] = (char)pBytes[4];
- pString[5] = (char)pBytes[5];
- pString[6] = (char)pBytes[6];
- pString[7] = (char)pBytes[7];
- pString += 8;
- pBytes += 8;
- byteCount -= 8;
- }
- for (int i = 0; i < byteCount; i++)
- {
- pString[i] = (char)pBytes[i];
- }
- }
-
- return s;
- }
-
- internal static int GetByteCount(string myString)
- {
- return myString.Length;
- }
- internal static unsafe void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex)
- {
- if (myString.Length == 0)
- {
- return;
- }
- fixed (byte* bufferPointer = bytes)
- {
- byte* newBufferPointer = bufferPointer + byteIndex;
- int finalIndex = charIndex + charCount;
- while (charIndex < finalIndex)
- {
- *newBufferPointer++ = (byte)myString[charIndex++];
- }
- }
- }
- internal static byte[] GetBytes(string myString)
- {
- byte[] bytes = new byte[myString.Length];
- if (myString.Length != 0)
- {
- GetBytes(myString, 0, myString.Length, bytes, 0);
- }
- return bytes;
- }
- }
-}
diff --git a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs
deleted file mode 100644
index 5ed49ec47..000000000
--- a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Net;
-using System.Security.Principal;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- public class HttpListenerWebSocketContext : WebSocketContext
- {
- private readonly Uri _requestUri;
- private readonly QueryParamCollection _headers;
- private readonly CookieCollection _cookieCollection;
- private readonly IPrincipal _user;
- private readonly bool _isAuthenticated;
- private readonly bool _isLocal;
- private readonly bool _isSecureConnection;
-
- private readonly string _origin;
- private readonly IEnumerable<string> _secWebSocketProtocols;
- private readonly string _secWebSocketVersion;
- private readonly string _secWebSocketKey;
-
- private readonly WebSocket _webSocket;
-
- internal HttpListenerWebSocketContext(
- Uri requestUri,
- QueryParamCollection headers,
- CookieCollection cookieCollection,
- IPrincipal user,
- bool isAuthenticated,
- bool isLocal,
- bool isSecureConnection,
- string origin,
- IEnumerable<string> secWebSocketProtocols,
- string secWebSocketVersion,
- string secWebSocketKey,
- WebSocket webSocket)
- {
- _cookieCollection = new CookieCollection();
- _cookieCollection.Add(cookieCollection);
-
- //_headers = new NameValueCollection(headers);
- _headers = headers;
- _user = CopyPrincipal(user);
-
- _requestUri = requestUri;
- _isAuthenticated = isAuthenticated;
- _isLocal = isLocal;
- _isSecureConnection = isSecureConnection;
- _origin = origin;
- _secWebSocketProtocols = secWebSocketProtocols;
- _secWebSocketVersion = secWebSocketVersion;
- _secWebSocketKey = secWebSocketKey;
- _webSocket = webSocket;
- }
-
- public override Uri RequestUri => _requestUri;
-
- public override QueryParamCollection Headers => _headers;
-
- public override string Origin => _origin;
-
- public override IEnumerable<string> SecWebSocketProtocols => _secWebSocketProtocols;
-
- public override string SecWebSocketVersion => _secWebSocketVersion;
-
- public override string SecWebSocketKey => _secWebSocketKey;
-
- public override CookieCollection CookieCollection => _cookieCollection;
-
- public override IPrincipal User => _user;
-
- public override bool IsAuthenticated => _isAuthenticated;
-
- public override bool IsLocal => _isLocal;
-
- public override bool IsSecureConnection => _isSecureConnection;
-
- public override WebSocket WebSocket => _webSocket;
-
- private static IPrincipal CopyPrincipal(IPrincipal user)
- {
- if (user != null)
- {
- throw new NotImplementedException();
- }
-
- return null;
- }
- }
-}
diff --git a/SocketHttpListener/Net/WebSockets/HttpWebSocket.Managed.cs b/SocketHttpListener/Net/WebSockets/HttpWebSocket.Managed.cs
deleted file mode 100644
index 1cfd2dc90..000000000
--- a/SocketHttpListener/Net/WebSockets/HttpWebSocket.Managed.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using System.Threading.Tasks;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- internal static partial class HttpWebSocket
- {
- private const string SupportedVersion = "13";
-
- internal static async Task<HttpListenerWebSocketContext> AcceptWebSocketAsyncCore(HttpListenerContext context,
- string subProtocol,
- int receiveBufferSize,
- TimeSpan keepAliveInterval,
- ArraySegment<byte>? internalBuffer = null)
- {
- ValidateOptions(subProtocol, receiveBufferSize, MinSendBufferSize, keepAliveInterval);
-
- // get property will create a new response if one doesn't exist.
- HttpListenerResponse response = context.Response;
- HttpListenerRequest request = context.Request;
- ValidateWebSocketHeaders(context);
-
- string secWebSocketVersion = request.Headers[HttpKnownHeaderNames.SecWebSocketVersion];
-
- // Optional for non-browser client
- string origin = request.Headers[HttpKnownHeaderNames.Origin];
-
- string[] secWebSocketProtocols = null;
- bool shouldSendSecWebSocketProtocolHeader =
- ProcessWebSocketProtocolHeader(
- request.Headers[HttpKnownHeaderNames.SecWebSocketProtocol],
- subProtocol,
- out var outgoingSecWebSocketProtocolString);
-
- if (shouldSendSecWebSocketProtocolHeader)
- {
- secWebSocketProtocols = new string[] { outgoingSecWebSocketProtocolString };
- response.Headers.Add(HttpKnownHeaderNames.SecWebSocketProtocol, outgoingSecWebSocketProtocolString);
- }
-
- // negotiate the websocket key return value
- string secWebSocketKey = request.Headers[HttpKnownHeaderNames.SecWebSocketKey];
- string secWebSocketAccept = HttpWebSocket.GetSecWebSocketAcceptString(secWebSocketKey);
-
- response.Headers.Add(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade);
- response.Headers.Add(HttpKnownHeaderNames.Upgrade, WebSocketUpgradeToken);
- response.Headers.Add(HttpKnownHeaderNames.SecWebSocketAccept, secWebSocketAccept);
-
- response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; // HTTP 101
- response.StatusDescription = HttpStatusDescription.Get(HttpStatusCode.SwitchingProtocols);
-
- var responseStream = response.OutputStream as HttpResponseStream;
-
- // Send websocket handshake headers
- await responseStream.WriteWebSocketHandshakeHeadersAsync().ConfigureAwait(false);
-
- //WebSocket webSocket = WebSocket.CreateFromStream(context.Connection.ConnectedStream, isServer: true, subProtocol, keepAliveInterval);
- var webSocket = new WebSocket(subProtocol);
-
- var webSocketContext = new HttpListenerWebSocketContext(
- request.Url,
- request.Headers,
- request.Cookies,
- context.User,
- request.IsAuthenticated,
- request.IsLocal,
- request.IsSecureConnection,
- origin,
- secWebSocketProtocols != null ? secWebSocketProtocols : Array.Empty<string>(),
- secWebSocketVersion,
- secWebSocketKey,
- webSocket);
-
- webSocket.SetContext(webSocketContext, context.Connection.Close, context.Connection.Stream);
-
- return webSocketContext;
- }
-
- private const bool WebSocketsSupported = true;
- }
-}
diff --git a/SocketHttpListener/Net/WebSockets/HttpWebSocket.cs b/SocketHttpListener/Net/WebSockets/HttpWebSocket.cs
deleted file mode 100644
index b346cc98e..000000000
--- a/SocketHttpListener/Net/WebSockets/HttpWebSocket.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Security.Cryptography;
-using System.Text;
-using System.Threading;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- internal static partial class HttpWebSocket
- {
- internal const string SecWebSocketKeyGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- internal const string WebSocketUpgradeToken = "websocket";
- internal const int DefaultReceiveBufferSize = 16 * 1024;
- internal const int DefaultClientSendBufferSize = 16 * 1024;
-
- [SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 used only for hashing purposes, not for crypto.")]
- internal static string GetSecWebSocketAcceptString(string secWebSocketKey)
- {
- string retVal;
-
- // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat.
- using (var sha1 = SHA1.Create())
- {
- string acceptString = string.Concat(secWebSocketKey, HttpWebSocket.SecWebSocketKeyGuid);
- byte[] toHash = Encoding.UTF8.GetBytes(acceptString);
- retVal = Convert.ToBase64String(sha1.ComputeHash(toHash));
- }
-
- return retVal;
- }
-
- // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server.
- internal static bool ProcessWebSocketProtocolHeader(string clientSecWebSocketProtocol,
- string subProtocol,
- out string acceptProtocol)
- {
- acceptProtocol = string.Empty;
- if (string.IsNullOrEmpty(clientSecWebSocketProtocol))
- {
- // client hasn't specified any Sec-WebSocket-Protocol header
- if (subProtocol != null)
- {
- // If the server specified _anything_ this isn't valid.
- throw new WebSocketException("UnsupportedProtocol");
- }
- // Treat empty and null from the server as the same thing here, server should not send headers.
- return false;
- }
-
- // here, we know the client specified something and it's non-empty.
-
- if (subProtocol == null)
- {
- // client specified some protocols, server specified 'null'. So server should send headers.
- return true;
- }
-
- // here, we know that the client has specified something, it's not empty
- // and the server has specified exactly one protocol
-
- string[] requestProtocols = clientSecWebSocketProtocol.Split(new char[] { ',' },
- StringSplitOptions.RemoveEmptyEntries);
- acceptProtocol = subProtocol;
-
- // client specified protocols, serverOptions has exactly 1 non-empty entry. Check that
- // this exists in the list the client specified.
- for (int i = 0; i < requestProtocols.Length; i++)
- {
- string currentRequestProtocol = requestProtocols[i].Trim();
- if (string.Equals(acceptProtocol, currentRequestProtocol, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- throw new WebSocketException("net_WebSockets_AcceptUnsupportedProtocol");
- }
-
- internal static void ValidateOptions(string subProtocol, int receiveBufferSize, int sendBufferSize, TimeSpan keepAliveInterval)
- {
- if (subProtocol != null)
- {
- WebSocketValidate.ValidateSubprotocol(subProtocol);
- }
-
- if (receiveBufferSize < MinReceiveBufferSize)
- {
- throw new ArgumentOutOfRangeException(nameof(receiveBufferSize), "The receiveBufferSize was too small.");
- }
-
- if (sendBufferSize < MinSendBufferSize)
- {
- throw new ArgumentOutOfRangeException(nameof(sendBufferSize), "The sendBufferSize was too small.");
- }
-
- if (receiveBufferSize > MaxBufferSize)
- {
- throw new ArgumentOutOfRangeException(nameof(receiveBufferSize), "The receiveBufferSize was too large.");
- }
-
- if (sendBufferSize > MaxBufferSize)
- {
- throw new ArgumentOutOfRangeException(nameof(sendBufferSize), "The sendBufferSize was too large.");
- }
-
- if (keepAliveInterval < Timeout.InfiniteTimeSpan) // -1 millisecond
- {
- throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), "The keepAliveInterval was too small.");
- }
- }
-
- internal const int MinSendBufferSize = 16;
- internal const int MinReceiveBufferSize = 256;
- internal const int MaxBufferSize = 64 * 1024;
-
- private static void ValidateWebSocketHeaders(HttpListenerContext context)
- {
- if (!WebSocketsSupported)
- {
- throw new PlatformNotSupportedException("net_WebSockets_UnsupportedPlatform");
- }
-
- if (!context.Request.IsWebSocketRequest)
- {
- throw new WebSocketException("net_WebSockets_AcceptNotAWebSocket");
- }
-
- string secWebSocketVersion = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketVersion];
- if (string.IsNullOrEmpty(secWebSocketVersion))
- {
- throw new WebSocketException("net_WebSockets_AcceptHeaderNotFound");
- }
-
- if (!string.Equals(secWebSocketVersion, SupportedVersion, StringComparison.OrdinalIgnoreCase))
- {
- throw new WebSocketException("net_WebSockets_AcceptUnsupportedWebSocketVersion");
- }
-
- string secWebSocketKey = context.Request.Headers[HttpKnownHeaderNames.SecWebSocketKey];
- bool isSecWebSocketKeyInvalid = string.IsNullOrWhiteSpace(secWebSocketKey);
- if (!isSecWebSocketKeyInvalid)
- {
- try
- {
- // key must be 16 bytes then base64-encoded
- isSecWebSocketKeyInvalid = Convert.FromBase64String(secWebSocketKey).Length != 16;
- }
- catch
- {
- isSecWebSocketKeyInvalid = true;
- }
- }
- if (isSecWebSocketKeyInvalid)
- {
- throw new WebSocketException("net_WebSockets_AcceptHeaderNotFound");
- }
- }
- }
-}
diff --git a/SocketHttpListener/Net/WebSockets/WebSocketCloseStatus.cs b/SocketHttpListener/Net/WebSockets/WebSocketCloseStatus.cs
deleted file mode 100644
index 5ac89cf48..000000000
--- a/SocketHttpListener/Net/WebSockets/WebSocketCloseStatus.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace SocketHttpListener.Net.WebSockets
-{
- public enum WebSocketCloseStatus
- {
- NormalClosure = 1000,
- EndpointUnavailable = 1001,
- ProtocolError = 1002,
- InvalidMessageType = 1003,
- Empty = 1005,
- // AbnormalClosure = 1006, // 1006 is reserved and should never be used by user
- InvalidPayloadData = 1007,
- PolicyViolation = 1008,
- MessageTooBig = 1009,
- MandatoryExtension = 1010,
- InternalServerError = 1011
- // TLSHandshakeFailed = 1015, // 1015 is reserved and should never be used by user
-
- // 0 - 999 Status codes in the range 0-999 are not used.
- // 1000 - 1999 Status codes in the range 1000-1999 are reserved for definition by this protocol.
- // 2000 - 2999 Status codes in the range 2000-2999 are reserved for use by extensions.
- // 3000 - 3999 Status codes in the range 3000-3999 MAY be used by libraries and frameworks. The
- // interpretation of these codes is undefined by this protocol. End applications MUST
- // NOT use status codes in this range.
- // 4000 - 4999 Status codes in the range 4000-4999 MAY be used by application code. The interpretation
- // of these codes is undefined by this protocol.
- }
-}
diff --git a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs
deleted file mode 100644
index 10ad86439..000000000
--- a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Net;
-using System.Security.Principal;
-using MediaBrowser.Model.Services;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- public abstract class WebSocketContext
- {
- public abstract Uri RequestUri { get; }
- public abstract QueryParamCollection Headers { get; }
- public abstract string Origin { get; }
- public abstract IEnumerable<string> SecWebSocketProtocols { get; }
- public abstract string SecWebSocketVersion { get; }
- public abstract string SecWebSocketKey { get; }
- public abstract CookieCollection CookieCollection { get; }
- public abstract IPrincipal User { get; }
- public abstract bool IsAuthenticated { get; }
- public abstract bool IsLocal { get; }
- public abstract bool IsSecureConnection { get; }
- public abstract WebSocket WebSocket { get; }
- }
-}
diff --git a/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs b/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs
deleted file mode 100644
index 0469e3b6c..000000000
--- a/SocketHttpListener/Net/WebSockets/WebSocketValidate.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-using System;
-using System.Globalization;
-using System.Text;
-using WebSocketState = System.Net.WebSockets.WebSocketState;
-
-namespace SocketHttpListener.Net.WebSockets
-{
- internal static partial class WebSocketValidate
- {
- internal const int MaxControlFramePayloadLength = 123;
- private const int CloseStatusCodeAbort = 1006;
- private const int CloseStatusCodeFailedTLSHandshake = 1015;
- private const int InvalidCloseStatusCodesFrom = 0;
- private const int InvalidCloseStatusCodesTo = 999;
- private const string Separators = "()<>@,;:\\\"/[]?={} ";
-
- internal static void ThrowIfInvalidState(WebSocketState currentState, bool isDisposed, WebSocketState[] validStates)
- {
- string validStatesText = string.Empty;
-
- if (validStates != null && validStates.Length > 0)
- {
- foreach (WebSocketState validState in validStates)
- {
- if (currentState == validState)
- {
- // Ordering is important to maintain .NET 4.5 WebSocket implementation exception behavior.
- if (isDisposed)
- {
- throw new ObjectDisposedException(nameof(WebSocket));
- }
-
- return;
- }
- }
-
- validStatesText = string.Join(", ", validStates);
- }
-
- throw new WebSocketException("net_WebSockets_InvalidState");
- }
-
- internal static void ValidateSubprotocol(string subProtocol)
- {
- if (string.IsNullOrWhiteSpace(subProtocol))
- {
- throw new ArgumentException("net_WebSockets_InvalidEmptySubProtocol");
- }
-
- string invalidChar = null;
- int i = 0;
- while (i < subProtocol.Length)
- {
- char ch = subProtocol[i];
- if (ch < 0x21 || ch > 0x7e)
- {
- invalidChar = string.Format(CultureInfo.InvariantCulture, "[{0}]", (int)ch);
- break;
- }
-
- if (!char.IsLetterOrDigit(ch) &&
- Separators.IndexOf(ch) >= 0)
- {
- invalidChar = ch.ToString();
- break;
- }
-
- i++;
- }
-
- if (invalidChar != null)
- {
- throw new ArgumentException("net_WebSockets_InvalidCharInProtocolString");
- }
- }
-
- internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, string statusDescription)
- {
- if (closeStatus == WebSocketCloseStatus.Empty && !string.IsNullOrEmpty(statusDescription))
- {
- throw new ArgumentException("net_WebSockets_ReasonNotNull");
- }
-
- int closeStatusCode = (int)closeStatus;
-
- if ((closeStatusCode >= InvalidCloseStatusCodesFrom &&
- closeStatusCode <= InvalidCloseStatusCodesTo) ||
- closeStatusCode == CloseStatusCodeAbort ||
- closeStatusCode == CloseStatusCodeFailedTLSHandshake)
- {
- // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort
- throw new ArgumentException("net_WebSockets_InvalidCloseStatusCode");
- }
-
- int length = 0;
- if (!string.IsNullOrEmpty(statusDescription))
- {
- length = Encoding.UTF8.GetByteCount(statusDescription);
- }
-
- if (length > MaxControlFramePayloadLength)
- {
- throw new ArgumentException("net_WebSockets_InvalidCloseStatusDescription");
- }
- }
-
- internal static void ValidateArraySegment(ArraySegment<byte> arraySegment, string parameterName)
- {
- if (arraySegment.Array == null)
- {
- throw new ArgumentNullException(parameterName + "." + nameof(arraySegment.Array));
- }
- if (arraySegment.Offset < 0 || arraySegment.Offset > arraySegment.Array.Length)
- {
- throw new ArgumentOutOfRangeException(parameterName + "." + nameof(arraySegment.Offset));
- }
- if (arraySegment.Count < 0 || arraySegment.Count > (arraySegment.Array.Length - arraySegment.Offset))
- {
- throw new ArgumentOutOfRangeException(parameterName + "." + nameof(arraySegment.Count));
- }
- }
-
- internal static void ValidateBuffer(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if (offset < 0 || offset > buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
-
- if (count < 0 || count > (buffer.Length - offset))
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
- }
- }
-}
diff --git a/SocketHttpListener/WebSocket.cs b/SocketHttpListener/WebSocket.cs
index 0dcb6a64b..afce871fd 100644
--- a/SocketHttpListener/WebSocket.cs
+++ b/SocketHttpListener/WebSocket.cs
@@ -4,11 +4,10 @@ using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
+using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using SocketHttpListener.Net.WebSockets;
-using HttpStatusCode = SocketHttpListener.Net.HttpStatusCode;
using WebSocketState = System.Net.WebSockets.WebSocketState;
namespace SocketHttpListener