aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-07-18 18:14:59 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-07-18 18:14:59 -0400
commitea559a6e274c2067cda780ba81bc5237c9e2ebf7 (patch)
treeb3ee580495b6df0b095e167b00577d69267eece3
parentb4b17d7717ff773d9782462c0eae967c4c7f2ad9 (diff)
create http listener abstraction
-rw-r--r--MediaBrowser.Common/Net/IServerManager.cs3
-rw-r--r--MediaBrowser.Controller/Net/IHttpServer.cs6
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs7
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs226
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs42
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs281
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj5
-rw-r--r--MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs7
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs4
9 files changed, 367 insertions, 214 deletions
diff --git a/MediaBrowser.Common/Net/IServerManager.cs b/MediaBrowser.Common/Net/IServerManager.cs
index f81c99ac6..7c14f98ce 100644
--- a/MediaBrowser.Common/Net/IServerManager.cs
+++ b/MediaBrowser.Common/Net/IServerManager.cs
@@ -26,8 +26,7 @@ namespace MediaBrowser.Common.Net
/// Starts this instance.
/// </summary>
/// <param name="urlPrefixes">The URL prefixes.</param>
- /// <param name="enableHttpLogging">if set to <c>true</c> [enable HTTP logging].</param>
- void Start(IEnumerable<string> urlPrefixes, bool enableHttpLogging);
+ void Start(IEnumerable<string> urlPrefixes);
/// <summary>
/// Starts the web socket server.
diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs
index 20f07c74d..9a3cc6cb5 100644
--- a/MediaBrowser.Controller/Net/IHttpServer.cs
+++ b/MediaBrowser.Controller/Net/IHttpServer.cs
@@ -39,12 +39,6 @@ namespace MediaBrowser.Controller.Net
void Stop();
/// <summary>
- /// Gets or sets a value indicating whether [enable HTTP request logging].
- /// </summary>
- /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value>
- bool EnableHttpRequestLogging { get; set; }
-
- /// <summary>
/// Occurs when [web socket connected].
/// </summary>
event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 064ac234f..904c7bcdd 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -23,12 +23,6 @@ namespace MediaBrowser.Model.Configuration
public WeatherUnits WeatherUnit { get; set; }
/// <summary>
- /// Gets or sets a value indicating whether [enable HTTP level logging].
- /// </summary>
- /// <value><c>true</c> if [enable HTTP level logging]; otherwise, <c>false</c>.</value>
- public bool EnableHttpLevelLogging { get; set; }
-
- /// <summary>
/// Gets or sets a value indicating whether [enable u pn p].
/// </summary>
/// <value><c>true</c> if [enable u pn p]; otherwise, <c>false</c>.</value>
@@ -223,7 +217,6 @@ namespace MediaBrowser.Model.Configuration
ImageSavingConvention = ImageSavingConvention.Compatible;
HttpServerPortNumber = 8096;
LegacyWebSocketPortNumber = 8945;
- EnableHttpLevelLogging = true;
EnableDashboardResponseCaching = true;
EnableAutomaticRestart = true;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 340149182..68b69cdf0 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.HttpServer.NetListener;
using ServiceStack;
using ServiceStack.Api.Swagger;
using ServiceStack.Host;
@@ -34,14 +35,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
private readonly List<IRestfulService> _restServices = new List<IRestfulService>();
- private HttpListener Listener { get; set; }
- protected bool IsStarted = false;
+ private IHttpListener _listener;
- private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
private readonly SmartThreadPool _threadPoolManager;
+ private const int IdleTimeout = 300;
- private const int IdleTimeout = 300;
-
private readonly ContainerAdapter _containerAdapter;
private readonly ConcurrentDictionary<string, string> _localEndPoints = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@@ -53,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <value>The local end points.</value>
public IEnumerable<string> LocalEndPoints
{
- get { return _localEndPoints.Keys.ToList(); }
+ get { return _listener == null ? new List<string>() : _listener.LocalEndPoints; }
}
public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, string serviceName, string handlerPath, string defaultRedirectPath, params Assembly[] assembliesWithServices)
@@ -148,120 +146,32 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public override ServiceStackHost Start(string listeningAtUrlBase)
{
- StartListener(Listen);
+ StartListener();
return this;
}
/// <summary>
/// Starts the Web Service
/// </summary>
- private void StartListener(WaitCallback listenCallback)
+ private void StartListener()
{
- // *** Already running - just leave it in place
- if (IsStarted)
- return;
-
- if (Listener == null)
- Listener = new HttpListener();
-
HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First());
- foreach (var prefix in UrlPrefixes)
- {
- _logger.Info("Adding HttpListener prefix " + prefix);
- Listener.Prefixes.Add(prefix);
- }
-
- IsStarted = true;
- _logger.Info("Starting HttpListner");
- Listener.Start();
- _logger.Info("HttpListener started");
-
- ThreadPool.QueueUserWorkItem(listenCallback);
- }
-
- private bool IsListening
- {
- get { return this.IsStarted && this.Listener != null && this.Listener.IsListening; }
- }
-
- // Loop here to begin processing of new requests.
- private void Listen(object state)
- {
- while (IsListening)
- {
- if (Listener == null) return;
-
- try
- {
- Listener.BeginGetContext(ListenerCallback, Listener);
- _listenForNextRequest.WaitOne();
- }
- catch (Exception ex)
- {
- _logger.Error("Listen()", ex);
- return;
- }
- if (Listener == null) return;
- }
- }
-
- // Handle the processing of a request in here.
- private void ListenerCallback(IAsyncResult asyncResult)
- {
- var listener = asyncResult.AsyncState as HttpListener;
- HttpListenerContext context;
-
- if (listener == null) return;
- var isListening = listener.IsListening;
-
- try
- {
- if (!isListening)
- {
- _logger.Debug("Ignoring ListenerCallback() as HttpListener is no longer listening"); return;
- }
- // The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework,
- // blocks until there is a request to be processed or some type of data is available.
- context = listener.EndGetContext(asyncResult);
- }
- catch (Exception ex)
+ _listener = new HttpListenerServer(_logger, _threadPoolManager)
{
- // You will get an exception when httpListener.Stop() is called
- // because there will be a thread stopped waiting on the .EndGetContext()
- // method, and again, that is just the way most Begin/End asynchronous
- // methods of the .NET Framework work.
- var errMsg = ex + ": " + IsListening;
- _logger.Warn(errMsg);
- return;
- }
- finally
- {
- // Once we know we have a request (or exception), we signal the other thread
- // so that it calls the BeginGetContext() (or possibly exits if we're not
- // listening any more) method to start handling the next incoming request
- // while we continue to process this request on a different thread.
- _listenForNextRequest.Set();
- }
+ WebSocketHandler = WebSocketHandler,
+ ErrorHandler = ErrorHandler,
+ RequestHandler = RequestHandler
+ };
- _threadPoolManager.QueueWorkItem(() => InitTask(context));
+ _listener.Start(UrlPrefixes);
}
- public virtual void InitTask(HttpListenerContext context)
+ private void WebSocketHandler(WebSocketConnectEventArgs args)
{
- 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)
+ if (WebSocketConnected != null)
{
- HandleError(ex, context);
+ WebSocketConnected(this, args);
}
}
@@ -280,43 +190,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
_localEndPoints.GetOrAdd(address, address);
}
- if (EnableHttpRequestLogging)
- {
- LoggerUtils.LogRequest(_logger, request);
- }
- }
-
- /// <summary>
- /// Processes the web socket request.
- /// </summary>
- /// <param name="ctx">The CTX.</param>
- /// <returns>Task.</returns>
- private async Task ProcessWebSocketRequest(HttpListenerContext ctx)
- {
-#if !__MonoCS__
- try
- {
- var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false);
- if (WebSocketConnected != null)
- {
- WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint.ToString() });
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("AcceptWebSocketAsync error", ex);
- ctx.Response.StatusCode = 500;
- ctx.Response.Close();
- }
-#endif
+ LoggerUtils.LogRequest(_logger, request);
}
- private void HandleError(Exception ex, HttpListenerContext context)
+ private void ErrorHandler(Exception ex, IRequest httpReq)
{
try
{
- var operationName = context.Request.GetOperationName();
- var httpReq = GetRequest(context, operationName);
var httpRes = httpReq.Response;
if (httpRes.IsClosed)
@@ -366,84 +246,54 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
}
- private static ListenerRequest GetRequest(HttpListenerContext httpContext, string operationName)
- {
- var req = new ListenerRequest(httpContext, operationName, RequestAttributes.None);
- req.RequestAttributes = req.GetAttributes();
-
- return req;
- }
-
/// <summary>
/// Shut down the Web Service
/// </summary>
public void Stop()
{
- if (Listener != null)
+ if (_listener != null)
{
- foreach (var prefix in UrlPrefixes)
- {
- Listener.Prefixes.Remove(prefix);
- }
-
- Listener.Close();
+ _listener.Stop();
}
}
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
- /// <param name="context"></param>
- protected Task ProcessRequestAsync(HttpListenerContext context)
+ /// <param name="httpReq">The HTTP req.</param>
+ /// <returns>Task.</returns>
+ protected Task RequestHandler(IHttpRequest httpReq, Uri url)
{
- var request = context.Request;
-
- LogHttpRequest(request);
+ var date = DateTime.Now;
- if (request.IsWebSocketRequest)
- {
- return ProcessWebSocketRequest(context);
- }
+ var httpRes = httpReq.Response;
- var localPath = request.Url.LocalPath;
+ var operationName = httpReq.OperationName;
+ var localPath = url.LocalPath;
if (string.Equals(localPath, "/" + HandlerPath + "/", StringComparison.OrdinalIgnoreCase))
{
- context.Response.Redirect(DefaultRedirectPath);
- context.Response.Close();
+ httpRes.RedirectToUrl(DefaultRedirectPath);
return Task.FromResult(true);
}
if (string.Equals(localPath, "/" + HandlerPath, StringComparison.OrdinalIgnoreCase))
{
- context.Response.Redirect(HandlerPath + "/" + DefaultRedirectPath);
- context.Response.Close();
+ httpRes.RedirectToUrl(HandlerPath + "/" + DefaultRedirectPath);
return Task.FromResult(true);
}
if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
{
- context.Response.Redirect(HandlerPath + "/" + DefaultRedirectPath);
- context.Response.Close();
+ httpRes.RedirectToUrl(HandlerPath + "/" + DefaultRedirectPath);
return Task.FromResult(true);
}
if (string.IsNullOrEmpty(localPath))
{
- context.Response.Redirect("/" + HandlerPath + "/" + DefaultRedirectPath);
- context.Response.Close();
+ httpRes.RedirectToUrl("/" + HandlerPath + "/" + DefaultRedirectPath);
return Task.FromResult(true);
}
- var date = DateTime.Now;
-
- if (string.IsNullOrEmpty(context.Request.RawUrl))
- return ((object)null).AsTaskResult();
-
- var operationName = context.Request.GetOperationName();
-
- var httpReq = GetRequest(context, operationName);
- var httpRes = httpReq.Response;
var handler = HttpHandlerFactory.GetHandler(httpReq);
- var url = request.Url.ToString();
var remoteIp = httpReq.RemoteIp;
var serviceStackHandler = handler as IServiceStackHandler;
@@ -461,15 +311,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
//Matches Exceptions handled in HttpListenerBase.InitTask()
var statusCode = httpRes.StatusCode;
+ var urlString = url.ToString();
task.ContinueWith(x =>
{
var duration = DateTime.Now - date;
- if (EnableHttpRequestLogging)
- {
- LoggerUtils.LogResponse(_logger, statusCode, url, remoteIp, duration);
- }
+ LoggerUtils.LogResponse(_logger, statusCode, urlString, remoteIp, duration);
}, TaskContinuationOptions.None);
@@ -481,12 +329,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
/// <summary>
- /// Gets or sets a value indicating whether [enable HTTP request logging].
- /// </summary>
- /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value>
- public bool EnableHttpRequestLogging { get; set; }
-
- /// <summary>
/// Adds the rest handlers.
/// </summary>
/// <param name="services">The services.</param>
@@ -530,8 +372,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
if (disposing)
{
- _threadPoolManager.Dispose();
-
+ _threadPoolManager.Dispose();
+
Stop();
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
new file mode 100644
index 000000000..1d80a263c
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
@@ -0,0 +1,42 @@
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+using ServiceStack.Web;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Server.Implementations.HttpServer
+{
+ public interface IHttpListener : IDisposable
+ {
+ IEnumerable<string> LocalEndPoints { get; }
+
+ /// <summary>
+ /// Gets or sets the error handler.
+ /// </summary>
+ /// <value>The error handler.</value>
+ Action<Exception, IRequest> ErrorHandler { get; set; }
+
+ /// <summary>
+ /// Gets or sets the request handler.
+ /// </summary>
+ /// <value>The request handler.</value>
+ Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
+
+ /// <summary>
+ /// Gets or sets the web socket handler.
+ /// </summary>
+ /// <value>The web socket handler.</value>
+ Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; }
+
+ /// <summary>
+ /// Starts this instance.
+ /// </summary>
+ /// <param name="urlPrefixes">The URL prefixes.</param>
+ void Start(IEnumerable<string> urlPrefixes);
+
+ /// <summary>
+ /// Stops this instance.
+ /// </summary>
+ void Stop();
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs b/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
new file mode 100644
index 000000000..51f0554d7
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
@@ -0,0 +1,281 @@
+using Amib.Threading;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Logging;
+using ServiceStack;
+using ServiceStack.Host.HttpListener;
+using ServiceStack.Web;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.HttpServer.NetListener
+{
+ public class HttpListenerServer : IHttpListener
+ {
+ private readonly ILogger _logger;
+ private HttpListener _listener;
+ private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
+ private readonly SmartThreadPool _threadPoolManager;
+
+ public System.Action<Exception, IRequest> ErrorHandler { get; set; }
+ public Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; }
+ public System.Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
+
+ private readonly ConcurrentDictionary<string, string> _localEndPoints = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
+ public HttpListenerServer(ILogger logger, SmartThreadPool threadPoolManager)
+ {
+ _logger = logger;
+
+ _threadPoolManager = threadPoolManager;
+ }
+
+ /// <summary>
+ /// Gets the local end points.
+ /// </summary>
+ /// <value>The local end points.</value>
+ public IEnumerable<string> LocalEndPoints
+ {
+ get { return _localEndPoints.Keys.ToList(); }
+ }
+
+ private List<string> UrlPrefixes { get; set; }
+
+ public void Start(IEnumerable<string> urlPrefixes)
+ {
+ UrlPrefixes = urlPrefixes.ToList();
+
+ if (_listener == null)
+ _listener = new System.Net.HttpListener();
+
+ //HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First());
+
+ foreach (var prefix in UrlPrefixes)
+ {
+ _logger.Info("Adding HttpListener prefix " + prefix);
+ _listener.Prefixes.Add(prefix);
+ }
+
+ _listener.Start();
+
+ ThreadPool.QueueUserWorkItem(Listen);
+ }
+
+ private bool IsListening
+ {
+ get { return _listener != null && _listener.IsListening; }
+ }
+
+ // Loop here to begin processing of new requests.
+ private void Listen(object state)
+ {
+ while (IsListening)
+ {
+ if (_listener == null) return;
+
+ try
+ {
+ _listener.BeginGetContext(ListenerCallback, _listener);
+ _listenForNextRequest.WaitOne();
+ }
+ catch (Exception ex)
+ {
+ _logger.Error("Listen()", ex);
+ return;
+ }
+ if (_listener == null) return;
+ }
+ }
+
+ // Handle the processing of a request in here.
+ private void ListenerCallback(IAsyncResult asyncResult)
+ {
+ var listener = asyncResult.AsyncState as HttpListener;
+ HttpListenerContext context;
+
+ if (listener == null) return;
+ var isListening = listener.IsListening;
+
+ try
+ {
+ if (!isListening)
+ {
+ _logger.Debug("Ignoring ListenerCallback() as HttpListener is no longer listening"); return;
+ }
+ // The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework,
+ // blocks until there is a request to be processed or some type of data is available.
+ context = listener.EndGetContext(asyncResult);
+ }
+ catch (Exception ex)
+ {
+ // You will get an exception when httpListener.Stop() is called
+ // because there will be a thread stopped waiting on the .EndGetContext()
+ // method, and again, that is just the way most Begin/End asynchronous
+ // methods of the .NET Framework work.
+ var errMsg = ex + ": " + IsListening;
+ _logger.Warn(errMsg);
+ return;
+ }
+ finally
+ {
+ // Once we know we have a request (or exception), we signal the other thread
+ // so that it calls the BeginGetContext() (or possibly exits if we're not
+ // listening any more) method to start handling the next incoming request
+ // while we continue to process this request on a different thread.
+ _listenForNextRequest.Set();
+ }
+
+ _threadPoolManager.QueueWorkItem(() => InitTask(context));
+ }
+
+ public virtual 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);
+ }
+ }
+
+ protected Task ProcessRequestAsync(HttpListenerContext context)
+ {
+ var request = context.Request;
+
+ LogHttpRequest(request);
+
+ if (request.IsWebSocketRequest)
+ {
+ return ProcessWebSocketRequest(context);
+ }
+
+ if (string.IsNullOrEmpty(context.Request.RawUrl))
+ return ((object)null).AsTaskResult();
+
+ var operationName = context.Request.GetOperationName();
+
+ var httpReq = GetRequest(context, operationName);
+
+ return RequestHandler(httpReq, request.Url);
+ }
+
+ /// <summary>
+ /// Processes the web socket request.
+ /// </summary>
+ /// <param name="ctx">The CTX.</param>
+ /// <returns>Task.</returns>
+ private async Task ProcessWebSocketRequest(HttpListenerContext ctx)
+ {
+#if !__MonoCS__
+ try
+ {
+ var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false);
+
+ if (WebSocketHandler != null)
+ {
+ WebSocketHandler(new WebSocketConnectEventArgs
+ {
+ WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger),
+ Endpoint = ctx.Request.RemoteEndPoint.ToString()
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("AcceptWebSocketAsync error", ex);
+ ctx.Response.StatusCode = 500;
+ ctx.Response.Close();
+ }
+#endif
+ }
+
+ private void HandleError(Exception ex, HttpListenerContext context)
+ {
+ var operationName = context.Request.GetOperationName();
+ var httpReq = GetRequest(context, operationName);
+
+ if (ErrorHandler != null)
+ {
+ ErrorHandler(ex, httpReq);
+ }
+ }
+
+ private static ListenerRequest GetRequest(HttpListenerContext httpContext, string operationName)
+ {
+ var req = new ListenerRequest(httpContext, operationName, RequestAttributes.None);
+ req.RequestAttributes = req.GetAttributes();
+
+ return req;
+ }
+
+ /// <summary>
+ /// Logs the HTTP request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ private void LogHttpRequest(HttpListenerRequest request)
+ {
+ var endpoint = request.LocalEndPoint;
+
+ if (endpoint != null)
+ {
+ var address = endpoint.ToString();
+
+ _localEndPoints.GetOrAdd(address, address);
+ }
+
+ LoggerUtils.LogRequest(_logger, request);
+ }
+
+ public void Stop()
+ {
+ if (_listener != null)
+ {
+ foreach (var prefix in UrlPrefixes)
+ {
+ _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)
+ {
+ _threadPoolManager.Dispose();
+
+ Stop();
+ }
+
+ //release unmanaged resources here...
+ _disposed = true;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 8d4eec29e..c24e9574f 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -96,6 +96,9 @@
<HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
</Reference>
<Reference Include="Mono.Posix" Condition=" '$(ConfigurationName)' == 'Release Mono' " />
+ <Reference Include="websocket-sharp">
+ <HintPath>..\ThirdParty\WebsocketSharp\websocket-sharp.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
@@ -134,6 +137,8 @@
<Compile Include="EntryPoints\ServerEventNotifier.cs" />
<Compile Include="EntryPoints\UserDataChangeNotifier.cs" />
<Compile Include="FileOrganization\OrganizerScheduledTask.cs" />
+ <Compile Include="HttpServer\NetListener\HttpListenerServer.cs" />
+ <Compile Include="HttpServer\IHttpListener.cs" />
<Compile Include="HttpServer\Security\AuthorizationContext.cs" />
<Compile Include="HttpServer\ContainerAdapter.cs" />
<Compile Include="HttpServer\GetSwaggerResource.cs" />
diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
index e66b87b0c..5931d7718 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
@@ -123,9 +123,9 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// <summary>
/// Starts this instance.
/// </summary>
- public void Start(IEnumerable<string> urlPrefixes, bool enableHttpLogging)
+ public void Start(IEnumerable<string> urlPrefixes)
{
- ReloadHttpServer(urlPrefixes, enableHttpLogging);
+ ReloadHttpServer(urlPrefixes);
}
public void StartWebSocketServer()
@@ -152,14 +152,13 @@ namespace MediaBrowser.Server.Implementations.ServerManager
/// <summary>
/// Restarts the Http Server, or starts it if not currently running
/// </summary>
- private void ReloadHttpServer(IEnumerable<string> urlPrefixes, bool enableHttpLogging)
+ private void ReloadHttpServer(IEnumerable<string> urlPrefixes)
{
_logger.Info("Loading Http Server");
try
{
HttpServer = _applicationHost.Resolve<IHttpServer>();
- HttpServer.EnableHttpRequestLogging = enableHttpLogging;
HttpServer.StartServer(urlPrefixes);
}
catch (SocketException ex)
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 60d1c92b4..da7f8631b 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -851,7 +851,7 @@ namespace MediaBrowser.ServerApplication
{
try
{
- ServerManager.Start(HttpServerUrlPrefixes, ServerConfigurationManager.Configuration.EnableHttpLevelLogging);
+ ServerManager.Start(HttpServerUrlPrefixes);
}
catch (Exception ex)
{
@@ -881,8 +881,6 @@ namespace MediaBrowser.ServerApplication
{
base.OnConfigurationUpdated(sender, e);
- HttpServer.EnableHttpRequestLogging = ServerConfigurationManager.Configuration.EnableHttpLevelLogging;
-
if (!HttpServer.UrlPrefixes.SequenceEqual(HttpServerUrlPrefixes, StringComparer.OrdinalIgnoreCase))
{
NotifyPendingRestart();