mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-04 03:27:21 -05:00 
			
		
		
		
	create http listener abstraction
This commit is contained in:
		
							parent
							
								
									b4b17d7717
								
							
						
					
					
						commit
						ea559a6e27
					
				@ -26,8 +26,7 @@ namespace MediaBrowser.Common.Net
 | 
				
			|||||||
        /// Starts this instance.
 | 
					        /// Starts this instance.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="urlPrefixes">The URL prefixes.</param>
 | 
					        /// <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);
 | 
				
			||||||
        void Start(IEnumerable<string> urlPrefixes, bool enableHttpLogging);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Starts the web socket server.
 | 
					        /// Starts the web socket server.
 | 
				
			||||||
 | 
				
			|||||||
@ -38,12 +38,6 @@ namespace MediaBrowser.Controller.Net
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        void Stop();
 | 
					        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>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Occurs when [web socket connected].
 | 
					        /// Occurs when [web socket connected].
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 | 
				
			|||||||
@ -22,12 +22,6 @@ namespace MediaBrowser.Model.Configuration
 | 
				
			|||||||
        /// <value>The weather unit.</value>
 | 
					        /// <value>The weather unit.</value>
 | 
				
			||||||
        public WeatherUnits WeatherUnit { get; set; }
 | 
					        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>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets or sets a value indicating whether [enable u pn p].
 | 
					        /// Gets or sets a value indicating whether [enable u pn p].
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@ -223,7 +217,6 @@ namespace MediaBrowser.Model.Configuration
 | 
				
			|||||||
            ImageSavingConvention = ImageSavingConvention.Compatible;
 | 
					            ImageSavingConvention = ImageSavingConvention.Compatible;
 | 
				
			||||||
            HttpServerPortNumber = 8096;
 | 
					            HttpServerPortNumber = 8096;
 | 
				
			||||||
            LegacyWebSocketPortNumber = 8945;
 | 
					            LegacyWebSocketPortNumber = 8945;
 | 
				
			||||||
            EnableHttpLevelLogging = true;
 | 
					 | 
				
			||||||
            EnableDashboardResponseCaching = true;
 | 
					            EnableDashboardResponseCaching = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EnableAutomaticRestart = true;
 | 
					            EnableAutomaticRestart = true;
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ using MediaBrowser.Common.Extensions;
 | 
				
			|||||||
using MediaBrowser.Common.Net;
 | 
					using MediaBrowser.Common.Net;
 | 
				
			||||||
using MediaBrowser.Controller.Net;
 | 
					using MediaBrowser.Controller.Net;
 | 
				
			||||||
using MediaBrowser.Model.Logging;
 | 
					using MediaBrowser.Model.Logging;
 | 
				
			||||||
 | 
					using MediaBrowser.Server.Implementations.HttpServer.NetListener;
 | 
				
			||||||
using ServiceStack;
 | 
					using ServiceStack;
 | 
				
			||||||
using ServiceStack.Api.Swagger;
 | 
					using ServiceStack.Api.Swagger;
 | 
				
			||||||
using ServiceStack.Host;
 | 
					using ServiceStack.Host;
 | 
				
			||||||
@ -34,12 +35,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private readonly List<IRestfulService> _restServices = new List<IRestfulService>();
 | 
					        private readonly List<IRestfulService> _restServices = new List<IRestfulService>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private HttpListener Listener { get; set; }
 | 
					        private IHttpListener _listener;
 | 
				
			||||||
        protected bool IsStarted = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
 | 
					 | 
				
			||||||
        private readonly SmartThreadPool _threadPoolManager;
 | 
					        private readonly SmartThreadPool _threadPoolManager;
 | 
				
			||||||
 | 
					 | 
				
			||||||
        private const int IdleTimeout = 300;
 | 
					        private const int IdleTimeout = 300;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly ContainerAdapter _containerAdapter;
 | 
					        private readonly ContainerAdapter _containerAdapter;
 | 
				
			||||||
