Merge pull request #2625 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-05-09 15:21:24 -04:00 committed by GitHub
commit f4a73e90d2
31 changed files with 396 additions and 72 deletions

View file

@ -392,10 +392,27 @@ namespace Emby.Common.Implementations.IO
if (_supportsAsyncFileStreams && isAsync) if (_supportsAsyncFileStreams && isAsync)
{ {
return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144, true); return GetFileStream(path, mode, access, share, FileOpenOptions.Asynchronous);
} }
return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144); return GetFileStream(path, mode, access, share, FileOpenOptions.None);
}
public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions)
{
if (_sharpCifsFileSystem.IsEnabledForPath(path))
{
return _sharpCifsFileSystem.GetFileStream(path, mode, access, share);
}
var defaultBufferSize = 4096;
return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), defaultBufferSize, GetFileOptions(fileOpenOptions));
}
private FileOptions GetFileOptions(FileOpenOptions mode)
{
var val = (int)mode;
return (FileOptions)val;
} }
private FileMode GetFileMode(FileOpenMode mode) private FileMode GetFileMode(FileOpenMode mode)

View file

@ -45,7 +45,7 @@
"System.Net.Requests": "4.3.0", "System.Net.Requests": "4.3.0",
"System.Xml.ReaderWriter": "4.3.0", "System.Xml.ReaderWriter": "4.3.0",
"System.Xml.XmlSerializer": "4.3.0", "System.Xml.XmlSerializer": "4.3.0",
"System.Net.Http": "4.3.0", "System.Net.Http": "4.3.2",
"System.Net.Primitives": "4.3.0", "System.Net.Primitives": "4.3.0",
"System.Net.Sockets": "4.3.0", "System.Net.Sockets": "4.3.0",
"System.Net.NetworkInformation": "4.3.0", "System.Net.NetworkInformation": "4.3.0",

View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2312DA6D-FF86-4597-9777-BCEEC32D96DD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Emby.Drawing.Skia</RootNamespace>
<AssemblyName>Emby.Drawing.Skia</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
<Name>MediaBrowser.Common</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
<Name>MediaBrowser.Controller</Name>
</ProjectReference>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="SkiaSharp, Version=1.57.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\SkiaSharp.1.57.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- 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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,25 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Emby.Drawing.Skia")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Emby.Drawing.Skia")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="SkiaSharp" version="1.57.1" targetFramework="portable45-net45+win8" />
</packages>

View file

@ -1132,7 +1132,8 @@ namespace Emby.Server.Core
// Custom cert // Custom cert
return new CertificateInfo return new CertificateInfo
{ {
Path = ServerConfigurationManager.Configuration.CertificatePath Path = ServerConfigurationManager.Configuration.CertificatePath,
Password = ServerConfigurationManager.Configuration.CertificatePassword
}; };
} }

View file

@ -68,7 +68,7 @@
"System.AppDomain": "2.0.11", "System.AppDomain": "2.0.11",
"System.Globalization.Extensions": "4.3.0", "System.Globalization.Extensions": "4.3.0",
"System.IO.FileSystem.Watcher": "4.3.0", "System.IO.FileSystem.Watcher": "4.3.0",
"System.Net.Security": "4.3.0", "System.Net.Security": "4.3.1",
"System.Security.Cryptography.X509Certificates": "4.3.0", "System.Security.Cryptography.X509Certificates": "4.3.0",
"System.Runtime.Extensions": "4.3.0", "System.Runtime.Extensions": "4.3.0",
"MediaBrowser.Model": { "MediaBrowser.Model": {

View file

@ -308,7 +308,7 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL"> <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath> <HintPath>..\packages\SQLitePCLRaw.core.1.1.5\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
</ItemGroup> </ItemGroup>

View file

@ -228,7 +228,8 @@ namespace Emby.Server.Implementations.HttpServer
_streamFactory, _streamFactory,
_enableDualModeSockets, _enableDualModeSockets,
GetRequest, GetRequest,
_fileSystem); _fileSystem,
_environment);
} }
private IHttpRequest GetRequest(HttpListenerContext httpContext) private IHttpRequest GetRequest(HttpListenerContext httpContext)
@ -452,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer
var date = DateTime.Now; var date = DateTime.Now;
var httpRes = httpReq.Response; var httpRes = httpReq.Response;
bool enableLog = false; bool enableLog = false;
bool logHeaders = false;
string urlToLog = null; string urlToLog = null;
string remoteIp = null; string remoteIp = null;
@ -490,13 +492,14 @@ namespace Emby.Server.Implementations.HttpServer
var urlString = url.OriginalString; var urlString = url.OriginalString;
enableLog = EnableLogging(urlString, localPath); enableLog = EnableLogging(urlString, localPath);
urlToLog = urlString; urlToLog = urlString;
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
if (enableLog) if (enableLog)
{ {
urlToLog = GetUrlToLog(urlString); urlToLog = GetUrlToLog(urlString);
remoteIp = httpReq.RemoteIp; remoteIp = httpReq.RemoteIp;
LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent); LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent, logHeaders ? httpReq.Headers : null);
} }
if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) || if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
@ -611,7 +614,7 @@ namespace Emby.Server.Implementations.HttpServer
var duration = DateTime.Now - date; var duration = DateTime.Now - date;
LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration); LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null);
} }
} }
} }

