aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/HttpServer
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer')
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs11
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs371
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs1
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs43
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs230
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs127
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs15
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs46
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs194
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs28
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs13
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs172
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs216
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs100
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs152
15 files changed, 257 insertions, 1462 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs b/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs
index 93d224b8d..235b62f69 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs
@@ -6,7 +6,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <summary>
/// Class ContainerAdapter
/// </summary>
- class ContainerAdapter : IContainerAdapter, IRelease
+ class ContainerAdapter : IContainerAdapter
{
/// <summary>
/// The _app host
@@ -40,14 +40,5 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
return _appHost.TryResolve<T>();
}
-
- /// <summary>
- /// Releases the specified instance.
- /// </summary>
- /// <param name="instance">The instance.</param>
- public void Release(object instance)
- {
- // Leave this empty so SS doesn't try to dispose our objects
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 805cb0353..ebb282503 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -8,24 +8,31 @@ using MediaBrowser.Server.Implementations.HttpServer.SocketSharp;
using ServiceStack;
using ServiceStack.Host;
using ServiceStack.Host.Handlers;
-using ServiceStack.Logging;
using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Net.Security;
+using System.Net.Sockets;
using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Common.Implementations.Net;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
using MediaBrowser.Controller;
+using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services;
-using ServiceStack.Api.Swagger;
+using MediaBrowser.Model.Text;
+using SocketHttpListener.Net;
+using SocketHttpListener.Primitives;
namespace MediaBrowser.Server.Implementations.HttpServer
{
@@ -49,21 +56,28 @@ namespace MediaBrowser.Server.Implementations.HttpServer
private readonly IServerConfigurationManager _config;
private readonly INetworkManager _networkManager;
- private readonly IMemoryStreamProvider _memoryStreamProvider;
+ private readonly IMemoryStreamFactory _memoryStreamProvider;
private readonly IServerApplicationHost _appHost;
+ private readonly ITextEncoding _textEncoding;
+ private readonly ISocketFactory _socketFactory;
+ private readonly ICryptoProvider _cryptoProvider;
+
public HttpListenerHost(IServerApplicationHost applicationHost,
ILogManager logManager,
IServerConfigurationManager config,
string serviceName,
- string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamProvider memoryStreamProvider, params Assembly[] assembliesWithServices)
- : base(serviceName, assembliesWithServices)
+ string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider)
+ : base(serviceName, new Assembly[] { })
{
_appHost = applicationHost;
DefaultRedirectPath = defaultRedirectPath;
_networkManager = networkManager;
_memoryStreamProvider = memoryStreamProvider;
+ _textEncoding = textEncoding;
+ _socketFactory = socketFactory;
+ _cryptoProvider = cryptoProvider;
_config = config;
_logger = logManager.GetLogger("HttpServer");
@@ -73,10 +87,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public string GlobalResponse { get; set; }
- public override void Configure(Container container)
+ public override void Configure()
{
HostConfig.Instance.DefaultRedirectPath = DefaultRedirectPath;
- HostConfig.Instance.LogUnobservedTaskExceptions = false;
HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int>
{
@@ -94,19 +107,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer
};
HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>();
- HostConfig.Instance.DebugMode = false;
-
- HostConfig.Instance.LogFactory = LogManager.LogFactory;
- HostConfig.Instance.AllowJsonpRequests = false;
// The Markdown feature causes slow startup times (5 mins+) on cold boots for some users
// Custom format allows images
HostConfig.Instance.EnableFeatures = Feature.Html | Feature.Json | Feature.Xml | Feature.CustomFormat;
- container.Adapter = _containerAdapter;
-
- Plugins.Add(new SwaggerFeature());
- Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization"));
+ Container.Adapter = _containerAdapter;
//Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
// new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()),
@@ -130,6 +136,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
}
+ protected override ILogger Logger
+ {
+ get
+ {
+ return _logger;
+ }
+ }
+
public override void OnAfterInit()
{
SetAppDomainData();
@@ -207,7 +221,33 @@ namespace MediaBrowser.Server.Implementations.HttpServer
private IHttpListener GetListener()
{
- return new WebSocketSharpListener(_logger, CertificatePath, _memoryStreamProvider);
+ var cert = !string.IsNullOrWhiteSpace(CertificatePath) && File.Exists(CertificatePath)
+ ? GetCert(CertificatePath) :
+ null;
+
+ return new WebSocketSharpListener(_logger, cert, _memoryStreamProvider, _textEncoding, _networkManager, _socketFactory, _cryptoProvider, new StreamFactory(), GetRequest);
+ }
+
+ public static ICertificate GetCert(string certificateLocation)
+ {
+ X509Certificate2 localCert = new X509Certificate2(certificateLocation);
+ //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
+ if (localCert.PrivateKey == null)
+ {
+ //throw new FileNotFoundException("Secure requested, no private key included", certificateLocation);
+ return null;
+ }
+
+ return new Certificate(localCert);
+ }
+
+ 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)
@@ -259,11 +299,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var contentType = httpReq.ResponseContentType;
- var serializer = HostContext.ContentTypes.GetResponseSerializer(contentType);
+ var serializer = ContentTypes.Instance.GetResponseSerializer(contentType);
if (serializer == null)
{
contentType = HostContext.Config.DefaultContentType;
- serializer = HostContext.ContentTypes.GetResponseSerializer(contentType);
+ serializer = ContentTypes.Instance.GetResponseSerializer(contentType);
}
var httpError = ex as IHttpError;
@@ -411,171 +451,170 @@ namespace MediaBrowser.Server.Implementations.HttpServer
protected async Task RequestHandler(IHttpRequest httpReq, Uri url)
{
var date = DateTime.Now;
-
var httpRes = httpReq.Response;
+ bool enableLog = false;
+ string urlToLog = null;
+ string remoteIp = null;
- if (_disposed)
+ try
{
- httpRes.StatusCode = 503;
- httpRes.Close();
- return ;
- }
+ if (_disposed)
+ {
+ httpRes.StatusCode = 503;
+ return;
+ }
- if (!ValidateHost(url))
- {
- httpRes.StatusCode = 400;
- httpRes.ContentType = "text/plain";
- httpRes.Write("Invalid host");
+ if (!ValidateHost(url))
+ {
+ httpRes.StatusCode = 400;
+ httpRes.ContentType = "text/plain";
+ httpRes.Write("Invalid host");
+ return;
+ }
- httpRes.Close();
- return;
- }
+ if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
+ {
+ httpRes.StatusCode = 200;
+ httpRes.AddHeader("Access-Control-Allow-Origin", "*");
+ httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
+ httpRes.AddHeader("Access-Control-Allow-Headers",
+ "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
+ httpRes.ContentType = "text/html";
+ return;
+ }
- if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.StatusCode = 200;
- httpRes.AddHeader("Access-Control-Allow-Origin", "*");
- httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
- httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
- httpRes.ContentType = "text/html";
+ var operationName = httpReq.OperationName;
+ var localPath = url.LocalPath;
- httpRes.Close();
- }
+ var urlString = url.OriginalString;
+ enableLog = EnableLogging(urlString, localPath);
+ urlToLog = urlString;
- var operationName = httpReq.OperationName;
- var localPath = url.LocalPath;
+ if (enableLog)
+ {
+ urlToLog = GetUrlToLog(urlString);
+ remoteIp = httpReq.RemoteIp;
- var urlString = url.OriginalString;
- var enableLog = EnableLogging(urlString, localPath);
- var urlToLog = urlString;
+ LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent);
+ }
- if (enableLog)
- {
- urlToLog = GetUrlToLog(urlString);
- LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent);
- }
+ if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
+ {
+ RedirectToUrl(httpRes, DefaultRedirectPath);
+ return;
+ }
+ if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
+ {
+ RedirectToUrl(httpRes, "emby/" + DefaultRedirectPath);
+ return;
+ }
- if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.RedirectToUrl(DefaultRedirectPath);
- return;
- }
- if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.RedirectToUrl("emby/" + DefaultRedirectPath);
- return;
- }
+ if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase) ||
+ localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ httpRes.StatusCode = 200;
+ httpRes.ContentType = "text/html";
+ var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase)
+ .Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase);
- if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase) ||
- localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1)
- {
- httpRes.StatusCode = 200;
- httpRes.ContentType = "text/html";
- var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase)
- .Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase);
+ if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
+ {
+ httpRes.Write(
+ "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
+ newUrl + "\">" + newUrl + "</a></body></html>");
+ return;
+ }
+ }
- if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
+ if (localPath.IndexOf("dashboard/", StringComparison.OrdinalIgnoreCase) != -1 &&
+ localPath.IndexOf("web/dashboard", StringComparison.OrdinalIgnoreCase) == -1)
{
- httpRes.Write("<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>");
+ httpRes.StatusCode = 200;
+ httpRes.ContentType = "text/html";
+ var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase)
+ .Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase);
- httpRes.Close();
- return;
+ if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
+ {
+ httpRes.Write(
+ "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
+ newUrl + "\">" + newUrl + "</a></body></html>");
+ return;
+ }
}
- }
- if (localPath.IndexOf("dashboard/", StringComparison.OrdinalIgnoreCase) != -1 &&
- localPath.IndexOf("web/dashboard", StringComparison.OrdinalIgnoreCase) == -1)
- {
- httpRes.StatusCode = 200;
- httpRes.ContentType = "text/html";
- var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase)
- .Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase);
+ if (string.Equals(localPath, "/web", StringComparison.OrdinalIgnoreCase))
+ {
+ RedirectToUrl(httpRes, DefaultRedirectPath);
+ return;
+ }
+ if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
+ {
+ RedirectToUrl(httpRes, "../" + DefaultRedirectPath);
+ return;
+ }
+ if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
+ {
+ RedirectToUrl(httpRes, DefaultRedirectPath);
+ return;
+ }
+ if (string.IsNullOrEmpty(localPath))
+ {
+ RedirectToUrl(httpRes, "/" + DefaultRedirectPath);
+ return;
+ }
- if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(localPath, "/emby/pin", StringComparison.OrdinalIgnoreCase))
{
- httpRes.Write("<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>");
+ RedirectToUrl(httpRes, "web/pin.html");
+ return;
+ }
- httpRes.Close();
+ if (!string.IsNullOrWhiteSpace(GlobalResponse))
+ {
+ httpRes.StatusCode = 503;
+ httpRes.ContentType = "text/html";
+ httpRes.Write(GlobalResponse);
return;
}
- }
- if (string.Equals(localPath, "/web", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.RedirectToUrl(DefaultRedirectPath);
- return;
- }
- if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.RedirectToUrl("../" + DefaultRedirectPath);
- return;
- }
- if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.RedirectToUrl(DefaultRedirectPath);
- return;
- }
- if (string.IsNullOrEmpty(localPath))
- {
- httpRes.RedirectToUrl("/" + DefaultRedirectPath);
- return;
- }
+ var handler = HttpHandlerFactory.GetHandler(httpReq);
- if (string.Equals(localPath, "/emby/pin", StringComparison.OrdinalIgnoreCase))
- {
- httpRes.RedirectToUrl("web/pin.html");
- return;
+ if (handler != null)
+ {
+ await handler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false);
+ }
}
-
- if (!string.IsNullOrWhiteSpace(GlobalResponse))
+ catch (Exception ex)
{
- httpRes.StatusCode = 503;
- httpRes.ContentType = "text/html";
- httpRes.Write(GlobalResponse);
-
- httpRes.Close();
- return;
+ ErrorHandler(ex, httpReq);
}
-
- var handler = HttpHandlerFactory.GetHandler(httpReq);
-
- var remoteIp = httpReq.RemoteIp;
-
- var serviceStackHandler = handler as IServiceStackHandler;
- if (serviceStackHandler != null)
+ finally
{
- var restHandler = serviceStackHandler as RestHandler;
- if (restHandler != null)
- {
- httpReq.OperationName = operationName = restHandler.RestPath.RequestType.GetOperationName();
- }
+ httpRes.Close();
- try
- {
- await serviceStackHandler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false);
- }
- finally
+ if (enableLog)
{
- httpRes.Close();
var statusCode = httpRes.StatusCode;
var duration = DateTime.Now - date;
- if (enableLog)
- {
- LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration);
- }
+ LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration);
}
}
- else
- {
- httpRes.Close();
- }
}
+ public static void RedirectToUrl(IResponse httpRes, string url)
+ {
+ httpRes.StatusCode = 302;
+ httpRes.AddHeader(HttpHeaders.Location, url);
+ httpRes.EndRequest();
+ }
+
+
/// <summary>
/// Adds the rest handlers.
/// </summary>
@@ -653,15 +692,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return "mediabrowser/" + path;
}
- /// <summary>
- /// Releases the specified instance.
- /// </summary>
- /// <param name="instance">The instance.</param>
- public override void Release(object instance)
- {
- // Leave this empty so SS doesn't try to dispose our objects
- }
-
private bool _disposed;
private readonly object _disposeLock = new object();
protected virtual void Dispose(bool disposing)
@@ -696,4 +726,37 @@ namespace MediaBrowser.Server.Implementations.HttpServer
Start(UrlPrefixes.First());
}
}
+
+ public class StreamFactory : IStreamFactory
+ {
+ public Stream CreateNetworkStream(ISocket socket, bool ownsSocket)
+ {
+ var netSocket = (NetSocket)socket;
+
+ return new NetworkStream(netSocket.Socket, ownsSocket);
+ }
+
+ public Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate)
+ {
+ var sslStream = (SslStream)stream;
+ var cert = (Certificate)certificate;
+
+ return sslStream.AuthenticateAsServerAsync(cert.X509Certificate);
+ }
+
+ public Stream CreateSslStream(Stream innerStream, bool leaveInnerStreamOpen)
+ {
+ return new SslStream(innerStream, leaveInnerStreamOpen);
+ }
+ }
+
+ public class Certificate : ICertificate
+ {
+ public Certificate(X509Certificate x509Certificate)
+ {
+ X509Certificate = x509Certificate;
+ }
+
+ public X509Certificate X509Certificate { get; private set; }
+ }
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index 95e1a35e6..4c251ba24 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -9,6 +9,7 @@ using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
+using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using ServiceStack;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
deleted file mode 100644
index bfbb228ed..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Globalization;
-using SocketHttpListener.Net;
-
-namespace MediaBrowser.Server.Implementations.HttpServer
-{
- public static class LoggerUtils
- {
- /// <summary>
- /// Logs the request.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="request">The request.</param>
- public static void LogRequest(ILogger logger, HttpListenerRequest request)
- {
- var url = request.Url.ToString();
-
- logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty);
- }
-
- public static void LogRequest(ILogger logger, string url, string method, string userAgent)
- {
- logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
- }
-
- /// <summary>
- /// Logs the response.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="statusCode">The status code.</param>
- /// <param name="url">The URL.</param>
- /// <param name="endPoint">The end point.</param>
- /// <param name="duration">The duration.</param>
- public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration)
- {
- var durationMs = duration.TotalMilliseconds;
- var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
-
- logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
deleted file mode 100644
index 7d4cd3b4d..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ /dev/null
@@ -1,230 +0,0 @@
-using MediaBrowser.Model.Logging;
-using ServiceStack.Web;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Server.Implementations.HttpServer
-{
- public class RangeRequestWriter : IAsyncStreamWriter, IHttpResult
- {
- /// <summary>
- /// Gets or sets the source stream.
- /// </summary>
- /// <value>The source stream.</value>
- private Stream SourceStream { get; set; }
- private string RangeHeader { get; set; }
- private bool IsHeadRequest { get; set; }
-
- private long RangeStart { get; set; }
- private long RangeEnd { get; set; }
- private long RangeLength { get; set; }
- private long TotalContentLength { get; set; }
-
- public Action OnComplete { get; set; }
- private readonly ILogger _logger;
-
- private const int BufferSize = 81920;
-
- /// <summary>
- /// The _options
- /// </summary>
- private readonly Dictionary<string, string> _options = new Dictionary<string, string>();
-
- /// <summary>
- /// The us culture
- /// </summary>
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public Func<IDisposable> ResultScope { get; set; }
- public List<Cookie> Cookies { get; private set; }
-
- /// <summary>
- /// Additional HTTP Headers
- /// </summary>
- /// <value>The headers.</value>
- public IDictionary<string, string> Headers
- {
- get { return _options; }
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="StreamWriter" /> class.
- /// </summary>
- /// <param name="rangeHeader">The range header.</param>
- /// <param name="source">The source.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- public RangeRequestWriter(string rangeHeader, Stream source, string contentType, bool isHeadRequest, ILogger logger)
- {
- if (string.IsNullOrEmpty(contentType))
- {
- throw new ArgumentNullException("contentType");
- }
-
- RangeHeader = rangeHeader;
- SourceStream = source;
- IsHeadRequest = isHeadRequest;
- this._logger = logger;
-
- ContentType = contentType;
- Headers["Content-Type"] = contentType;
- Headers["Accept-Ranges"] = "bytes";
- StatusCode = HttpStatusCode.PartialContent;
-
- Cookies = new List<Cookie>();
- SetRangeValues();
- }
-
- /// <summary>
- /// Sets the range values.
- /// </summary>
- private void SetRangeValues()
- {
- var requestedRange = RequestedRanges[0];
-
- TotalContentLength = SourceStream.Length;
-
- // If the requested range is "0-", we can optimize by just doing a stream copy
- if (!requestedRange.Value.HasValue)
- {
- RangeEnd = TotalContentLength - 1;
- }
- else
- {
- RangeEnd = requestedRange.Value.Value;
- }
-
- 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);
-
- if (RangeStart > 0)
- {
- SourceStream.Position = RangeStart;
- }
- }
-
- /// <summary>
- /// The _requested ranges
- /// </summary>
- private List<KeyValuePair<long, long?>> _requestedRanges;
- /// <summary>
- /// Gets the requested ranges.
- /// </summary>
- /// <value>The requested ranges.</value>
- protected List<KeyValuePair<long, long?>> RequestedRanges
- {
- get
- {
- if (_requestedRanges == null)
- {
- _requestedRanges = new List<KeyValuePair<long, long?>>();
-
- // Example: bytes=0-,32-63
- var ranges = RangeHeader.Split('=')[1].Split(',');
-
- foreach (var range in ranges)
- {
- var vals = range.Split('-');
-
- long start = 0;
- long? end = null;
-
- if (!string.IsNullOrEmpty(vals[0]))
- {
- start = long.Parse(vals[0], UsCulture);
- }
- if (!string.IsNullOrEmpty(vals[1]))
- {
- end = long.Parse(vals[1], UsCulture);
- }
-
- _requestedRanges.Add(new KeyValuePair<long, long?>(start, end));
- }
- }
-
- return _requestedRanges;
- }
- }
-
- public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
- {
- try
- {
- // Headers only
- if (IsHeadRequest)
- {
- return;
- }
-
- using (var source = SourceStream)
- {
- // If the requested range is "0-", we can optimize by just doing a stream copy
- if (RangeEnd >= TotalContentLength - 1)
- {
- await source.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false);
- }
- else
- {
- await CopyToInternalAsync(source, responseStream, RangeLength).ConfigureAwait(false);
- }
- }
- }
- finally
- {
- if (OnComplete != null)
- {
- OnComplete();
- }
- }
- }
-
- private async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength)
- {
- var array = new byte[BufferSize];
- int count;
- while ((count = await source.ReadAsync(array, 0, array.Length).ConfigureAwait(false)) != 0)
- {
- var bytesToCopy = Math.Min(count, copyLength);
-
- await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy)).ConfigureAwait(false);
-
- copyLength -= bytesToCopy;
-
- if (copyLength <= 0)
- {
- break;
- }
- }
- }
-
- public string ContentType { get; set; }
-
- public IRequest RequestContext { get; set; }
-
- public object Response { get; set; }
-
- public IContentTypeWriter ResponseFilter { get; set; }
-
- public int Status { get; set; }
-
- public HttpStatusCode StatusCode
- {
- get { return (HttpStatusCode)Status; }
- set { Status = (int)value; }
- }
-
- public string StatusDescription { get; set; }
-
- public int PaddingLength { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs
deleted file mode 100644
index 6247e4c17..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations.HttpServer.SocketSharp;
-using System;
-using System.Globalization;
-using System.Net;
-using System.Text;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Server.Implementations.HttpServer
-{
- public class ResponseFilter
- {
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- private readonly ILogger _logger;
-
- public ResponseFilter(ILogger logger)
- {
- _logger = logger;
- }
-
- /// <summary>
- /// Filters the response.
- /// </summary>
- /// <param name="req">The req.</param>
- /// <param name="res">The res.</param>
- /// <param name="dto">The dto.</param>
- public void FilterResponse(IRequest req, IResponse res, object dto)
- {
- // Try to prevent compatibility view
- res.AddHeader("X-UA-Compatible", "IE=Edge");
-
- var exception = dto as Exception;
-
- if (exception != null)
- {
- _logger.ErrorException("Error processing request for {0}", exception, req.RawUrl);
-
- if (!string.IsNullOrEmpty(exception.Message))
- {
- var error = exception.Message.Replace(Environment.NewLine, " ");
- error = RemoveControlCharacters(error);
-
- res.AddHeader("X-Application-Error-Code", error);
- }
- }
-
- var vary = "Accept-Encoding";
-
- var hasHeaders = dto as IHasHeaders;
- var sharpResponse = res as WebSocketSharpResponse;
-
- if (hasHeaders != null)
- {
- if (!hasHeaders.Headers.ContainsKey("Server"))
- {
- hasHeaders.Headers["Server"] = "Mono-HTTPAPI/1.1, UPnP/1.0 DLNADOC/1.50";
- //hasHeaders.Headers["Server"] = "Mono-HTTPAPI/1.1";
- }
-
- // Content length has to be explicitly set on on HttpListenerResponse or it won't be happy
- string contentLength;
-
- if (hasHeaders.Headers.TryGetValue("Content-Length", out contentLength) && !string.IsNullOrEmpty(contentLength))
- {
- var length = long.Parse(contentLength, UsCulture);
-
- if (length > 0)
- {
- res.SetContentLength(length);
-
- var listenerResponse = res.OriginalResponse as HttpListenerResponse;
-
- if (listenerResponse != null)
- {
- // Disable chunked encoding. Technically this is only needed when using Content-Range, but
- // anytime we know the content length there's no need for it
- listenerResponse.SendChunked = false;
- return;
- }
-
- if (sharpResponse != null)
- {
- sharpResponse.SendChunked = false;
- }
- }
- }
-
- string hasHeadersVary;
- if (hasHeaders.Headers.TryGetValue("Vary", out hasHeadersVary))
- {
- vary = hasHeadersVary;
- }
-
- hasHeaders.Headers["Vary"] = vary;
- }
-
- //res.KeepAlive = false;
-
- // Per Google PageSpeed
- // This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed.
- // The correct version of the resource is delivered based on the client request header.
- // This is a good choice for applications that are singly homed and depend on public proxies for user locality.
- res.AddHeader("Vary", vary);
- }
-
- /// <summary>
- /// Removes the control characters.
- /// </summary>
- /// <param name="inString">The in string.</param>
- /// <returns>System.String.</returns>
- public static string RemoveControlCharacters(string inString)
- {
- if (inString == null) return null;
-
- var newString = new StringBuilder();
-
- foreach (var ch in inString)
- {
- if (!char.IsControl(ch))
- {
- newString.Append(ch);
- }
- }
- return newString.ToString();
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs
index 4dff2d5a3..5da515900 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs
@@ -2,9 +2,11 @@
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
-using ServiceStack.Logging;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Text;
namespace MediaBrowser.Server.Implementations.HttpServer
{
@@ -21,13 +23,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
ILogManager logManager,
IServerConfigurationManager config,
INetworkManager networkmanager,
- IMemoryStreamProvider streamProvider,
+ IMemoryStreamFactory streamProvider,
string serverName,
- string defaultRedirectpath)
+ string defaultRedirectpath,
+ ITextEncoding textEncoding,
+ ISocketFactory socketFactory,
+ ICryptoProvider cryptoProvider)
{
- LogManager.LogFactory = new ServerLogFactory(logManager);
-
- return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, networkmanager, streamProvider);
+ return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, networkmanager, streamProvider, textEncoding, socketFactory, cryptoProvider);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs
deleted file mode 100644
index 40af3f3b0..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-using MediaBrowser.Model.Logging;
-using ServiceStack.Logging;
-
-namespace MediaBrowser.Server.Implementations.HttpServer
-{
- /// <summary>
- /// Class ServerLogFactory
- /// </summary>
- public class ServerLogFactory : ILogFactory
- {
- /// <summary>
- /// The _log manager
- /// </summary>
- private readonly ILogManager _logManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ServerLogFactory"/> class.
- /// </summary>
- /// <param name="logManager">The log manager.</param>
- public ServerLogFactory(ILogManager logManager)
- {
- _logManager = logManager;
- }
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <param name="typeName">Name of the type.</param>
- /// <returns>ILog.</returns>
- public ILog GetLogger(string typeName)
- {
- return new ServerLogger(_logManager.GetLogger(typeName));
- }
-
- /// <summary>
- /// Gets the logger.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns>ILog.</returns>
- public ILog GetLogger(Type type)
- {
- return GetLogger(type.Name);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs
deleted file mode 100644
index bf7924784..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs
+++ /dev/null
@@ -1,194 +0,0 @@
-using MediaBrowser.Model.Logging;
-using ServiceStack.Logging;
-using System;
-
-namespace MediaBrowser.Server.Implementations.HttpServer
-{
- /// <summary>
- /// Class ServerLogger
- /// </summary>
- public class ServerLogger : ILog
- {
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ServerLogger"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- public ServerLogger(ILogger logger)
- {
- _logger = logger;
- }
-
- /// <summary>
- /// Logs a Debug message and exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- public void Debug(object message, Exception exception)
- {
- _logger.ErrorException(GetMesssage(message), exception);
- }
-
- /// <summary>
- /// Logs a Debug message.
- /// </summary>
- /// <param name="message">The message.</param>
- public void Debug(object message)
- {
- // Way too verbose. Can always make this configurable if needed again.
- //_logger.Debug(GetMesssage(message));
- }
-
- /// <summary>
- /// Logs a Debug format message.
- /// </summary>
- /// <param name="format">The format.</param>
- /// <param name="args">The args.</param>
- public void DebugFormat(string format, params object[] args)
- {
- // Way too verbose. Can always make this configurable if needed again.
- //_logger.Debug(format, args);
- }
-
- /// <summary>
- /// Logs a Error message and exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- public void Error(object message, Exception exception)
- {
- _logger.ErrorException(GetMesssage(message), exception);
- }
-
- /// <summary>
- /// Logs a Error message.
- /// </summary>
- /// <param name="message">The message.</param>
- public void Error(object message)
- {
- _logger.Error(GetMesssage(message));
- }
-
- /// <summary>
- /// Logs a Error format message.
- /// </summary>
- /// <param name="format">The format.</param>
- /// <param name="args">The args.</param>
- public void ErrorFormat(string format, params object[] args)
- {
- _logger.Error(format, args);
- }
-
- /// <summary>
- /// Logs a Fatal message and exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- public void Fatal(object message, Exception exception)
- {
- _logger.FatalException(GetMesssage(message), exception);
- }
-
- /// <summary>
- /// Logs a Fatal message.
- /// </summary>
- /// <param name="message">The message.</param>
- public void Fatal(object message)
- {
- _logger.Fatal(GetMesssage(message));
- }
-
- /// <summary>
- /// Logs a Error format message.
- /// </summary>
- /// <param name="format">The format.</param>
- /// <param name="args">The args.</param>
- public void FatalFormat(string format, params object[] args)
- {
- _logger.Fatal(format, args);
- }
-
- /// <summary>
- /// Logs an Info message and exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- public void Info(object message, Exception exception)
- {
- _logger.ErrorException(GetMesssage(message), exception);
- }
-
- /// <summary>
- /// Logs an Info message and exception.
- /// </summary>
- /// <param name="message">The message.</param>
- public void Info(object message)
- {
- _logger.Info(GetMesssage(message));
- }
-
- /// <summary>
- /// Logs an Info format message.
- /// </summary>
- /// <param name="format">The format.</param>
- /// <param name="args">The args.</param>
- public void InfoFormat(string format, params object[] args)
- {
- _logger.Info(format, args);
- }
-
- /// <summary>
- /// Gets or sets a value indicating whether this instance is debug enabled.
- /// </summary>
- /// <value><c>true</c> if this instance is debug enabled; otherwise, <c>false</c>.</value>
- public bool IsDebugEnabled
- {
- get { return true; }
- }
-
- /// <summary>
- /// Logs a Warning message and exception.
- /// </summary>
- /// <param name="message">The message.</param>
- /// <param name="exception">The exception.</param>
- public void Warn(object message, Exception exception)
- {
- _logger.ErrorException(GetMesssage(message), exception);
- }
-
- /// <summary>
- /// Logs a Warning message.
- /// </summary>
- /// <param name="message">The message.</param>
- public void Warn(object message)
- {
- // Hide StringMapTypeDeserializer messages
- // _logger.Warn(GetMesssage(message));
- }
-
- /// <summary>
- /// Logs a Warning format message.
- /// </summary>
- /// <param name="format">The format.</param>
- /// <param name="args">The args.</param>
- public void WarnFormat(string format, params object[] args)
- {
- // Hide StringMapTypeDeserializer messages
- // _logger.Warn(format, args);
- }
-
- /// <summary>
- /// Gets the messsage.
- /// </summary>
- /// <param name="o">The o.</param>
- /// <returns>System.String.</returns>
- private string GetMesssage(object o)
- {
- return o == null ? string.Empty : o.ToString();
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs
deleted file mode 100644
index 154313fb9..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using MediaBrowser.Model.Logging;
-using SocketHttpListener.Net;
-using System;
-
-namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
-{
- public static class Extensions
- {
- public static string GetOperationName(this HttpListenerRequest request)
- {
- return request.Url.Segments[request.Url.Segments.Length - 1];
- }
-
- public static void CloseOutputStream(this HttpListenerResponse response, ILogger logger)
- {
- try
- {
- response.OutputStream.Flush();
- response.OutputStream.Close();
- response.Close();
- }
- catch (Exception ex)
- {
- logger.ErrorException("Error in HttpListenerResponseWrapper: " + ex.Message, ex);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
index 13ae48cff..543eb4afe 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs
@@ -2,11 +2,10 @@
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
+using System.Net;
using System.Text;
using System.Threading.Tasks;
-using System.Web;
using MediaBrowser.Model.Services;
-using ServiceStack;
namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
@@ -128,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
get
{
- return string.IsNullOrEmpty(request.Headers[HttpHeaders.Accept]) ? null : request.Headers[HttpHeaders.Accept];
+ return string.IsNullOrEmpty(request.Headers["Accept"]) ? null : request.Headers["Accept"];
}
}
@@ -136,7 +135,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
get
{
- return string.IsNullOrEmpty(request.Headers[HttpHeaders.Authorization]) ? null : request.Headers[HttpHeaders.Authorization];
+ return string.IsNullOrEmpty(request.Headers["Authorization"]) ? null : request.Headers["Authorization"];
}
}
@@ -152,7 +151,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
string msg = String.Format("A potentially dangerous Request.{0} value was " +
"detected from the client ({1}={2}).", name, key, v);
- throw new HttpRequestValidationException(msg);
+ throw new Exception(msg);
}
static void ValidateNameValueCollection(string name, QueryParamCollection coll)
@@ -278,9 +277,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
void AddRawKeyValue(StringBuilder key, StringBuilder value)
{
- string decodedKey = HttpUtility.UrlDecode(key.ToString(), ContentEncoding);
+ string decodedKey = WebUtility.UrlDecode(key.ToString());
form.Add(decodedKey,
- HttpUtility.UrlDecode(value.ToString(), ContentEncoding));
+ WebUtility.UrlDecode(value.ToString()));
key.Length = 0;
value.Length = 0;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
deleted file mode 100644
index d363c4de6..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using MediaBrowser.Common.Events;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using WebSocketState = MediaBrowser.Model.Net.WebSocketState;
-
-namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
-{
- public class SharpWebSocket : IWebSocket
- {
- /// <summary>
- /// The logger
- /// </summary>
- private readonly ILogger _logger;
-
- public event EventHandler<EventArgs> Closed;
-
- /// <summary>
- /// Gets or sets the web socket.
- /// </summary>
- /// <value>The web socket.</value>
- private SocketHttpListener.WebSocket WebSocket { get; set; }
-
- private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
-
- /// <summary>
- /// Initializes a new instance of the <see cref="NativeWebSocket" /> class.
- /// </summary>
- /// <param name="socket">The socket.</param>
- /// <param name="logger">The logger.</param>
- /// <exception cref="System.ArgumentNullException">socket</exception>
- public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger)
- {
- if (socket == null)
- {
- throw new ArgumentNullException("socket");
- }
-
- if (logger == null)
- {
- throw new ArgumentNullException("logger");
- }
-
- _logger = logger;
- WebSocket = socket;
-
- socket.OnMessage += socket_OnMessage;
- socket.OnClose += socket_OnClose;
- socket.OnError += socket_OnError;
-
- WebSocket.ConnectAsServer();
- }
-
- void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e)
- {
- _logger.Error("Error in SharpWebSocket: {0}", e.Message ?? string.Empty);
- //EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger);
- }
-
- void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e)
- {
- EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger);
- }
-
- void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e)
- {
- //if (!string.IsNullOrWhiteSpace(e.Data))
- //{
- // if (OnReceive != null)
- // {
- // OnReceive(e.Data);
- // }
- // return;
- //}
- if (OnReceiveBytes != null)
- {
- OnReceiveBytes(e.RawData);
- }
- }
-
- /// <summary>
- /// Gets or sets the state.
- /// </summary>
- /// <value>The state.</value>
- public WebSocketState State
- {
- get
- {
- WebSocketState commonState;
-
- if (!Enum.TryParse(WebSocket.ReadyState.ToString(), true, out commonState))
- {
- _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.ReadyState.ToString());
- }
-
- return commonState;
- }
- }
-
- /// <summary>
- /// Sends the async.
- /// </summary>
- /// <param name="bytes">The bytes.</param>
- /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken)
- {
- var completionSource = new TaskCompletionSource<bool>();
-
- WebSocket.SendAsync(bytes, res => completionSource.TrySetResult(true));
-
- return completionSource.Task;
- }
-
- /// <summary>
- /// Sends the asynchronous.
- /// </summary>
- /// <param name="text">The text.</param>
- /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken)
- {
- var completionSource = new TaskCompletionSource<bool>();
-
- WebSocket.SendAsync(text, res => completionSource.TrySetResult(true));
-
- return completionSource.Task;
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- WebSocket.OnMessage -= socket_OnMessage;
- WebSocket.OnClose -= socket_OnClose;
- WebSocket.OnError -= socket_OnError;
-
- _cancellationTokenSource.Cancel();
-
- WebSocket.Close();
- }
- }
-
- /// <summary>
- /// Gets or sets the receive action.
- /// </summary>
- /// <value>The receive action.</value>
- public Action<byte[]> OnReceiveBytes { get; set; }
-
- /// <summary>
- /// Gets or sets the on receive.
- /// </summary>
- /// <value>The on receive.</value>
- public Action<string> OnReceive { get; set; }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
deleted file mode 100644
index 56f8ab429..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ /dev/null
@@ -1,216 +0,0 @@
-using System.Collections.Specialized;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.Logging;
-using SocketHttpListener.Net;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Emby.Server.Implementations.HttpServer;
-using Emby.Server.Implementations.Logging;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-using ServiceStack;
-
-namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
-{
- public class WebSocketSharpListener : IHttpListener
- {
- private HttpListener _listener;
-
- private readonly ILogger _logger;
- private readonly string _certificatePath;
- private readonly IMemoryStreamProvider _memoryStreamProvider;
-
- public WebSocketSharpListener(ILogger logger, string certificatePath, IMemoryStreamProvider memoryStreamProvider)
- {
- _logger = logger;
- _certificatePath = certificatePath;
- _memoryStreamProvider = memoryStreamProvider;
- }
-
- public Action<Exception, IRequest> ErrorHandler { get; set; }
-
- public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
-
- public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
-
- public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
-
- public void Start(IEnumerable<string> urlPrefixes)
- {
- if (_listener == null)
- _listener = new HttpListener(new PatternsLogger(_logger), _certificatePath);
-
- foreach (var prefix in urlPrefixes)
- {
- _logger.Info("Adding HttpListener prefix " + prefix);
- _listener.Prefixes.Add(prefix);
- }
-
- _listener.OnContext = ProcessContext;
-
- _listener.Start();
- }
-
- private void ProcessContext(HttpListenerContext context)
- {
- Task.Factory.StartNew(() => InitTask(context));
- }
-
- private void InitTask(HttpListenerContext context)
- {
- try
- {
- var task = this.ProcessRequestAsync(context);
- task.ContinueWith(x => HandleError(x.Exception, context), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
-
- //if (task.Status == TaskStatus.Created)
- //{
- // task.RunSynchronously();
- //}
- }
- catch (Exception ex)
- {
- HandleError(ex, context);
- }
- }
-
- private Task ProcessRequestAsync(HttpListenerContext context)
- {
- var request = context.Request;
-
- if (request.IsWebSocketRequest)
- {
- LoggerUtils.LogRequest(_logger, request);
-
- ProcessWebSocketRequest(context);
- return Task.FromResult(true);
- }
-
- if (string.IsNullOrEmpty(context.Request.RawUrl))
- return ((object)null).AsTaskResult();
-
- var httpReq = GetRequest(context);
-
- return RequestHandler(httpReq, request.Url);
- }
-
- private void ProcessWebSocketRequest(HttpListenerContext ctx)
- {
- try
- {
- var endpoint = ctx.Request.RemoteEndPoint.ToString();
- var url = ctx.Request.RawUrl;
- var queryString = ctx.Request.QueryString ?? new NameValueCollection();
-
- var queryParamCollection = new QueryParamCollection();
-
- foreach (var key in queryString.AllKeys)
- {
- queryParamCollection[key] = queryString[key];
- }
-
- var connectingArgs = new WebSocketConnectingEventArgs
- {
- Url = url,
- QueryString = queryParamCollection,
- Endpoint = endpoint
- };
-
- if (WebSocketConnecting != null)
- {
- WebSocketConnecting(connectingArgs);
- }
-
- if (connectingArgs.AllowConnection)
- {
- _logger.Debug("Web socket connection allowed");
-
- var webSocketContext = ctx.AcceptWebSocket(null);
-
- if (WebSocketConnected != null)
- {
- WebSocketConnected(new WebSocketConnectEventArgs
- {
- Url = url,
- QueryString = queryParamCollection,
- WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger),
- Endpoint = endpoint
- });
- }
- }
- else
- {
- _logger.Warn("Web socket connection not allowed");
- ctx.Response.StatusCode = 401;
- ctx.Response.Close();
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("AcceptWebSocketAsync error", ex);
- ctx.Response.StatusCode = 500;
- ctx.Response.Close();
- }
- }
-
- private IHttpRequest GetRequest(HttpListenerContext httpContext)
- {
- var operationName = httpContext.Request.GetOperationName();
-
- var req = new WebSocketSharpRequest(httpContext, operationName, RequestAttributes.None, _logger, _memoryStreamProvider);
-
- return req;
- }
-
- private void HandleError(Exception ex, HttpListenerContext context)
- {
- var httpReq = GetRequest(context);
-
- if (ErrorHandler != null)
- {
- ErrorHandler(ex, httpReq);
- }
- }
-
- public void Stop()
- {
- if (_listener != null)
- {
- foreach (var prefix in _listener.Prefixes.ToList())
- {
- _listener.Prefixes.Remove(prefix);
- }
-
- _listener.Close();
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- private bool _disposed;
- private readonly object _disposeLock = new object();
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed) return;
-
- lock (_disposeLock)
- {
- if (_disposed) return;
-
- if (disposing)
- {
- Stop();
- }
-
- //release unmanaged resources here...
- _disposed = true;
- }
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
index 72047609d..6f44fcce7 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs
@@ -1,17 +1,14 @@
using System;
using System.Collections.Generic;
-using System.Collections.Specialized;
using System.IO;
using System.Text;
using Emby.Server.Implementations.HttpServer.SocketSharp;
using Funq;
-using MediaBrowser.Common.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
using ServiceStack;
using ServiceStack.Host;
-using ServiceStack.Web;
using SocketHttpListener.Net;
using IHttpFile = MediaBrowser.Model.Services.IHttpFile;
using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest;
@@ -25,9 +22,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
public Container Container { get; set; }
private readonly HttpListenerRequest request;
private readonly IHttpResponse response;
- private readonly IMemoryStreamProvider _memoryStreamProvider;
+ private readonly IMemoryStreamFactory _memoryStreamProvider;
- public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger, IMemoryStreamProvider memoryStreamProvider)
+ public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, ILogger logger, IMemoryStreamFactory memoryStreamProvider)
{
this.OperationName = operationName;
_memoryStreamProvider = memoryStreamProvider;
@@ -55,36 +52,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
get { return response; }
}
- public T TryResolve<T>()
- {
- if (typeof(T) == typeof(IHttpRequest))
- throw new Exception("You don't need to use IHttpRequest.TryResolve<IHttpRequest> to resolve itself");
-
- if (typeof(T) == typeof(IHttpResponse))
- throw new Exception("Resolve IHttpResponse with 'Response' property instead of IHttpRequest.TryResolve<IHttpResponse>");
-
- return Container == null
- ? HostContext.TryResolve<T>()
- : Container.TryResolve<T>();
- }
-
public string OperationName { get; set; }
public object Dto { get; set; }
- public string GetRawBody()
- {
- if (bufferedStream != null)
- {
- return bufferedStream.ToArray().FromUtf8Bytes();
- }
-
- using (var reader = new StreamReader(InputStream))
- {
- return reader.ReadToEnd();
- }
- }
-
public string RawUrl
{
get { return request.RawUrl; }
@@ -104,7 +75,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
get
{
- return String.IsNullOrEmpty(request.Headers[HttpHeaders.XForwardedFor]) ? null : request.Headers[HttpHeaders.XForwardedFor];
+ return String.IsNullOrEmpty(request.Headers["X-Forwarded-For"]) ? null : request.Headers["X-Forwarded-For"];
}
}
@@ -112,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
get
{
- return string.IsNullOrEmpty(request.Headers[HttpHeaders.XForwardedPort]) ? (int?)null : int.Parse(request.Headers[HttpHeaders.XForwardedPort]);
+ return string.IsNullOrEmpty(request.Headers["X-Forwarded-Port"]) ? (int?)null : int.Parse(request.Headers["X-Forwarded-Port"]);
}
}
@@ -120,7 +91,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
get
{
- return string.IsNullOrEmpty(request.Headers[HttpHeaders.XForwardedProtocol]) ? null : request.Headers[HttpHeaders.XForwardedProtocol];
+ return string.IsNullOrEmpty(request.Headers["X-Forwarded-Proto"]) ? null : request.Headers["X-Forwarded-Proto"];
}
}
@@ -128,7 +99,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
get
{
- return String.IsNullOrEmpty(request.Headers[HttpHeaders.XRealIp]) ? null : request.Headers[HttpHeaders.XRealIp];
+ return String.IsNullOrEmpty(request.Headers["X-Real-IP"]) ? null : request.Headers["X-Real-IP"];
}
}
@@ -140,7 +111,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
return remoteIp ??
(remoteIp = (CheckBadChars(XForwardedFor)) ??
(NormalizeIp(CheckBadChars(XRealIp)) ??
- (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null)));
+ (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.IpAddress.ToString()) : null)));
}
}
@@ -280,7 +251,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
defaultContentType = HostContext.Config.DefaultContentType;
}
- var customContentTypes = HostContext.ContentTypes.ContentTypeFormats.Values;
+ var customContentTypes = ContentTypes.Instance.ContentTypeFormats.Values;
var preferredContentTypes = new string[] {};
var acceptsAnything = false;
@@ -328,11 +299,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
}
}
- if (httpReq.ContentType.MatchesContentType(MimeTypes.Soap12))
- {
- return MimeTypes.Soap12;
- }
-
if (acceptContentTypes == null && httpReq.ContentType == MimeTypes.Soap11)
{
return MimeTypes.Soap11;
@@ -344,10 +310,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
private static string GetQueryStringContentType(IRequest httpReq)
{
- var callback = httpReq.QueryString[Keywords.Callback];
- if (!string.IsNullOrEmpty(callback)) return MimeTypes.Json;
-
- var format = httpReq.QueryString[Keywords.Format];
+ var format = httpReq.QueryString["format"];
if (format == null)
{
const int formatMaxLength = 4;
@@ -359,12 +322,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
}
format = format.LeftPart('.').ToLower();
- if (format.Contains("json")) return MimeTypes.Json;
+ if (format.Contains("json")) return "application/json";
if (format.Contains("xml")) return MimeTypes.Xml;
- if (format.Contains("jsv")) return MimeTypes.Jsv;
string contentType;
- HostContext.ContentTypes.ContentTypeFormats.TryGetValue(format, out contentType);
+ ContentTypes.Instance.ContentTypeFormats.TryGetValue(format, out contentType);
return contentType;
}
@@ -474,10 +436,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
get { return request.UserAgent; }
}
- private QueryParamCollection headers;
public QueryParamCollection Headers
{
- get { return headers ?? (headers = ToQueryParams(request.Headers)); }
+ get { return request.Headers; }
}
private QueryParamCollection queryString;
@@ -492,18 +453,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
get { return formData ?? (formData = this.Form); }
}
- private QueryParamCollection ToQueryParams(NameValueCollection collection)
- {
- var result = new QueryParamCollection();
-
- foreach (var key in collection.AllKeys)
- {
- result[key] = collection[key];
- }
-
- return result;
- }
-
public bool IsLocal
{
get { return request.IsLocal; }
@@ -563,21 +512,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
}
}
- public bool UseBufferedStream
- {
- get { return bufferedStream != null; }
- set
- {
- bufferedStream = value
- ? bufferedStream ?? _memoryStreamProvider.CreateNew(request.InputStream.ReadFully())
- : null;
- }
- }
-
- private MemoryStream bufferedStream;
public Stream InputStream
{
- get { return bufferedStream ?? request.InputStream; }
+ get { return request.InputStream; }
}
public long ContentLength
@@ -613,7 +550,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
}
}
- static Stream GetSubStream(Stream stream, IMemoryStreamProvider streamProvider)
+ static Stream GetSubStream(Stream stream, IMemoryStreamFactory streamProvider)
{
if (stream is MemoryStream)
{
@@ -654,4 +591,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
return pathInfo;
}
}
+
+ public class HttpFile : IHttpFile
+ {
+ public string Name { get; set; }
+ public string FileName { get; set; }
+ public long ContentLength { get; set; }
+ public string ContentType { get; set; }
+ public Stream InputStream { get; set; }
+ }
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
deleted file mode 100644
index 3aae6c9ca..000000000
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using MediaBrowser.Model.Logging;
-using ServiceStack;
-using ServiceStack.Host;
-using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
-using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
-using IRequest = MediaBrowser.Model.Services.IRequest;
-
-namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
-{
- public class WebSocketSharpResponse : IHttpResponse
- {
- private readonly ILogger _logger;
- private readonly HttpListenerResponse _response;
-
- public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request)
- {
- _logger = logger;
- this._response = response;
- Items = new Dictionary<string, object>();
- Request = request;
- }
-
- public IRequest Request { get; private set; }
- public bool UseBufferedStream { get; set; }
- public Dictionary<string, object> Items { get; private set; }
- public object OriginalResponse
- {
- get { return _response; }
- }
-
- public int StatusCode
- {
- get { return this._response.StatusCode; }
- set { this._response.StatusCode = value; }
- }
-
- public string StatusDescription
- {
- get { return this._response.StatusDescription; }
- set { this._response.StatusDescription = value; }
- }
-
- public string ContentType
- {
- get { return _response.ContentType; }
- set { _response.ContentType = value; }
- }
-
- //public ICookies Cookies { get; set; }
-
- public void AddHeader(string name, string value)
- {
- if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase))
- {
- ContentType = value;
- return;
- }
-
- _response.AddHeader(name, value);
- }
-
- public string GetHeader(string name)
- {
- return _response.Headers[name];
- }
-
- public void Redirect(string url)
- {
- _response.Redirect(url);
- }
-
- public Stream OutputStream
- {
- get { return _response.OutputStream; }
- }
-
- public object Dto { get; set; }
-
- public void Write(string text)
- {
- var bOutput = System.Text.Encoding.UTF8.GetBytes(text);
- _response.ContentLength64 = bOutput.Length;
-
- var outputStream = _response.OutputStream;
- outputStream.Write(bOutput, 0, bOutput.Length);
- Close();
- }
-
- public void Close()
- {
- if (!this.IsClosed)
- {
- this.IsClosed = true;
-
- try
- {
- this._response.CloseOutputStream(_logger);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing HttpListener output stream", ex);
- }
- }
- }
-
- public void End()
- {
- Close();
- }
-
- public void Flush()
- {
- _response.OutputStream.Flush();
- }
-
- public bool IsClosed
- {
- get;
- private set;
- }
-
- public void SetContentLength(long contentLength)
- {
- //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;
- }
-
- public void SetCookie(Cookie cookie)
- {
- var cookieStr = cookie.AsHeaderValue();
- _response.Headers.Add(HttpHeaders.SetCookie, cookieStr);
- }
-
- public bool SendChunked
- {
- get { return _response.SendChunked; }
- set { _response.SendChunked = value; }
- }
-
- public bool KeepAlive { get; set; }
-
- public void ClearCookies()
- {
- }
- }
-}