diff options
6 files changed, 56 insertions, 115 deletions
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index 6ea1bd08e..2232b3eeb 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -66,11 +66,6 @@ namespace Emby.Server.Implementations.HttpClientManager // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c ServicePointManager.Expect100Continue = false; - -#if NET46 -// Trakt requests sometimes fail without this - ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls; -#endif } /// <summary> @@ -106,23 +101,6 @@ namespace Emby.Server.Implementations.HttpClientManager return client; } - private static WebRequest CreateWebRequest(string url) - { - try - { - return WebRequest.Create(url); - } - catch (NotSupportedException) - { - //Webrequest creation does fail on MONO randomly when using WebRequest.Create - //the issue occurs in the GetCreator method here: http://www.oschina.net/code/explore/mono-2.8.1/mcs/class/System/System.Net/WebRequest.cs - - var type = Type.GetType("System.Net.HttpRequestCreator, System, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"); - var creator = Activator.CreateInstance(type, nonPublic: true) as IWebRequestCreate; - return creator.Create(new Uri(url)) as HttpWebRequest; - } - } - private WebRequest GetRequest(HttpRequestOptions options, string method) { string url = options.Url; @@ -135,7 +113,7 @@ namespace Emby.Server.Implementations.HttpClientManager url = url.Replace(userInfo + "@", string.Empty); } - var request = CreateWebRequest(url); + var request = WebRequest.Create(url); if (request is HttpWebRequest httpWebRequest) { @@ -627,14 +605,16 @@ namespace Emby.Server.Implementations.HttpClientManager var exception = new HttpException(webException.Message, webException); - var response = webException.Response as HttpWebResponse; - if (response != null) + using (var response = webException.Response as HttpWebResponse) { - exception.StatusCode = response.StatusCode; - - if ((int)response.StatusCode == 429) + if (response != null) { - client.LastTimeout = DateTime.UtcNow; + exception.StatusCode = response.StatusCode; + + if ((int)response.StatusCode == 429) + { + client.LastTimeout = DateTime.UtcNow; + } } } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 7445fd3c2..75ca57ebb 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -422,18 +422,20 @@ namespace Emby.Server.Implementations.HttpServer /// <summary> /// Pres the process optimized result. /// </summary> - private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) + private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options) { bool noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; + AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified); if (!noCache) { - if (IsNotModified(requestContext, cacheKey)) + DateTime.TryParse(requestContext.Headers.Get("If-Modified-Since"), out var ifModifiedSinceHeader); + + if (IsNotModified(ifModifiedSinceHeader, options.CacheDuration, options.DateLastModified)) { - AddAgeHeader(responseHeaders, lastDateModified); - AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration); + AddAgeHeader(responseHeaders, options.DateLastModified); - var result = new HttpResult(Array.Empty<byte>(), contentType ?? "text/html", HttpStatusCode.NotModified); + var result = new HttpResult(Array.Empty<byte>(), options.ContentType ?? "text/html", HttpStatusCode.NotModified); AddResponseHeaders(result, responseHeaders); @@ -441,8 +443,6 @@ namespace Emby.Server.Implementations.HttpServer } } - AddCachingHeaders(responseHeaders, cacheKeyString, cacheDuration); - return null; } @@ -487,9 +487,6 @@ namespace Emby.Server.Implementations.HttpServer options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path); } - var cacheKey = path + options.DateLastModified.Value.Ticks; - - options.CacheKey = cacheKey.GetMD5(); options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare)); options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); @@ -520,7 +517,6 @@ namespace Emby.Server.Implementations.HttpServer return GetStaticResult(requestContext, new StaticResultOptions { CacheDuration = cacheDuration, - CacheKey = cacheKey, ContentFactory = factoryFn, ContentType = contentType, DateLastModified = lastDateModified, @@ -534,14 +530,10 @@ namespace Emby.Server.Implementations.HttpServer options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); var contentType = options.ContentType; - var etag = requestContext.Headers.Get("If-None-Match"); - var cacheKey = etag != null ? new Guid(etag.Trim('\"')) : Guid.Empty; - if (!cacheKey.Equals(Guid.Empty)) + if (!string.IsNullOrEmpty(requestContext.Headers.Get("If-Modified-Since"))) { - 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); + var result = GetCachedResult(requestContext, options.ResponseHeaders, options); if (result != null) { @@ -553,6 +545,8 @@ namespace Emby.Server.Implementations.HttpServer var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase); var factoryFn = options.ContentFactory; var responseHeaders = options.ResponseHeaders; + AddCachingHeaders(responseHeaders, options.CacheDuration, false, options.DateLastModified); + AddAgeHeader(responseHeaders, options.DateLastModified); var rangeHeader = requestContext.Headers.Get("Range"); @@ -566,21 +560,10 @@ namespace Emby.Server.Implementations.HttpServer }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); - // Generate an ETag based on identifying information - TODO read contents from filesystem instead? - var responseId = $"{hasHeaders.ContentType}{options.Path}{hasHeaders.TotalContentLength}"; - var hashedId = MD5.Create().ComputeHash(Encoding.Default.GetBytes(responseId)); - hasHeaders.Headers["ETag"] = new Guid(hashedId).ToString("N"); - return hasHeaders; } var stream = await factoryFn().ConfigureAwait(false); - // Generate an etag based on stream content - var streamHash = MD5.Create().ComputeHash(stream); - var newEtag = new Guid(streamHash).ToString("N"); - - // reset position so the response can re-use it -- TODO is this ok? - stream.Position = 0; var totalContentLength = options.ContentLength; if (!totalContentLength.HasValue) @@ -603,7 +586,6 @@ namespace Emby.Server.Implementations.HttpServer }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); - hasHeaders.Headers["ETag"] = newEtag; return hasHeaders; } else @@ -628,7 +610,6 @@ namespace Emby.Server.Implementations.HttpServer }; AddResponseHeaders(hasHeaders, options.ResponseHeaders); - hasHeaders.Headers["ETag"] = newEtag; return hasHeaders; } } @@ -641,37 +622,28 @@ namespace Emby.Server.Implementations.HttpServer /// <summary> /// Adds the caching responseHeaders. /// </summary> - private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration) + private void AddCachingHeaders(IDictionary<string, string> responseHeaders, TimeSpan? cacheDuration, + bool noCache, DateTime? lastModifiedDate) { - if (cacheDuration.HasValue) - { - responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); - } - else if (!string.IsNullOrEmpty(cacheKey)) - { - responseHeaders["Cache-Control"] = "public"; - } - else + if (noCache) { responseHeaders["Cache-Control"] = "no-cache, no-store, must-revalidate"; responseHeaders["pragma"] = "no-cache, no-store, must-revalidate"; + return; } - AddExpiresHeader(responseHeaders, cacheKey, cacheDuration); - } - - /// <summary> - /// Adds the expires header. - /// </summary> - private static void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration) - { if (cacheDuration.HasValue) { - responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r"); + responseHeaders["Cache-Control"] = "public, max-age=" + cacheDuration.Value.TotalSeconds; } - else if (string.IsNullOrEmpty(cacheKey)) + else { - responseHeaders["Expires"] = "-1"; + responseHeaders["Cache-Control"] = "public"; + } + + if (lastModifiedDate.HasValue) + { + responseHeaders["Last-Modified"] = lastModifiedDate.ToString(); } } @@ -687,32 +659,6 @@ namespace Emby.Server.Implementations.HttpServer 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) - { - var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match"); - - bool hasCacheKey = !cacheKey.Equals(Guid.Empty); - - // Validate If-None-Match - if (hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader)) - { - if (Guid.TryParse(ifNoneMatchHeader, out var ifNoneMatch) - && cacheKey.Equals(ifNoneMatch)) - { - return true; - } - } - - return false; - } /// <summary> /// Determines whether [is not modified] [the specified if modified since]. diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs index a54de12be..7a179913a 100644 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -12,8 +12,6 @@ namespace MediaBrowser.Controller.Net public string ContentType { get; set; } public TimeSpan? CacheDuration { get; set; } public DateTime? DateLastModified { get; set; } - public Guid CacheKey { get; set; } - public Func<Task<Stream>> ContentFactory { get; set; } public bool IsHeadRequest { get; set; } diff --git a/deployment/debian-package-x64/pkg-src/changelog b/deployment/debian-package-x64/pkg-src/changelog index d5872e4a7..a4b55a4ec 100644 --- a/deployment/debian-package-x64/pkg-src/changelog +++ b/deployment/debian-package-x64/pkg-src/changelog @@ -1,4 +1,4 @@ -jellyfin (10.2.0~rc1) unstable; urgency=medium +jellyfin (10.2.0~rc2) unstable; urgency=medium * jellyfin: * PR452 Use EF Core for Activity database @@ -70,7 +70,11 @@ jellyfin (10.2.0~rc1) unstable; urgency=medium * PR842 Use VAAPI-enabled ffmpeg * PR852 Use SQLitePCL.pretty.netstandard on NuGet * PR853 Fix poor handling of cache directories - * PR8 rebase to latest master + * PR864: Add support for ZIP plugin archives + * PR868: Fix audio streaming via BaseProgressiveStreamingService + * PR869: Remove DLL support and require all packages/plugins to be zip archives + * PR872: Fix potential NullReferenceException + * PR890: Drop ETag and use Last-Modified header * jellyfin-web: * PR24 Add Master codeowners * PR34 Revert "Add Master codeowners" @@ -91,12 +95,14 @@ jellyfin (10.2.0~rc1) unstable; urgency=medium * PR95 add display language option back * PR112 Removed seasonal theme support * PR116 Consolidate all strings into a single file per language + * PR117 Fix volume slider behavior * PR118 Enable and fix PiP for Safari * PR119 Make the toggle track visible on all themes * PR121 Fix syntax error in site.js * PR127 Change sharedcomponents module to core + * PR135 Make sure fallback culture is always available - -- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 10 Feb 2019 01:18:23 -0500 + -- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 13 Feb 2019 01:03:20 -0500 jellyfin (10.1.0-1) unstable; urgency=medium diff --git a/deployment/debian-package-x64/pkg-src/control b/deployment/debian-package-x64/pkg-src/control index 74bebeaf1..88d10438b 100644 --- a/deployment/debian-package-x64/pkg-src/control +++ b/deployment/debian-package-x64/pkg-src/control @@ -18,6 +18,11 @@ Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server Architecture: any -Depends: at, libsqlite3-0, ffmpeg, libfontconfig1, libfreetype6, libssl1.0.0 | libssl1.0.2 +Depends: at, + libsqlite3-0, + ffmpeg (<7:4.1) | jellyfin-ffmpeg, + libfontconfig1, + libfreetype6, + libssl1.0.0 | libssl1.0.2 Description: Jellyfin is a home media server. It is built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono. It features a REST-based api with built-in documentation to facilitate client development. We also have client libraries for our api to enable rapid development. diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec index 343d23e91..03fc0b6ff 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec @@ -8,7 +8,7 @@ Name: jellyfin Version: 10.2.0 -Release: rc1%{?dist} +Release: rc2%{?dist} Summary: The Free Software Media Browser License: GPLv2 URL: https://jellyfin.media @@ -140,7 +140,7 @@ fi %systemd_postun_with_restart jellyfin.service %changelog -* Sun Feb 10 2019 Jellyfin Packaging Team <packaging@jellyfin.org> +* Wed Feb 13 2019 Jellyfin Packaging Team <packaging@jellyfin.org> - jellyfin: - PR452 Use EF Core for Activity database - PR535 Clean up streambuilder @@ -211,7 +211,11 @@ fi - PR842 Use VAAPI-enabled ffmpeg - PR852 Use SQLitePCL.pretty.netstandard on NuGet - PR853 Fix poor handling of cache directories -- PR8 rebase to latest master +- PR864 Add support for ZIP plugin archives +- PR868 Fix audio streaming via BaseProgressiveStreamingService +- PR869 Remove DLL support and require all packages/plugins to be zip archives +- PR872 Fix potential NullReferenceException +- PR890 Drop ETag and use Last-Modified header - jellyfin-web: - PR24 Add Master codeowners - PR34 Revert "Add Master codeowners" @@ -232,10 +236,12 @@ fi - PR95 add display language option back - PR112 Removed seasonal theme support - PR116 Consolidate all strings into a single file per language +- PR117 Fix volume slider behavior - PR118 Enable and fix PiP for Safari - PR119 Make the toggle track visible on all themes - PR121 Fix syntax error in site.js - PR127 Change sharedcomponents module to core +- PR135 Make sure fallback culture is always available * Sun Jan 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org> - jellyfin: - PR335 Build scripts and build system consolidation. |