View file

@ -353,31 +353,28 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary> /// <summary>
/// Pres the process optimized result. /// Pres the process optimized result.
/// </summary> /// </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) 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); responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) var noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
if (!noCache)
{ {
AddAgeHeader(responseHeaders, lastDateModified); if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration); {
AddAgeHeader(responseHeaders, lastDateModified);
AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache);
var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified); var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
AddResponseHeaders(result, responseHeaders); AddResponseHeaders(result, responseHeaders);
return result; return result;
}
} }
AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration); AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache);
return null; return null;
} }
@ -673,11 +670,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary> /// <summary>
/// Adds the caching responseHeaders. /// Adds the caching responseHeaders.
/// </summary> /// </summary>
/// <param name="responseHeaders">The responseHeaders.</param> private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache)
/// <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 // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
// https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching
@ -687,11 +680,11 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r");
} }
if (cacheDuration.HasValue) if (!noCache && cacheDuration.HasValue)
{ {
responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
} }
else if (!string.IsNullOrEmpty(cacheKey)) else if (!noCache && !string.IsNullOrEmpty(cacheKey))
{ {
responseHeaders["Cache-Control"] = "public"; responseHeaders["Cache-Control"] = "public";
} }
@ -701,18 +694,15 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["pragma"] = "no-cache, no-store, must-revalidate"; responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
} }
AddExpiresHeader(responseHeaders, cacheKey, cacheDuration); AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache);
} }
/// <summary> /// <summary>
/// Adds the expires header. /// Adds the expires header.
/// </summary> /// </summary>
/// <param name="responseHeaders">The responseHeaders.</param> private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache)
/// <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) if (!noCache && cacheDuration.HasValue)
{ {
responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r"); responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
} }

View file

@ -1,6 +1,8 @@
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
using System.Globalization; using System.Globalization;
using System.Linq;
using MediaBrowser.Model.Services;
using SocketHttpListener.Net; using SocketHttpListener.Net;
namespace Emby.Server.Implementations.HttpServer namespace Emby.Server.Implementations.HttpServer
@ -19,9 +21,18 @@ namespace Emby.Server.Implementations.HttpServer
logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty); 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) public static void LogRequest(ILogger logger, string url, string method, string userAgent, QueryParamCollection headers)
{ {
logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty); if (headers == null)
{
logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty);
}
else
{
var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray());
logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
}
} }
/// <summary> /// <summary>
@ -32,12 +43,13 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="url">The URL.</param> /// <param name="url">The URL.</param>
/// <param name="endPoint">The end point.</param> /// <param name="endPoint">The end point.</param>
/// <param name="duration">The duration.</param> /// <param name="duration">The duration.</param>
public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration) public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration, QueryParamCollection headers)
{ {
var durationMs = duration.TotalMilliseconds; var durationMs = duration.TotalMilliseconds;
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms"; 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); var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
} }
} }
} }

View file

