aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/HttpServer
diff options
context:
space:
mode:
authorBond-009 <bond.009@outlook.com>2019-03-07 21:08:57 +0100
committerGitHub <noreply@github.com>2019-03-07 21:08:57 +0100
commit10a0d6bdba821449abfb1d48e9708ba6f3fc6a62 (patch)
tree602be322daedca127ba66de07837ac8e792730a7 /Emby.Server.Implementations/HttpServer
parentae0ecc1b10982d9240ecdcc82cb7299fc708aafb (diff)
parent0abe57e930e44eab9566991f33b089d1e61cfb83 (diff)
Merge pull request #1010 from cvium/kestrel_poc
Remove System.Net and port to Kestrel
Diffstat (limited to 'Emby.Server.Implementations/HttpServer')
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs46
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs85
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs88
-rw-r--r--Emby.Server.Implementations/HttpServer/IHttpListener.cs17
-rw-r--r--Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs9
-rw-r--r--Emby.Server.Implementations/HttpServer/ResponseFilter.cs10
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/StreamWriter.cs15
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs39
9 files changed, 110 insertions, 202 deletions
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index 7aedba9b3..c4d2a70e2 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -5,15 +5,19 @@ 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;
+using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
public class FileWriter : IHttpResult
{
+ private readonly IStreamHelper _streamHelper;
private ILogger Logger { get; set; }
+ private readonly IFileSystem _fileSystem;
private string RangeHeader { get; set; }
private bool IsHeadRequest { get; set; }
@@ -42,25 +46,27 @@ namespace Emby.Server.Implementations.HttpServer
public string Path { get; set; }
- public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem)
+ public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper)
{
if (string.IsNullOrEmpty(contentType))
{
throw new ArgumentNullException(nameof(contentType));
}
+ _streamHelper = streamHelper;
+ _fileSystem = fileSystem;
+
Path = path;
Logger = logger;
RangeHeader = rangeHeader;
- Headers["Content-Type"] = contentType;
+ Headers[HeaderNames.ContentType] = contentType;
TotalContentLength = fileSystem.GetFileInfo(path).Length;
- Headers["Accept-Ranges"] = "bytes";
+ Headers[HeaderNames.AcceptRanges] = "bytes";
if (string.IsNullOrWhiteSpace(rangeHeader))
{
- Headers["Content-Length"] = TotalContentLength.ToString(UsCulture);
StatusCode = HttpStatusCode.OK;
}
else
@@ -93,13 +99,10 @@ namespace Emby.Server.Implementations.HttpServer
RangeStart = requestedRange.Key;
RangeLength = 1 + RangeEnd - RangeStart;
- // Content-Length is the length of what we're serving, not the original content
- var lengthString = RangeLength.ToString(UsCulture);
- Headers["Content-Length"] = lengthString;
- var rangeString = string.Format("bytes {0}-{1}/{2}", RangeStart, RangeEnd, TotalContentLength);
- Headers["Content-Range"] = rangeString;
+ var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
+ Headers[HeaderNames.ContentRange] = rangeString;
- Logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
+ Logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Range: {2}", Path, RangeHeader, rangeString);
}
/// <summary>
@@ -145,8 +148,7 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- private string[] SkipLogExtensions = new string[]
- {
+ private static readonly string[] SkipLogExtensions = {
".js",
".html",
".css"
@@ -163,8 +165,10 @@ namespace Emby.Server.Implementations.HttpServer
}
var path = Path;
+ var offset = RangeStart;
+ var count = RangeLength;
- if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1))
+ if (string.IsNullOrWhiteSpace(RangeHeader) || RangeStart <= 0 && RangeEnd >= TotalContentLength - 1)
{
var extension = System.IO.Path.GetExtension(path);
@@ -173,20 +177,15 @@ namespace Emby.Server.Implementations.HttpServer
Logger.LogDebug("Transmit file {0}", path);
}
- //var count = FileShare == FileShareMode.ReadWrite ? TotalContentLength : 0;
-
- await response.TransmitFile(path, 0, 0, FileShare, cancellationToken).ConfigureAwait(false);
- return;
+ offset = 0;
+ count = 0;
}
- await response.TransmitFile(path, RangeStart, RangeLength, FileShare, cancellationToken).ConfigureAwait(false);
+ await response.TransmitFile(path, offset, count, FileShare, _fileSystem, _streamHelper, cancellationToken).ConfigureAwait(false);
}
finally
{
- if (OnComplete != null)
- {
- OnComplete();
- }
+ OnComplete?.Invoke();
}
}
@@ -203,8 +202,5 @@ namespace Emby.Server.Implementations.HttpServer
get => (HttpStatusCode)Status;
set => Status = (int)value;
}
-
- public string StatusDescription { get; set; }
-
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index ee746c669..d1b1b5b24 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Net;
using Emby.Server.Implementations.Services;
+using Emby.Server.Implementations.SocketSharp;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
@@ -20,6 +21,9 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Internal;
+using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using ServiceStack.Text.Jsv;
@@ -29,12 +33,8 @@ namespace Emby.Server.Implementations.HttpServer
public class HttpListenerHost : IHttpServer, IDisposable
{
private string DefaultRedirectPath { get; set; }
-
- private readonly ILogger _logger;
public string[] UrlPrefixes { get; private set; }
- private IHttpListener _listener;
-
public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
private readonly IServerConfigurationManager _config;
@@ -42,6 +42,7 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IServerApplicationHost _appHost;
private readonly IJsonSerializer _jsonSerializer;
private readonly IXmlSerializer _xmlSerializer;
+ private readonly IHttpListener _socketListener;
private readonly Func<Type, Func<string, object>> _funcParseFn;
public Action<IRequest, IResponse, object>[] ResponseFilters { get; set; }
@@ -59,15 +60,18 @@ namespace Emby.Server.Implementations.HttpServer
IConfiguration configuration,
INetworkManager networkManager,
IJsonSerializer jsonSerializer,
- IXmlSerializer xmlSerializer)
+ IXmlSerializer xmlSerializer,
+ IHttpListener socketListener)
{
_appHost = applicationHost;
- _logger = loggerFactory.CreateLogger("HttpServer");
+ Logger = loggerFactory.CreateLogger("HttpServer");
_config = config;
DefaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
_networkManager = networkManager;
_jsonSerializer = jsonSerializer;
_xmlSerializer = xmlSerializer;
+ _socketListener = socketListener;
+ _socketListener.WebSocketConnected = OnWebSocketConnected;
_funcParseFn = t => s => JsvReader.GetParseFn(t)(s);
@@ -77,7 +81,7 @@ namespace Emby.Server.Implementations.HttpServer
public string GlobalResponse { get; set; }
- protected ILogger Logger => _logger;
+ protected ILogger Logger { get; }
public object CreateInstance(Type type)
{
@@ -143,11 +147,11 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger)
+ var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, Logger)
{
OnReceive = ProcessWebSocketMessageReceived,
Url = e.Url,
- QueryString = e.QueryString ?? new QueryParamCollection()
+ QueryString = e.QueryString ?? new QueryCollection()
};
connection.Closed += Connection_Closed;
@@ -212,11 +216,11 @@ namespace Emby.Server.Implementations.HttpServer
if (logExceptionStackTrace)
{
- _logger.LogError(ex, "Error processing request");
+ Logger.LogError(ex, "Error processing request");
}
else if (logExceptionMessage)
{
- _logger.LogError(ex.Message);
+ Logger.LogError(ex.Message);
}
var httpRes = httpReq.Response;
@@ -234,7 +238,7 @@ namespace Emby.Server.Implementations.HttpServer
}
catch (Exception errorEx)
{
- _logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
+ Logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
}
}
@@ -277,14 +281,6 @@ namespace Emby.Server.Implementations.HttpServer
}
}
-
- if (_listener != null)
- {
- _logger.LogInformation("Stopping HttpListener...");
- var task = _listener.Stop();
- Task.WaitAll(task);
- _logger.LogInformation("HttpListener stopped");
- }
}
public static string RemoveQueryStringByKey(string url, string key)
@@ -292,7 +288,7 @@ namespace Emby.Server.Implementations.HttpServer
var uri = new Uri(url);
// this gets all the query string key value pairs as a collection
- var newQueryString = MyHttpUtility.ParseQueryString(uri.Query);
+ var newQueryString = QueryHelpers.ParseQuery(uri.Query);
var originalCount = newQueryString.Count;
@@ -313,7 +309,7 @@ namespace Emby.Server.Implementations.HttpServer
string pagePathWithoutQueryString = url.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0];
return newQueryString.Count > 0
- ? string.Format("{0}?{1}", pagePathWithoutQueryString, newQueryString)
+ ? QueryHelpers.AddQueryString(pagePathWithoutQueryString, newQueryString.ToDictionary(kv => kv.Key, kv => kv.Value.ToString()))
: pagePathWithoutQueryString;
}
@@ -422,7 +418,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
- protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
+ public async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
{
var stopWatch = new Stopwatch();
stopWatch.Start();
@@ -599,17 +595,17 @@ namespace Emby.Server.Implementations.HttpServer
}
finally
{
- httpRes.Close();
-
+ // TODO response closes automatically after the handler is done, but some functions rely on knowing if it's closed or not
+ httpRes.IsClosed = true;
stopWatch.Stop();
var elapsed = stopWatch.Elapsed;
if (elapsed.TotalMilliseconds > 500)
{
- _logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
+ Logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
}
else
{
- _logger.LogDebug("HTTP Response {StatusCode} to {RemoteIp}. Time: {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
+ Logger.LogDebug("HTTP Response {StatusCode} to {RemoteIp}. Time: {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
}
}
}
@@ -622,7 +618,7 @@ namespace Emby.Server.Implementations.HttpServer
var pathParts = pathInfo.TrimStart('/').Split('/');
if (pathParts.Length == 0)
{
- _logger.LogError("Path parts empty for PathInfo: {PathInfo}, Url: {RawUrl}", pathInfo, httpReq.RawUrl);
+ Logger.LogError("Path parts empty for PathInfo: {PathInfo}, Url: {RawUrl}", pathInfo, httpReq.RawUrl);
return null;
}
@@ -636,15 +632,13 @@ namespace Emby.Server.Implementations.HttpServer
};
}
- _logger.LogError("Could not find handler for {PathInfo}", pathInfo);
+ Logger.LogError("Could not find handler for {PathInfo}", pathInfo);
return null;
}
private static Task Write(IResponse response, string text)
{
var bOutput = Encoding.UTF8.GetBytes(text);
- response.SetContentLength(bOutput.Length);
-
return response.OutputStream.WriteAsync(bOutput, 0, bOutput.Length);
}
@@ -663,6 +657,7 @@ namespace Emby.Server.Implementations.HttpServer
}
else
{
+ // TODO what is this?
var httpsUrl = url
.Replace("http://", "https://", StringComparison.OrdinalIgnoreCase)
.Replace(":" + _config.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture), ":" + _config.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase);
@@ -689,7 +684,7 @@ namespace Emby.Server.Implementations.HttpServer
ServiceController = new ServiceController();
- _logger.LogInformation("Calling ServiceStack AppHost.Init");
+ Logger.LogInformation("Calling ServiceStack AppHost.Init");
var types = services.Select(r => r.GetType()).ToArray();
@@ -697,7 +692,7 @@ namespace Emby.Server.Implementations.HttpServer
ResponseFilters = new Action<IRequest, IResponse, object>[]
{
- new ResponseFilter(_logger).FilterResponse
+ new ResponseFilter(Logger).FilterResponse
};
}
@@ -759,8 +754,12 @@ namespace Emby.Server.Implementations.HttpServer
return _jsonSerializer.DeserializeFromStreamAsync(stream, type);
}
- //TODO Add Jellyfin Route Path Normalizer
+ public Task ProcessWebSocketRequest(HttpContext context)
+ {
+ return _socketListener.ProcessWebSocketRequest(context);
+ }
+ //TODO Add Jellyfin Route Path Normalizer
private static string NormalizeEmbyRoutePath(string path)
{
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
@@ -793,6 +792,7 @@ namespace Emby.Server.Implementations.HttpServer
private bool _disposed;
private readonly object _disposeLock = new object();
+
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
@@ -821,7 +821,7 @@ namespace Emby.Server.Implementations.HttpServer
return Task.CompletedTask;
}
- _logger.LogDebug("Websocket message received: {0}", result.MessageType);
+ Logger.LogDebug("Websocket message received: {0}", result.MessageType);
var tasks = _webSocketListeners.Select(i => Task.Run(async () =>
{
@@ -831,7 +831,7 @@ namespace Emby.Server.Implementations.HttpServer
}
catch (Exception ex)
{
- _logger.LogError(ex, "{0} failed processing WebSocket message {1}", i.GetType().Name, result.MessageType ?? string.Empty);
+ Logger.LogError(ex, "{0} failed processing WebSocket message {1}", i.GetType().Name, result.MessageType ?? string.Empty);
}
}));
@@ -842,18 +842,5 @@ namespace Emby.Server.Implementations.HttpServer
{
Dispose(true);
}
-
- public void StartServer(string[] urlPrefixes, IHttpListener httpListener)
- {
- UrlPrefixes = urlPrefixes;
-
- _listener = httpListener;
-
- _listener.WebSocketConnected = OnWebSocketConnected;
- _listener.ErrorHandler = ErrorHandler;
- _listener.RequestHandler = RequestHandler;
-
- _listener.Start(UrlPrefixes);
- }
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index 070717d48..463265862 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -16,6 +16,8 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
using IRequest = MediaBrowser.Model.Services.IRequest;
using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
@@ -32,17 +34,16 @@ namespace Emby.Server.Implementations.HttpServer
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _jsonSerializer;
-
- private IBrotliCompressor _brotliCompressor;
+ private readonly IStreamHelper _streamHelper;
/// <summary>
/// Initializes a new instance of the <see cref="HttpResultFactory" /> class.
/// </summary>
- public HttpResultFactory(ILoggerFactory loggerfactory, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IBrotliCompressor brotliCompressor)
+ public HttpResultFactory(ILoggerFactory loggerfactory, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IStreamHelper streamHelper)
{
_fileSystem = fileSystem;
_jsonSerializer = jsonSerializer;
- _brotliCompressor = brotliCompressor;
+ _streamHelper = streamHelper;
_logger = loggerfactory.CreateLogger("HttpResultFactory");
}
@@ -76,7 +77,7 @@ namespace Emby.Server.Implementations.HttpServer
public object GetRedirectResult(string url)
{
var responseHeaders = new Dictionary<string, string>();
- responseHeaders["Location"] = url;
+ responseHeaders[HeaderNames.Location] = url;
var result = new HttpResult(Array.Empty<byte>(), "text/plain", HttpStatusCode.Redirect);
@@ -97,9 +98,9 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary<string, string>();
}
- if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires))
+ if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string expires))
{
- responseHeaders["Expires"] = "-1";
+ responseHeaders[HeaderNames.Expires] = "-1";
}
AddResponseHeaders(result, responseHeaders);
@@ -131,7 +132,7 @@ namespace Emby.Server.Implementations.HttpServer
content = Array.Empty<byte>();
}
- result = new StreamWriter(content, contentType, contentLength);
+ result = new StreamWriter(content, contentType);
}
else
{
@@ -143,9 +144,9 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary<string, string>();
}
- if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _))
+ if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string _))
{
- responseHeaders["Expires"] = "-1";
+ responseHeaders[HeaderNames.Expires] = "-1";
}
AddResponseHeaders(result, responseHeaders);
@@ -175,7 +176,7 @@ namespace Emby.Server.Implementations.HttpServer
bytes = Array.Empty<byte>();
}
- result = new StreamWriter(bytes, contentType, contentLength);
+ result = new StreamWriter(bytes, contentType);
}
else
{
@@ -187,9 +188,9 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary<string, string>();
}
- if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _))
+ if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string _))
{
- responseHeaders["Expires"] = "-1";
+ responseHeaders[HeaderNames.Expires] = "-1";
}
AddResponseHeaders(result, responseHeaders);
@@ -214,7 +215,7 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
- responseHeaders["Expires"] = "-1";
+ responseHeaders[HeaderNames.Expires] = "-1";
return ToOptimizedResultInternal(requestContext, result, responseHeaders);
}
@@ -246,9 +247,9 @@ namespace Emby.Server.Implementations.HttpServer
private static string GetCompressionType(IRequest request)
{
- var acceptEncoding = request.Headers["Accept-Encoding"];
+ var acceptEncoding = request.Headers[HeaderNames.AcceptEncoding].ToString();
- if (acceptEncoding != null)
+ if (string.IsNullOrEmpty(acceptEncoding))
{
//if (_brotliCompressor != null && acceptEncoding.IndexOf("br", StringComparison.OrdinalIgnoreCase) != -1)
// return "br";
@@ -326,21 +327,21 @@ namespace Emby.Server.Implementations.HttpServer
}
content = Compress(content, requestedCompressionType);
- responseHeaders["Content-Encoding"] = requestedCompressionType;
+ responseHeaders[HeaderNames.ContentEncoding] = requestedCompressionType;
- responseHeaders["Vary"] = "Accept-Encoding";
+ responseHeaders[HeaderNames.Vary] = HeaderNames.AcceptEncoding;
var contentLength = content.Length;
if (isHeadRequest)
{
- var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength);
+ var result = new StreamWriter(Array.Empty<byte>(), contentType);
AddResponseHeaders(result, responseHeaders);
return result;
}
else
{
- var result = new StreamWriter(content, contentType, contentLength);
+ var result = new StreamWriter(content, contentType);
AddResponseHeaders(result, responseHeaders);
return result;
}
@@ -348,11 +349,6 @@ namespace Emby.Server.Implementations.HttpServer
private byte[] Compress(byte[] bytes, string compressionType)
{
- if (string.Equals(compressionType, "br", StringComparison.OrdinalIgnoreCase))
- {
- return CompressBrotli(bytes);
- }
-
if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase))
{
return Deflate(bytes);
@@ -366,11 +362,6 @@ namespace Emby.Server.Implementations.HttpServer
throw new NotSupportedException(compressionType);
}
- private byte[] CompressBrotli(byte[] bytes)
- {
- return _brotliCompressor.Compress(bytes);
- }
-
private static byte[] Deflate(byte[] bytes)
{
// In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream
@@ -424,12 +415,12 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options)
{
- bool noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
+ bool noCache = (requestContext.Headers[HeaderNames.CacheControl].ToString()).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified);
if (!noCache)
{
- DateTime.TryParse(requestContext.Headers.Get("If-Modified-Since"), out var ifModifiedSinceHeader);
+ DateTime.TryParse(requestContext.Headers[HeaderNames.IfModifiedSince], out var ifModifiedSinceHeader);
if (IsNotModified(ifModifiedSinceHeader, options.CacheDuration, options.DateLastModified))
{
@@ -530,7 +521,7 @@ namespace Emby.Server.Implementations.HttpServer
options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var contentType = options.ContentType;
- if (!string.IsNullOrEmpty(requestContext.Headers.Get("If-Modified-Since")))
+ if (!StringValues.IsNullOrEmpty(requestContext.Headers[HeaderNames.IfModifiedSince]))
{
// See if the result is already cached in the browser
var result = GetCachedResult(requestContext, options.ResponseHeaders, options);
@@ -548,11 +539,11 @@ namespace Emby.Server.Implementations.HttpServer
AddCachingHeaders(responseHeaders, options.CacheDuration, false, options.DateLastModified);
AddAgeHeader(responseHeaders, options.DateLastModified);
- var rangeHeader = requestContext.Headers.Get("Range");
+ var rangeHeader = requestContext.Headers[HeaderNames.Range];
if (!isHeadRequest && !string.IsNullOrEmpty(options.Path))
{
- var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
+ var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem, _streamHelper)
{
OnComplete = options.OnComplete,
OnError = options.OnError,
@@ -590,11 +581,6 @@ namespace Emby.Server.Implementations.HttpServer
}
else
{
- if (totalContentLength.HasValue)
- {
- responseHeaders["Content-Length"] = totalContentLength.Value.ToString(UsCulture);
- }
-
if (isHeadRequest)
{
using (stream)
@@ -615,11 +601,6 @@ namespace Emby.Server.Implementations.HttpServer
}
/// <summary>
- /// The us culture
- /// </summary>
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
/// Adds the caching responseHeaders.
/// </summary>
private void AddCachingHeaders(IDictionary<string, string> responseHeaders, TimeSpan? cacheDuration,
@@ -627,23 +608,23 @@ namespace Emby.Server.Implementations.HttpServer
{
if (noCache)
{
- responseHeaders["Cache-Control"] = "no-cache, no-store, must-revalidate";
- responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
+ responseHeaders[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate";
+ responseHeaders[HeaderNames.Pragma] = "no-cache, no-store, must-revalidate";
return;
}
if (cacheDuration.HasValue)
{
- responseHeaders["Cache-Control"] = "public, max-age=" + cacheDuration.Value.TotalSeconds;
+ responseHeaders[HeaderNames.CacheControl] = "public, max-age=" + cacheDuration.Value.TotalSeconds;
}
else
{
- responseHeaders["Cache-Control"] = "public";
+ responseHeaders[HeaderNames.CacheControl] = "public";
}
if (lastModifiedDate.HasValue)
{
- responseHeaders["Last-Modified"] = lastModifiedDate.ToString();
+ responseHeaders[HeaderNames.LastModified] = lastModifiedDate.ToString();
}
}
@@ -656,7 +637,7 @@ namespace Emby.Server.Implementations.HttpServer
{
if (lastDateModified.HasValue)
{
- responseHeaders["Age"] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture);
+ responseHeaders[HeaderNames.Age] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture);
}
}
@@ -714,9 +695,4 @@ namespace Emby.Server.Implementations.HttpServer
}
}
}
-
- public interface IBrotliCompressor
- {
- byte[] Compress(byte[] content);
- }
}
diff --git a/Emby.Server.Implementations/HttpServer/IHttpListener.cs b/Emby.Server.Implementations/HttpServer/IHttpListener.cs
index 835091361..005656d2c 100644
--- a/Emby.Server.Implementations/HttpServer/IHttpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/IHttpListener.cs
@@ -1,10 +1,9 @@
using System;
-using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Net;
-using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
namespace Emby.Server.Implementations.HttpServer
{
@@ -29,20 +28,10 @@ namespace Emby.Server.Implementations.HttpServer
Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
/// <summary>
- /// Gets or sets the web socket connecting.
- /// </summary>
- /// <value>The web socket connecting.</value>
- Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
-
- /// <summary>
- /// Starts this instance.
- /// </summary>
- /// <param name="urlPrefixes">The URL prefixes.</param>
- void Start(IEnumerable<string> urlPrefixes);
-
- /// <summary>
/// Stops this instance.
/// </summary>
Task Stop();
+
+ Task ProcessWebSocketRequest(HttpContext ctx);
}
}
diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
index 891a76ec2..449159834 100644
--- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
@@ -66,8 +67,8 @@ namespace Emby.Server.Implementations.HttpServer
this._logger = logger;
ContentType = contentType;
- Headers["Content-Type"] = contentType;
- Headers["Accept-Ranges"] = "bytes";
+ Headers[HeaderNames.ContentType] = contentType;
+ Headers[HeaderNames.AcceptRanges] = "bytes";
StatusCode = HttpStatusCode.PartialContent;
SetRangeValues(contentLength);
@@ -95,9 +96,7 @@ namespace Emby.Server.Implementations.HttpServer
RangeStart = requestedRange.Key;
RangeLength = 1 + RangeEnd - RangeStart;
- // Content-Length is the length of what we're serving, not the original content
- Headers["Content-Length"] = RangeLength.ToString(UsCulture);
- Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", RangeStart, RangeEnd, TotalContentLength);
+ Headers[HeaderNames.ContentRange] = $"bytes {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..a53d9bf0b 100644
--- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
+++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
@@ -3,6 +3,7 @@ using System.Globalization;
using System.Text;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
@@ -25,7 +26,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", "*");
@@ -44,20 +45,19 @@ namespace Emby.Server.Implementations.HttpServer
if (dto is IHasHeaders hasHeaders)
{
- if (!hasHeaders.Headers.ContainsKey("Server"))
+ if (!hasHeaders.Headers.ContainsKey(HeaderNames.Server))
{
- hasHeaders.Headers["Server"] = "Microsoft-NetCore/2.0, UPnP/1.0 DLNADOC/1.50";
+ hasHeaders.Headers[HeaderNames.Server] = "Microsoft-NetCore/2.0, UPnP/1.0 DLNADOC/1.50";
}
// Content length has to be explicitly set on on HttpListenerResponse or it won't be happy
- if (hasHeaders.Headers.TryGetValue("Content-Length", out string contentLength)
+ if (hasHeaders.Headers.TryGetValue(HeaderNames.ContentLength, out string contentLength)
&& !string.IsNullOrEmpty(contentLength))
{
var length = long.Parse(contentLength, UsCulture);
if (length > 0)
{
- res.SetContentLength(length);
res.SendChunked = false;
}
}
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index cab41e65b..276312a30 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Model.Services;
+using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer.Security
{
@@ -176,7 +177,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
if (string.IsNullOrEmpty(auth))
{
- auth = httpReq.Headers["Authorization"];
+ auth = httpReq.Headers[HeaderNames.Authorization];
}
return GetAuthorization(auth);
diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
index cb2e3580b..66a13e20d 100644
--- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs
@@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
@@ -52,12 +53,7 @@ namespace Emby.Server.Implementations.HttpServer
SourceStream = source;
- Headers["Content-Type"] = contentType;
-
- if (source.CanSeek)
- {
- Headers["Content-Length"] = source.Length.ToString(UsCulture);
- }
+ Headers[HeaderNames.ContentType] = contentType;
}
/// <summary>
@@ -65,8 +61,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
/// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param>
- /// <param name="logger">The logger.</param>
- public StreamWriter(byte[] source, string contentType, int contentLength)
+ public StreamWriter(byte[] source, string contentType)
{
if (string.IsNullOrEmpty(contentType))
{
@@ -75,9 +70,7 @@ namespace Emby.Server.Implementations.HttpServer
SourceBytes = source;
- Headers["Content-Type"] = contentType;
-
- Headers["Content-Length"] = contentLength.ToString(UsCulture);
+ Headers[HeaderNames.ContentType] = contentType;
}
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
index e9d0bac74..54a16040f 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using UtfUnknown;
@@ -67,7 +68,7 @@ namespace Emby.Server.Implementations.HttpServer
/// Gets or sets the query string.
/// </summary>
/// <value>The query string.</value>
- public QueryParamCollection QueryString { get; set; }
+ public IQueryCollection QueryString { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
@@ -101,12 +102,6 @@ namespace Emby.Server.Implementations.HttpServer
_socket = socket;
_socket.OnReceiveBytes = OnReceiveInternal;
- var memorySocket = socket as IMemoryWebSocket;
- if (memorySocket != null)
- {
- memorySocket.OnReceiveMemoryBytes = OnReceiveInternal;
- }
-
RemoteEndPoint = remoteEndPoint;
_logger = logger;
@@ -142,34 +137,6 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- /// <summary>
- /// Called when [receive].
- /// </summary>
- /// <param name="memory">The memory block.</param>
- /// <param name="length">The length of the memory block.</param>
- private void OnReceiveInternal(Memory<byte> memory, int length)
- {
- LastActivityDate = DateTime.UtcNow;
-
- if (OnReceive == null)
- {
- return;
- }
-
- var bytes = memory.Slice(0, length).ToArray();
-
- var charset = CharsetDetector.DetectFromBytes(bytes).Detected?.EncodingName;
-
- if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase))
- {
- OnReceiveInternal(Encoding.UTF8.GetString(bytes, 0, bytes.Length));
- }
- else
- {
- OnReceiveInternal(Encoding.ASCII.GetString(bytes, 0, bytes.Length));
- }
- }
-
private void OnReceiveInternal(string message)
{
LastActivityDate = DateTime.UtcNow;
@@ -193,7 +160,7 @@ namespace Emby.Server.Implementations.HttpServer
var info = new WebSocketMessageInfo
{
MessageType = stub.MessageType,
- Data = stub.Data == null ? null : stub.Data.ToString(),
+ Data = stub.Data?.ToString(),
Connection = this
};