|  | @@ -1,5 +1,6 @@
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  |  using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using System.Diagnostics;
 | 
	
		
			
				|  |  |  using System.Globalization;
 | 
	
		
			
				|  |  |  using System.IO;
 | 
	
		
			
				|  |  |  using System.Linq;
 | 
	
	
		
			
				|  | @@ -286,31 +287,6 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private static readonly string[] _skipLogExtensions =
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            ".js",
 | 
	
		
			
				|  |  | -            ".css",
 | 
	
		
			
				|  |  | -            ".woff",
 | 
	
		
			
				|  |  | -            ".woff2",
 | 
	
		
			
				|  |  | -            ".ttf",
 | 
	
		
			
				|  |  | -            ".html"
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private bool EnableLogging(string url, string localPath)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            var extension = GetExtension(url);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            return ((string.IsNullOrEmpty(extension) || !_skipLogExtensions.Contains(extension))
 | 
	
		
			
				|  |  | -                && (string.IsNullOrEmpty(localPath) || localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private static string GetExtension(string url)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            var parts = url.Split(new[] { '?' }, 2);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            return Path.GetExtension(parts[0]);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          public static string RemoveQueryStringByKey(string url, string key)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var uri = new Uri(url);
 | 
	
	
		
			
				|  | @@ -448,10 +424,9 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
		
			
				|  |  |          protected async Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            var date = DateTime.Now;
 | 
	
		
			
				|  |  | +            var stopWatch = new Stopwatch();
 | 
	
		
			
				|  |  | +            stopWatch.Start();
 | 
	
		
			
				|  |  |              var httpRes = httpReq.Response;
 | 
	
		
			
				|  |  | -            bool enableLog = false;
 | 
	
		
			
				|  |  | -            bool logHeaders = false;
 | 
	
		
			
				|  |  |              string urlToLog = null;
 | 
	
		
			
				|  |  |              string remoteIp = httpReq.RemoteIp;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -498,18 +473,8 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |                      return;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                var operationName = httpReq.OperationName;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                enableLog = EnableLogging(urlString, localPath);
 | 
	
		
			
				|  |  | -                urlToLog = urlString;
 | 
	
		
			
				|  |  | -                logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                if (enableLog)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    urlToLog = GetUrlToLog(urlString);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent, logHeaders ? httpReq.Headers : null);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +                urlToLog = GetUrlToLog(urlString);
 | 
	
		
			
				|  |  | +                Logger.LogDebug("HTTP {HttpMethod} {Url} UserAgent: {UserAgent} \nHeaders: {@Headers}", urlToLog, httpReq.UserAgent ?? string.Empty, httpReq.HttpMethod, httpReq.Headers);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
 | 
	
		
			
				|  |  |                      string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
 | 
	
	
		
			
				|  | @@ -517,6 +482,7 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |                      RedirectToUrl(httpRes, DefaultRedirectPath);
 | 
	
		
			
				|  |  |                      return;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                  if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
 | 
	
		
			
				|  |  |                      string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
	
		
			
				|  | @@ -562,16 +528,19 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |                      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);
 | 
	
	
		
			
				|  | @@ -607,33 +576,21 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (handler != null)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, httpReq.OperationName, cancellationToken).ConfigureAwait(false);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  else
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      await ErrorHandler(new FileNotFoundException(), httpReq, false, false).ConfigureAwait(false);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            catch (OperationCanceledException ex)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            catch (IOException ex)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            catch (SocketException ex)
 | 
	
		
			
				|  |  | +            catch (Exception ex) when (ex is SocketException || ex is IOException || ex is OperationCanceledException)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  await ErrorHandler(ex, httpReq, false, false).ConfigureAwait(false);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              catch (SecurityException ex)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  await ErrorHandler(ex, httpReq, false, true).ConfigureAwait(false);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              catch (Exception ex)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var logException = !string.Equals(ex.GetType().Name, "SocketException", StringComparison.OrdinalIgnoreCase);
 | 
	
	
		
			
				|  | @@ -644,13 +601,15 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  httpRes.Close();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (enableLog)
 | 
	
		
			
				|  |  | +                stopWatch.Stop();
 | 
	
		
			
				|  |  | +                var elapsed = stopWatch.Elapsed;
 | 
	
		
			
				|  |  | +                if (elapsed.Milliseconds > 500)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    var statusCode = httpRes.StatusCode;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var duration = DateTime.Now - date;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null);
 | 
	
		
			
				|  |  | +                    _logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:ss.fff}. {Url}", httpRes.StatusCode, remoteIp, stopWatch.Elapsed, urlToLog);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    _logger.LogDebug("HTTP Response {StatusCode} to {RemoteIp}. Time: {Elapsed:ss.fff}. {Url}", httpRes.StatusCode, remoteIp, stopWatch.Elapsed, urlToLog);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -663,12 +622,11 @@ namespace Emby.Server.Implementations.HttpServer
 | 
	
		
			
				|  |  |              var pathParts = pathInfo.TrimStart('/').Split('/');
 | 
	
		
			
				|  |  |              if (pathParts.Length == 0)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                _logger.LogError("Path parts empty for PathInfo: {pathInfo}, Url: {RawUrl}", pathInfo, httpReq.RawUrl);
 | 
	
		
			
				|  |  | +                _logger.LogError("Path parts empty for PathInfo: {PathInfo}, Url: {RawUrl}", pathInfo, httpReq.RawUrl);
 | 
	
		
			
				|  |  |                  return null;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var restPath = ServiceHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, out string contentType);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              if (restPath != null)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  return new ServiceHandler
 |