@ -10,6 +10,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text; using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives; using SocketHttpListener.Primitives;
@ -30,8 +31,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory; private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
private readonly bool _enableDualMode; private readonly bool _enableDualMode;
private readonly IEnvironmentInfo _environment;
public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem) public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func<HttpListenerContext, IHttpRequest> httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment)
{ {
_logger = logger; _logger = logger;
_certificate = certificate; _certificate = certificate;
@ -44,6 +46,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_enableDualMode = enableDualMode; _enableDualMode = enableDualMode;
_httpRequestFactory = httpRequestFactory; _httpRequestFactory = httpRequestFactory;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_environment = environment;
} }
public Action<Exception, IRequest, bool> ErrorHandler { get; set; } public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
@ -56,7 +59,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
public void Start(IEnumerable<string> urlPrefixes) public void Start(IEnumerable<string> urlPrefixes)
{ {
if (_listener == null) if (_listener == null)
_listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem); _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment);
_listener.EnableDualMode = _enableDualMode; _listener.EnableDualMode = _enableDualMode;

View file

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Services;
using SocketHttpListener.Net; using SocketHttpListener.Net;
using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse; using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
@ -66,6 +67,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
_response.AddHeader(name, value); _response.AddHeader(name, value);
} }
public QueryParamCollection Headers
{
get
{
return _response.Headers;
}
}
public string GetHeader(string name) public string GetHeader(string name)
{ {
return _response.Headers[name]; return _response.Headers[name];

View file

@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Images
{ {
return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
} }
if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre) if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum)
{ {
return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false);
} }

View file

@ -3,5 +3,5 @@
<package id="Emby.XmlTv" version="1.0.8" targetFramework="portable45-net45+win8" /> <package id="Emby.XmlTv" version="1.0.8" targetFramework="portable45-net45+win8" />
<package id="MediaBrowser.Naming" version="1.0.5" targetFramework="portable45-net45+win8" /> <package id="MediaBrowser.Naming" version="1.0.5" targetFramework="portable45-net45+win8" />
<package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" /> <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
<package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="portable45-net45+win8" /> <package id="SQLitePCLRaw.core" version="1.1.5" targetFramework="portable45-net45+win8" />
</packages> </packages>

View file

@ -671,12 +671,15 @@ namespace MediaBrowser.Api.Playback
request.AudioCodec = EncodingHelper.InferAudioCodec(url); request.AudioCodec = EncodingHelper.InferAudioCodec(url);
} }
var enableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) /*||
string.Equals(Request.Headers.Get("GetContentFeatures.DLNA.ORG"), "1", StringComparison.OrdinalIgnoreCase)*/;
var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType) var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType)
{ {
Request = request, Request = request,
RequestedUrl = url, RequestedUrl = url,
UserAgent = Request.UserAgent, UserAgent = Request.UserAgent,
EnableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) EnableDlnaHeaders = enableDlnaHeaders
}; };
var auth = AuthorizationContext.GetAuthorizationInfo(Request); var auth = AuthorizationContext.GetAuthorizationInfo(Request);

View file

@ -55,6 +55,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary> /// </summary>
/// <value>The value pointing to the file system where the ssl certiifcate is located..</value> /// <value>The value pointing to the file system where the ssl certiifcate is located..</value>
public string CertificatePath { get; set; } public string CertificatePath { get; set; }
public string CertificatePassword { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this instance is port authorized. /// Gets or sets a value indicating whether this instance is port authorized.

View file

@ -108,6 +108,8 @@ namespace MediaBrowser.Model.IO
/// <returns>FileStream.</returns> /// <returns>FileStream.</returns>
Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false); Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false);
Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions);
/// <summary> /// <summary>
/// Opens the read. /// Opens the read.
/// </summary> /// </summary>
@ -402,4 +404,46 @@ namespace MediaBrowser.Model.IO
ReadWrite = 3 ReadWrite = 3
} }
//
// Summary:
// Represents advanced options for creating a System.IO.FileStream object.
[Flags]
public enum FileOpenOptions
{
//
// Summary:
// Indicates that the system should write through any intermediate cache and go
// directly to disk.
WriteThrough = int.MinValue,
//
// Summary:
// Indicates that no additional options should be used when creating a System.IO.FileStream
// object.
None = 0,
//
// Summary:
// Indicates that a file is encrypted and can be decrypted only by using the same
// user account used for encryption.
Encrypted = 16384,
//
// Summary:
// Indicates that a file is automatically deleted when it is no longer in use.
DeleteOnClose = 67108864,
//
// Summary:
// Indicates that the file is to be accessed sequentially from beginning to end.
// The system can use this as a hint to optimize file caching. If an application
// moves the file pointer for random access, optimum caching may not occur; however,
// correct operation is still guaranteed.
SequentialScan = 134217728,
//
// Summary:
// Indicates that the file is accessed randomly. The system can use this as a hint
// to optimize file caching.
RandomAccess = 268435456,
//
// Summary:
// Indicates that a file can be used for asynchronous reading and writing.
Asynchronous = 1073741824
}
} }

