diff options
| author | Luke <luke.pulverenti@gmail.com> | 2016-12-18 00:44:33 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-12-18 00:44:33 -0500 |
| commit | e7cebb91a73354dc3e0d0b6340c9fbd6511f4406 (patch) | |
| tree | 6f1c368c766c17b7514fe749c0e92e69cd89194a /MediaBrowser.Server.Implementations/HttpServer | |
| parent | 025905a3e4d50b9a2e07fbf4ff0a203af6604ced (diff) | |
| parent | aaa027f3229073e9a40756c3157d41af2a442922 (diff) | |
Merge pull request #2350 from MediaBrowser/beta
Beta
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer')
25 files changed, 0 insertions, 5943 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriter.cs deleted file mode 100644 index e44b0c6af..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/AsyncStreamWriter.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using ServiceStack; -using ServiceStack.Web; -using MediaBrowser.Controller.Net; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public class AsyncStreamWriter : IStreamWriter, IAsyncStreamWriter, IHasOptions - { - /// <summary> - /// Gets or sets the source stream. - /// </summary> - /// <value>The source stream.</value> - private IAsyncStreamSource _source; - - public Action OnComplete { get; set; } - public Action OnError { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="AsyncStreamWriter" /> class. - /// </summary> - public AsyncStreamWriter(IAsyncStreamSource source) - { - _source = source; - } - - public IDictionary<string, string> Options - { - get - { - var hasOptions = _source as IHasOptions; - if (hasOptions != null) - { - return hasOptions.Options; - } - - return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - } - - /// <summary> - /// Writes to. - /// </summary> - /// <param name="responseStream">The response stream.</param> - public void WriteTo(Stream responseStream) - { - var task = _source.WriteToAsync(responseStream); - Task.WaitAll(task); - } - - public async Task WriteToAsync(Stream responseStream) - { - await _source.WriteToAsync(responseStream).ConfigureAwait(false); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs b/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs deleted file mode 100644 index 93d224b8d..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/ContainerAdapter.cs +++ /dev/null @@ -1,53 +0,0 @@ -using MediaBrowser.Common; -using ServiceStack.Configuration; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class ContainerAdapter - /// </summary> - class ContainerAdapter : IContainerAdapter, IRelease - { - /// <summary> - /// The _app host - /// </summary> - private readonly IApplicationHost _appHost; - - /// <summary> - /// Initializes a new instance of the <see cref="ContainerAdapter" /> class. - /// </summary> - /// <param name="appHost">The app host.</param> - public ContainerAdapter(IApplicationHost appHost) - { - _appHost = appHost; - } - /// <summary> - /// Resolves this instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T Resolve<T>() - { - return _appHost.Resolve<T>(); - } - - /// <summary> - /// Tries the resolve. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T TryResolve<T>() - { - return _appHost.TryResolve<T>(); - } - - /// <summary> - /// Releases the specified instance. - /// </summary> - /// <param name="instance">The instance.</param> - public void Release(object instance) - { - // Leave this empty so SS doesn't try to dispose our objects - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/GetSwaggerResource.cs b/MediaBrowser.Server.Implementations/HttpServer/GetSwaggerResource.cs deleted file mode 100644 index 36a257f63..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/GetSwaggerResource.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ServiceStack; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class GetDashboardResource - /// </summary> - [Route("/swagger-ui/{ResourceName*}", "GET")] - public class GetSwaggerResource - { - /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value>The name.</value> - public string ResourceName { get; set; } - } -}
\ No newline at end of file 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 diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs deleted file mode 100644 index 10d6f7493..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ /dev/null @@ -1,691 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using ServiceStack; -using ServiceStack.Web; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using CommonIO; -using MimeTypes = MediaBrowser.Model.Net.MimeTypes; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class HttpResultFactory - /// </summary> - public class HttpResultFactory : IHttpResultFactory - { - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - private readonly IFileSystem _fileSystem; - private readonly IJsonSerializer _jsonSerializer; - - /// <summary> - /// Initializes a new instance of the <see cref="HttpResultFactory" /> class. - /// </summary> - /// <param name="logManager">The log manager.</param> - /// <param name="fileSystem">The file system.</param> - /// <param name="jsonSerializer">The json serializer.</param> - public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer) - { - _fileSystem = fileSystem; - _jsonSerializer = jsonSerializer; - _logger = logManager.GetLogger("HttpResultFactory"); - } - - /// <summary> - /// Gets the result. - /// </summary> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - public object GetResult(object content, string contentType, IDictionary<string, string> responseHeaders = null) - { - return GetHttpResult(content, contentType, responseHeaders); - } - - /// <summary> - /// Gets the HTTP result. - /// </summary> - /// <param name="content">The content.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>IHasOptions.</returns> - private IHasOptions GetHttpResult(object content, string contentType, IDictionary<string, string> responseHeaders = null) - { - IHasOptions result; - - var stream = content as Stream; - - if (stream != null) - { - result = new StreamWriter(stream, contentType, _logger); - } - - else - { - var bytes = content as byte[]; - - if (bytes != null) - { - result = new StreamWriter(bytes, contentType, _logger); - } - else - { - var text = content as string; - - if (text != null) - { - result = new StreamWriter(Encoding.UTF8.GetBytes(text), contentType, _logger); - } - else - { - result = new HttpResult(content, contentType); - } - } - } - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(); - } - - responseHeaders["Expires"] = "-1"; - AddResponseHeaders(result, responseHeaders); - - return result; - } - - /// <summary> - /// Gets the optimized result. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="requestContext">The request context.</param> - /// <param name="result">The result.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">result</exception> - public object GetOptimizedResult<T>(IRequest requestContext, T result, IDictionary<string, string> responseHeaders = null) - where T : class - { - return GetOptimizedResultInternal<T>(requestContext, result, true, responseHeaders); - } - - private object GetOptimizedResultInternal<T>(IRequest requestContext, T result, bool addCachePrevention, IDictionary<string, string> responseHeaders = null) - where T : class - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - var optimizedResult = requestContext.ToOptimizedResult(result); - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - if (addCachePrevention) - { - responseHeaders["Expires"] = "-1"; - } - - // Apply headers - var hasOptions = optimizedResult as IHasOptions; - - if (hasOptions != null) - { - AddResponseHeaders(hasOptions, responseHeaders); - } - - return optimizedResult; - } - - /// <summary> - /// Gets the optimized result using cache. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey - /// or - /// factoryFn</exception> - public object GetOptimizedResultUsingCache<T>(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, IDictionary<string, string> responseHeaders = null) - where T : class - { - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (factoryFn == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - // See if the result is already cached in the browser - var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, null); - - if (result != null) - { - return result; - } - - return GetOptimizedResultInternal(requestContext, factoryFn(), false, responseHeaders); - } - - /// <summary> - /// To the cached result. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey</exception> - public object GetCachedResult<T>(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, string contentType, IDictionary<string, string> responseHeaders = null) - where T : class - { - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (factoryFn == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - if (responseHeaders == null) - { - responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - // See if the result is already cached in the browser - var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, contentType); - - if (result != null) - { - return result; - } - - result = factoryFn(); - - // Apply caching headers - var hasOptions = result as IHasOptions; - - if (hasOptions != null) - { - AddResponseHeaders(hasOptions, responseHeaders); - return hasOptions; - } - - IHasOptions httpResult; - - var stream = result as Stream; - - if (stream != null) - { - httpResult = new StreamWriter(stream, contentType, _logger); - } - else - { - // Otherwise wrap into an HttpResult - httpResult = new HttpResult(result, contentType ?? "text/html", HttpStatusCode.NotModified); - } - - AddResponseHeaders(httpResult, responseHeaders); - - return httpResult; - } - - /// <summary> - /// Pres the process optimized result. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="cacheKeyString">The cache key string.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns>System.Object.</returns> - private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) - { - responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString); - - if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) - { - AddAgeHeader(responseHeaders, lastDateModified); - AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration); - - var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified); - - AddResponseHeaders(result, responseHeaders); - - return result; - } - - AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration); - - return null; - } - - public Task<object> GetStaticFileResult(IRequest requestContext, - string path, - FileShare fileShare = FileShare.Read) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - return GetStaticFileResult(requestContext, new StaticFileResultOptions - { - Path = path, - FileShare = fileShare - }); - } - - public Task<object> GetStaticFileResult(IRequest requestContext, - StaticFileResultOptions options) - { - var path = options.Path; - var fileShare = options.FileShare; - - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - if (fileShare != FileShare.Read && fileShare != FileShare.ReadWrite) - { - throw new ArgumentException("FileShare must be either Read or ReadWrite"); - } - - if (string.IsNullOrWhiteSpace(options.ContentType)) - { - options.ContentType = MimeTypes.GetMimeType(path); - } - - if (!options.DateLastModified.HasValue) - { - options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path); - } - - var cacheKey = path + options.DateLastModified.Value.Ticks; - - options.CacheKey = cacheKey.GetMD5(); - options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare)); - - return GetStaticResult(requestContext, options); - } - - /// <summary> - /// Gets the file stream. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="fileShare">The file share.</param> - /// <returns>Stream.</returns> - private Stream GetFileStream(string path, FileShare fileShare) - { - return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare); - } - - public Task<object> GetStaticResult(IRequest requestContext, - Guid cacheKey, - DateTime? lastDateModified, - TimeSpan? cacheDuration, - string contentType, - Func<Task<Stream>> factoryFn, - IDictionary<string, string> responseHeaders = null, - bool isHeadRequest = false) - { - return GetStaticResult(requestContext, new StaticResultOptions - { - CacheDuration = cacheDuration, - CacheKey = cacheKey, - ContentFactory = factoryFn, - ContentType = contentType, - DateLastModified = lastDateModified, - IsHeadRequest = isHeadRequest, - ResponseHeaders = responseHeaders - }); - } - - public async Task<object> GetStaticResult(IRequest requestContext, StaticResultOptions options) - { - var cacheKey = options.CacheKey; - options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - var contentType = options.ContentType; - - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (options.ContentFactory == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - // See if the result is already cached in the browser - var result = GetCachedResult(requestContext, options.ResponseHeaders, cacheKey, key, options.DateLastModified, options.CacheDuration, contentType); - - if (result != null) - { - return result; - } - - var compress = ShouldCompressResponse(requestContext, contentType); - var hasOptions = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false); - AddResponseHeaders(hasOptions, options.ResponseHeaders); - - return hasOptions; - } - - /// <summary> - /// Shoulds the compress response. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool ShouldCompressResponse(IRequest requestContext, string contentType) - { - // It will take some work to support compression with byte range requests - if (!string.IsNullOrEmpty(requestContext.GetHeader("Range"))) - { - return false; - } - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Don't compress images - if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(contentType, "application/x-javascript", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - if (string.Equals(contentType, "application/xml", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - return false; - } - - return true; - } - - /// <summary> - /// The us culture - /// </summary> - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - private async Task<IHasOptions> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress) - { - var isHeadRequest = options.IsHeadRequest; - var factoryFn = options.ContentFactory; - var contentType = options.ContentType; - var responseHeaders = options.ResponseHeaders; - - var requestedCompressionType = requestContext.GetCompressionType(); - - if (!compress || string.IsNullOrEmpty(requestedCompressionType)) - { - var rangeHeader = requestContext.GetHeader("Range"); - - var stream = await factoryFn().ConfigureAwait(false); - - if (!string.IsNullOrEmpty(rangeHeader)) - { - return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) - { - OnComplete = options.OnComplete - }; - } - - responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture); - - if (isHeadRequest) - { - stream.Dispose(); - - return GetHttpResult(new byte[] { }, contentType); - } - - return new StreamWriter(stream, contentType, _logger) - { - OnComplete = options.OnComplete, - OnError = options.OnError - }; - } - - string content; - - using (var stream = await factoryFn().ConfigureAwait(false)) - { - using (var reader = new StreamReader(stream)) - { - content = await reader.ReadToEndAsync().ConfigureAwait(false); - } - } - - var contents = content.Compress(requestedCompressionType); - - responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture); - - if (isHeadRequest) - { - return GetHttpResult(new byte[] { }, contentType); - } - - return new CompressedResult(contents, requestedCompressionType, contentType); - } - - /// <summary> - /// Adds the caching responseHeaders. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) - { - // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant - // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching - if (lastDateModified.HasValue && (string.IsNullOrEmpty(cacheKey) || cacheDuration.HasValue)) - { - AddAgeHeader(responseHeaders, lastDateModified); - responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); - } - - if (cacheDuration.HasValue) - { - responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); - } - else if (!string.IsNullOrEmpty(cacheKey)) - { - responseHeaders["Cache-Control"] = "public"; - } - else - { - responseHeaders["Cache-Control"] = "no-cache, no-store, must-revalidate"; - responseHeaders["pragma"] = "no-cache, no-store, must-revalidate"; - } - - AddExpiresHeader(responseHeaders, cacheKey, cacheDuration); - } - - /// <summary> - /// Adds the expires header. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration) - { - if (cacheDuration.HasValue) - { - responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r"); - } - else if (string.IsNullOrEmpty(cacheKey)) - { - responseHeaders["Expires"] = "-1"; - } - } - - /// <summary> - /// Adds the age header. - /// </summary> - /// <param name="responseHeaders">The responseHeaders.</param> - /// <param name="lastDateModified">The last date modified.</param> - private void AddAgeHeader(IDictionary<string, string> responseHeaders, DateTime? lastDateModified) - { - if (lastDateModified.HasValue) - { - responseHeaders["Age"] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture); - } - } - /// <summary> - /// Determines whether [is not modified] [the specified cache key]. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <returns><c>true</c> if [is not modified] [the specified cache key]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(IRequest requestContext, Guid? cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) - { - var isNotModified = true; - - var ifModifiedSinceHeader = requestContext.GetHeader("If-Modified-Since"); - - if (!string.IsNullOrEmpty(ifModifiedSinceHeader)) - { - DateTime ifModifiedSince; - - if (DateTime.TryParse(ifModifiedSinceHeader, out ifModifiedSince)) - { - isNotModified = IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified); - } - } - - var ifNoneMatchHeader = requestContext.GetHeader("If-None-Match"); - - // Validate If-None-Match - if (isNotModified && (cacheKey.HasValue || !string.IsNullOrEmpty(ifNoneMatchHeader))) - { - Guid ifNoneMatch; - - if (Guid.TryParse(ifNoneMatchHeader ?? string.Empty, out ifNoneMatch)) - { - if (cacheKey.HasValue && cacheKey.Value == ifNoneMatch) - { - return true; - } - } - } - - return false; - } - - /// <summary> - /// Determines whether [is not modified] [the specified if modified since]. - /// </summary> - /// <param name="ifModifiedSince">If modified since.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="dateModified">The date modified.</param> - /// <returns><c>true</c> if [is not modified] [the specified if modified since]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(DateTime ifModifiedSince, TimeSpan? cacheDuration, DateTime? dateModified) - { - if (dateModified.HasValue) - { - var lastModified = NormalizeDateForComparison(dateModified.Value); - ifModifiedSince = NormalizeDateForComparison(ifModifiedSince); - - return lastModified <= ifModifiedSince; - } - - if (cacheDuration.HasValue) - { - var cacheExpirationDate = ifModifiedSince.Add(cacheDuration.Value); - - if (DateTime.UtcNow < cacheExpirationDate) - { - return true; - } - } - - return false; - } - - - /// <summary> - /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that - /// </summary> - /// <param name="date">The date.</param> - /// <returns>DateTime.</returns> - private DateTime NormalizeDateForComparison(DateTime date) - { - return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind); - } - - /// <summary> - /// Adds the response headers. - /// </summary> - /// <param name="hasOptions">The has options.</param> - /// <param name="responseHeaders">The response headers.</param> - private void AddResponseHeaders(IHasOptions hasOptions, IEnumerable<KeyValuePair<string, string>> responseHeaders) - { - foreach (var item in responseHeaders) - { - hasOptions.Options[item.Key] = item.Value; - } - } - - public object GetAsyncStreamWriter(IAsyncStreamSource streamSource) - { - return new AsyncStreamWriter(streamSource); - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs deleted file mode 100644 index dc315601f..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs +++ /dev/null @@ -1,46 +0,0 @@ -using MediaBrowser.Controller.Net; -using ServiceStack.Web; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public interface IHttpListener : IDisposable - { - /// <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> WebSocketConnected { get; set; } - - /// <summary> - /// Gets or sets the web socket connecting. - /// </summary> - /// <value>The web socket connecting.</value> - Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; } - - /// <summary> - /// Starts this instance. - /// </summary> - /// <param name="urlPrefixes">The URL prefixes.</param> - void Start(IEnumerable<string> urlPrefixes); - - /// <summary> - /// Stops this instance. - /// </summary> - void Stop(); - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs deleted file mode 100644 index bfbb228ed..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs +++ /dev/null @@ -1,43 +0,0 @@ -using MediaBrowser.Model.Logging; -using System; -using System.Globalization; -using SocketHttpListener.Net; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public static class LoggerUtils - { - /// <summary> - /// Logs the request. - /// </summary> - /// <param name="logger">The logger.</param> - /// <param name="request">The request.</param> - public static void LogRequest(ILogger logger, HttpListenerRequest request) - { - var url = request.Url.ToString(); - - logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty); - } - - public static void LogRequest(ILogger logger, string url, string method, string userAgent) - { - logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty); - } - - /// <summary> - /// Logs the response. - /// </summary> - /// <param name="logger">The logger.</param> - /// <param name="statusCode">The status code.</param> - /// <param name="url">The URL.</param> - /// <param name="endPoint">The end point.</param> - /// <param name="duration">The duration.</param> - public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration) - { - var durationMs = duration.TotalMilliseconds; - var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms"; - - logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs deleted file mode 100644 index 4b94095f5..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ /dev/null @@ -1,293 +0,0 @@ -using MediaBrowser.Model.Logging; -using ServiceStack.Web; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Net; -using System.Threading.Tasks; -using ServiceStack; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public class RangeRequestWriter : IStreamWriter, IAsyncStreamWriter, IHttpResult - { - /// <summary> - /// Gets or sets the source stream. - /// </summary> - /// <value>The source stream.</value> - private Stream SourceStream { get; set; } - private string RangeHeader { get; set; } - private bool IsHeadRequest { get; set; } - - private long RangeStart { get; set; } - private long RangeEnd { get; set; } - private long RangeLength { get; set; } - private long TotalContentLength { get; set; } - - public Action OnComplete { get; set; } - private readonly ILogger _logger; - - private const int BufferSize = 81920; - - /// <summary> - /// The _options - /// </summary> - private readonly Dictionary<string, string> _options = new Dictionary<string, string>(); - - /// <summary> - /// The us culture - /// </summary> - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - public Func<IDisposable> ResultScope { get; set; } - public List<Cookie> Cookies { get; private set; } - - /// <summary> - /// Additional HTTP Headers - /// </summary> - /// <value>The headers.</value> - public Dictionary<string, string> Headers - { - get { return _options; } - } - - /// <summary> - /// Gets the options. - /// </summary> - /// <value>The options.</value> - public IDictionary<string, string> Options - { - get { return Headers; } - } - - /// <summary> - /// Initializes a new instance of the <see cref="StreamWriter" /> class. - /// </summary> - /// <param name="rangeHeader">The range header.</param> - /// <param name="source">The source.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param> - public RangeRequestWriter(string rangeHeader, Stream source, string contentType, bool isHeadRequest, ILogger logger) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException("contentType"); - } - - RangeHeader = rangeHeader; - SourceStream = source; - IsHeadRequest = isHeadRequest; - this._logger = logger; - - ContentType = contentType; - Options["Content-Type"] = contentType; - Options["Accept-Ranges"] = "bytes"; - StatusCode = HttpStatusCode.PartialContent; - - Cookies = new List<Cookie>(); - SetRangeValues(); - } - - /// <summary> - /// Sets the range values. - /// </summary> - private void SetRangeValues() - { - var requestedRange = RequestedRanges[0]; - - TotalContentLength = SourceStream.Length; - - // If the requested range is "0-", we can optimize by just doing a stream copy - if (!requestedRange.Value.HasValue) - { - RangeEnd = TotalContentLength - 1; - } - else - { - RangeEnd = requestedRange.Value.Value; - } - - RangeStart = requestedRange.Key; - RangeLength = 1 + RangeEnd - RangeStart; - - // Content-Length is the length of what we're serving, not the original content - Options["Content-Length"] = RangeLength.ToString(UsCulture); - Options["Content-Range"] = string.Format("bytes {0}-{1}/{2}", RangeStart, RangeEnd, TotalContentLength); - - if (RangeStart > 0) - { - SourceStream.Position = RangeStart; - } - } - - /// <summary> - /// The _requested ranges - /// </summary> - private List<KeyValuePair<long, long?>> _requestedRanges; - /// <summary> - /// Gets the requested ranges. - /// </summary> - /// <value>The requested ranges.</value> - protected List<KeyValuePair<long, long?>> RequestedRanges - { - get - { - if (_requestedRanges == null) - { - _requestedRanges = new List<KeyValuePair<long, long?>>(); - - // Example: bytes=0-,32-63 - var ranges = RangeHeader.Split('=')[1].Split(','); - - foreach (var range in ranges) - { - var vals = range.Split('-'); - - long start = 0; - long? end = null; - - if (!string.IsNullOrEmpty(vals[0])) - { - start = long.Parse(vals[0], UsCulture); - } - if (!string.IsNullOrEmpty(vals[1])) - { - end = long.Parse(vals[1], UsCulture); - } - - _requestedRanges.Add(new KeyValuePair<long, long?>(start, end)); - } - } - - return _requestedRanges; - } - } - - /// <summary> - /// Writes to. - /// </summary> - /// <param name="responseStream">The response stream.</param> - public void WriteTo(Stream responseStream) - { - try - { - // Headers only - if (IsHeadRequest) - { - return; - } - - using (var source = SourceStream) - { - // If the requested range is "0-", we can optimize by just doing a stream copy - if (RangeEnd >= TotalContentLength - 1) - { - source.CopyTo(responseStream, BufferSize); - } - else - { - CopyToInternal(source, responseStream, RangeLength); - } - } - } - finally - { - if (OnComplete != null) - { - OnComplete(); - } - } - } - - private void CopyToInternal(Stream source, Stream destination, long copyLength) - { - var array = new byte[BufferSize]; - int count; - while ((count = source.Read(array, 0, array.Length)) != 0) - { - var bytesToCopy = Math.Min(count, copyLength); - - destination.Write(array, 0, Convert.ToInt32(bytesToCopy)); - - copyLength -= bytesToCopy; - - if (copyLength <= 0) - { - break; - } - } - } - - public async Task WriteToAsync(Stream responseStream) - { - try - { - // Headers only - if (IsHeadRequest) - { - return; - } - - using (var source = SourceStream) - { - // If the requested range is "0-", we can optimize by just doing a stream copy - if (RangeEnd >= TotalContentLength - 1) - { - await source.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); - } - else - { - await CopyToInternalAsync(source, responseStream, RangeLength).ConfigureAwait(false); - } - } - } - finally - { - if (OnComplete != null) - { - OnComplete(); - } - } - } - - private async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength) - { - var array = new byte[BufferSize]; - int count; - while ((count = await source.ReadAsync(array, 0, array.Length).ConfigureAwait(false)) != 0) - { - var bytesToCopy = Math.Min(count, copyLength); - - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy)).ConfigureAwait(false); - - copyLength -= bytesToCopy; - - if (copyLength <= 0) - { - break; - } - } - } - - public string ContentType { get; set; } - - public IRequest RequestContext { get; set; } - - public object Response { get; set; } - - public IContentTypeWriter ResponseFilter { get; set; } - - public int Status { get; set; } - - public HttpStatusCode StatusCode - { - get { return (HttpStatusCode)Status; } - set { Status = (int)value; } - } - - public string StatusDescription { get; set; } - - public int PaddingLength { get; set; } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs deleted file mode 100644 index ee05702f4..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs +++ /dev/null @@ -1,127 +0,0 @@ -using MediaBrowser.Model.Logging; -using MediaBrowser.Server.Implementations.HttpServer.SocketSharp; -using ServiceStack.Web; -using System; -using System.Globalization; -using System.Net; -using System.Text; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public class ResponseFilter - { - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - private readonly ILogger _logger; - - public ResponseFilter(ILogger logger) - { - _logger = logger; - } - - /// <summary> - /// Filters the response. - /// </summary> - /// <param name="req">The req.</param> - /// <param name="res">The res.</param> - /// <param name="dto">The dto.</param> - public void FilterResponse(IRequest req, IResponse res, object dto) - { - // Try to prevent compatibility view - res.AddHeader("X-UA-Compatible", "IE=Edge"); - - var exception = dto as Exception; - - if (exception != null) - { - _logger.ErrorException("Error processing request for {0}", exception, req.RawUrl); - - if (!string.IsNullOrEmpty(exception.Message)) - { - var error = exception.Message.Replace(Environment.NewLine, " "); - error = RemoveControlCharacters(error); - - res.AddHeader("X-Application-Error-Code", error); - } - } - - var vary = "Accept-Encoding"; - - var hasOptions = dto as IHasOptions; - var sharpResponse = res as WebSocketSharpResponse; - - if (hasOptions != null) - { - if (!hasOptions.Options.ContainsKey("Server")) - { - hasOptions.Options["Server"] = "Mono-HTTPAPI/1.1, UPnP/1.0 DLNADOC/1.50"; - //hasOptions.Options["Server"] = "Mono-HTTPAPI/1.1"; - } - - // Content length has to be explicitly set on on HttpListenerResponse or it won't be happy - string contentLength; - - if (hasOptions.Options.TryGetValue("Content-Length", out contentLength) && !string.IsNullOrEmpty(contentLength)) - { - var length = long.Parse(contentLength, UsCulture); - - if (length > 0) - { - res.SetContentLength(length); - - var listenerResponse = res.OriginalResponse as HttpListenerResponse; - - if (listenerResponse != null) - { - // Disable chunked encoding. Technically this is only needed when using Content-Range, but - // anytime we know the content length there's no need for it - listenerResponse.SendChunked = false; - return; - } - - if (sharpResponse != null) - { - sharpResponse.SendChunked = false; - } - } - } - - string hasOptionsVary; - if (hasOptions.Options.TryGetValue("Vary", out hasOptionsVary)) - { - vary = hasOptionsVary; - } - - hasOptions.Options["Vary"] = vary; - } - - //res.KeepAlive = false; - - // Per Google PageSpeed - // This instructs the proxies to cache two versions of the resource: one compressed, and one uncompressed. - // The correct version of the resource is delivered based on the client request header. - // This is a good choice for applications that are singly homed and depend on public proxies for user locality. - res.AddHeader("Vary", vary); - } - - /// <summary> - /// Removes the control characters. - /// </summary> - /// <param name="inString">The in string.</param> - /// <returns>System.String.</returns> - public static string RemoveControlCharacters(string inString) - { - if (inString == null) return null; - - var newString = new StringBuilder(); - - foreach (var ch in inString) - { - if (!char.IsControl(ch)) - { - newString.Append(ch); - } - } - return newString.ToString(); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs deleted file mode 100644 index d8f7d889c..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ /dev/null @@ -1,246 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Connect; -using MediaBrowser.Controller.Devices; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Session; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class AuthService : IAuthService - { - private readonly IServerConfigurationManager _config; - - public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager, ISessionManager sessionManager, IDeviceManager deviceManager) - { - AuthorizationContext = authorizationContext; - _config = config; - DeviceManager = deviceManager; - SessionManager = sessionManager; - ConnectManager = connectManager; - UserManager = userManager; - } - - public IUserManager UserManager { get; private set; } - public IAuthorizationContext AuthorizationContext { get; private set; } - public IConnectManager ConnectManager { get; private set; } - public ISessionManager SessionManager { get; private set; } - public IDeviceManager DeviceManager { get; private set; } - - /// <summary> - /// Redirect the client to a specific URL if authentication failed. - /// If this property is null, simply `401 Unauthorized` is returned. - /// </summary> - public string HtmlRedirect { get; set; } - - public void Authenticate(IServiceRequest request, - IAuthenticationAttributes authAttribtues) - { - ValidateUser(request, authAttribtues); - } - - private void ValidateUser(IServiceRequest request, - IAuthenticationAttributes authAttribtues) - { - // This code is executed before the service - var auth = AuthorizationContext.GetAuthorizationInfo(request); - - if (!IsExemptFromAuthenticationToken(auth, authAttribtues)) - { - var valid = IsValidConnectKey(auth.Token); - - if (!valid) - { - ValidateSecurityToken(request, auth.Token); - } - } - - var user = string.IsNullOrWhiteSpace(auth.UserId) - ? null - : UserManager.GetUserById(auth.UserId); - - if (user == null & !string.IsNullOrWhiteSpace(auth.UserId)) - { - throw new SecurityException("User with Id " + auth.UserId + " not found"); - } - - if (user != null) - { - ValidateUserAccess(user, request, authAttribtues, auth); - } - - var info = GetTokenInfo(request); - - if (!IsExemptFromRoles(auth, authAttribtues, info)) - { - var roles = authAttribtues.GetRoles().ToList(); - - ValidateRoles(roles, user); - } - - if (!string.IsNullOrWhiteSpace(auth.DeviceId) && - !string.IsNullOrWhiteSpace(auth.Client) && - !string.IsNullOrWhiteSpace(auth.Device)) - { - SessionManager.LogSessionActivity(auth.Client, - auth.Version, - auth.DeviceId, - auth.Device, - request.RemoteIp, - user); - } - } - - private void ValidateUserAccess(User user, IServiceRequest request, - IAuthenticationAttributes authAttribtues, - AuthorizationInfo auth) - { - if (user.Policy.IsDisabled) - { - throw new SecurityException("User account has been disabled.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - - if (!user.Policy.IsAdministrator && - !authAttribtues.EscapeParentalControl && - !user.IsParentalScheduleAllowed()) - { - request.AddResponseHeader("X-Application-Error-Code", "ParentalControl"); - - throw new SecurityException("This user account is not allowed access at this time.") - { - SecurityExceptionType = SecurityExceptionType.ParentalControl - }; - } - - if (!string.IsNullOrWhiteSpace(auth.DeviceId)) - { - if (!DeviceManager.CanAccessDevice(user.Id.ToString("N"), auth.DeviceId)) - { - throw new SecurityException("User is not allowed access from this device.") - { - SecurityExceptionType = SecurityExceptionType.ParentalControl - }; - } - } - } - - private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) - { - if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) - { - return true; - } - - return false; - } - - private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo) - { - if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) - { - return true; - } - - if (string.IsNullOrWhiteSpace(auth.Token)) - { - return true; - } - - if (tokenInfo != null && string.IsNullOrWhiteSpace(tokenInfo.UserId)) - { - return true; - } - - return false; - } - - private void ValidateRoles(List<string> roles, User user) - { - if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.Policy.IsAdministrator) - { - throw new SecurityException("User does not have admin access.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - } - if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.Policy.EnableContentDeletion) - { - throw new SecurityException("User does not have delete access.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - } - if (roles.Contains("download", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.Policy.EnableContentDownloading) - { - throw new SecurityException("User does not have download access.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - } - } - - private AuthenticationInfo GetTokenInfo(IServiceRequest request) - { - object info; - request.Items.TryGetValue("OriginalAuthenticationInfo", out info); - return info as AuthenticationInfo; - } - - private bool IsValidConnectKey(string token) - { - if (string.IsNullOrEmpty(token)) - { - return false; - } - - return ConnectManager.IsAuthorizationTokenValid(token); - } - - private void ValidateSecurityToken(IServiceRequest request, string token) - { - if (string.IsNullOrWhiteSpace(token)) - { - throw new SecurityException("Access token is required."); - } - - var info = GetTokenInfo(request); - - if (info == null) - { - throw new SecurityException("Access token is invalid or expired."); - } - - if (!info.IsActive) - { - throw new SecurityException("Access token has expired."); - } - - //if (!string.IsNullOrWhiteSpace(info.UserId)) - //{ - // var user = _userManager.GetUserById(info.UserId); - - // if (user == null || user.Configuration.IsDisabled) - // { - // throw new SecurityException("User account has been disabled."); - // } - //} - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs deleted file mode 100644 index bc3e7b163..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ /dev/null @@ -1,195 +0,0 @@ -using MediaBrowser.Controller.Connect; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using ServiceStack.Web; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class AuthorizationContext : IAuthorizationContext - { - private readonly IAuthenticationRepository _authRepo; - private readonly IConnectManager _connectManager; - - public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager) - { - _authRepo = authRepo; - _connectManager = connectManager; - } - - public AuthorizationInfo GetAuthorizationInfo(object requestContext) - { - var req = new ServiceStackServiceRequest((IRequest)requestContext); - return GetAuthorizationInfo(req); - } - - public AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext) - { - object cached; - if (requestContext.Items.TryGetValue("AuthorizationInfo", out cached)) - { - return (AuthorizationInfo)cached; - } - - return GetAuthorization(requestContext); - } - - /// <summary> - /// Gets the authorization. - /// </summary> - /// <param name="httpReq">The HTTP req.</param> - /// <returns>Dictionary{System.StringSystem.String}.</returns> - private AuthorizationInfo GetAuthorization(IServiceRequest httpReq) - { - var auth = GetAuthorizationDictionary(httpReq); - - string deviceId = null; - string device = null; - string client = null; - string version = null; - - if (auth != null) - { - auth.TryGetValue("DeviceId", out deviceId); - auth.TryGetValue("Device", out device); - auth.TryGetValue("Client", out client); - auth.TryGetValue("Version", out version); - } - - var token = httpReq.Headers["X-Emby-Token"]; - - if (string.IsNullOrWhiteSpace(token)) - { - token = httpReq.Headers["X-MediaBrowser-Token"]; - } - if (string.IsNullOrWhiteSpace(token)) - { - token = httpReq.QueryString["api_key"]; - } - - var info = new AuthorizationInfo - { - Client = client, - Device = device, - DeviceId = deviceId, - Version = version, - Token = token - }; - - if (!string.IsNullOrWhiteSpace(token)) - { - var result = _authRepo.Get(new AuthenticationInfoQuery - { - AccessToken = token - }); - - var tokenInfo = result.Items.FirstOrDefault(); - - if (tokenInfo != null) - { - info.UserId = tokenInfo.UserId; - - // TODO: Remove these checks for IsNullOrWhiteSpace - if (string.IsNullOrWhiteSpace(info.Client)) - { - info.Client = tokenInfo.AppName; - } - if (string.IsNullOrWhiteSpace(info.Device)) - { - info.Device = tokenInfo.DeviceName; - } - if (string.IsNullOrWhiteSpace(info.DeviceId)) - { - info.DeviceId = tokenInfo.DeviceId; - } - if (string.IsNullOrWhiteSpace(info.Version)) - { - info.Version = tokenInfo.AppVersion; - } - } - else - { - var user = _connectManager.GetUserFromExchangeToken(token); - if (user != null) - { - info.UserId = user.Id.ToString("N"); - } - } - httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo; - } - - httpReq.Items["AuthorizationInfo"] = info; - - return info; - } - - /// <summary> - /// Gets the auth. - /// </summary> - /// <param name="httpReq">The HTTP req.</param> - /// <returns>Dictionary{System.StringSystem.String}.</returns> - private Dictionary<string, string> GetAuthorizationDictionary(IServiceRequest httpReq) - { - var auth = httpReq.Headers["X-Emby-Authorization"]; - - if (string.IsNullOrWhiteSpace(auth)) - { - auth = httpReq.Headers["Authorization"]; - } - - return GetAuthorization(auth); - } - - /// <summary> - /// Gets the authorization. - /// </summary> - /// <param name="authorizationHeader">The authorization header.</param> - /// <returns>Dictionary{System.StringSystem.String}.</returns> - private Dictionary<string, string> GetAuthorization(string authorizationHeader) - { - if (authorizationHeader == null) return null; - - var parts = authorizationHeader.Split(new[] { ' ' }, 2); - - // There should be at least to parts - if (parts.Length != 2) return null; - - // It has to be a digest request - if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - // Remove uptil the first space - authorizationHeader = parts[1]; - parts = authorizationHeader.Split(','); - - var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - - foreach (var item in parts) - { - var param = item.Trim().Split(new[] { '=' }, 2); - - if (param.Length == 2) - { - var value = NormalizeValue (param[1].Trim(new[] { '"' })); - result.Add(param[0], value); - } - } - - return result; - } - - private string NormalizeValue(string value) - { - if (string.IsNullOrWhiteSpace (value)) - { - return value; - } - - return System.Net.WebUtility.HtmlEncode(value); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionAuthProvider.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionAuthProvider.cs deleted file mode 100644 index 7c3173101..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionAuthProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using MediaBrowser.Controller.Net; -using ServiceStack; -using ServiceStack.Auth; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class SessionAuthProvider : CredentialsAuthProvider - { - private readonly ISessionContext _sessionContext; - - public SessionAuthProvider(ISessionContext sessionContext) - { - _sessionContext = sessionContext; - } - - public override bool TryAuthenticate(IServiceBase authService, string userName, string password) - { - return true; - } - - public override bool IsAuthorized(IAuthSession session, IAuthTokens tokens, Authenticate request = null) - { - return true; - } - - protected override void SaveUserAuth(IServiceBase authService, IAuthSession session, IAuthRepository authRepo, IAuthTokens tokens) - { - } - - public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request) - { - return base.Authenticate(authService, session, request); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs deleted file mode 100644 index a498d32fa..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs +++ /dev/null @@ -1,67 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Session; -using ServiceStack.Web; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class SessionContext : ISessionContext - { - private readonly IUserManager _userManager; - private readonly ISessionManager _sessionManager; - private readonly IAuthorizationContext _authContext; - - public SessionContext(IUserManager userManager, IAuthorizationContext authContext, ISessionManager sessionManager) - { - _userManager = userManager; - _authContext = authContext; - _sessionManager = sessionManager; - } - - public Task<SessionInfo> GetSession(IServiceRequest requestContext) - { - var authorization = _authContext.GetAuthorizationInfo(requestContext); - - //if (!string.IsNullOrWhiteSpace(authorization.Token)) - //{ - // var auth = GetTokenInfo(requestContext); - // if (auth != null) - // { - // return _sessionManager.GetSessionByAuthenticationToken(auth, authorization.DeviceId, requestContext.RemoteIp, authorization.Version); - // } - //} - - var user = string.IsNullOrWhiteSpace(authorization.UserId) ? null : _userManager.GetUserById(authorization.UserId); - return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.RemoteIp, user); - } - - private AuthenticationInfo GetTokenInfo(IServiceRequest request) - { - object info; - request.Items.TryGetValue("OriginalAuthenticationInfo", out info); - return info as AuthenticationInfo; - } - - public Task<SessionInfo> GetSession(object requestContext) - { - var req = new ServiceStackServiceRequest((IRequest)requestContext); - return GetSession(req); - } - - public async Task<User> GetUser(IServiceRequest requestContext) - { - var session = await GetSession(requestContext).ConfigureAwait(false); - - return session == null || !session.UserId.HasValue ? null : _userManager.GetUserById(session.UserId.Value); - } - - public Task<User> GetUser(object requestContext) - { - var req = new ServiceStackServiceRequest((IRequest)requestContext); - return GetUser(req); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs deleted file mode 100644 index 8a7c14eb6..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs +++ /dev/null @@ -1,33 +0,0 @@ -using MediaBrowser.Common; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using ServiceStack.Logging; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class ServerFactory - /// </summary> - public static class ServerFactory - { - /// <summary> - /// Creates the server. - /// </summary> - /// <returns>IHttpServer.</returns> - public static IHttpServer CreateServer(IApplicationHost applicationHost, - ILogManager logManager, - IServerConfigurationManager config, - INetworkManager _networkmanager, - IMemoryStreamProvider streamProvider, - string serverName, - string defaultRedirectpath) - { - LogManager.LogFactory = new ServerLogFactory(logManager); - - return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager, streamProvider); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs deleted file mode 100644 index 40af3f3b0..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerLogFactory.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using MediaBrowser.Model.Logging; -using ServiceStack.Logging; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class ServerLogFactory - /// </summary> - public class ServerLogFactory : ILogFactory - { - /// <summary> - /// The _log manager - /// </summary> - private readonly ILogManager _logManager; - - /// <summary> - /// Initializes a new instance of the <see cref="ServerLogFactory"/> class. - /// </summary> - /// <param name="logManager">The log manager.</param> - public ServerLogFactory(ILogManager logManager) - { - _logManager = logManager; - } - - /// <summary> - /// Gets the logger. - /// </summary> - /// <param name="typeName">Name of the type.</param> - /// <returns>ILog.</returns> - public ILog GetLogger(string typeName) - { - return new ServerLogger(_logManager.GetLogger(typeName)); - } - - /// <summary> - /// Gets the logger. - /// </summary> - /// <param name="type">The type.</param> - /// <returns>ILog.</returns> - public ILog GetLogger(Type type) - { - return GetLogger(type.Name); - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs deleted file mode 100644 index bf7924784..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerLogger.cs +++ /dev/null @@ -1,194 +0,0 @@ -using MediaBrowser.Model.Logging; -using ServiceStack.Logging; -using System; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class ServerLogger - /// </summary> - public class ServerLogger : ILog - { - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="ServerLogger"/> class. - /// </summary> - /// <param name="logger">The logger.</param> - public ServerLogger(ILogger logger) - { - _logger = logger; - } - - /// <summary> - /// Logs a Debug message and exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - public void Debug(object message, Exception exception) - { - _logger.ErrorException(GetMesssage(message), exception); - } - - /// <summary> - /// Logs a Debug message. - /// </summary> - /// <param name="message">The message.</param> - public void Debug(object message) - { - // Way too verbose. Can always make this configurable if needed again. - //_logger.Debug(GetMesssage(message)); - } - - /// <summary> - /// Logs a Debug format message. - /// </summary> - /// <param name="format">The format.</param> - /// <param name="args">The args.</param> - public void DebugFormat(string format, params object[] args) - { - // Way too verbose. Can always make this configurable if needed again. - //_logger.Debug(format, args); - } - - /// <summary> - /// Logs a Error message and exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - public void Error(object message, Exception exception) - { - _logger.ErrorException(GetMesssage(message), exception); - } - - /// <summary> - /// Logs a Error message. - /// </summary> - /// <param name="message">The message.</param> - public void Error(object message) - { - _logger.Error(GetMesssage(message)); - } - - /// <summary> - /// Logs a Error format message. - /// </summary> - /// <param name="format">The format.</param> - /// <param name="args">The args.</param> - public void ErrorFormat(string format, params object[] args) - { - _logger.Error(format, args); - } - - /// <summary> - /// Logs a Fatal message and exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - public void Fatal(object message, Exception exception) - { - _logger.FatalException(GetMesssage(message), exception); - } - - /// <summary> - /// Logs a Fatal message. - /// </summary> - /// <param name="message">The message.</param> - public void Fatal(object message) - { - _logger.Fatal(GetMesssage(message)); - } - - /// <summary> - /// Logs a Error format message. - /// </summary> - /// <param name="format">The format.</param> - /// <param name="args">The args.</param> - public void FatalFormat(string format, params object[] args) - { - _logger.Fatal(format, args); - } - - /// <summary> - /// Logs an Info message and exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - public void Info(object message, Exception exception) - { - _logger.ErrorException(GetMesssage(message), exception); - } - - /// <summary> - /// Logs an Info message and exception. - /// </summary> - /// <param name="message">The message.</param> - public void Info(object message) - { - _logger.Info(GetMesssage(message)); - } - - /// <summary> - /// Logs an Info format message. - /// </summary> - /// <param name="format">The format.</param> - /// <param name="args">The args.</param> - public void InfoFormat(string format, params object[] args) - { - _logger.Info(format, args); - } - - /// <summary> - /// Gets or sets a value indicating whether this instance is debug enabled. - /// </summary> - /// <value><c>true</c> if this instance is debug enabled; otherwise, <c>false</c>.</value> - public bool IsDebugEnabled - { - get { return true; } - } - - /// <summary> - /// Logs a Warning message and exception. - /// </summary> - /// <param name="message">The message.</param> - /// <param name="exception">The exception.</param> - public void Warn(object message, Exception exception) - { - _logger.ErrorException(GetMesssage(message), exception); - } - - /// <summary> - /// Logs a Warning message. - /// </summary> - /// <param name="message">The message.</param> - public void Warn(object message) - { - // Hide StringMapTypeDeserializer messages - // _logger.Warn(GetMesssage(message)); - } - - /// <summary> - /// Logs a Warning format message. - /// </summary> - /// <param name="format">The format.</param> - /// <param name="args">The args.</param> - public void WarnFormat(string format, params object[] args) - { - // Hide StringMapTypeDeserializer messages - // _logger.Warn(format, args); - } - - /// <summary> - /// Gets the messsage. - /// </summary> - /// <param name="o">The o.</param> - /// <returns>System.String.</returns> - private string GetMesssage(object o) - { - return o == null ? string.Empty : o.ToString(); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs deleted file mode 100644 index 154313fb9..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/Extensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using MediaBrowser.Model.Logging; -using SocketHttpListener.Net; -using System; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public static class Extensions - { - public static string GetOperationName(this HttpListenerRequest request) - { - return request.Url.Segments[request.Url.Segments.Length - 1]; - } - - public static void CloseOutputStream(this HttpListenerResponse response, ILogger logger) - { - try - { - response.OutputStream.Flush(); - response.OutputStream.Close(); - response.Close(); - } - catch (Exception ex) - { - logger.ErrorException("Error in HttpListenerResponseWrapper: " + ex.Message, ex); - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs deleted file mode 100644 index 3ef48d13a..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs +++ /dev/null @@ -1,941 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Text; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public static class MyHttpUtility - { - sealed class HttpQSCollection : NameValueCollection - { - public override string ToString() - { - int count = Count; - if (count == 0) - return ""; - StringBuilder sb = new StringBuilder(); - string[] keys = AllKeys; - for (int i = 0; i < count; i++) - { - sb.AppendFormat("{0}={1}&", keys[i], this[keys[i]]); - } - if (sb.Length > 0) - sb.Length--; - return sb.ToString(); - } - } - - // Must be sorted - static readonly long[] entities = new long[] { - (long)'A' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, - (long)'A' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'A' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'A' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'A' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24, - (long)'A' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24, - (long)'A' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'A' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'B' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, - (long)'C' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16, - (long)'C' << 56 | (long)'h' << 48 | (long)'i' << 40, - (long)'D' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16, - (long)'D' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24, - (long)'E' << 56 | (long)'T' << 48 | (long)'H' << 40, - (long)'E' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'E' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'E' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'E' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, - (long)'E' << 56 | (long)'t' << 48 | (long)'a' << 40, - (long)'E' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'G' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24, - (long)'I' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'I' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'I' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'I' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32, - (long)'I' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'K' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24, - (long)'L' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16, - (long)'M' << 56 | (long)'u' << 48, - (long)'N' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'N' << 56 | (long)'u' << 48, - (long)'O' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, - (long)'O' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'O' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'O' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'O' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24, - (long)'O' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8, - (long)'O' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16, - (long)'O' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'O' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'P' << 56 | (long)'h' << 48 | (long)'i' << 40, - (long)'P' << 56 | (long)'i' << 48, - (long)'P' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24, - (long)'P' << 56 | (long)'s' << 48 | (long)'i' << 40, - (long)'R' << 56 | (long)'h' << 48 | (long)'o' << 40, - (long)'S' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16, - (long)'S' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24, - (long)'T' << 56 | (long)'H' << 48 | (long)'O' << 40 | (long)'R' << 32 | (long)'N' << 24, - (long)'T' << 56 | (long)'a' << 48 | (long)'u' << 40, - (long)'T' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24, - (long)'U' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'U' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'U' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'U' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, - (long)'U' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'X' << 56 | (long)'i' << 48, - (long)'Y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'Y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'Z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, - (long)'a' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'a' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'a' << 56 | (long)'c' << 48 | (long)'u' << 40 | (long)'t' << 32 | (long)'e' << 24, - (long)'a' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, - (long)'a' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'a' << 56 | (long)'l' << 48 | (long)'e' << 40 | (long)'f' << 32 | (long)'s' << 24 | (long)'y' << 16 | (long)'m' << 8, - (long)'a' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24, - (long)'a' << 56 | (long)'m' << 48 | (long)'p' << 40, - (long)'a' << 56 | (long)'n' << 48 | (long)'d' << 40, - (long)'a' << 56 | (long)'n' << 48 | (long)'g' << 40, - (long)'a' << 56 | (long)'p' << 48 | (long)'o' << 40 | (long)'s' << 32, - (long)'a' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24, - (long)'a' << 56 | (long)'s' << 48 | (long)'y' << 40 | (long)'m' << 32 | (long)'p' << 24, - (long)'a' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'a' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'b' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'b' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, - (long)'b' << 56 | (long)'r' << 48 | (long)'v' << 40 | (long)'b' << 32 | (long)'a' << 24 | (long)'r' << 16, - (long)'b' << 56 | (long)'u' << 48 | (long)'l' << 40 | (long)'l' << 32, - (long)'c' << 56 | (long)'a' << 48 | (long)'p' << 40, - (long)'c' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16, - (long)'c' << 56 | (long)'e' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'l' << 24, - (long)'c' << 56 | (long)'e' << 48 | (long)'n' << 40 | (long)'t' << 32, - (long)'c' << 56 | (long)'h' << 48 | (long)'i' << 40, - (long)'c' << 56 | (long)'i' << 48 | (long)'r' << 40 | (long)'c' << 32, - (long)'c' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'b' << 32 | (long)'s' << 24, - (long)'c' << 56 | (long)'o' << 48 | (long)'n' << 40 | (long)'g' << 32, - (long)'c' << 56 | (long)'o' << 48 | (long)'p' << 40 | (long)'y' << 32, - (long)'c' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'r' << 24, - (long)'c' << 56 | (long)'u' << 48 | (long)'p' << 40, - (long)'c' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'n' << 16, - (long)'d' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'d' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16, - (long)'d' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'d' << 56 | (long)'e' << 48 | (long)'g' << 40, - (long)'d' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24, - (long)'d' << 56 | (long)'i' << 48 | (long)'a' << 40 | (long)'m' << 32 | (long)'s' << 24, - (long)'d' << 56 | (long)'i' << 48 | (long)'v' << 40 | (long)'i' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'e' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'e' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'e' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'e' << 56 | (long)'m' << 48 | (long)'p' << 40 | (long)'t' << 32 | (long)'y' << 24, - (long)'e' << 56 | (long)'m' << 48 | (long)'s' << 40 | (long)'p' << 32, - (long)'e' << 56 | (long)'n' << 48 | (long)'s' << 40 | (long)'p' << 32, - (long)'e' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, - (long)'e' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'i' << 32 | (long)'v' << 24, - (long)'e' << 56 | (long)'t' << 48 | (long)'a' << 40, - (long)'e' << 56 | (long)'t' << 48 | (long)'h' << 40, - (long)'e' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'e' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'o' << 32, - (long)'e' << 56 | (long)'x' << 48 | (long)'i' << 40 | (long)'s' << 32 | (long)'t' << 24, - (long)'f' << 56 | (long)'n' << 48 | (long)'o' << 40 | (long)'f' << 32, - (long)'f' << 56 | (long)'o' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'l' << 24 | (long)'l' << 16, - (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'2' << 16, - (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'4' << 16, - (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'3' << 24 | (long)'4' << 16, - (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'l' << 24, - (long)'g' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24, - (long)'g' << 56 | (long)'e' << 48, - (long)'g' << 56 | (long)'t' << 48, - (long)'h' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'h' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'h' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'t' << 24 | (long)'s' << 16, - (long)'h' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'l' << 32 | (long)'i' << 24 | (long)'p' << 16, - (long)'i' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'i' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'i' << 56 | (long)'e' << 48 | (long)'x' << 40 | (long)'c' << 32 | (long)'l' << 24, - (long)'i' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'i' << 56 | (long)'m' << 48 | (long)'a' << 40 | (long)'g' << 32 | (long)'e' << 24, - (long)'i' << 56 | (long)'n' << 48 | (long)'f' << 40 | (long)'i' << 32 | (long)'n' << 24, - (long)'i' << 56 | (long)'n' << 48 | (long)'t' << 40, - (long)'i' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32, - (long)'i' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'e' << 32 | (long)'s' << 24 | (long)'t' << 16, - (long)'i' << 56 | (long)'s' << 48 | (long)'i' << 40 | (long)'n' << 32, - (long)'i' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'k' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24, - (long)'l' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'l' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16, - (long)'l' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32, - (long)'l' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'l' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'l' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24, - (long)'l' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'l' << 56 | (long)'e' << 48, - (long)'l' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16, - (long)'l' << 56 | (long)'o' << 48 | (long)'w' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'t' << 16, - (long)'l' << 56 | (long)'o' << 48 | (long)'z' << 40, - (long)'l' << 56 | (long)'r' << 48 | (long)'m' << 40, - (long)'l' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16, - (long)'l' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'l' << 56 | (long)'t' << 48, - (long)'m' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'r' << 32, - (long)'m' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24, - (long)'m' << 56 | (long)'i' << 48 | (long)'c' << 40 | (long)'r' << 32 | (long)'o' << 24, - (long)'m' << 56 | (long)'i' << 48 | (long)'d' << 40 | (long)'d' << 32 | (long)'o' << 24 | (long)'t' << 16, - (long)'m' << 56 | (long)'i' << 48 | (long)'n' << 40 | (long)'u' << 32 | (long)'s' << 24, - (long)'m' << 56 | (long)'u' << 48, - (long)'n' << 56 | (long)'a' << 48 | (long)'b' << 40 | (long)'l' << 32 | (long)'a' << 24, - (long)'n' << 56 | (long)'b' << 48 | (long)'s' << 40 | (long)'p' << 32, - (long)'n' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24, - (long)'n' << 56 | (long)'e' << 48, - (long)'n' << 56 | (long)'i' << 48, - (long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40, - (long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'i' << 32 | (long)'n' << 24, - (long)'n' << 56 | (long)'s' << 48 | (long)'u' << 40 | (long)'b' << 32, - (long)'n' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'n' << 56 | (long)'u' << 48, - (long)'o' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'o' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'o' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, - (long)'o' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'o' << 56 | (long)'l' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'e' << 24, - (long)'o' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24, - (long)'o' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8, - (long)'o' << 56 | (long)'p' << 48 | (long)'l' << 40 | (long)'u' << 32 | (long)'s' << 24, - (long)'o' << 56 | (long)'r' << 48, - (long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'f' << 32, - (long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'m' << 32, - (long)'o' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16, - (long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, - (long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24 | (long)'s' << 16, - (long)'o' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'a' << 32, - (long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'t' << 32, - (long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'m' << 32 | (long)'i' << 24 | (long)'l' << 16, - (long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'p' << 32, - (long)'p' << 56 | (long)'h' << 48 | (long)'i' << 40, - (long)'p' << 56 | (long)'i' << 48, - (long)'p' << 56 | (long)'i' << 48 | (long)'v' << 40, - (long)'p' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'s' << 32 | (long)'m' << 24 | (long)'n' << 16, - (long)'p' << 56 | (long)'o' << 48 | (long)'u' << 40 | (long)'n' << 32 | (long)'d' << 24, - (long)'p' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24, - (long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'d' << 32, - (long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'p' << 32, - (long)'p' << 56 | (long)'s' << 48 | (long)'i' << 40, - (long)'q' << 56 | (long)'u' << 48 | (long)'o' << 40 | (long)'t' << 32, - (long)'r' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'r' << 56 | (long)'a' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'c' << 24, - (long)'r' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32, - (long)'r' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'r' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'r' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24, - (long)'r' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'r' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'l' << 32, - (long)'r' << 56 | (long)'e' << 48 | (long)'g' << 40, - (long)'r' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16, - (long)'r' << 56 | (long)'h' << 48 | (long)'o' << 40, - (long)'r' << 56 | (long)'l' << 48 | (long)'m' << 40, - (long)'r' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16, - (long)'r' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'s' << 56 | (long)'b' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, - (long)'s' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16, - (long)'s' << 56 | (long)'d' << 48 | (long)'o' << 40 | (long)'t' << 32, - (long)'s' << 56 | (long)'e' << 48 | (long)'c' << 40 | (long)'t' << 32, - (long)'s' << 56 | (long)'h' << 48 | (long)'y' << 40, - (long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24, - (long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24 | (long)'f' << 16, - (long)'s' << 56 | (long)'i' << 48 | (long)'m' << 40, - (long)'s' << 56 | (long)'p' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24 | (long)'s' << 16, - (long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40, - (long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40 | (long)'e' << 32, - (long)'s' << 56 | (long)'u' << 48 | (long)'m' << 40, - (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40, - (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'1' << 32, - (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'2' << 32, - (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'3' << 32, - (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'e' << 32, - (long)'s' << 56 | (long)'z' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, - (long)'t' << 56 | (long)'a' << 48 | (long)'u' << 40, - (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'4' << 16, - (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24, - (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24 | (long)'s' << 16 | (long)'y' << 8 | (long)'m' << 0, - (long)'t' << 56 | (long)'h' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'s' << 24 | (long)'p' << 16, - (long)'t' << 56 | (long)'h' << 48 | (long)'o' << 40 | (long)'r' << 32 | (long)'n' << 24, - (long)'t' << 56 | (long)'i' << 48 | (long)'l' << 40 | (long)'d' << 32 | (long)'e' << 24, - (long)'t' << 56 | (long)'i' << 48 | (long)'m' << 40 | (long)'e' << 32 | (long)'s' << 24, - (long)'t' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24, - (long)'u' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'u' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'u' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, - (long)'u' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, - (long)'u' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, - (long)'u' << 56 | (long)'m' << 48 | (long)'l' << 40, - (long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'h' << 24, - (long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, - (long)'u' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'w' << 56 | (long)'e' << 48 | (long)'i' << 40 | (long)'e' << 32 | (long)'r' << 24 | (long)'p' << 16, - (long)'x' << 56 | (long)'i' << 48, - (long)'y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, - (long)'y' << 56 | (long)'e' << 48 | (long)'n' << 40, - (long)'y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, - (long)'z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, - (long)'z' << 56 | (long)'w' << 48 | (long)'j' << 40, - (long)'z' << 56 | (long)'w' << 48 | (long)'n' << 40 | (long)'j' << 32 - }; - - static readonly char[] entities_values = new char[] { - '\u00C6', - '\u00C1', - '\u00C2', - '\u00C0', - '\u0391', - '\u00C5', - '\u00C3', - '\u00C4', - '\u0392', - '\u00C7', - '\u03A7', - '\u2021', - '\u0394', - '\u00D0', - '\u00C9', - '\u00CA', - '\u00C8', - '\u0395', - '\u0397', - '\u00CB', - '\u0393', - '\u00CD', - '\u00CE', - '\u00CC', - '\u0399', - '\u00CF', - '\u039A', - '\u039B', - '\u039C', - '\u00D1', - '\u039D', - '\u0152', - '\u00D3', - '\u00D4', - '\u00D2', - '\u03A9', - '\u039F', - '\u00D8', - '\u00D5', - '\u00D6', - '\u03A6', - '\u03A0', - '\u2033', - '\u03A8', - '\u03A1', - '\u0160', - '\u03A3', - '\u00DE', - '\u03A4', - '\u0398', - '\u00DA', - '\u00DB', - '\u00D9', - '\u03A5', - '\u00DC', - '\u039E', - '\u00DD', - '\u0178', - '\u0396', - '\u00E1', - '\u00E2', - '\u00B4', - '\u00E6', - '\u00E0', - '\u2135', - '\u03B1', - '\u0026', - '\u2227', - '\u2220', - '\u0027', - '\u00E5', - '\u2248', - '\u00E3', - '\u00E4', - '\u201E', - '\u03B2', - '\u00A6', - '\u2022', - '\u2229', - '\u00E7', - '\u00B8', - '\u00A2', - '\u03C7', - '\u02C6', - '\u2663', - '\u2245', - '\u00A9', - '\u21B5', - '\u222A', - '\u00A4', - '\u21D3', - '\u2020', - '\u2193', - '\u00B0', - '\u03B4', - '\u2666', - '\u00F7', - '\u00E9', - '\u00EA', - '\u00E8', - '\u2205', - '\u2003', - '\u2002', - '\u03B5', - '\u2261', - '\u03B7', - '\u00F0', - '\u00EB', - '\u20AC', - '\u2203', - '\u0192', - '\u2200', - '\u00BD', - '\u00BC', - '\u00BE', - '\u2044', - '\u03B3', - '\u2265', - '\u003E', - '\u21D4', - '\u2194', - '\u2665', - '\u2026', - '\u00ED', - '\u00EE', - '\u00A1', - '\u00EC', - '\u2111', - '\u221E', - '\u222B', - '\u03B9', - '\u00BF', - '\u2208', - '\u00EF', - '\u03BA', - '\u21D0', - '\u03BB', - '\u2329', - '\u00AB', - '\u2190', - '\u2308', - '\u201C', - '\u2264', - '\u230A', - '\u2217', - '\u25CA', - '\u200E', - '\u2039', - '\u2018', - '\u003C', - '\u00AF', - '\u2014', - '\u00B5', - '\u00B7', - '\u2212', - '\u03BC', - '\u2207', - '\u00A0', - '\u2013', - '\u2260', - '\u220B', - '\u00AC', - '\u2209', - '\u2284', - '\u00F1', - '\u03BD', - '\u00F3', - '\u00F4', - '\u0153', - '\u00F2', - '\u203E', - '\u03C9', - '\u03BF', - '\u2295', - '\u2228', - '\u00AA', - '\u00BA', - '\u00F8', - '\u00F5', - '\u2297', - '\u00F6', - '\u00B6', - '\u2202', - '\u2030', - '\u22A5', - '\u03C6', - '\u03C0', - '\u03D6', - '\u00B1', - '\u00A3', - '\u2032', - '\u220F', - '\u221D', - '\u03C8', - '\u0022', - '\u21D2', - '\u221A', - '\u232A', - '\u00BB', - '\u2192', - '\u2309', - '\u201D', - '\u211C', - '\u00AE', - '\u230B', - '\u03C1', - '\u200F', - '\u203A', - '\u2019', - '\u201A', - '\u0161', - '\u22C5', - '\u00A7', - '\u00AD', - '\u03C3', - '\u03C2', - '\u223C', - '\u2660', - '\u2282', - '\u2286', - '\u2211', - '\u2283', - '\u00B9', - '\u00B2', - '\u00B3', - '\u2287', - '\u00DF', - '\u03C4', - '\u2234', - '\u03B8', - '\u03D1', - '\u2009', - '\u00FE', - '\u02DC', - '\u00D7', - '\u2122', - '\u21D1', - '\u00FA', - '\u2191', - '\u00FB', - '\u00F9', - '\u00A8', - '\u03D2', - '\u03C5', - '\u00FC', - '\u2118', - '\u03BE', - '\u00FD', - '\u00A5', - '\u00FF', - '\u03B6', - '\u200D', - '\u200C' - }; - - #region Methods - - static void WriteCharBytes(IList buf, char ch, Encoding e) - { - if (ch > 255) - { - foreach (byte b in e.GetBytes(new char[] { ch })) - buf.Add(b); - } - else - buf.Add((byte)ch); - } - - public static string UrlDecode(string s, Encoding e) - { - if (null == s) - return null; - - if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) - return s; - - if (e == null) - e = Encoding.UTF8; - - long len = s.Length; - var bytes = new List<byte>(); - int xchar; - char ch; - - for (int i = 0; i < len; i++) - { - ch = s[i]; - if (ch == '%' && i + 2 < len && s[i + 1] != '%') - { - if (s[i + 1] == 'u' && i + 5 < len) - { - // unicode hex sequence - xchar = GetChar(s, i + 2, 4); - if (xchar != -1) - { - WriteCharBytes(bytes, (char)xchar, e); - i += 5; - } - else - WriteCharBytes(bytes, '%', e); - } - else if ((xchar = GetChar(s, i + 1, 2)) != -1) - { - WriteCharBytes(bytes, (char)xchar, e); - i += 2; - } - else - { - WriteCharBytes(bytes, '%', e); - } - continue; - } - - if (ch == '+') - WriteCharBytes(bytes, ' ', e); - else - WriteCharBytes(bytes, ch, e); - } - - byte[] buf = bytes.ToArray(); - bytes = null; - return e.GetString(buf); - - } - - static int GetInt(byte b) - { - char c = (char)b; - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -1; - } - - static int GetChar(string str, int offset, int length) - { - int val = 0; - int end = length + offset; - for (int i = offset; i < end; i++) - { - char c = str[i]; - if (c > 127) - return -1; - - int current = GetInt((byte)c); - if (current == -1) - return -1; - val = (val << 4) + current; - } - - return val; - } - - static bool TryConvertKeyToEntity(string key, out char value) - { - var token = CalculateKeyValue(key); - if (token == 0) - { - value = '\0'; - return false; - } - - var idx = Array.BinarySearch(entities, token); - if (idx < 0) - { - value = '\0'; - return false; - } - - value = entities_values[idx]; - return true; - } - - static long CalculateKeyValue(string s) - { - if (s.Length > 8) - return 0; - - long key = 0; - for (int i = 0; i < s.Length; ++i) - { - long ch = s[i]; - if (ch > 'z' || ch < '0') - return 0; - - key |= ch << ((7 - i) * 8); - } - - return key; - } - - /// <summary> - /// Decodes an HTML-encoded string and returns the decoded string. - /// </summary> - /// <param name="s">The HTML string to decode. </param> - /// <returns>The decoded text.</returns> - public static string HtmlDecode(string s) - { - if (s == null) - throw new ArgumentNullException("s"); - - if (s.IndexOf('&') == -1) - return s; - - StringBuilder entity = new StringBuilder(); - StringBuilder output = new StringBuilder(); - int len = s.Length; - // 0 -> nothing, - // 1 -> right after '&' - // 2 -> between '&' and ';' but no '#' - // 3 -> '#' found after '&' and getting numbers - int state = 0; - int number = 0; - int digit_start = 0; - bool hex_number = false; - - for (int i = 0; i < len; i++) - { - char c = s[i]; - if (state == 0) - { - if (c == '&') - { - entity.Append(c); - state = 1; - } - else - { - output.Append(c); - } - continue; - } - - if (c == '&') - { - state = 1; - if (digit_start > 0) - { - entity.Append(s, digit_start, i - digit_start); - digit_start = 0; - } - - output.Append(entity.ToString()); - entity.Length = 0; - entity.Append('&'); - continue; - } - - switch (state) - { - case 1: - if (c == ';') - { - state = 0; - output.Append(entity.ToString()); - output.Append(c); - entity.Length = 0; - break; - } - - number = 0; - hex_number = false; - if (c != '#') - { - state = 2; - } - else - { - state = 3; - } - entity.Append(c); - - break; - case 2: - entity.Append(c); - if (c == ';') - { - string key = entity.ToString(); - state = 0; - entity.Length = 0; - - if (key.Length > 1) - { - var skey = key.Substring(1, key.Length - 2); - if (TryConvertKeyToEntity(skey, out c)) - { - output.Append(c); - break; - } - } - - output.Append(key); - } - - break; - case 3: - if (c == ';') - { - if (number < 0x10000) - { - output.Append((char)number); - } - else - { - output.Append((char)(0xd800 + ((number - 0x10000) >> 10))); - output.Append((char)(0xdc00 + ((number - 0x10000) & 0x3ff))); - } - state = 0; - entity.Length = 0; - digit_start = 0; - break; - } - - if (c == 'x' || c == 'X' && !hex_number) - { - digit_start = i; - hex_number = true; - break; - } - - if (Char.IsDigit(c)) - { - if (digit_start == 0) - digit_start = i; - - number = number * (hex_number ? 16 : 10) + ((int)c - '0'); - break; - } - - if (hex_number) - { - if (c >= 'a' && c <= 'f') - { - number = number * 16 + 10 + ((int)c - 'a'); - break; - } - if (c >= 'A' && c <= 'F') - { - number = number * 16 + 10 + ((int)c - 'A'); - break; - } - } - - state = 2; - if (digit_start > 0) - { - entity.Append(s, digit_start, i - digit_start); - digit_start = 0; - } - - entity.Append(c); - break; - } - } - - if (entity.Length > 0) - { - output.Append(entity); - } - else if (digit_start > 0) - { - output.Append(s, digit_start, s.Length - digit_start); - } - return output.ToString(); - } - - public static NameValueCollection ParseQueryString(string query) - { - return ParseQueryString(query, Encoding.UTF8); - } - - public static NameValueCollection ParseQueryString(string query, Encoding encoding) - { - if (query == null) - throw new ArgumentNullException("query"); - if (encoding == null) - throw new ArgumentNullException("encoding"); - if (query.Length == 0 || (query.Length == 1 && query[0] == '?')) - return new NameValueCollection(); - if (query[0] == '?') - query = query.Substring(1); - - NameValueCollection result = new HttpQSCollection(); - ParseQueryString(query, encoding, result); - return result; - } - - internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result) - { - if (query.Length == 0) - return; - - string decoded = HtmlDecode(query); - int decodedLength = decoded.Length; - int namePos = 0; - bool first = true; - while (namePos <= decodedLength) - { - int valuePos = -1, valueEnd = -1; - for (int q = namePos; q < decodedLength; q++) - { - if (valuePos == -1 && decoded[q] == '=') - { - valuePos = q + 1; - } - else if (decoded[q] == '&') - { - valueEnd = q; - break; - } - } - - if (first) - { - first = false; - if (decoded[namePos] == '?') - namePos++; - } - - string name, value; - if (valuePos == -1) - { - name = null; - valuePos = namePos; - } - else - { - name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding); - } - if (valueEnd < 0) - { - namePos = -1; - valueEnd = decoded.Length; - } - else - { - namePos = valueEnd + 1; - } - value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding); - - result.Add(name, value); - if (namePos == -1) - break; - } - } - #endregion // Methods - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs deleted file mode 100644 index d20dd7ec0..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs +++ /dev/null @@ -1,916 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.Globalization; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using ServiceStack; -using ServiceStack.Web; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public partial class WebSocketSharpRequest : IHttpRequest - { - static internal string GetParameter(string header, string attr) - { - int ap = header.IndexOf(attr); - if (ap == -1) - return null; - - ap += attr.Length; - if (ap >= header.Length) - return null; - - char ending = header[ap]; - if (ending != '"') - ending = ' '; - - int end = header.IndexOf(ending, ap + 1); - if (end == -1) - return ending == '"' ? null : header.Substring(ap); - - return header.Substring(ap + 1, end - ap - 1); - } - - async Task LoadMultiPart() - { - string boundary = GetParameter(ContentType, "; boundary="); - if (boundary == null) - return; - - using (var requestStream = GetSubStream(InputStream, _memoryStreamProvider)) - { - //DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request - //Not ending with \r\n? - var ms = _memoryStreamProvider.CreateNew(32 * 1024); - await requestStream.CopyToAsync(ms).ConfigureAwait(false); - - var input = ms; - ms.WriteByte((byte)'\r'); - ms.WriteByte((byte)'\n'); - - input.Position = 0; - - //Uncomment to debug - //var content = new StreamReader(ms).ReadToEnd(); - //Console.WriteLine(boundary + "::" + content); - //input.Position = 0; - - var multi_part = new HttpMultipart(input, boundary, ContentEncoding); - - HttpMultipart.Element e; - while ((e = multi_part.ReadNextElement()) != null) - { - if (e.Filename == null) - { - byte[] copy = new byte[e.Length]; - - input.Position = e.Start; - input.Read(copy, 0, (int)e.Length); - - form.Add(e.Name, (e.Encoding ?? ContentEncoding).GetString(copy)); - } - else - { - // - // We use a substream, as in 2.x we will support large uploads streamed to disk, - // - HttpPostedFile sub = new HttpPostedFile(e.Filename, e.ContentType, input, e.Start, e.Length); - files.AddFile(e.Name, sub); - } - } - } - } - - public NameValueCollection Form - { - get - { - if (form == null) - { - form = new WebROCollection(); - files = new HttpFileCollection(); - - if (IsContentType("multipart/form-data", true)) - { - var task = LoadMultiPart(); - Task.WaitAll(task); - } - else if (IsContentType("application/x-www-form-urlencoded", true)) - { - var task = LoadWwwForm(); - Task.WaitAll(task); - } - - form.Protect(); - } - -#if NET_4_0 - if (validateRequestNewMode && !checked_form) { - // Setting this before calling the validator prevents - // possible endless recursion - checked_form = true; - ValidateNameValueCollection ("Form", query_string_nvc, RequestValidationSource.Form); - } else -#endif - if (validate_form && !checked_form) - { - checked_form = true; - ValidateNameValueCollection("Form", form); - } - - return form; - } - } - - public string Accept - { - get - { - return string.IsNullOrEmpty(request.Headers[HttpHeaders.Accept]) ? null : request.Headers[HttpHeaders.Accept]; - } - } - - public string Authorization - { - get - { - return string.IsNullOrEmpty(request.Headers[HttpHeaders.Authorization]) ? null : request.Headers[HttpHeaders.Authorization]; - } - } - - protected bool validate_cookies, validate_query_string, validate_form; - protected bool checked_cookies, checked_query_string, checked_form; - - static void ThrowValidationException(string name, string key, string value) - { - string v = "\"" + value + "\""; - if (v.Length > 20) - v = v.Substring(0, 16) + "...\""; - - string msg = String.Format("A potentially dangerous Request.{0} value was " + - "detected from the client ({1}={2}).", name, key, v); - - throw new HttpRequestValidationException(msg); - } - - static void ValidateNameValueCollection(string name, NameValueCollection coll) - { - if (coll == null) - return; - - foreach (string key in coll.Keys) - { - string val = coll[key]; - if (val != null && val.Length > 0 && IsInvalidString(val)) - ThrowValidationException(name, key, val); - } - } - - internal static bool IsInvalidString(string val) - { - int validationFailureIndex; - - return IsInvalidString(val, out validationFailureIndex); - } - - internal static bool IsInvalidString(string val, out int validationFailureIndex) - { - validationFailureIndex = 0; - - int len = val.Length; - if (len < 2) - return false; - - char current = val[0]; - for (int idx = 1; idx < len; idx++) - { - char next = val[idx]; - // See http://secunia.com/advisories/14325 - if (current == '<' || current == '\xff1c') - { - if (next == '!' || next < ' ' - || (next >= 'a' && next <= 'z') - || (next >= 'A' && next <= 'Z')) - { - validationFailureIndex = idx - 1; - return true; - } - } - else if (current == '&' && next == '#') - { - validationFailureIndex = idx - 1; - return true; - } - - current = next; - } - - return false; - } - - public void ValidateInput() - { - validate_cookies = true; - validate_query_string = true; - validate_form = true; - } - - bool IsContentType(string ct, bool starts_with) - { - if (ct == null || ContentType == null) return false; - - if (starts_with) - return StrUtils.StartsWith(ContentType, ct, true); - - return String.Compare(ContentType, ct, true, Helpers.InvariantCulture) == 0; - } - - async Task LoadWwwForm() - { - using (Stream input = GetSubStream(InputStream, _memoryStreamProvider)) - { - using (var ms = _memoryStreamProvider.CreateNew()) - { - await input.CopyToAsync(ms).ConfigureAwait(false); - ms.Position = 0; - - using (StreamReader s = new StreamReader(ms, ContentEncoding)) - { - StringBuilder key = new StringBuilder(); - StringBuilder value = new StringBuilder(); - int c; - - while ((c = s.Read()) != -1) - { - if (c == '=') - { - value.Length = 0; - while ((c = s.Read()) != -1) - { - if (c == '&') - { - AddRawKeyValue(key, value); - break; - } - else - value.Append((char)c); - } - if (c == -1) - { - AddRawKeyValue(key, value); - return; - } - } - else if (c == '&') - AddRawKeyValue(key, value); - else - key.Append((char)c); - } - if (c == -1) - AddRawKeyValue(key, value); - } - } - } - } - - void AddRawKeyValue(StringBuilder key, StringBuilder value) - { - string decodedKey = HttpUtility.UrlDecode(key.ToString(), ContentEncoding); - form.Add(decodedKey, - HttpUtility.UrlDecode(value.ToString(), ContentEncoding)); - - key.Length = 0; - value.Length = 0; - } - - WebROCollection form; - - HttpFileCollection files; - - public sealed class HttpFileCollection : NameObjectCollectionBase - { - internal HttpFileCollection() - { - } - - internal void AddFile(string name, HttpPostedFile file) - { - BaseAdd(name, file); - } - - public void CopyTo(Array dest, int index) - { - /* XXX this is kind of gross and inefficient - * since it makes a copy of the superclass's - * list */ - object[] values = BaseGetAllValues(); - values.CopyTo(dest, index); - } - - public string GetKey(int index) - { - return BaseGetKey(index); - } - - public HttpPostedFile Get(int index) - { - return (HttpPostedFile)BaseGet(index); - } - - public HttpPostedFile Get(string key) - { - return (HttpPostedFile)BaseGet(key); - } - - public HttpPostedFile this[string key] - { - get - { - return Get(key); - } - } - - public HttpPostedFile this[int index] - { - get - { - return Get(index); - } - } - - public string[] AllKeys - { - get - { - return BaseGetAllKeys(); - } - } - } - class WebROCollection : NameValueCollection - { - bool got_id; - int id; - - public bool GotID - { - get { return got_id; } - } - - public int ID - { - get { return id; } - set - { - got_id = true; - id = value; - } - } - public void Protect() - { - IsReadOnly = true; - } - - public void Unprotect() - { - IsReadOnly = false; - } - - public override string ToString() - { - StringBuilder result = new StringBuilder(); - foreach (string key in AllKeys) - { - if (result.Length > 0) - result.Append('&'); - - if (key != null && key.Length > 0) - { - result.Append(key); - result.Append('='); - } - result.Append(Get(key)); - } - - return result.ToString(); - } - } - - public sealed class HttpPostedFile - { - string name; - string content_type; - Stream stream; - - class ReadSubStream : Stream - { - Stream s; - long offset; - long end; - long position; - - public ReadSubStream(Stream s, long offset, long length) - { - this.s = s; - this.offset = offset; - this.end = offset + length; - position = offset; - } - - public override void Flush() - { - } - - public override int Read(byte[] buffer, int dest_offset, int count) - { - if (buffer == null) - throw new ArgumentNullException("buffer"); - - if (dest_offset < 0) - throw new ArgumentOutOfRangeException("dest_offset", "< 0"); - - if (count < 0) - throw new ArgumentOutOfRangeException("count", "< 0"); - - int len = buffer.Length; - if (dest_offset > len) - throw new ArgumentException("destination offset is beyond array size"); - // reordered to avoid possible integer overflow - if (dest_offset > len - count) - throw new ArgumentException("Reading would overrun buffer"); - - if (count > end - position) - count = (int)(end - position); - - if (count <= 0) - return 0; - - s.Position = position; - int result = s.Read(buffer, dest_offset, count); - if (result > 0) - position += result; - else - position = end; - - return result; - } - - public override int ReadByte() - { - if (position >= end) - return -1; - - s.Position = position; - int result = s.ReadByte(); - if (result < 0) - position = end; - else - position++; - - return result; - } - - public override long Seek(long d, SeekOrigin origin) - { - long real; - switch (origin) - { - case SeekOrigin.Begin: - real = offset + d; - break; - case SeekOrigin.End: - real = end + d; - break; - case SeekOrigin.Current: - real = position + d; - break; - default: - throw new ArgumentException(); - } - - long virt = real - offset; - if (virt < 0 || virt > Length) - throw new ArgumentException(); - - position = s.Seek(real, SeekOrigin.Begin); - return position; - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override bool CanRead - { - get { return true; } - } - public override bool CanSeek - { - get { return true; } - } - public override bool CanWrite - { - get { return false; } - } - - public override long Length - { - get { return end - offset; } - } - - public override long Position - { - get - { - return position - offset; - } - set - { - if (value > Length) - throw new ArgumentOutOfRangeException(); - - position = Seek(value, SeekOrigin.Begin); - } - } - } - - internal HttpPostedFile(string name, string content_type, Stream base_stream, long offset, long length) - { - this.name = name; - this.content_type = content_type; - this.stream = new ReadSubStream(base_stream, offset, length); - } - - public string ContentType - { - get - { - return content_type; - } - } - - public int ContentLength - { - get - { - return (int)stream.Length; - } - } - - public string FileName - { - get - { - return name; - } - } - - public Stream InputStream - { - get - { - return stream; - } - } - } - - class Helpers - { - public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture; - } - - internal sealed class StrUtils - { - StrUtils() { } - - public static bool StartsWith(string str1, string str2) - { - return StartsWith(str1, str2, false); - } - - public static bool StartsWith(string str1, string str2, bool ignore_case) - { - int l2 = str2.Length; - if (l2 == 0) - return true; - - int l1 = str1.Length; - if (l2 > l1) - return false; - - return 0 == String.Compare(str1, 0, str2, 0, l2, ignore_case, Helpers.InvariantCulture); - } - - public static bool EndsWith(string str1, string str2) - { - return EndsWith(str1, str2, false); - } - - public static bool EndsWith(string str1, string str2, bool ignore_case) - { - int l2 = str2.Length; - if (l2 == 0) - return true; - - int l1 = str1.Length; - if (l2 > l1) - return false; - - return 0 == String.Compare(str1, l1 - l2, str2, 0, l2, ignore_case, Helpers.InvariantCulture); - } - } - - class HttpMultipart - { - - public class Element - { - public string ContentType; - public string Name; - public string Filename; - public Encoding Encoding; - public long Start; - public long Length; - - public override string ToString() - { - return "ContentType " + ContentType + ", Name " + Name + ", Filename " + Filename + ", Start " + - Start.ToString() + ", Length " + Length.ToString(); - } - } - - Stream data; - string boundary; - byte[] boundary_bytes; - byte[] buffer; - bool at_eof; - Encoding encoding; - StringBuilder sb; - - const byte HYPHEN = (byte)'-', LF = (byte)'\n', CR = (byte)'\r'; - - // See RFC 2046 - // In the case of multipart entities, in which one or more different - // sets of data are combined in a single body, a "multipart" media type - // field must appear in the entity's header. The body must then contain - // one or more body parts, each preceded by a boundary delimiter line, - // and the last one followed by a closing boundary delimiter line. - // After its boundary delimiter line, each body part then consists of a - // header area, a blank line, and a body area. Thus a body part is - // similar to an RFC 822 message in syntax, but different in meaning. - - public HttpMultipart(Stream data, string b, Encoding encoding) - { - this.data = data; - //DB: 30/01/11: cannot set or read the Position in HttpListener in Win.NET - //var ms = new MemoryStream(32 * 1024); - //data.CopyTo(ms); - //this.data = ms; - - boundary = b; - boundary_bytes = encoding.GetBytes(b); - buffer = new byte[boundary_bytes.Length + 2]; // CRLF or '--' - this.encoding = encoding; - sb = new StringBuilder(); - } - - string ReadLine() - { - // CRLF or LF are ok as line endings. - bool got_cr = false; - int b = 0; - sb.Length = 0; - while (true) - { - b = data.ReadByte(); - if (b == -1) - { - return null; - } - - if (b == LF) - { - break; - } - got_cr = b == CR; - sb.Append((char)b); - } - - if (got_cr) - sb.Length--; - - return sb.ToString(); - - } - - static string GetContentDispositionAttribute(string l, string name) - { - int idx = l.IndexOf(name + "=\""); - if (idx < 0) - return null; - int begin = idx + name.Length + "=\"".Length; - int end = l.IndexOf('"', begin); - if (end < 0) - return null; - if (begin == end) - return ""; - return l.Substring(begin, end - begin); - } - - string GetContentDispositionAttributeWithEncoding(string l, string name) - { - int idx = l.IndexOf(name + "=\""); - if (idx < 0) - return null; - int begin = idx + name.Length + "=\"".Length; - int end = l.IndexOf('"', begin); - if (end < 0) - return null; - if (begin == end) - return ""; - - string temp = l.Substring(begin, end - begin); - byte[] source = new byte[temp.Length]; - for (int i = temp.Length - 1; i >= 0; i--) - source[i] = (byte)temp[i]; - - return encoding.GetString(source); - } - - bool ReadBoundary() - { - try - { - string line = ReadLine(); - while (line == "") - line = ReadLine(); - if (line[0] != '-' || line[1] != '-') - return false; - - if (!StrUtils.EndsWith(line, boundary, false)) - return true; - } - catch - { - } - - return false; - } - - string ReadHeaders() - { - string s = ReadLine(); - if (s == "") - return null; - - return s; - } - - bool CompareBytes(byte[] orig, byte[] other) - { - for (int i = orig.Length - 1; i >= 0; i--) - if (orig[i] != other[i]) - return false; - - return true; - } - - long MoveToNextBoundary() - { - long retval = 0; - bool got_cr = false; - - int state = 0; - int c = data.ReadByte(); - while (true) - { - if (c == -1) - return -1; - - if (state == 0 && c == LF) - { - retval = data.Position - 1; - if (got_cr) - retval--; - state = 1; - c = data.ReadByte(); - } - else if (state == 0) - { - got_cr = c == CR; - c = data.ReadByte(); - } - else if (state == 1 && c == '-') - { - c = data.ReadByte(); - if (c == -1) - return -1; - - if (c != '-') - { - state = 0; - got_cr = false; - continue; // no ReadByte() here - } - - int nread = data.Read(buffer, 0, buffer.Length); - int bl = buffer.Length; - if (nread != bl) - return -1; - - if (!CompareBytes(boundary_bytes, buffer)) - { - state = 0; - data.Position = retval + 2; - if (got_cr) - { - data.Position++; - got_cr = false; - } - c = data.ReadByte(); - continue; - } - - if (buffer[bl - 2] == '-' && buffer[bl - 1] == '-') - { - at_eof = true; - } - else if (buffer[bl - 2] != CR || buffer[bl - 1] != LF) - { - state = 0; - data.Position = retval + 2; - if (got_cr) - { - data.Position++; - got_cr = false; - } - c = data.ReadByte(); - continue; - } - data.Position = retval + 2; - if (got_cr) - data.Position++; - break; - } - else - { - // state == 1 - state = 0; // no ReadByte() here - } - } - - return retval; - } - - public Element ReadNextElement() - { - if (at_eof || ReadBoundary()) - return null; - - Element elem = new Element(); - string header; - while ((header = ReadHeaders()) != null) - { - if (StrUtils.StartsWith(header, "Content-Disposition:", true)) - { - elem.Name = GetContentDispositionAttribute(header, "name"); - elem.Filename = StripPath(GetContentDispositionAttributeWithEncoding(header, "filename")); - } - else if (StrUtils.StartsWith(header, "Content-Type:", true)) - { - elem.ContentType = header.Substring("Content-Type:".Length).Trim(); - elem.Encoding = GetEncoding(elem.ContentType); - } - } - - long start = 0; - start = data.Position; - elem.Start = start; - long pos = MoveToNextBoundary(); - if (pos == -1) - return null; - - elem.Length = pos - start; - return elem; - } - - static string StripPath(string path) - { - if (path == null || path.Length == 0) - return path; - - if (path.IndexOf(":\\") != 1 && !path.StartsWith("\\\\")) - return path; - return path.Substring(path.LastIndexOf('\\') + 1); - } - } - - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs deleted file mode 100644 index d363c4de6..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs +++ /dev/null @@ -1,172 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; -using WebSocketState = MediaBrowser.Model.Net.WebSocketState; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public class SharpWebSocket : IWebSocket - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - public event EventHandler<EventArgs> Closed; - - /// <summary> - /// Gets or sets the web socket. - /// </summary> - /// <value>The web socket.</value> - private SocketHttpListener.WebSocket WebSocket { get; set; } - - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - /// <summary> - /// Initializes a new instance of the <see cref="NativeWebSocket" /> class. - /// </summary> - /// <param name="socket">The socket.</param> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">socket</exception> - public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger) - { - if (socket == null) - { - throw new ArgumentNullException("socket"); - } - - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - _logger = logger; - WebSocket = socket; - - socket.OnMessage += socket_OnMessage; - socket.OnClose += socket_OnClose; - socket.OnError += socket_OnError; - - WebSocket.ConnectAsServer(); - } - - void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e) - { - _logger.Error("Error in SharpWebSocket: {0}", e.Message ?? string.Empty); - //EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); - } - - void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e) - { - EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); - } - - void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e) - { - //if (!string.IsNullOrWhiteSpace(e.Data)) - //{ - // if (OnReceive != null) - // { - // OnReceive(e.Data); - // } - // return; - //} - if (OnReceiveBytes != null) - { - OnReceiveBytes(e.RawData); - } - } - - /// <summary> - /// Gets or sets the state. - /// </summary> - /// <value>The state.</value> - public WebSocketState State - { - get - { - WebSocketState commonState; - - if (!Enum.TryParse(WebSocket.ReadyState.ToString(), true, out commonState)) - { - _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.ReadyState.ToString()); - } - - return commonState; - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) - { - var completionSource = new TaskCompletionSource<bool>(); - - WebSocket.SendAsync(bytes, res => completionSource.TrySetResult(true)); - - return completionSource.Task; - } - - /// <summary> - /// Sends the asynchronous. - /// </summary> - /// <param name="text">The text.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) - { - var completionSource = new TaskCompletionSource<bool>(); - - WebSocket.SendAsync(text, res => completionSource.TrySetResult(true)); - - return completionSource.Task; - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - WebSocket.OnMessage -= socket_OnMessage; - WebSocket.OnClose -= socket_OnClose; - WebSocket.OnError -= socket_OnError; - - _cancellationTokenSource.Cancel(); - - WebSocket.Close(); - } - } - - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> - public Action<byte[]> OnReceiveBytes { get; set; } - - /// <summary> - /// Gets or sets the on receive. - /// </summary> - /// <value>The on receive.</value> - public Action<string> OnReceive { get; set; } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs deleted file mode 100644 index b090c97c6..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System.Collections.Specialized; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Server.Implementations.Logging; -using ServiceStack; -using ServiceStack.Web; -using SocketHttpListener.Net; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using MediaBrowser.Common.IO; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public class WebSocketSharpListener : IHttpListener - { - private HttpListener _listener; - - private readonly ILogger _logger; - private readonly string _certificatePath; - private readonly IMemoryStreamProvider _memoryStreamProvider; - - public WebSocketSharpListener(ILogger logger, string certificatePath, IMemoryStreamProvider memoryStreamProvider) - { - _logger = logger; - _certificatePath = certificatePath; - _memoryStreamProvider = memoryStreamProvider; - } - - public Action<Exception, IRequest> ErrorHandler { get; set; } - - public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; } - - public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; } - - public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; } - - public void Start(IEnumerable<string> urlPrefixes) - { - if (_listener == null) - _listener = new HttpListener(new PatternsLogger(_logger), _certificatePath); - - foreach (var prefix in urlPrefixes) - { - _logger.Info("Adding HttpListener prefix " + prefix); - _listener.Prefixes.Add(prefix); - } - - _listener.OnContext = ProcessContext; - - _listener.Start(); - } - - private void ProcessContext(HttpListenerContext context) - { - Task.Factory.StartNew(() => InitTask(context)); - } - - private 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); - } - } - - private Task ProcessRequestAsync(HttpListenerContext context) - { - var request = context.Request; - - if (request.IsWebSocketRequest) - { - LoggerUtils.LogRequest(_logger, request); - - ProcessWebSocketRequest(context); - return Task.FromResult(true); - } - - if (string.IsNullOrEmpty(context.Request.RawUrl)) - return ((object)null).AsTaskResult(); - - var httpReq = GetRequest(context); - - return RequestHandler(httpReq, request.Url); - } - - private void ProcessWebSocketRequest(HttpListenerContext ctx) - { - try - { - var endpoint = ctx.Request.RemoteEndPoint.ToString(); - var url = ctx.Request.RawUrl; - var queryString = new NameValueCollection(ctx.Request.QueryString ?? new NameValueCollection()); - - var connectingArgs = new WebSocketConnectingEventArgs - { - Url = url, - QueryString = queryString, - Endpoint = endpoint - }; - - if (WebSocketConnecting != null) - { - WebSocketConnecting(connectingArgs); - } - - if (connectingArgs.AllowConnection) - { - _logger.Debug("Web socket connection allowed"); - - var webSocketContext = ctx.AcceptWebSocket(null); - - if (WebSocketConnected != null) - { - WebSocketConnected(new WebSocketConnectEventArgs - { - Url = url, - QueryString = queryString, - WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger), - Endpoint = endpoint - }); - } - } - else - { - _logger.Warn("Web socket connection not allowed"); - ctx.Response.StatusCode = 401; - ctx.Response.Close(); - } - } - catch (Exception ex) - { - _logger.ErrorException("AcceptWebSocketAsync error", ex); - ctx.Response.StatusCode = 500; - ctx.Response.Close(); - } - } - - private IHttpRequest GetRequest(HttpListenerContext httpContext) - { - var operationName = httpContext.Request.GetOperationName(); - - var req = new WebSocketSharpRequest(httpContext, operationName, RequestAttributes.None, _logger, _memoryStreamProvider); - req.RequestAttributes = req.GetAttributes(); - - return req; - } - - private void HandleError(Exception ex, HttpListenerContext context) - { - var httpReq = GetRequest(context); - - if (ErrorHandler != null) - { - ErrorHandler(ex, httpReq); - } - } - - public void Stop() - { - if (_listener != null) - { - foreach (var prefix in _listener.Prefixes.ToList()) - { - _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) - { - Stop(); - } - - //release unmanaged resources here... - _disposed = true; - } - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs deleted file mode 100644 index b5c8d0107..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs +++ /dev/null @@ -1,494 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Funq; -using MediaBrowser.Common.IO; -using MediaBrowser.Model.Logging; -using ServiceStack; -using ServiceStack.Host; -using ServiceStack.Web; -using SocketHttpListener.Net; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public partial class WebSocketSharpRequest : IHttpRequest - { - public Container Container { get; set; } - private readonly HttpListenerRequest request; - private readonly IHttpResponse response; - private readonly IMemoryStreamProvider _memoryStreamProvider; - - public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger, IMemoryStreamProvider memoryStreamProvider) - { - this.OperationName = operationName; - this.RequestAttributes = requestAttributes; - _memoryStreamProvider = memoryStreamProvider; - this.request = httpContext.Request; - this.response = new WebSocketSharpResponse(logger, httpContext.Response, this); - - this.RequestPreferences = new RequestPreferences(this); - } - - public HttpListenerRequest HttpRequest - { - get { return request; } - } - - public object OriginalRequest - { - get { return request; } - } - - public IResponse Response - { - get { return response; } - } - - public IHttpResponse HttpResponse - { - get { return response; } - } - - public RequestAttributes RequestAttributes { get; set; } - - public IRequestPreferences RequestPreferences { get; private set; } - - public T TryResolve<T>() - { - if (typeof(T) == typeof(IHttpRequest)) - throw new Exception("You don't need to use IHttpRequest.TryResolve<IHttpRequest> to resolve itself"); - - if (typeof(T) == typeof(IHttpResponse)) - throw new Exception("Resolve IHttpResponse with 'Response' property instead of IHttpRequest.TryResolve<IHttpResponse>"); - - return Container == null - ? HostContext.TryResolve<T>() - : Container.TryResolve<T>(); - } - - public string OperationName { get; set; } - - public object Dto { get; set; } - - public string GetRawBody() - { - if (bufferedStream != null) - { - return bufferedStream.ToArray().FromUtf8Bytes(); - } - - using (var reader = new StreamReader(InputStream)) - { - return reader.ReadToEnd(); - } - } - - public string RawUrl - { - get { return request.RawUrl; } - } - - public string AbsoluteUri - { - get { return request.Url.AbsoluteUri.TrimEnd('/'); } - } - - public string UserHostAddress - { - get { return request.UserHostAddress; } - } - - public string XForwardedFor - { - get - { - return String.IsNullOrEmpty(request.Headers[HttpHeaders.XForwardedFor]) ? null : request.Headers[HttpHeaders.XForwardedFor]; - } - } - - public int? XForwardedPort - { - get - { - return string.IsNullOrEmpty(request.Headers[HttpHeaders.XForwardedPort]) ? (int?)null : int.Parse(request.Headers[HttpHeaders.XForwardedPort]); - } - } - - public string XForwardedProtocol - { - get - { - return string.IsNullOrEmpty(request.Headers[HttpHeaders.XForwardedProtocol]) ? null : request.Headers[HttpHeaders.XForwardedProtocol]; - } - } - - public string XRealIp - { - get - { - return String.IsNullOrEmpty(request.Headers[HttpHeaders.XRealIp]) ? null : request.Headers[HttpHeaders.XRealIp]; - } - } - - private string remoteIp; - public string RemoteIp - { - get - { - return remoteIp ?? - (remoteIp = (CheckBadChars(XForwardedFor)) ?? - (NormalizeIp(CheckBadChars(XRealIp)) ?? - (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null))); - } - } - - private static readonly char[] HttpTrimCharacters = new char[] { (char)0x09, (char)0xA, (char)0xB, (char)0xC, (char)0xD, (char)0x20 }; - - // - // CheckBadChars - throws on invalid chars to be not found in header name/value - // - internal static string CheckBadChars(string name) - { - if (name == null || name.Length == 0) - { - return name; - } - - // VALUE check - //Trim spaces from both ends - name = name.Trim(HttpTrimCharacters); - - //First, check for correctly formed multi-line value - //Second, check for absenece of CTL characters - int crlf = 0; - for (int i = 0; i < name.Length; ++i) - { - char c = (char)(0x000000ff & (uint)name[i]); - switch (crlf) - { - case 0: - if (c == '\r') - { - crlf = 1; - } - else if (c == '\n') - { - // Technically this is bad HTTP. But it would be a breaking change to throw here. - // Is there an exploit? - crlf = 2; - } - else if (c == 127 || (c < ' ' && c != '\t')) - { - throw new ArgumentException("net_WebHeaderInvalidControlChars"); - } - break; - - case 1: - if (c == '\n') - { - crlf = 2; - break; - } - throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); - - case 2: - if (c == ' ' || c == '\t') - { - crlf = 0; - break; - } - throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); - } - } - if (crlf != 0) - { - throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); - } - return name; - } - - internal static bool ContainsNonAsciiChars(string token) - { - for (int i = 0; i < token.Length; ++i) - { - if ((token[i] < 0x20) || (token[i] > 0x7e)) - { - return true; - } - } - return false; - } - - private string NormalizeIp(string ip) - { - if (!string.IsNullOrWhiteSpace(ip)) - { - // Handle ipv4 mapped to ipv6 - const string srch = "::ffff:"; - var index = ip.IndexOf(srch, StringComparison.OrdinalIgnoreCase); - if (index == 0) - { - ip = ip.Substring(srch.Length); - } - } - - return ip; - } - - public bool IsSecureConnection - { - get { return request.IsSecureConnection || XForwardedProtocol == "https"; } - } - - public string[] AcceptTypes - { - get { return request.AcceptTypes; } - } - - private Dictionary<string, object> items; - public Dictionary<string, object> Items - { - get { return items ?? (items = new Dictionary<string, object>()); } - } - - private string responseContentType; - public string ResponseContentType - { - get - { - return responseContentType - ?? (responseContentType = this.GetResponseContentType()); - } - set - { - this.responseContentType = value; - HasExplicitResponseContentType = true; - } - } - - public bool HasExplicitResponseContentType { get; private set; } - - private string pathInfo; - public string PathInfo - { - get - { - if (this.pathInfo == null) - { - var mode = HostContext.Config.HandlerFactoryPath; - - var pos = request.RawUrl.IndexOf("?"); - if (pos != -1) - { - var path = request.RawUrl.Substring(0, pos); - this.pathInfo = HttpRequestExtensions.GetPathInfo( - path, - mode, - mode ?? ""); - } - else - { - this.pathInfo = request.RawUrl; - } - - this.pathInfo = this.pathInfo.UrlDecode(); - this.pathInfo = NormalizePathInfo(pathInfo, mode); - } - return this.pathInfo; - } - } - - private Dictionary<string, System.Net.Cookie> cookies; - public IDictionary<string, System.Net.Cookie> Cookies - { - get - { - if (cookies == null) - { - cookies = new Dictionary<string, System.Net.Cookie>(); - for (var i = 0; i < this.request.Cookies.Count; i++) - { - var httpCookie = this.request.Cookies[i]; - cookies[httpCookie.Name] = new System.Net.Cookie(httpCookie.Name, httpCookie.Value, httpCookie.Path, httpCookie.Domain); - } - } - - return cookies; - } - } - - public string UserAgent - { - get { return request.UserAgent; } - } - - private NameValueCollectionWrapper headers; - public INameValueCollection Headers - { - get { return headers ?? (headers = new NameValueCollectionWrapper(request.Headers)); } - } - - private NameValueCollectionWrapper queryString; - public INameValueCollection QueryString - { - get { return queryString ?? (queryString = new NameValueCollectionWrapper(MyHttpUtility.ParseQueryString(request.Url.Query))); } - } - - private NameValueCollectionWrapper formData; - public INameValueCollection FormData - { - get { return formData ?? (formData = new NameValueCollectionWrapper(this.Form)); } - } - - public bool IsLocal - { - get { return request.IsLocal; } - } - - private string httpMethod; - public string HttpMethod - { - get - { - return httpMethod - ?? (httpMethod = Param(HttpHeaders.XHttpMethodOverride) - ?? request.HttpMethod); - } - } - - public string Verb - { - get { return HttpMethod; } - } - - public string Param(string name) - { - return Headers[name] - ?? QueryString[name] - ?? FormData[name]; - } - - public string ContentType - { - get { return request.ContentType; } - } - - public Encoding contentEncoding; - public Encoding ContentEncoding - { - get { return contentEncoding ?? request.ContentEncoding; } - set { contentEncoding = value; } - } - - public Uri UrlReferrer - { - get { return request.UrlReferrer; } - } - - public static Encoding GetEncoding(string contentTypeHeader) - { - var param = GetParameter(contentTypeHeader, "charset="); - if (param == null) return null; - try - { - return Encoding.GetEncoding(param); - } - catch (ArgumentException) - { - return null; - } - } - - public bool UseBufferedStream - { - get { return bufferedStream != null; } - set - { - bufferedStream = value - ? bufferedStream ?? _memoryStreamProvider.CreateNew(request.InputStream.ReadFully()) - : null; - } - } - - private MemoryStream bufferedStream; - public Stream InputStream - { - get { return bufferedStream ?? request.InputStream; } - } - - public long ContentLength - { - get { return request.ContentLength64; } - } - - private IHttpFile[] httpFiles; - public IHttpFile[] Files - { - get - { - if (httpFiles == null) - { - if (files == null) - return httpFiles = new IHttpFile[0]; - - httpFiles = new IHttpFile[files.Count]; - for (var i = 0; i < files.Count; i++) - { - var reqFile = files[i]; - - httpFiles[i] = new HttpFile - { - ContentType = reqFile.ContentType, - ContentLength = reqFile.ContentLength, - FileName = reqFile.FileName, - InputStream = reqFile.InputStream, - }; - } - } - return httpFiles; - } - } - - static Stream GetSubStream(Stream stream, IMemoryStreamProvider streamProvider) - { - if (stream is MemoryStream) - { - var other = (MemoryStream)stream; - try - { - return new MemoryStream(other.GetBuffer(), 0, (int)other.Length, false, true); - } - catch (UnauthorizedAccessException) - { - return new MemoryStream(other.ToArray(), 0, (int)other.Length, false, true); - } - } - - return stream; - } - - public static string GetHandlerPathIfAny(string listenerUrl) - { - if (listenerUrl == null) return null; - var pos = listenerUrl.IndexOf("://", StringComparison.InvariantCultureIgnoreCase); - if (pos == -1) return null; - var startHostUrl = listenerUrl.Substring(pos + "://".Length); - var endPos = startHostUrl.IndexOf('/'); - if (endPos == -1) return null; - var endHostUrl = startHostUrl.Substring(endPos + 1); - return String.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/'); - } - - public static string NormalizePathInfo(string pathInfo, string handlerPath) - { - if (handlerPath != null && pathInfo.TrimStart('/').StartsWith( - handlerPath, StringComparison.InvariantCultureIgnoreCase)) - { - return pathInfo.TrimStart('/').Substring(handlerPath.Length); - } - - return pathInfo; - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs deleted file mode 100644 index a58645ec5..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using MediaBrowser.Model.Logging; -using ServiceStack; -using ServiceStack.Host; -using ServiceStack.Web; -using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse; - -namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp -{ - public class WebSocketSharpResponse : IHttpResponse - { - private readonly ILogger _logger; - private readonly HttpListenerResponse response; - - public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request) - { - _logger = logger; - this.response = response; - Items = new Dictionary<string, object>(); - Request = request; - } - - public IRequest Request { get; private set; } - public bool UseBufferedStream { get; set; } - public Dictionary<string, object> Items { get; private set; } - public object OriginalResponse - { - get { return response; } - } - - public int StatusCode - { - get { return this.response.StatusCode; } - set { this.response.StatusCode = value; } - } - - public string StatusDescription - { - get { return this.response.StatusDescription; } - set { this.response.StatusDescription = value; } - } - - public string ContentType - { - get { return response.ContentType; } - set { response.ContentType = value; } - } - - public ICookies Cookies { get; set; } - - public void AddHeader(string name, string value) - { - if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase)) - { - ContentType = value; - return; - } - - response.AddHeader(name, value); - } - - public string GetHeader(string name) - { - return response.Headers[name]; - } - - public void Redirect(string url) - { - response.Redirect(url); - } - - public Stream OutputStream - { - get { return response.OutputStream; } - } - - public object Dto { get; set; } - - public void Write(string text) - { - var bOutput = System.Text.Encoding.UTF8.GetBytes(text); - response.ContentLength64 = bOutput.Length; - - var outputStream = response.OutputStream; - outputStream.Write(bOutput, 0, bOutput.Length); - Close(); - } - - public void Close() - { - if (!this.IsClosed) - { - this.IsClosed = true; - - try - { - this.response.CloseOutputStream(_logger); - } - catch (Exception ex) - { - _logger.ErrorException("Error closing HttpListener output stream", ex); - } - } - } - - public void End() - { - Close(); - } - - public void Flush() - { - response.OutputStream.Flush(); - } - - public bool IsClosed - { - get; - private set; - } - - public void SetContentLength(long contentLength) - { - //you can happily set the Content-Length header in Asp.Net - //but HttpListener will complain if you do - you have to set ContentLength64 on the response. - //workaround: HttpListener throws "The parameter is incorrect" exceptions when we try to set the Content-Length header - response.ContentLength64 = contentLength; - } - - public void SetCookie(Cookie cookie) - { - var cookieStr = cookie.AsHeaderValue(); - response.Headers.Add(HttpHeaders.SetCookie, cookieStr); - } - - public bool SendChunked - { - get { return response.SendChunked; } - set { response.SendChunked = value; } - } - - public bool KeepAlive { get; set; } - - public void ClearCookies() - { - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs deleted file mode 100644 index 5f122fb96..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ /dev/null @@ -1,169 +0,0 @@ -using MediaBrowser.Model.Logging; -using ServiceStack.Web; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using ServiceStack; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class StreamWriter - /// </summary> - public class StreamWriter : IStreamWriter, IAsyncStreamWriter, IHasOptions - { - private ILogger Logger { get; set; } - - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// <summary> - /// Gets or sets the source stream. - /// </summary> - /// <value>The source stream.</value> - private Stream SourceStream { get; set; } - - /// <summary> - /// The _options - /// </summary> - private readonly IDictionary<string, string> _options = new Dictionary<string, string>(); - /// <summary> - /// Gets the options. - /// </summary> - /// <value>The options.</value> - public IDictionary<string, string> Options - { - get { return _options; } - } - - public Action OnComplete { get; set; } - public Action OnError { get; set; } - private readonly byte[] _bytes; - - /// <summary> - /// Initializes a new instance of the <see cref="StreamWriter" /> class. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="logger">The logger.</param> - public StreamWriter(Stream source, string contentType, ILogger logger) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException("contentType"); - } - - SourceStream = source; - Logger = logger; - - Options["Content-Type"] = contentType; - - if (source.CanSeek) - { - Options["Content-Length"] = source.Length.ToString(UsCulture); - } - } - - /// <summary> - /// Initializes a new instance of the <see cref="StreamWriter"/> class. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="logger">The logger.</param> - public StreamWriter(byte[] source, string contentType, ILogger logger) - : this(new MemoryStream(source), contentType, logger) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException("contentType"); - } - - _bytes = source; - Logger = logger; - - Options["Content-Type"] = contentType; - - Options["Content-Length"] = source.Length.ToString(UsCulture); - } - - private const int BufferSize = 81920; - - /// <summary> - /// Writes to. - /// </summary> - /// <param name="responseStream">The response stream.</param> - public void WriteTo(Stream responseStream) - { - try - { - if (_bytes != null) - { - responseStream.Write(_bytes, 0, _bytes.Length); - } - else - { - using (var src = SourceStream) - { - src.CopyTo(responseStream, BufferSize); - } - } - } - catch (Exception ex) - { - Logger.ErrorException("Error streaming data", ex); - - if (OnError != null) - { - OnError(); - } - - throw; - } - finally - { - if (OnComplete != null) - { - OnComplete(); - } - } - } - - public async Task WriteToAsync(Stream responseStream) - { - try - { - if (_bytes != null) - { - await responseStream.WriteAsync(_bytes, 0, _bytes.Length); - } - else - { - using (var src = SourceStream) - { - await src.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); - } - } - } - catch (Exception ex) - { - Logger.ErrorException("Error streaming data", ex); - - if (OnError != null) - { - OnError(); - } - - throw; - } - finally - { - if (OnComplete != null) - { - OnComplete(); - } - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs b/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs deleted file mode 100644 index d91f316d6..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/SwaggerService.cs +++ /dev/null @@ -1,43 +0,0 @@ -using MediaBrowser.Controller; -using MediaBrowser.Controller.Net; -using ServiceStack.Web; -using System.IO; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public class SwaggerService : IHasResultFactory, IRestfulService - { - private readonly IServerApplicationPaths _appPaths; - - public SwaggerService(IServerApplicationPaths appPaths) - { - _appPaths = appPaths; - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetSwaggerResource request) - { - var swaggerDirectory = Path.Combine(_appPaths.ApplicationResourcesPath, "swagger-ui"); - - var requestedFile = Path.Combine(swaggerDirectory, request.ResourceName.Replace('/', Path.DirectorySeparatorChar)); - - return ResultFactory.GetStaticFileResult(Request, requestedFile).Result; - } - - /// <summary> - /// Gets or sets the result factory. - /// </summary> - /// <value>The result factory.</value> - public IHttpResultFactory ResultFactory { get; set; } - - /// <summary> - /// Gets or sets the request context. - /// </summary> - /// <value>The request context.</value> - public IRequest Request { get; set; } - } -} |
