diff options
Diffstat (limited to 'MediaBrowser.Common.Implementations')
19 files changed, 584 insertions, 273 deletions
diff --git a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs index 23d40cf67f..3d759ca545 100644 --- a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs +++ b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs @@ -4,6 +4,7 @@ using SharpCompress.Archive.SevenZip; using SharpCompress.Archive.Tar; using SharpCompress.Common; using SharpCompress.Reader; +using SharpCompress.Reader.Zip; using System.IO; namespace MediaBrowser.Common.Implementations.Archiving @@ -48,6 +49,21 @@ namespace MediaBrowser.Common.Implementations.Archiving } } + public void ExtractAllFromZip(Stream source, string targetPath, bool overwriteExistingFiles) + { + using (var reader = ZipReader.Open(source)) + { + var options = ExtractOptions.ExtractFullPath; + + if (overwriteExistingFiles) + { + options = options | ExtractOptions.Overwrite; + } + + reader.WriteAllToDirectory(targetPath, options); + } + } + /// <summary> /// Extracts all from7z. /// </summary> diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index c59d1a3b00..4de1adcfa8 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -193,17 +193,28 @@ namespace MediaBrowser.Common.Implementations } } + public virtual string OperatingSystemDisplayName + { + get { return Environment.OSVersion.VersionString; } + } + /// <summary> /// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class. /// </summary> - protected BaseApplicationHost(TApplicationPathsType applicationPaths, ILogManager logManager) + protected BaseApplicationHost(TApplicationPathsType applicationPaths, + ILogManager logManager, + IFileSystem fileSystem) { FailedAssemblies = new List<string>(); ApplicationPaths = applicationPaths; LogManager = logManager; + FileSystemManager = fileSystem; ConfigurationManager = GetConfigurationManager(); + + // Initialize this early in case the -v command line option is used + Logger = LogManager.GetLogger("App"); } /// <summary> @@ -225,7 +236,6 @@ namespace MediaBrowser.Common.Implementations JsonSerializer = CreateJsonSerializer(); - Logger = LogManager.GetLogger("App"); OnLoggerLoaded(true); LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false); @@ -263,7 +273,7 @@ namespace MediaBrowser.Common.Implementations if (!isFirstLoad) { - LogEnvironmentInfo(Logger, ApplicationPaths); + LogEnvironmentInfo(Logger, ApplicationPaths, false); } // Put the app config in the log for troubleshooting purposes @@ -282,20 +292,36 @@ namespace MediaBrowser.Common.Implementations } } - public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths) + public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup) { - logger.Info("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())); + logger.LogMultiline("Media Browser", LogSeverity.Info, GetBaseExceptionMessage(appPaths)); + } - logger.Info("Server: {0}", Environment.MachineName); - logger.Info("Operating system: {0}", Environment.OSVersion.ToString()); - logger.Info("Processor count: {0}", Environment.ProcessorCount); - logger.Info("64-Bit OS: {0}", Environment.Is64BitOperatingSystem); - logger.Info("64-Bit Process: {0}", Environment.Is64BitProcess); - logger.Info("Program data path: {0}", appPaths.ProgramDataPath); + protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths) + { + var builder = new StringBuilder(); + + builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs()))); + + builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion)); + builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount)); + builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem)); + builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess)); + builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath)); + + Type type = Type.GetType("Mono.Runtime"); + if (type != null) + { + MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); + if (displayName != null) + { + builder.AppendLine("Mono: " + displayName.Invoke(null, null)); + } + } - logger.Info("Application Path: {0}", appPaths.ApplicationPath); + builder.AppendLine(string.Format("Application Path: {0}", appPaths.ApplicationPath)); - logger.Info("*** When reporting issues please include the entire log file. ***".ToUpper()); + return builder; } protected virtual IJsonSerializer CreateJsonSerializer() @@ -353,14 +379,13 @@ namespace MediaBrowser.Common.Implementations /// <returns>Task.</returns> public virtual Task RunStartupTasks() { - return Task.Run(() => - { - Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false)); + Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false)); + + ConfigureAutorun (); - Task.Run(() => ConfigureAutorun()); + ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated; - ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated; - }); + return Task.FromResult (true); } /// <summary> @@ -424,46 +449,43 @@ namespace MediaBrowser.Common.Implementations /// <returns>Task.</returns> protected virtual Task RegisterResources(IProgress<double> progress) { - return Task.Run(() => - { - RegisterSingleInstance(ConfigurationManager); - RegisterSingleInstance<IApplicationHost>(this); + RegisterSingleInstance(ConfigurationManager); + RegisterSingleInstance<IApplicationHost>(this); - RegisterSingleInstance<IApplicationPaths>(ApplicationPaths); + RegisterSingleInstance<IApplicationPaths>(ApplicationPaths); - TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, Logger); + TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, Logger); - RegisterSingleInstance(JsonSerializer); - RegisterSingleInstance(XmlSerializer); + RegisterSingleInstance(JsonSerializer); + RegisterSingleInstance(XmlSerializer); - RegisterSingleInstance(LogManager); - RegisterSingleInstance(Logger); + RegisterSingleInstance(LogManager); + RegisterSingleInstance(Logger); - RegisterSingleInstance(TaskManager); + RegisterSingleInstance(TaskManager); - FileSystemManager = CreateFileSystemManager(); - RegisterSingleInstance(FileSystemManager); + RegisterSingleInstance(FileSystemManager); - HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager, ConfigurationManager); - RegisterSingleInstance(HttpClient); + HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager); + RegisterSingleInstance(HttpClient); - NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager")); - RegisterSingleInstance(NetworkManager); + NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager")); + RegisterSingleInstance(NetworkManager); - SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, NetworkManager, LogManager); - RegisterSingleInstance(SecurityManager); + SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, NetworkManager, LogManager); + RegisterSingleInstance(SecurityManager); - InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, NetworkManager, ConfigurationManager); - RegisterSingleInstance(InstallationManager); + InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, NetworkManager, ConfigurationManager); + RegisterSingleInstance(InstallationManager); - ZipClient = new ZipClient(); - RegisterSingleInstance(ZipClient); + ZipClient = new ZipClient(); + RegisterSingleInstance(ZipClient); - IsoManager = new IsoManager(); - RegisterSingleInstance(IsoManager); + IsoManager = new IsoManager(); + RegisterSingleInstance(IsoManager); - RegisterModules(); - }); + RegisterModules(); + return Task.FromResult (true); } private void RegisterModules() @@ -485,11 +507,6 @@ namespace MediaBrowser.Common.Implementations } } - protected virtual IFileSystem CreateFileSystemManager() - { - return new CommonFileSystem(Logger, true); - } - /// <summary> /// Gets a list of types within an assembly /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference @@ -685,18 +702,11 @@ namespace MediaBrowser.Common.Implementations return parts; } - private Version _version; /// <summary> - /// Gets the current application version + /// Gets the application version. /// </summary> /// <value>The application version.</value> - public Version ApplicationVersion - { - get - { - return _version ?? (_version = GetType().Assembly.GetName().Version); - } - } + public abstract Version ApplicationVersion { get; } /// <summary> /// Handles the ConfigurationUpdated event of the ConfigurationManager control. diff --git a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs index 668b1395d8..4ad63b2e3f 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs @@ -1,6 +1,4 @@ using MediaBrowser.Common.Configuration; -using System; -using System.Configuration; using System.IO; namespace MediaBrowser.Common.Implementations @@ -12,45 +10,16 @@ namespace MediaBrowser.Common.Implementations public abstract class BaseApplicationPaths : IApplicationPaths { /// <summary> - /// The _use debug path - /// </summary> - private readonly bool _useDebugPath; - - /// <summary> - /// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class. - /// </summary> - protected BaseApplicationPaths(bool useDebugPath, string applicationPath) - { - _useDebugPath = useDebugPath; - ApplicationPath = applicationPath; - } - - /// <summary> /// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class. /// </summary> protected BaseApplicationPaths(string programDataPath, string applicationPath) { - _programDataPath = programDataPath; + ProgramDataPath = programDataPath; ApplicationPath = applicationPath; } public string ApplicationPath { get; private set; } - - /// <summary> - /// The _program data path - /// </summary> - private string _programDataPath; - /// <summary> - /// Gets the path to the program data folder - /// </summary> - /// <value>The program data path.</value> - public string ProgramDataPath - { - get - { - return _programDataPath ?? (_programDataPath = GetProgramDataPath()); - } - } + public string ProgramDataPath { get; private set; } /// <summary> /// Gets the path to the system folder @@ -202,35 +171,5 @@ namespace MediaBrowser.Common.Implementations return Path.Combine(CachePath, "temp"); } } - - /// <summary> - /// Gets the path to the application's ProgramDataFolder - /// </summary> - /// <returns>System.String.</returns> - private string GetProgramDataPath() - { - var programDataPath = _useDebugPath ? ConfigurationManager.AppSettings["DebugProgramDataPath"] : ConfigurationManager.AppSettings["ReleaseProgramDataPath"]; - - programDataPath = programDataPath.Replace("%ApplicationData%", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); - - // If it's a relative path, e.g. "..\" - if (!Path.IsPathRooted(programDataPath)) - { - var path = Path.GetDirectoryName(ApplicationPath); - - if (string.IsNullOrEmpty(path)) - { - throw new ApplicationException("Unable to determine running assembly location"); - } - - programDataPath = Path.Combine(path, programDataPath); - - programDataPath = Path.GetFullPath(programDataPath); - } - - Directory.CreateDirectory(programDataPath); - - return programDataPath; - } } } diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs index 4a70697fa2..c53947e443 100644 --- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs +++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.Common.Implementations.Configuration UpdateCachePath(); } - public void AddParts(IEnumerable<IConfigurationFactory> factories) + public virtual void AddParts(IEnumerable<IConfigurationFactory> factories) { _configurationFactories = factories.ToArray(); @@ -208,20 +208,51 @@ namespace MediaBrowser.Common.Implementations.Configuration lock (_configurationSyncLock) { - return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer); + return LoadConfiguration(file, configurationType); } }); } + private object LoadConfiguration(string path, Type configurationType) + { + try + { + return XmlSerializer.DeserializeFromFile(configurationType, path); + } + catch (FileNotFoundException) + { + return Activator.CreateInstance(configurationType); + } + catch (DirectoryNotFoundException) + { + return Activator.CreateInstance(configurationType); + } + catch (Exception ex) + { + Logger.ErrorException("Error loading configuration file: {0}", ex, path); + + return Activator.CreateInstance(configurationType); + } + } + public void SaveConfiguration(string key, object configuration) { - var configurationType = GetConfigurationType(key); + var configurationStore = GetConfigurationStore(key); + var configurationType = configurationStore.ConfigurationType; if (configuration.GetType() != configurationType) { throw new ArgumentException("Expected configuration type is " + configurationType.Name); } + var validatingStore = configurationStore as IValidatingConfiguration; + if (validatingStore != null) + { + var currentConfiguration = GetConfiguration(key); + + validatingStore.Validate(currentConfiguration, configuration); + } + EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs { Key = key, @@ -239,6 +270,11 @@ namespace MediaBrowser.Common.Implementations.Configuration XmlSerializer.SerializeToFile(configuration, path); } + OnNamedConfigurationUpdated(key, configuration); + } + + protected virtual void OnNamedConfigurationUpdated(string key, object configuration) + { EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs { Key = key, @@ -249,9 +285,14 @@ namespace MediaBrowser.Common.Implementations.Configuration public Type GetConfigurationType(string key) { - return _configurationStores - .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)) + return GetConfigurationStore(key) .ConfigurationType; } + + private ConfigurationStore GetConfigurationStore(string key) + { + return _configurationStores + .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)); + } } } diff --git a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs new file mode 100644 index 0000000000..ff5b8bd599 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs @@ -0,0 +1,59 @@ +using MediaBrowser.Model.Serialization; +using System; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Common.Implementations.Configuration +{ + /// <summary> + /// Class ConfigurationHelper + /// </summary> + public static class ConfigurationHelper + { + /// <summary> + /// Reads an xml configuration file from the file system + /// It will immediately re-serialize and save if new serialization data is available due to property changes + /// </summary> + /// <param name="type">The type.</param> + /// <param name="path">The path.</param> + /// <param name="xmlSerializer">The XML serializer.</param> + /// <returns>System.Object.</returns> + public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer) + { + object configuration; + + byte[] buffer = null; + + // Use try/catch to avoid the extra file system lookup using File.Exists + try + { + buffer = File.ReadAllBytes(path); + + configuration = xmlSerializer.DeserializeFromBytes(type, buffer); + } + catch (Exception) + { + configuration = Activator.CreateInstance(type); + } + + using (var stream = new MemoryStream()) + { + xmlSerializer.SerializeToStream(configuration, stream); + + // Take the object we just got and serialize it back to bytes + var newBytes = stream.ToArray(); + + // If the file didn't exist before, or if something has changed, re-save + if (buffer == null || !buffer.SequenceEqual(newBytes)) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + // Save it after load in case we got new items + File.WriteAllBytes(path, newBytes); + } + + return configuration; + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs index 5af236026e..7c0dc1e1f0 100644 --- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs +++ b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs @@ -38,7 +38,10 @@ namespace MediaBrowser.Common.Implementations.Devices _logger.Error("Invalid value found in device id file"); } } - catch (FileNotFoundException ex) + catch (DirectoryNotFoundException) + { + } + catch (FileNotFoundException) { } catch (Exception ex) diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 5702af6d1c..1f82c5eb0c 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Common.Configuration; +using System.Net.Sockets; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; @@ -12,7 +14,6 @@ using System.IO; using System.Linq; using System.Net; using System.Net.Cache; -using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -40,7 +41,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; - private readonly IConfigurationManager _config; /// <summary> /// Initializes a new instance of the <see cref="HttpClientManager" /> class. @@ -51,7 +51,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// <exception cref="System.ArgumentNullException">appPaths /// or /// logger</exception> - public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IConfigurationManager config) + public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem) { if (appPaths == null) { @@ -64,7 +64,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager _logger = logger; _fileSystem = fileSystem; - _config = config; _appPaths = appPaths; // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c @@ -122,7 +121,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } request.Method = method; - request.Timeout = 20000; + request.Timeout = options.TimeoutMs; if (!string.IsNullOrEmpty(options.Host)) { @@ -134,9 +133,22 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager request.Referer = options.Referer; } + //request.ServicePoint.BindIPEndPointDelegate = BindIPEndPointCallback; + return request; } + private static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount) + { + // Prefer local ipv4 + if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) + { + return new IPEndPoint(IPAddress.IPv6Any, 0); + } + + return new IPEndPoint(IPAddress.Any, 0); + } + private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options) { foreach (var header in options.RequestHeaders.ToList()) @@ -157,6 +169,20 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } /// <summary> + /// The _semaphoreLocks + /// </summary> + private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>(StringComparer.OrdinalIgnoreCase); + /// <summary> + /// Gets the lock. + /// </summary> + /// <param name="url">The filename.</param> + /// <returns>System.Object.</returns> + private SemaphoreSlim GetLock(string url) + { + return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1)); + } + + /// <summary> /// Gets the response internal. /// </summary> /// <param name="options">The options.</param> @@ -216,6 +242,110 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// </exception> public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod) { + HttpResponseInfo response; + + if (options.CacheMode == CacheMode.None) + { + response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false); + return response; + } + + var url = options.Url; + var urlHash = url.ToLower().GetMD5().ToString("N"); + var semaphore = GetLock(url); + + var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash); + + response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false); + if (response != null) + { + return response; + } + + await semaphore.WaitAsync(options.CancellationToken).ConfigureAwait(false); + + try + { + response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false); + if (response != null) + { + return response; + } + + response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false); + + if (response.StatusCode == HttpStatusCode.OK) + { + await CacheResponse(response, responseCachePath).ConfigureAwait(false); + } + + return response; + } + finally + { + semaphore.Release(); + } + } + + private async Task<HttpResponseInfo> GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url) + { + try + { + if (_fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow) + { + using (var stream = _fileSystem.GetFileStream(responseCachePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) + { + var memoryStream = new MemoryStream(); + + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); + memoryStream.Position = 0; + + return new HttpResponseInfo + { + ResponseUrl = url, + Content = memoryStream, + StatusCode = HttpStatusCode.OK, + Headers = new NameValueCollection(), + ContentLength = memoryStream.Length + }; + } + } + } + catch (FileNotFoundException) + { + + } + catch (DirectoryNotFoundException) + { + + } + + return null; + } + + private async Task CacheResponse(HttpResponseInfo response, string responseCachePath) + { + Directory.CreateDirectory(Path.GetDirectoryName(responseCachePath)); + + using (var responseStream = response.Content) + { + using (var fileStream = _fileSystem.GetFileStream(responseCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true)) + { + var memoryStream = new MemoryStream(); + + await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false); + + memoryStream.Position = 0; + await memoryStream.CopyToAsync(fileStream).ConfigureAwait(false); + + memoryStream.Position = 0; + response.Content = memoryStream; + } + } + } + + private async Task<HttpResponseInfo> SendAsyncInternal(HttpRequestOptions options, string httpMethod) + { ValidateParams(options); options.CancellationToken.ThrowIfCancellationRequested(); @@ -236,11 +366,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager !string.IsNullOrEmpty(options.RequestContent) || string.Equals(httpMethod, "post", StringComparison.OrdinalIgnoreCase)) { - var bytes = options.RequestContentBytes ?? + var bytes = options.RequestContentBytes ?? Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty); httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded"; - + httpWebRequest.ContentLength = bytes.Length; httpWebRequest.GetRequestStream().Write(bytes, 0, bytes.Length); } @@ -271,7 +401,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager if (!options.BufferContent) { - var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false); + var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false); var httpResponse = (HttpWebResponse)response; @@ -279,10 +409,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.CancellationToken.ThrowIfCancellationRequested(); - return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse)); + return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse), httpResponse); } - using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) + using (var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false)) { var httpResponse = (HttpWebResponse)response; @@ -298,7 +428,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager memoryStream.Position = 0; - return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length); + return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length, null); } } } @@ -315,21 +445,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager throw exception; } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); - - throw new HttpException(ex.Message, ex); - } - catch (WebException ex) - { - throw GetException(ex, options); - } catch (Exception ex) { - _logger.ErrorException("Error getting response from " + options.Url, ex); - - throw; + throw GetException(ex, options); } finally { @@ -361,9 +479,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return exception; } - private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength) + private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable) { - return new HttpResponseInfo + return new HttpResponseInfo(disposable) { Content = content, @@ -517,21 +635,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return GetResponseInfo(httpResponse, tempFile, contentLength); } } - catch (OperationCanceledException ex) - { - throw GetTempFileException(ex, options, tempFile); - } - catch (HttpRequestException ex) - { - throw GetTempFileException(ex, options, tempFile); - } - catch (WebException ex) - { - throw GetTempFileException(ex, options, tempFile); - } catch (Exception ex) { - throw GetTempFileException(ex, options, tempFile); + DeleteTempFile(tempFile); + throw GetException(ex, options); } finally { @@ -556,44 +663,25 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// <summary> - /// Handles the temp file exception. - /// </summary> - /// <param name="ex">The ex.</param> - /// <param name="options">The options.</param> - /// <param name="tempFile">The temp file.</param> - /// <returns>Task.</returns> - /// <exception cref="HttpException"></exception> - private Exception GetTempFileException(Exception ex, HttpRequestOptions options, string tempFile) + private Exception GetException(Exception ex, HttpRequestOptions options) { - var operationCanceledException = ex as OperationCanceledException; + var webException = ex as WebException + ?? ex.InnerException as WebException; - if (operationCanceledException != null) + if (webException != null) { - // Cleanup - DeleteTempFile(tempFile); - - return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException); + return GetException(webException, options); } - _logger.ErrorException("Error getting response from " + options.Url, ex); - - // Cleanup - DeleteTempFile(tempFile); + var operationCanceledException = ex as OperationCanceledException + ?? ex.InnerException as OperationCanceledException; - var httpRequestException = ex as HttpRequestException; - - if (httpRequestException != null) + if (operationCanceledException != null) { - return new HttpException(ex.Message, ex); + return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException); } - var webException = ex as WebException; - - if (webException != null) - { - throw GetException(webException, options); - } + _logger.ErrorException("Error getting response from " + options.Url, ex); return ex; } @@ -724,5 +812,47 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { return Post(url, postData, null, cancellationToken); } + + private Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout) + { + var taskCompletion = new TaskCompletionSource<WebResponse>(); + + Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null); + + ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, timeout, true); + asyncTask.ContinueWith(task => + { + taskCompletion.TrySetResult(task.Result); + + }, TaskContinuationOptions.NotOnFaulted); + + // Handle errors + asyncTask.ContinueWith(task => + { + if (task.Exception != null) + { + taskCompletion.TrySetException(task.Exception); + } + else + { + taskCompletion.TrySetException(new List<Exception>()); + } + + }, TaskContinuationOptions.OnlyOnFaulted); + + return taskCompletion.Task; + } + + private static void TimeoutCallback(object state, bool timedOut) + { + if (timedOut) + { + WebRequest request = (WebRequest)state; + if (state != null) + { + request.Abort(); + } + } + } } } diff --git a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs index 2d67ec9756..68df0e52ac 100644 --- a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs +++ b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs @@ -15,11 +15,31 @@ namespace MediaBrowser.Common.Implementations.IO protected ILogger Logger; private readonly bool _supportsAsyncFileStreams; + private char[] _invalidFileNameChars; - public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams) + public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool usePresetInvalidFileNameChars) { Logger = logger; _supportsAsyncFileStreams = supportsAsyncFileStreams; + + SetInvalidFileNameChars(usePresetInvalidFileNameChars); + } + + private void SetInvalidFileNameChars(bool usePresetInvalidFileNameChars) + { + // GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac. + + if (usePresetInvalidFileNameChars) + { + _invalidFileNameChars = new char[41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', + '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', + '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' }; + } + else + { + _invalidFileNameChars = Path.GetInvalidFileNameChars(); + } } /// <summary> @@ -129,18 +149,6 @@ namespace MediaBrowser.Common.Implementations.IO /// The space char /// </summary> private const char SpaceChar = ' '; - /// <summary> - /// The invalid file name chars - /// </summary> - #if __MonoCS__ - //GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac. - private static readonly char[] InvalidFileNameChars = new char [41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', - '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', - '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', - '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' }; - #else - private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars(); - #endif /// <summary> /// Takes a filename and removes invalid characters @@ -157,7 +165,7 @@ namespace MediaBrowser.Common.Implementations.IO var builder = new StringBuilder(filename); - foreach (var c in InvalidFileNameChars) + foreach (var c in _invalidFileNameChars) { builder = builder.Replace(c, SpaceChar); } @@ -300,7 +308,7 @@ namespace MediaBrowser.Common.Implementations.IO { throw new ArgumentNullException("path"); } - + return path.IndexOf(parentPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) != -1; } @@ -310,12 +318,12 @@ namespace MediaBrowser.Common.Implementations.IO { throw new ArgumentNullException("path"); } - + var parent = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(parent)) { - return false; + return false; } return true; @@ -382,5 +390,24 @@ namespace MediaBrowser.Common.Implementations.IO { return Path.GetFileNameWithoutExtension(path); } + + public bool IsPathFile(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException("path"); + } + + // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\ + + if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 && + !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + return true; + + //return Path.IsPathRooted(path); + } } } diff --git a/MediaBrowser.Common.Implementations/Logging/LogHelper.cs b/MediaBrowser.Common.Implementations/Logging/LogHelper.cs index 91e937ca7c..8080c2111c 100644 --- a/MediaBrowser.Common.Implementations/Logging/LogHelper.cs +++ b/MediaBrowser.Common.Implementations/Logging/LogHelper.cs @@ -15,6 +15,11 @@ namespace MediaBrowser.Common.Implementations.Logging /// <returns>StringBuilder.</returns> public static StringBuilder GetLogMessage(Exception exception) { + if (exception == null) + { + throw new ArgumentNullException("exception"); + } + var messageText = new StringBuilder(); messageText.AppendLine(exception.Message); diff --git a/MediaBrowser.Common.Implementations/Logging/NLogger.cs b/MediaBrowser.Common.Implementations/Logging/NLogger.cs index c87b58f70a..29b6188903 100644 --- a/MediaBrowser.Common.Implementations/Logging/NLogger.cs +++ b/MediaBrowser.Common.Implementations/Logging/NLogger.cs @@ -14,6 +14,8 @@ namespace MediaBrowser.Common.Implementations.Logging /// </summary> private readonly NLog.Logger _logger; + private readonly ILogManager _logManager; + /// <summary> /// The _lock object /// </summary> @@ -23,8 +25,10 @@ namespace MediaBrowser.Common.Implementations.Logging /// Initializes a new instance of the <see cref="NLogger" /> class. /// </summary> /// <param name="name">The name.</param> - public NLogger(string name) + /// <param name="logManager">The log manager.</param> + public NLogger(string name, ILogManager logManager) { + _logManager = logManager; lock (LockObject) { _logger = NLog.LogManager.GetLogger(name); @@ -96,6 +100,13 @@ namespace MediaBrowser.Common.Implementations.Logging var messageText = LogHelper.GetLogMessage(exception); + var prefix = _logManager.ExceptionMessagePrefix; + + if (!string.IsNullOrWhiteSpace(prefix)) + { + messageText.Insert(0, prefix); + } + LogMultiline(message, level, messageText); } diff --git a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs index b8ee60f018..77d9f80f9f 100644 --- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs +++ b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs @@ -2,6 +2,7 @@ using NLog; using NLog.Config; using NLog.Targets; +using NLog.Targets.Wrappers; using System; using System.IO; using System.Linq; @@ -34,6 +35,12 @@ namespace MediaBrowser.Common.Implementations.Logging public string LogFilePath { get; private set; } /// <summary> + /// Gets or sets the exception message prefix. + /// </summary> + /// <value>The exception message prefix.</value> + public string ExceptionMessagePrefix { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="NlogManager" /> class. /// </summary> /// <param name="logDirectory">The log directory.</param> @@ -42,6 +49,8 @@ namespace MediaBrowser.Common.Implementations.Logging { LogDirectory = logDirectory; LogFilePrefix = logFileNamePrefix; + + LogManager.Configuration = new LoggingConfiguration (); } private LogSeverity _severity = LogSeverity.Debug; @@ -86,16 +95,22 @@ namespace MediaBrowser.Common.Implementations.Logging /// <param name="level">The level.</param> private void AddFileTarget(string path, LogSeverity level) { - var logFile = new FileTarget + RemoveTarget("ApplicationLogFileWrapper"); + + var wrapper = new AsyncTargetWrapper (); + wrapper.Name = "ApplicationLogFileWrapper"; + + var logFile = new FileTarget { FileName = path, Layout = "${longdate} ${level} - ${logger}: ${message}" }; - RemoveTarget("ApplicationLogFile"); logFile.Name = "ApplicationLogFile"; - AddLogTarget(logFile, level); + wrapper.WrappedTarget = logFile; + + AddLogTarget(wrapper, level); } /// <summary> @@ -150,7 +165,7 @@ namespace MediaBrowser.Common.Implementations.Logging /// <returns>ILogger.</returns> public ILogger GetLogger(string name) { - return new NLogger(name); + return new NLogger(name, this); } /// <summary> @@ -216,22 +231,27 @@ namespace MediaBrowser.Common.Implementations.Logging public void AddConsoleOutput() { + RemoveTarget("ConsoleTargetWrapper"); + + var wrapper = new AsyncTargetWrapper (); + wrapper.Name = "ConsoleTargetWrapper"; + var target = new ConsoleTarget() { Layout = "${level}, ${logger}, ${message}", Error = false }; - RemoveTarget("ConsoleTarget"); - target.Name = "ConsoleTarget"; - AddLogTarget(target, LogSeverity); + wrapper.WrappedTarget = target; + + AddLogTarget(wrapper, LogSeverity); } public void RemoveConsoleOutput() { - RemoveTarget("ConsoleTarget"); + RemoveTarget("ConsoleTargetWrapper"); } } } diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 81df199241..ff08c31bce 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -11,10 +11,10 @@ <AssemblyName>MediaBrowser.Common.Implementations</AssemblyName> <FileAlignment>512</FileAlignment> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> - <RestorePackages>true</RestorePackages> <ProductVersion>10.0.0</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <RestorePackages>true</RestorePackages> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -27,7 +27,7 @@ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> + <DebugType>none</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> <DefineConstants>TRACE</DefineConstants> @@ -36,7 +36,7 @@ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' "> - <DebugType>pdbonly</DebugType> + <DebugType>none</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release Mono\</OutputPath> <DefineConstants>TRACE</DefineConstants> @@ -52,24 +52,23 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\NLog.3.1.0.0\lib\net45\NLog.dll</HintPath> </Reference> - <Reference Include="SimpleInjector, Version=2.5.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> + <Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath> + </Reference> + <Reference Include="SimpleInjector, Version=2.6.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\SimpleInjector.2.5.2\lib\net45\SimpleInjector.dll</HintPath> + <HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.dll</HintPath> </Reference> - <Reference Include="SimpleInjector.Diagnostics, Version=2.5.2.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> + <Reference Include="SimpleInjector.Diagnostics, Version=2.6.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\SimpleInjector.2.5.2\lib\net45\SimpleInjector.Diagnostics.dll</HintPath> + <HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.Diagnostics.dll</HintPath> </Reference> <Reference Include="System" /> - <Reference Include="System.Configuration" /> <Reference Include="System.Core" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Net" /> - <Reference Include="System.Net.Http" /> <Reference Include="System.Xml" /> - <Reference Include="SharpCompress"> - <HintPath>..\packages\sharpcompress.0.10.2\lib\net40\SharpCompress.dll</HintPath> - </Reference> <Reference Include="ServiceStack.Text"> <HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath> </Reference> @@ -82,6 +81,7 @@ <Compile Include="BaseApplicationHost.cs" /> <Compile Include="BaseApplicationPaths.cs" /> <Compile Include="Configuration\BaseConfigurationManager.cs" /> + <Compile Include="Configuration\ConfigurationHelper.cs" /> <Compile Include="Devices\DeviceId.cs" /> <Compile Include="HttpClientManager\HttpClientInfo.cs" /> <Compile Include="HttpClientManager\HttpClientManager.cs" /> @@ -97,6 +97,7 @@ <Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" /> <Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" /> <Compile Include="ScheduledTasks\Tasks\ReloadLoggerFileTask.cs" /> + <Compile Include="Security\MbAdmin.cs" /> <Compile Include="Security\MBLicenseFile.cs" /> <Compile Include="Security\PluginSecurityManager.cs" /> <Compile Include="Security\RegRecord.cs" /> @@ -120,11 +121,11 @@ </ItemGroup> <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> - <Import Project="$(SolutionDir)\.nuget\NuGet.targets" /> <PropertyGroup> - <PostBuildEvent Condition=" '$(ConfigurationName)' != 'Release Mono' ">if '$(ConfigurationName)' == 'Release' ( -xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i -)</PostBuildEvent> + <PostBuildEvent /> + </PropertyGroup> + <PropertyGroup> + <PostBuildEvent /> </PropertyGroup> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index 8159be6340..bf6ebf7ef7 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -24,14 +24,46 @@ namespace MediaBrowser.Common.Implementations.Networking /// <returns>IPAddress.</returns> public IEnumerable<string> GetLocalIpAddresses() { - var list = GetIPsDefault().Where(i => !IPAddress.IsLoopback(i)).Select(i => i.ToString()).ToList(); + var list = GetIPsDefault() + .Where(i => !IPAddress.IsLoopback(i)) + .Select(i => i.ToString()) + .Where(FilterIpAddress) + .ToList(); if (list.Count > 0) { return list; } - return GetLocalIpAddressesFallback(); + return GetLocalIpAddressesFallback().Where(FilterIpAddress); + } + + private bool FilterIpAddress(string address) + { + if (address.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return true; + } + + private bool IsInPrivateAddressSpace(string endpoint) + { + // Private address space: + // http://en.wikipedia.org/wiki/Private_network + + return + + // If url was requested with computer name, we may see this + endpoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 || + + endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase); } public bool IsInLocalNetwork(string endpoint) @@ -46,6 +78,11 @@ namespace MediaBrowser.Common.Implementations.Networking throw new ArgumentNullException("endpoint"); } + if (IsInPrivateAddressSpace(endpoint)) + { + return true; + } + const int lengthMatch = 4; if (endpoint.Length >= lengthMatch) @@ -59,24 +96,6 @@ namespace MediaBrowser.Common.Implementations.Networking } } - // Private address space: - // http://en.wikipedia.org/wiki/Private_network - - var isPrivate = - - // If url was requested with computer name, we may see this - endpoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 || - - endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase); - - if (isPrivate) - { - return true; - } - IPAddress address; if (resolveHost && !IPAddress.TryParse(endpoint, out address)) { diff --git a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs index 8f3225f4e9..63381efcdf 100644 --- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs +++ b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs @@ -101,6 +101,10 @@ namespace MediaBrowser.Common.Implementations.Security { contents = File.ReadAllLines(licenseFile); } + catch (DirectoryNotFoundException) + { + (File.Create(licenseFile)).Close(); + } catch (FileNotFoundException) { (File.Create(licenseFile)).Close(); diff --git a/MediaBrowser.Common.Implementations/Security/MbAdmin.cs b/MediaBrowser.Common.Implementations/Security/MbAdmin.cs new file mode 100644 index 0000000000..ab4a83257c --- /dev/null +++ b/MediaBrowser.Common.Implementations/Security/MbAdmin.cs @@ -0,0 +1,13 @@ + +namespace MediaBrowser.Common.Implementations.Security +{ + public class MbAdmin + { + public const string HttpUrl = "http://www.mb3admin.com/admin/"; + + /// <summary> + /// Leaving as http for now until we get it squared away + /// </summary> + public const string HttpsUrl = "http://www.mb3admin.com/admin/"; + } +} diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs index 4d693e40c3..3e81e839fc 100644 --- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs +++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Common.Implementations.Security /// </summary> public class PluginSecurityManager : ISecurityManager { - private const string MBValidateUrl = Constants.Constants.MbAdminUrl + "service/registration/validate"; + private const string MBValidateUrl = MbAdmin.HttpsUrl + "service/registration/validate"; /// <summary> /// The _is MB supporter @@ -160,13 +160,12 @@ namespace MediaBrowser.Common.Implementations.Security return new SupporterInfo(); } - var url = Constants.Constants.MbAdminUrl + "/service/supporter/retrieve?key=" + key; + var url = MbAdmin.HttpsUrl + "/service/supporter/retrieve?key=" + key; using (var stream = await _httpClient.Get(url, CancellationToken.None).ConfigureAwait(false)) { var response = _jsonSerializer.DeserializeFromStream<SuppporterInfoResponse>(stream); - var info = new SupporterInfo { Email = response.email, @@ -187,15 +186,18 @@ namespace MediaBrowser.Common.Implementations.Security string mb2Equivalent = null, string version = null) { + var lastChecked = LicenseFile.LastChecked(feature); + //check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho var reg = new RegRecord { - registered = LicenseFile.LastChecked(feature) > DateTime.UtcNow.AddDays(-3) + // Cache the result for up to a week + registered = lastChecked > DateTime.UtcNow.AddDays(-7) }; var success = reg.registered; - if (!reg.registered) + if (!(lastChecked > DateTime.UtcNow.AddDays(-1))) { var mac = _networkManager.GetMacAddress(); var data = new Dictionary<string, string> @@ -206,7 +208,7 @@ namespace MediaBrowser.Common.Implementations.Security { "systemid", _appHost.SystemId }, { "mb2equiv", mb2Equivalent }, { "ver", version }, - { "platform", Environment.OSVersion.VersionString }, + { "platform", _appHost.OperatingSystemDisplayName }, { "isservice", _appHost.IsRunningAsService.ToString().ToLower() } }; diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs index cef744753a..04030522f3 100644 --- a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Serialization; using System; +using System.Collections.Concurrent; using System.IO; using System.Xml; @@ -10,6 +11,17 @@ namespace MediaBrowser.Common.Implementations.Serialization /// </summary> public class XmlSerializer : IXmlSerializer { + // Need to cache these + // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html + private readonly ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer> _serializers = + new ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer>(); + + private System.Xml.Serialization.XmlSerializer GetSerializer(Type type) + { + var key = type.FullName; + return _serializers.GetOrAdd(key, k => new System.Xml.Serialization.XmlSerializer(type)); + } + /// <summary> /// Serializes to writer. /// </summary> @@ -18,7 +30,7 @@ namespace MediaBrowser.Common.Implementations.Serialization private void SerializeToWriter(object obj, XmlTextWriter writer) { writer.Formatting = Formatting.Indented; - var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); + var netSerializer = GetSerializer(obj.GetType()); netSerializer.Serialize(writer, obj); } @@ -32,8 +44,7 @@ namespace MediaBrowser.Common.Implementations.Serialization { using (var reader = new XmlTextReader(stream)) { - var netSerializer = new System.Xml.Serialization.XmlSerializer(type); - + var netSerializer = GetSerializer(type); return netSerializer.Deserialize(reader); } } diff --git a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs index b022dc6719..f3a9859681 100644 --- a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs +++ b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; +using MediaBrowser.Common.Implementations.Security; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Progress; @@ -161,7 +162,7 @@ namespace MediaBrowser.Common.Implementations.Updates { "systemid", _applicationHost.SystemId } }; - using (var json = await _httpClient.Post(Constants.Constants.MbAdminUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false)) + using (var json = await _httpClient.Post(MbAdmin.HttpsUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); @@ -203,7 +204,7 @@ namespace MediaBrowser.Common.Implementations.Updates } } - using (var json = await _httpClient.Get(Constants.Constants.MbAdminUrl + "service/MB3Packages.json", cancellationToken).ConfigureAwait(false)) + using (var json = await _httpClient.Get(MbAdmin.HttpUrl + "service/MB3Packages.json", cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index adc4fe562e..63d288bbbb 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="NLog" version="3.1.0.0" targetFramework="net45" /> - <package id="SharpCompress" version="0.10.2" targetFramework="net45" /> - <package id="SimpleInjector" version="2.5.2" targetFramework="net45" /> + <package id="SimpleInjector" version="2.6.1" targetFramework="net45" /> </packages> |
