diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs | 676 |
1 files changed, 0 insertions, 676 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs deleted file mode 100644 index b3d3ec13c..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ /dev/null @@ -1,676 +0,0 @@ -using Funq; -using MediaBrowser.Common; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Server.Implementations.HttpServer.SocketSharp; -using ServiceStack; -using ServiceStack.Api.Swagger; -using ServiceStack.Host; -using ServiceStack.Host.Handlers; -using ServiceStack.Host.HttpListener; -using ServiceStack.Logging; -using ServiceStack.Web; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Security; -using MediaBrowser.Model.Extensions; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public class HttpListenerHost : ServiceStackHost, IHttpServer - { - private string DefaultRedirectPath { get; set; } - - private readonly ILogger _logger; - public IEnumerable<string> UrlPrefixes { get; private set; } - - private readonly List<IRestfulService> _restServices = new List<IRestfulService>(); - - private IHttpListener _listener; - - private readonly ContainerAdapter _containerAdapter; - - public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; - public event EventHandler<WebSocketConnectingEventArgs> WebSocketConnecting; - - public string CertificatePath { get; private set; } - - private readonly IServerConfigurationManager _config; - private readonly INetworkManager _networkManager; - private readonly IMemoryStreamProvider _memoryStreamProvider; - - public HttpListenerHost(IApplicationHost applicationHost, - ILogManager logManager, - IServerConfigurationManager config, - string serviceName, - string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamProvider memoryStreamProvider, params Assembly[] assembliesWithServices) - : base(serviceName, assembliesWithServices) - { - DefaultRedirectPath = defaultRedirectPath; - _networkManager = networkManager; - _memoryStreamProvider = memoryStreamProvider; - _config = config; - - _logger = logManager.GetLogger("HttpServer"); - - _containerAdapter = new ContainerAdapter(applicationHost); - } - - public string GlobalResponse { get; set; } - - public override void Configure(Container container) - { - HostConfig.Instance.DefaultRedirectPath = DefaultRedirectPath; - HostConfig.Instance.LogUnobservedTaskExceptions = false; - - HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int> - { - {typeof (InvalidOperationException), 500}, - {typeof (NotImplementedException), 500}, - {typeof (ResourceNotFoundException), 404}, - {typeof (FileNotFoundException), 404}, - {typeof (DirectoryNotFoundException), 404}, - {typeof (SecurityException), 401}, - {typeof (PaymentRequiredException), 402}, - {typeof (UnauthorizedAccessException), 500}, - {typeof (ApplicationException), 500}, - {typeof (PlatformNotSupportedException), 500}, - {typeof (NotSupportedException), 500} - }; - - HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>(); - HostConfig.Instance.DebugMode = false; - - HostConfig.Instance.LogFactory = LogManager.LogFactory; - HostConfig.Instance.AllowJsonpRequests = false; - - // The Markdown feature causes slow startup times (5 mins+) on cold boots for some users - // Custom format allows images - HostConfig.Instance.EnableFeatures = Feature.Html | Feature.Json | Feature.Xml | Feature.CustomFormat; - - container.Adapter = _containerAdapter; - - Plugins.RemoveAll(x => x is NativeTypesFeature); - Plugins.Add(new SwaggerFeature()); - Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization")); - - //Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { - // new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()), - //})); - - //PreRequestFilters.Add((httpReq, httpRes) => - //{ - // //Handles Request and closes Responses after emitting global HTTP Headers - // if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) - // { - // httpRes.EndRequest(); //add a 'using ServiceStack;' - // } - //}); - - HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); - } - - public override void OnAfterInit() - { - SetAppDomainData(); - - base.OnAfterInit(); - } - - public override void OnConfigLoad() - { - base.OnConfigLoad(); - - Config.HandlerFactoryPath = null; - - Config.MetadataRedirectPath = "metadata"; - } - - protected override ServiceController CreateServiceController(params Assembly[] assembliesWithServices) - { - var types = _restServices.Select(r => r.GetType()).ToArray(); - - return new ServiceController(this, () => types); - } - - public virtual void SetAppDomainData() - { - //Required for Mono to resolve VirtualPathUtility and Url.Content urls - var domain = Thread.GetDomain(); // or AppDomain.Current - domain.SetData(".appDomain", "1"); - domain.SetData(".appVPath", "/"); - domain.SetData(".appPath", domain.BaseDirectory); - if (string.IsNullOrEmpty(domain.GetData(".appId") as string)) - { - domain.SetData(".appId", "1"); - } - if (string.IsNullOrEmpty(domain.GetData(".domainId") as string)) - { - domain.SetData(".domainId", "1"); - } - } - - public override ServiceStackHost Start(string listeningAtUrlBase) - { - StartListener(); - return this; - } - - /// <summary> - /// Starts the Web Service - /// </summary> - private void StartListener() - { - HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First()); - - _listener = GetListener(); - - _listener.WebSocketConnected = OnWebSocketConnected; - _listener.WebSocketConnecting = OnWebSocketConnecting; - _listener.ErrorHandler = ErrorHandler; - _listener.RequestHandler = RequestHandler; - - _listener.Start(UrlPrefixes); - } - - private IHttpListener GetListener() - { - return new WebSocketSharpListener(_logger, CertificatePath, _memoryStreamProvider); - } - - private void OnWebSocketConnecting(WebSocketConnectingEventArgs args) - { - if (_disposed) - { - return; - } - - if (WebSocketConnecting != null) - { - WebSocketConnecting(this, args); - } - } - - private void OnWebSocketConnected(WebSocketConnectEventArgs args) - { - if (_disposed) - { - return; - } - - if (WebSocketConnected != null) - { - WebSocketConnected(this, args); - } - } - - private void ErrorHandler(Exception ex, IRequest httpReq) - { - try - { - var httpRes = httpReq.Response; - - if (httpRes.IsClosed) - { - return; - } - - var errorResponse = new ErrorResponse - { - ResponseStatus = new ResponseStatus - { - ErrorCode = ex.GetType().GetOperationName(), - Message = ex.Message, - StackTrace = ex.StackTrace - } - }; - - var contentType = httpReq.ResponseContentType; - - var serializer = HostContext.ContentTypes.GetResponseSerializer(contentType); - if (serializer == null) - { - contentType = HostContext.Config.DefaultContentType; - serializer = HostContext.ContentTypes.GetResponseSerializer(contentType); - } - - var httpError = ex as IHttpError; - if (httpError != null) - { - httpRes.StatusCode = httpError.Status; - httpRes.StatusDescription = httpError.StatusDescription; - } - else - { - httpRes.StatusCode = 500; - } - - httpRes.ContentType = contentType; - - serializer(httpReq, errorResponse, httpRes); - - httpRes.Close(); - } - catch - { - //_logger.ErrorException("Error this.ProcessRequest(context)(Exception while writing error to the response)", errorEx); - } - } - - /// <summary> - /// Shut down the Web Service - /// </summary> - public void Stop() - { - if (_listener != null) - { - _listener.Stop(); - } - } - - private readonly Dictionary<string, int> _skipLogExtensions = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase) - { - {".js", 0}, - {".css", 0}, - {".woff", 0}, - {".woff2", 0}, - {".ttf", 0}, - {".html", 0} - }; - - private bool EnableLogging(string url, string localPath) - { - var extension = GetExtension(url); - - if (string.IsNullOrWhiteSpace(extension) || !_skipLogExtensions.ContainsKey(extension)) - { - if (string.IsNullOrWhiteSpace(localPath) || localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1) - { - return true; - } - } - - return false; - } - - private 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); - - // this gets all the query string key value pairs as a collection - var newQueryString = MyHttpUtility.ParseQueryString(uri.Query); - - if (newQueryString.Count == 0) - { - return url; - } - - // this removes the key if exists - newQueryString.Remove(key); - - // this gets the page path from root without QueryString - string pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path); - - return newQueryString.Count > 0 - ? String.Format("{0}?{1}", pagePathWithoutQueryString, newQueryString) - : pagePathWithoutQueryString; - } - - private string GetUrlToLog(string url) - { - url = RemoveQueryStringByKey(url, "api_key"); - - return url; - } - - private string NormalizeConfiguredLocalAddress(string address) - { - var index = address.Trim('/').IndexOf('/'); - - if (index != -1) - { - address = address.Substring(index + 1); - } - - return address.Trim('/'); - } - - private bool ValidateHost(Uri url) - { - var hosts = _config - .Configuration - .LocalNetworkAddresses - .Select(NormalizeConfiguredLocalAddress) - .ToList(); - - if (hosts.Count == 0) - { - return true; - } - - var host = url.Host ?? string.Empty; - - _logger.Debug("Validating host {0}", host); - - if (_networkManager.IsInPrivateAddressSpace(host)) - { - hosts.Add("localhost"); - hosts.Add("127.0.0.1"); - - return hosts.Any(i => host.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1); - } - - return true; - } - - /// <summary> - /// Overridable method that can be used to implement a custom hnandler - /// </summary> - /// <param name="httpReq">The HTTP req.</param> - /// <param name="url">The URL.</param> - /// <returns>Task.</returns> - protected async Task RequestHandler(IHttpRequest httpReq, Uri url) - { - var date = DateTime.Now; - - var httpRes = httpReq.Response; - - if (_disposed) - { - httpRes.StatusCode = 503; - httpRes.Close(); - return ; - } - - if (!ValidateHost(url)) - { - httpRes.StatusCode = 400; - httpRes.ContentType = "text/plain"; - httpRes.Write("Invalid host"); - - httpRes.Close(); - return; - } - - if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) - { - httpRes.StatusCode = 200; - httpRes.AddHeader("Access-Control-Allow-Origin", "*"); - httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); - httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization"); - httpRes.ContentType = "text/html"; - - httpRes.Close(); - } - - var operationName = httpReq.OperationName; - var localPath = url.LocalPath; - - var urlString = url.OriginalString; - var enableLog = EnableLogging(urlString, localPath); - var urlToLog = urlString; - - if (enableLog) - { - urlToLog = GetUrlToLog(urlString); - LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent); - } - - if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) || - string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase)) - { - httpRes.RedirectToUrl(DefaultRedirectPath); - return; - } - if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) || - string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase)) - { - httpRes.RedirectToUrl("emby/" + DefaultRedirectPath); - return; - } - - if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) || - string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase) || - localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1) - { - httpRes.StatusCode = 200; - httpRes.ContentType = "text/html"; - var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase) - .Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase); - - if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase)) - { - httpRes.Write("<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>"); - - httpRes.Close(); - return; - } - } - - if (localPath.IndexOf("dashboard/", StringComparison.OrdinalIgnoreCase) != -1 && - localPath.IndexOf("web/dashboard", StringComparison.OrdinalIgnoreCase) == -1) - { - httpRes.StatusCode = 200; - httpRes.ContentType = "text/html"; - var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase) - .Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase); - - if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase)) - { - httpRes.Write("<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>"); - - httpRes.Close(); - return; - } - } - - if (string.Equals(localPath, "/web", StringComparison.OrdinalIgnoreCase)) - { - httpRes.RedirectToUrl(DefaultRedirectPath); - return; - } - if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase)) - { - httpRes.RedirectToUrl("../" + DefaultRedirectPath); - return; - } - if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)) - { - httpRes.RedirectToUrl(DefaultRedirectPath); - return; - } - if (string.IsNullOrEmpty(localPath)) - { - httpRes.RedirectToUrl("/" + DefaultRedirectPath); - return; - } - - if (string.Equals(localPath, "/emby/pin", StringComparison.OrdinalIgnoreCase)) - { - httpRes.RedirectToUrl("web/pin.html"); - return; - } - - if (!string.IsNullOrWhiteSpace(GlobalResponse)) - { - httpRes.StatusCode = 503; - httpRes.ContentType = "text/html"; - httpRes.Write(GlobalResponse); - - httpRes.Close(); - return; - } - - var handler = HttpHandlerFactory.GetHandler(httpReq); - - var remoteIp = httpReq.RemoteIp; - - var serviceStackHandler = handler as IServiceStackHandler; - if (serviceStackHandler != null) - { - var restHandler = serviceStackHandler as RestHandler; - if (restHandler != null) - { - httpReq.OperationName = operationName = restHandler.RestPath.RequestType.GetOperationName(); - } - - try - { - await serviceStackHandler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false); - } - finally - { - httpRes.Close(); - var statusCode = httpRes.StatusCode; - - var duration = DateTime.Now - date; - - if (enableLog) - { - LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration); - } - } - } - else - { - httpRes.Close(); - } - } - - /// <summary> - /// Adds the rest handlers. - /// </summary> - /// <param name="services">The services.</param> - public void Init(IEnumerable<IRestfulService> services) - { - _restServices.AddRange(services); - - ServiceController = CreateServiceController(); - - _logger.Info("Calling ServiceStack AppHost.Init"); - - base.Init(); - } - - public override RouteAttribute[] GetRouteAttributes(Type requestType) - { - var routes = base.GetRouteAttributes(requestType).ToList(); - var clone = routes.ToList(); - - foreach (var route in clone) - { - routes.Add(new RouteAttribute(NormalizeEmbyRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - - routes.Add(new RouteAttribute(NormalizeRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - - routes.Add(new RouteAttribute(DoubleNormalizeEmbyRoutePath(route.Path), route.Verbs) - { - Notes = route.Notes, - Priority = route.Priority, - Summary = route.Summary - }); - } - - return routes.ToArray(); - } - - private string NormalizeEmbyRoutePath(string path) - { - if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - { - return "/emby" + path; - } - - return "emby/" + path; - } - - private string DoubleNormalizeEmbyRoutePath(string path) - { - if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - { - return "/emby/emby" + path; - } - - return "emby/emby/" + path; - } - - private string NormalizeRoutePath(string path) - { - if (path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - { - return "/mediabrowser" + path; - } - - return "mediabrowser/" + path; - } - - /// <summary> - /// Releases the specified instance. - /// </summary> - /// <param name="instance">The instance.</param> - public override void Release(object instance) - { - // Leave this empty so SS doesn't try to dispose our objects - } - - private bool _disposed; - private readonly object _disposeLock = new object(); - protected virtual void Dispose(bool disposing) - { - if (_disposed) return; - base.Dispose(); - - lock (_disposeLock) - { - if (_disposed) return; - - if (disposing) - { - Stop(); - } - - //release unmanaged resources here... - _disposed = true; - } - } - - public override void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public void StartServer(IEnumerable<string> urlPrefixes, string certificatePath) - { - CertificatePath = certificatePath; - UrlPrefixes = urlPrefixes.ToList(); - Start(UrlPrefixes.First()); - } - } -}
\ No newline at end of file |