@ -53,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 | 
				
			|||||||
        /// <value>The local end points.</value>
 | 
					        /// <value>The local end points.</value>
 | 
				
			||||||
        public IEnumerable<string> LocalEndPoints
 | 
					        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)
 | 
					        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)
 | 
					        public override ServiceStackHost Start(string listeningAtUrlBase)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            StartListener(Listen);
 | 
					            StartListener();
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Starts the Web Service
 | 
					        /// Starts the Web Service
 | 
				
			||||||
        /// </summary>
 | 
					        /// </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());
 | 
					            HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach (var prefix in UrlPrefixes)
 | 
					            _listener = new HttpListenerServer(_logger, _threadPoolManager)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _logger.Info("Adding HttpListener prefix " + prefix);
 | 
					                WebSocketHandler = WebSocketHandler,
 | 
				
			||||||
                Listener.Prefixes.Add(prefix);
 | 
					                ErrorHandler = ErrorHandler,
 | 
				
			||||||
 | 
					                RequestHandler = RequestHandler
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _listener.Start(UrlPrefixes);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            IsStarted = true;
 | 
					        private void WebSocketHandler(WebSocketConnectEventArgs args)
 | 
				
			||||||
            _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; }
 | 
					            if (WebSocketConnected != null)
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Loop here to begin processing of new requests.
 | 
					 | 
				
			||||||
        private void Listen(object state)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
            while (IsListening)
 | 
					                WebSocketConnected(this, args);
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                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);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -280,43 +190,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 | 
				
			|||||||
                _localEndPoints.GetOrAdd(address, address);
 | 
					                _localEndPoints.GetOrAdd(address, address);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (EnableHttpRequestLogging)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
            LoggerUtils.LogRequest(_logger, request);
 | 
					            LoggerUtils.LogRequest(_logger, request);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        private void ErrorHandler(Exception ex, IRequest httpReq)
 | 
				
			||||||
        /// 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
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void HandleError(Exception ex, HttpListenerContext context)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var operationName = context.Request.GetOperationName();
 | 
					 | 
				
			||||||
                var httpReq = GetRequest(context, operationName);
 | 
					 | 
				
			||||||
                var httpRes = httpReq.Response;
 | 
					                var httpRes = httpReq.Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (httpRes.IsClosed)
 | 
					                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>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Shut down the Web Service
 | 
					        /// Shut down the Web Service
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public void Stop()
 | 
					        public void Stop()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (Listener != null)
 | 
					            if (_listener != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                foreach (var prefix in UrlPrefixes)
 | 
					                _listener.Stop();
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    Listener.Prefixes.Remove(prefix);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Listener.Close();
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Overridable method that can be used to implement a custom hnandler
 | 
					        /// Overridable method that can be used to implement a custom hnandler
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="context"></param>
 | 
					        /// <param name="httpReq">The HTTP req.</param>
 | 
				
			||||||
        protected Task ProcessRequestAsync(HttpListenerContext context)
 | 
					        /// <returns>Task.</returns>
 | 
				
			||||||
 | 
					        protected Task RequestHandler(IHttpRequest httpReq, Uri url)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var request = context.Request;
 | 
					            var date = DateTime.Now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            LogHttpRequest(request);
 | 
					            var httpRes = httpReq.Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (request.IsWebSocketRequest)
 | 
					            var operationName = httpReq.OperationName;
 | 
				
			||||||
            {
 | 
					            var localPath = url.LocalPath;
 | 
				
			||||||
                return ProcessWebSocketRequest(context);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var localPath = request.Url.LocalPath;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (string.Equals(localPath, "/" + HandlerPath + "/", StringComparison.OrdinalIgnoreCase))
 | 
					            if (string.Equals(localPath, "/" + HandlerPath + "/", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                context.Response.Redirect(DefaultRedirectPath);
 | 
					                httpRes.RedirectToUrl(DefaultRedirectPath);
 | 
				
			||||||
                context.Response.Close();
 | 
					 | 
				
			||||||
                return Task.FromResult(true);
 | 
					                return Task.FromResult(true);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (string.Equals(localPath, "/" + HandlerPath, StringComparison.OrdinalIgnoreCase))
 | 
					            if (string.Equals(localPath, "/" + HandlerPath, StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                context.Response.Redirect(HandlerPath + "/" + DefaultRedirectPath);
 | 
					                httpRes.RedirectToUrl(HandlerPath + "/" + DefaultRedirectPath);
 | 
				
			||||||
                context.Response.Close();
 | 
					 | 
				
			||||||
                return Task.FromResult(true);
 | 
					                return Task.FromResult(true);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
 | 
					            if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                context.Response.Redirect(HandlerPath + "/" + DefaultRedirectPath);
 | 
					                httpRes.RedirectToUrl(HandlerPath + "/" + DefaultRedirectPath);
 | 
				
			||||||
                context.Response.Close();
 | 
					 | 
				
			||||||
                return Task.FromResult(true);
 | 
					                return Task.FromResult(true);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (string.IsNullOrEmpty(localPath))
 | 
					            if (string.IsNullOrEmpty(localPath))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                context.Response.Redirect("/" + HandlerPath + "/" + DefaultRedirectPath);
 | 
					                httpRes.RedirectToUrl("/" + HandlerPath + "/" + DefaultRedirectPath);
 | 
				
			||||||
                context.Response.Close();
 | 
					 | 
				
			||||||
                return Task.FromResult(true);
 | 
					                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 handler = HttpHandlerFactory.GetHandler(httpReq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var url = request.Url.ToString();
 | 
					 | 
				
			||||||
            var remoteIp = httpReq.RemoteIp;
 | 
					            var remoteIp = httpReq.RemoteIp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var serviceStackHandler = handler as IServiceStackHandler;
 | 
					            var serviceStackHandler = handler as IServiceStackHandler;
 | 
				
			||||||
@ -461,15 +311,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 | 
				
			|||||||
                //Matches Exceptions handled in HttpListenerBase.InitTask()
 | 
					                //Matches Exceptions handled in HttpListenerBase.InitTask()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var statusCode = httpRes.StatusCode;
 | 
					                var statusCode = httpRes.StatusCode;
 | 
				
			||||||
 | 
					                var urlString = url.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                task.ContinueWith(x =>
 | 
					                task.ContinueWith(x =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var duration = DateTime.Now - date;
 | 
					                    var duration = DateTime.Now - date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (EnableHttpRequestLogging)
 | 
					                    LoggerUtils.LogResponse(_logger, statusCode, urlString, remoteIp, duration);
 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        LoggerUtils.LogResponse(_logger, statusCode, url, remoteIp, duration);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                }, TaskContinuationOptions.None);
 | 
					                }, TaskContinuationOptions.None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -480,12 +328,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 | 
				
			|||||||
                .AsTaskException();
 | 
					                .AsTaskException();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <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>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Adds the rest handlers.
 | 
					        /// Adds the rest handlers.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 | 
				
			|||||||
@ -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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -96,6 +96,9 @@
 | 
				
			|||||||
      <HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
 | 
					      <HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
 | 
				
			||||||
    </Reference>
 | 
					    </Reference>
 | 
				
			||||||
    <Reference Include="Mono.Posix" Condition=" '$(ConfigurationName)' == 'Release Mono' " />
 | 
					    <Reference Include="Mono.Posix" Condition=" '$(ConfigurationName)' == 'Release Mono' " />
 | 
				
			||||||
 | 
					    <Reference Include="websocket-sharp">
 | 
				
			||||||
 | 
					      <HintPath>..\ThirdParty\WebsocketSharp\websocket-sharp.dll</HintPath>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <Compile Include="..\SharedVersion.cs">
 | 
					    <Compile Include="..\SharedVersion.cs">
 | 
				
			||||||
@ -134,6 +137,8 @@
 | 
				
			|||||||
    <Compile Include="EntryPoints\ServerEventNotifier.cs" />
 | 
					    <Compile Include="EntryPoints\ServerEventNotifier.cs" />
 | 
				
			||||||
    <Compile Include="EntryPoints\UserDataChangeNotifier.cs" />
 | 
					    <Compile Include="EntryPoints\UserDataChangeNotifier.cs" />
 | 
				
			||||||
    <Compile Include="FileOrganization\OrganizerScheduledTask.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\Security\AuthorizationContext.cs" />
 | 
				
			||||||
    <Compile Include="HttpServer\ContainerAdapter.cs" />
 | 
					    <Compile Include="HttpServer\ContainerAdapter.cs" />
 | 
				
			||||||
    <Compile Include="HttpServer\GetSwaggerResource.cs" />
 | 
					    <Compile Include="HttpServer\GetSwaggerResource.cs" />
 | 
				
			||||||
 | 
				
			|||||||
@ -123,9 +123,9 @@ namespace MediaBrowser.Server.Implementations.ServerManager
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Starts this instance.
 | 
					        /// Starts this instance.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public void Start(IEnumerable<string> urlPrefixes, bool enableHttpLogging)
 | 
					        public void Start(IEnumerable<string> urlPrefixes)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ReloadHttpServer(urlPrefixes, enableHttpLogging);
 | 
					            ReloadHttpServer(urlPrefixes);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void StartWebSocketServer()
 | 
					        public void StartWebSocketServer()
 | 
				
			||||||
@ -152,14 +152,13 @@ namespace MediaBrowser.Server.Implementations.ServerManager
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Restarts the Http Server, or starts it if not currently running
 | 
					        /// Restarts the Http Server, or starts it if not currently running
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        private void ReloadHttpServer(IEnumerable<string> urlPrefixes, bool enableHttpLogging)
 | 
					        private void ReloadHttpServer(IEnumerable<string> urlPrefixes)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _logger.Info("Loading Http Server");
 | 
					            _logger.Info("Loading Http Server");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                HttpServer = _applicationHost.Resolve<IHttpServer>();
 | 
					                HttpServer = _applicationHost.Resolve<IHttpServer>();
 | 
				
			||||||
                HttpServer.EnableHttpRequestLogging = enableHttpLogging;
 | 
					 | 
				
			||||||
                HttpServer.StartServer(urlPrefixes);
 | 
					                HttpServer.StartServer(urlPrefixes);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (SocketException ex)
 | 
					            catch (SocketException ex)
 | 
				
			||||||
 | 
				
			|||||||
@ -851,7 +851,7 @@ namespace MediaBrowser.ServerApplication
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ServerManager.Start(HttpServerUrlPrefixes, ServerConfigurationManager.Configuration.EnableHttpLevelLogging);
 | 
					                ServerManager.Start(HttpServerUrlPrefixes);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -881,8 +881,6 @@ namespace MediaBrowser.ServerApplication
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            base.OnConfigurationUpdated(sender, e);
 | 
					            base.OnConfigurationUpdated(sender, e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            HttpServer.EnableHttpRequestLogging = ServerConfigurationManager.Configuration.EnableHttpLevelLogging;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!HttpServer.UrlPrefixes.SequenceEqual(HttpServerUrlPrefixes, StringComparer.OrdinalIgnoreCase))
 | 
					            if (!HttpServer.UrlPrefixes.SequenceEqual(HttpServerUrlPrefixes, StringComparer.OrdinalIgnoreCase))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                NotifyPendingRestart();
 | 
					                NotifyPendingRestart();
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user