View file

@ -155,6 +155,8 @@ namespace MediaBrowser.Model.Services
//Add Metadata to Response //Add Metadata to Response
Dictionary<string, object> Items { get; } Dictionary<string, object> Items { get; }
QueryParamCollection Headers { get; }
Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken); Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken);
} }
} }

View file

@ -200,6 +200,7 @@ namespace MediaBrowser.Providers.Manager
MergeCriticRating(source, target, lockedFields, replaceData); MergeCriticRating(source, target, lockedFields, replaceData);
MergeAwards(source, target, lockedFields, replaceData); MergeAwards(source, target, lockedFields, replaceData);
MergeTrailers(source, target, lockedFields, replaceData); MergeTrailers(source, target, lockedFields, replaceData);
MergeVideoInfo(source, target, lockedFields, replaceData);
if (mergeMetadataSettings) if (mergeMetadataSettings)
{ {
@ -307,5 +308,19 @@ namespace MediaBrowser.Providers.Manager
} }
} }
} }
private static void MergeVideoInfo(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
{
var sourceCast = source as Video;
var targetCast = target as Video;
if (sourceCast != null && targetCast != null)
{
if (replaceData || targetCast.Video3DFormat == null)
{
targetCast.Video3DFormat = sourceCast.Video3DFormat;
}
}
}
} }
} }

View file

@ -94,11 +94,11 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL"> <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll</HintPath> <HintPath>..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SQLitePCLRaw.provider.sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=62684c7b4f184e3f, processorArchitecture=MSIL"> <Reference Include="SQLitePCLRaw.provider.sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=62684c7b4f184e3f, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath> <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />

View file

@ -5,6 +5,6 @@
<package id="ServiceStack.Text" version="4.5.4" targetFramework="net46" /> <package id="ServiceStack.Text" version="4.5.4" targetFramework="net46" />
<package id="SharpCompress" version="0.14.0" targetFramework="net46" /> <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
<package id="SimpleInjector" version="3.3.2" targetFramework="net46" /> <package id="SimpleInjector" version="3.3.2" targetFramework="net46" />
<package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="net46" /> <package id="SQLitePCLRaw.core" version="1.1.5" targetFramework="net46" />
<package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.2" targetFramework="net46" /> <package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.5" targetFramework="net46" />
</packages> </packages>

View file

@ -99,12 +99,16 @@
<HintPath>..\packages\SimpleInjector.3.3.2\lib\net45\SimpleInjector.dll</HintPath> <HintPath>..\packages\SimpleInjector.3.3.2\lib\net45\SimpleInjector.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SkiaSharp, Version=1.57.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\SkiaSharp.1.57.1\lib\net45\SkiaSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL"> <Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll</HintPath> <HintPath>..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SQLitePCLRaw.provider.sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=62684c7b4f184e3f, processorArchitecture=MSIL"> <Reference Include="SQLitePCLRaw.provider.sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=62684c7b4f184e3f, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath> <HintPath>..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
@ -1174,6 +1178,13 @@
<PostBuildEvent> <PostBuildEvent>
</PostBuildEvent> </PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<Import Project="..\packages\SkiaSharp.1.57.1\build\net45\SkiaSharp.targets" Condition="Exists('..\packages\SkiaSharp.1.57.1\build\net45\SkiaSharp.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\SkiaSharp.1.57.1\build\net45\SkiaSharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SkiaSharp.1.57.1\build\net45\SkiaSharp.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

View file

