|
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
@ -23,8 +24,6 @@ using MediaBrowser.Model.Serialization;
|
|
|
|
|
using MediaBrowser.Model.Services;
|
|
|
|
|
using MediaBrowser.Model.System;
|
|
|
|
|
using MediaBrowser.Model.Text;
|
|
|
|
|
using SocketHttpListener.Net;
|
|
|
|
|
using SocketHttpListener.Primitives;
|
|
|
|
|
|
|
|
|
|
namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
{
|
|
|
|
@ -55,9 +54,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
private readonly IFileSystem _fileSystem;
|
|
|
|
|
private readonly IJsonSerializer _jsonSerializer;
|
|
|
|
|
private readonly IXmlSerializer _xmlSerializer;
|
|
|
|
|
private readonly ICertificate _certificate;
|
|
|
|
|
private readonly X509Certificate _certificate;
|
|
|
|
|
private readonly IEnvironmentInfo _environment;
|
|
|
|
|
private readonly IStreamFactory _streamFactory;
|
|
|
|
|
private readonly Func<Type, Func<string, object>> _funcParseFn;
|
|
|
|
|
private readonly bool _enableDualModeSockets;
|
|
|
|
|
|
|
|
|
@ -71,7 +69,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
ILogger logger,
|
|
|
|
|
IServerConfigurationManager config,
|
|
|
|
|
string serviceName,
|
|
|
|
|
string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
|
|
|
|
|
string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, X509Certificate certificate, Func<Type, Func<string, object>> funcParseFn, bool enableDualModeSockets, IFileSystem fileSystem)
|
|
|
|
|
{
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
|
|
|
@ -86,7 +84,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
_xmlSerializer = xmlSerializer;
|
|
|
|
|
_environment = environment;
|
|
|
|
|
_certificate = certificate;
|
|
|
|
|
_streamFactory = streamFactory;
|
|
|
|
|
_funcParseFn = funcParseFn;
|
|
|
|
|
_enableDualModeSockets = enableDualModeSockets;
|
|
|
|
|
_fileSystem = fileSystem;
|
|
|
|
@ -183,20 +180,10 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string GetHandlerPathIfAny(string listenerUrl)
|
|
|
|
|
{
|
|
|
|
|
if (listenerUrl == null) return null;
|
|
|
|
|
var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
if (pos == -1) return null;
|
|
|
|
|
var startHostUrl = listenerUrl.Substring(pos + "://".Length);
|
|
|
|
|
var endPos = startHostUrl.IndexOf('/');
|
|
|
|
|
if (endPos == -1) return null;
|
|
|
|
|
var endHostUrl = startHostUrl.Substring(endPos + 1);
|
|
|
|
|
return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IHttpListener GetListener()
|
|
|
|
|
{
|
|
|
|
|
//return new KestrelHost.KestrelListener(_logger, _environment, _fileSystem);
|
|
|
|
|
|
|
|
|
|
return new WebSocketSharpListener(_logger,
|
|
|
|
|
_certificate,
|
|
|
|
|
_memoryStreamProvider,
|
|
|
|
@ -204,22 +191,11 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
_networkManager,
|
|
|
|
|
_socketFactory,
|
|
|
|
|
_cryptoProvider,
|
|
|
|
|
_streamFactory,
|
|
|
|
|
_enableDualModeSockets,
|
|
|
|
|
GetRequest,
|
|
|
|
|
_fileSystem,
|
|
|
|
|
_environment);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IHttpRequest GetRequest(HttpListenerContext httpContext)
|
|
|
|
|
{
|
|
|
|
|
var operationName = httpContext.Request.GetOperationName();
|
|
|
|
|
|
|
|
|
|
var req = new WebSocketSharpRequest(httpContext, operationName, _logger, _memoryStreamProvider);
|
|
|
|
|
|
|
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
if (_disposed)
|
|
|
|
@ -332,7 +308,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
if (_listener != null)
|
|
|
|
|
{
|
|
|
|
|
_logger.Info("Stopping HttpListener...");
|
|
|
|
|
_listener.Stop();
|
|
|
|
|
var task = _listener.Stop();
|
|
|
|
|
Task.WaitAll(task);
|
|
|
|
|
_logger.Info("HttpListener stopped");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -418,7 +395,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
return address.Trim('/');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool ValidateHost(Uri url)
|
|
|
|
|
private bool ValidateHost(string host)
|
|
|
|
|
{
|
|
|
|
|
var hosts = _config
|
|
|
|
|
.Configuration
|
|
|
|
@ -431,7 +408,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var host = url.Host ?? string.Empty;
|
|
|
|
|
host = host ?? string.Empty;
|
|
|
|
|
|
|
|
|
|
_logger.Debug("Validating host {0}", host);
|
|
|
|
|
|
|
|
|
@ -449,7 +426,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, Uri url, CancellationToken cancellationToken)
|
|
|
|
|
protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
var date = DateTime.Now;
|
|
|
|
|
var httpRes = httpReq.Response;
|
|
|
|
@ -468,7 +445,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ValidateHost(url))
|
|
|
|
|
if (!ValidateHost(host))
|
|
|
|
|
{
|
|
|
|
|
httpRes.StatusCode = 400;
|
|
|
|
|
httpRes.ContentType = "text/plain";
|
|
|
|
@ -488,9 +465,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var operationName = httpReq.OperationName;
|
|
|
|
|
var localPath = url.LocalPath;
|
|
|
|
|
|
|
|
|
|
var urlString = url.OriginalString;
|
|
|
|
|
enableLog = EnableLogging(urlString, localPath);
|
|
|
|
|
urlToLog = urlString;
|
|
|
|
|
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
|
|
|
|
@ -710,12 +685,19 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
Summary = route.Summary
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
|
|
|
|
|
routes.Add(new RouteAttribute(NormalizeMediaBrowserRoutePath(route.Path), route.Verbs)
|
|
|
|
|
{
|
|
|
|
|
Notes = route.Notes,
|
|
|
|
|
Priority = route.Priority,
|
|
|
|
|
Summary = route.Summary
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs)
|
|
|
|
|
//{
|
|
|
|
|
// Notes = route.Notes,
|
|
|
|
|
// Priority = route.Priority,
|
|
|
|
|
// Summary = route.Summary
|
|
|
|
|
//});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return routes.ToArray(routes.Count);
|
|
|
|
@ -756,6 +738,16 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
return "emby/" + path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string NormalizeMediaBrowserRoutePath(string path)
|
|
|
|
|
{
|
|
|
|
|
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
return "/mediabrowser" + path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "mediabrowser/" + path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string DoubleNormalizeEmbyRoutePath(string path)
|
|
|
|
|
{
|
|
|
|
|
if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase))
|
|
|
|
@ -795,8 +787,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|
|
|
|
{
|
|
|
|
|
UrlPrefixes = urlPrefixes;
|
|
|
|
|
|
|
|
|
|
WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
|
|
|
|
|
|
|
|
|
|
_listener = GetListener();
|
|
|
|
|
|
|
|
|
|
_listener.WebSocketConnected = OnWebSocketConnected;
|
|
|
|
|