diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs | 226 |
1 files changed, 34 insertions, 192 deletions
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(); } |