@ -5,6 +5,7 @@
<package id="ServiceStack.Text" version="4.5.4" targetFramework="net462" /> <package id="ServiceStack.Text" version="4.5.4" targetFramework="net462" />
<package id="SharpCompress" version="0.14.0" targetFramework="net462" /> <package id="SharpCompress" version="0.14.0" targetFramework="net462" />
<package id="SimpleInjector" version="3.3.2" targetFramework="net462" /> <package id="SimpleInjector" version="3.3.2" targetFramework="net462" />
<package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="net462" /> <package id="SkiaSharp" version="1.57.1" targetFramework="net462" />
<package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.2" targetFramework="net462" /> <package id="SQLitePCLRaw.core" version="1.1.5" targetFramework="net462" />
<package id="SQLitePCLRaw.provider.sqlite3.net45" version="1.1.5" targetFramework="net462" />
</packages> </packages>

View file

@ -80,6 +80,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Net", "Emby.Dr
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Skia", "Emby.Drawing.Skia\Emby.Drawing.Skia.csproj", "{2312DA6D-FF86-4597-9777-BCEEC32D96DD}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -1099,6 +1101,46 @@ Global
{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x64.Build.0 = Release|Any CPU {4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x64.Build.0 = Release|Any CPU
{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.ActiveCfg = Release|Any CPU {4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.ActiveCfg = Release|Any CPU
{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.Build.0 = Release|Any CPU {4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Win32.Build.0 = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x64.ActiveCfg = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x64.Build.0 = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x86.ActiveCfg = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x86.Build.0 = Debug|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Any CPU.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Win32.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Win32.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x64.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x64.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x86.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x86.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Any CPU.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Win32.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Win32.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x64.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x64.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x86.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x86.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Any CPU.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Any CPU.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Mixed Platforms.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Win32.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Win32.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.Build.0 = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.ActiveCfg = Release|Any CPU
{2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.15.1")] [assembly: AssemblyVersion("3.2.15.2")]

View file

@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text; using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives; using SocketHttpListener.Primitives;
@ -33,8 +34,9 @@ namespace SocketHttpListener.Net
private readonly ITextEncoding _textEncoding; private readonly ITextEncoding _textEncoding;
private readonly IMemoryStreamFactory _memoryStreamFactory; private readonly IMemoryStreamFactory _memoryStreamFactory;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IEnvironmentInfo _environment;
public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{ {
this.listener = listener; this.listener = listener;
_logger = logger; _logger = logger;
@ -44,6 +46,7 @@ namespace SocketHttpListener.Net
_memoryStreamFactory = memoryStreamFactory; _memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding; _textEncoding = textEncoding;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_environment = environment;
this.secure = secure; this.secure = secure;
this.cert = cert; this.cert = cert;
@ -109,7 +112,7 @@ namespace SocketHttpListener.Net
return; return;
} }
HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem).ConfigureAwait(false); HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false);
//_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId); //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId);
lock (listener.unregistered) lock (listener.unregistered)

View file

@ -106,7 +106,7 @@ namespace SocketHttpListener.Net
} }
else else
{ {
epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem); epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo);
p[port] = epl; p[port] = epl;
} }

View file

@ -6,6 +6,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text; using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives; using SocketHttpListener.Primitives;
@ -41,8 +42,9 @@ namespace SocketHttpListener.Net
private readonly ITextEncoding _textEncoding; private readonly ITextEncoding _textEncoding;
private readonly IStreamFactory _streamFactory; private readonly IStreamFactory _streamFactory;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IEnvironmentInfo _environment;
private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{ {
_logger = logger; _logger = logger;
this.sock = sock; this.sock = sock;
@ -53,6 +55,7 @@ namespace SocketHttpListener.Net
_memoryStreamFactory = memoryStreamFactory; _memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding; _textEncoding = textEncoding;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_environment = environment;
_streamFactory = streamFactory; _streamFactory = streamFactory;
} }
@ -84,9 +87,9 @@ namespace SocketHttpListener.Net
Init(); Init();
} }
public static async Task<HttpConnection> Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) public static async Task<HttpConnection> Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment)
{ {
var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem); var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment);
await connection.InitStream().ConfigureAwait(false); await connection.InitStream().ConfigureAwait(false);
@ -217,7 +220,7 @@ namespace SocketHttpListener.Net
{ {
var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure; var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure;
o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger); o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment);
} }
else else
{ {

View file

@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text; using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives; using SocketHttpListener.Primitives;
@ -22,6 +23,7 @@ namespace SocketHttpListener.Net
internal ITextEncoding TextEncoding { get; private set; } internal ITextEncoding TextEncoding { get; private set; }
internal IMemoryStreamFactory MemoryStreamFactory { get; private set; } internal IMemoryStreamFactory MemoryStreamFactory { get; private set; }
internal INetworkManager NetworkManager { get; private set; } internal INetworkManager NetworkManager { get; private set; }
internal IEnvironmentInfo EnvironmentInfo { get; private set; }
public bool EnableDualMode { get; set; } public bool EnableDualMode { get; set; }
@ -40,7 +42,7 @@ namespace SocketHttpListener.Net
public Action<HttpListenerContext> OnContext { get; set; } public Action<HttpListenerContext> OnContext { get; set; }
public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem) public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
{ {
_logger = logger; _logger = logger;
CryptoProvider = cryptoProvider; CryptoProvider = cryptoProvider;
@ -50,19 +52,20 @@ namespace SocketHttpListener.Net
TextEncoding = textEncoding; TextEncoding = textEncoding;
MemoryStreamFactory = memoryStreamFactory; MemoryStreamFactory = memoryStreamFactory;
FileSystem = fileSystem; FileSystem = fileSystem;
EnvironmentInfo = environmentInfo;
prefixes = new HttpListenerPrefixCollection(logger, this); prefixes = new HttpListenerPrefixCollection(logger, this);
registry = new Dictionary<HttpListenerContext, HttpListenerContext>(); registry = new Dictionary<HttpListenerContext, HttpListenerContext>();
connections = new Dictionary<HttpConnection, HttpConnection>(); connections = new Dictionary<HttpConnection, HttpConnection>();
auth_schemes = AuthenticationSchemes.Anonymous; auth_schemes = AuthenticationSchemes.Anonymous;
} }
public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem) public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
:this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem) :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
{ {
} }
public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem) public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo)
: this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem) : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo)
{ {
_certificate = certificate; _certificate = certificate;
} }

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Text; using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives; using SocketHttpListener.Primitives;
@ -28,8 +29,9 @@ namespace SocketHttpListener.Net
private readonly IAcceptSocket _socket; private readonly IAcceptSocket _socket;
private readonly bool _supportsDirectSocketAccess; private readonly bool _supportsDirectSocketAccess;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IEnvironmentInfo _environment;
internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger) internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger, IEnvironmentInfo environment)
{ {
this.response = response; this.response = response;
_memoryStreamFactory = memoryStreamFactory; _memoryStreamFactory = memoryStreamFactory;
@ -38,6 +40,7 @@ namespace SocketHttpListener.Net
_socket = socket; _socket = socket;
_supportsDirectSocketAccess = supportsDirectSocketAccess; _supportsDirectSocketAccess = supportsDirectSocketAccess;
_logger = logger; _logger = logger;
_environment = environment;
this.stream = stream; this.stream = stream;
} }
@ -344,7 +347,20 @@ namespace SocketHttpListener.Net
private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
{ {
using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, true)) var allowAsync = _environment.OperatingSystem != OperatingSystem.Windows;
var fileOpenOptions = offset > 0
? FileOpenOptions.RandomAccess
: FileOpenOptions.SequentialScan;
if (allowAsync)
{
fileOpenOptions |= FileOpenOptions.Asynchronous;
}
// use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
{ {
if (offset > 0) if (offset > 0)
{ {
@ -355,11 +371,53 @@ namespace SocketHttpListener.Net
if (count > 0) if (count > 0)
{ {
await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false); if (allowAsync)
{
await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
}
else
{
await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
}
} }
else else
{ {
await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false); if (allowAsync)
{
await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false);
}
else
{
fs.CopyTo(targetStream, 81920);
}
}
}
}
private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
{
var array = new byte[81920];
int bytesRead;
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
{
if (bytesRead == 0)
{
break;
}
var bytesToWrite = Math.Min(bytesRead, copyLength);
if (bytesToWrite > 0)
{
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
}
copyLength -= bytesToWrite;
if (copyLength <= 0)
{
break;
} }
} }
} }
@ -368,7 +426,7 @@ namespace SocketHttpListener.Net
{ {
var array = new byte[81920]; var array = new byte[81920];
int bytesRead; int bytesRead;
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{ {
if (bytesRead == 0) if (bytesRead == 0)