update file responses
This commit is contained in:
parent
ff03a01853
commit
198cb1bc9c
|
@ -392,10 +392,27 @@ namespace Emby.Common.Implementations.IO
|
|||
|
||||
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)
|
||||
|
|
65
Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
Normal file
65
Emby.Drawing.Skia/Emby.Drawing.Skia.csproj
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?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>
|
||||
<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>
|
25
Emby.Drawing.Skia/Properties/AssemblyInfo.cs
Normal file
25
Emby.Drawing.Skia/Properties/AssemblyInfo.cs
Normal 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
|
||||
//
|
|
@ -1132,7 +1132,8 @@ namespace Emby.Server.Core
|
|||
// Custom cert
|
||||
return new CertificateInfo
|
||||
{
|
||||
Path = ServerConfigurationManager.Configuration.CertificatePath
|
||||
Path = ServerConfigurationManager.Configuration.CertificatePath,
|
||||
Password = ServerConfigurationManager.Configuration.CertificatePassword
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -228,7 +228,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
_streamFactory,
|
||||
_enableDualModeSockets,
|
||||
GetRequest,
|
||||
_fileSystem);
|
||||
_fileSystem,
|
||||
_environment);
|
||||
}
|
||||
|
||||
private IHttpRequest GetRequest(HttpListenerContext httpContext)
|
||||
|
@ -452,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
var date = DateTime.Now;
|
||||
var httpRes = httpReq.Response;
|
||||
bool enableLog = false;
|
||||
bool logHeaders = false;
|
||||
string urlToLog = null;
|
||||
string remoteIp = null;
|
||||
|
||||
|
@ -490,13 +492,14 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
var urlString = url.OriginalString;
|
||||
enableLog = EnableLogging(urlString, localPath);
|
||||
urlToLog = urlString;
|
||||
logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
|
||||
if (enableLog)
|
||||
{
|
||||
urlToLog = GetUrlToLog(urlString);
|
||||
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) ||
|
||||
|
@ -611,7 +614,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
var duration = DateTime.Now - date;
|
||||
|
||||
LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration);
|
||||
LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -353,31 +353,28 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
/// <summary>
|
||||
/// Pres the process optimized result.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <param name="responseHeaders">The responseHeaders.</param>
|
||||
/// <param name="cacheKey">The cache key.</param>
|
||||
/// <param name="cacheKeyString">The cache key string.</param>
|
||||
/// <param name="lastDateModified">The last date modified.</param>
|
||||
/// <param name="cacheDuration">Duration of the cache.</param>
|
||||
/// <param name="contentType">Type of the content.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType)
|
||||
{
|
||||
responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
|
||||
|
||||
if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
|
||||
var noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
|
||||
if (!noCache)
|
||||
{
|
||||
AddAgeHeader(responseHeaders, lastDateModified);
|
||||
AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
|
||||
if (IsNotModified(requestContext, cacheKey, lastDateModified, 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;
|
||||
}
|
||||
|
@ -673,11 +670,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
/// <summary>
|
||||
/// Adds the caching responseHeaders.
|
||||
/// </summary>
|
||||
/// <param name="responseHeaders">The responseHeaders.</param>
|
||||
/// <param name="cacheKey">The cache key.</param>
|
||||
/// <param name="lastDateModified">The last date modified.</param>
|
||||
/// <param name="cacheDuration">Duration of the cache.</param>
|
||||
private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration)
|
||||
private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache)
|
||||
{
|
||||
// Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
|
||||
// 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");
|
||||
}
|
||||
|
||||
if (cacheDuration.HasValue)
|
||||
if (!noCache && cacheDuration.HasValue)
|
||||
{
|
||||
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";
|
||||
}
|
||||
|
@ -701,18 +694,15 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
|
||||
AddExpiresHeader(responseHeaders, cacheKey, cacheDuration);
|
||||
AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the expires header.
|
||||
/// </summary>
|
||||
/// <param name="responseHeaders">The responseHeaders.</param>
|
||||
/// <param name="cacheKey">The cache key.</param>
|
||||
/// <param name="cacheDuration">Duration of the cache.</param>
|
||||
private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration)
|
||||
private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache)
|
||||
{
|
||||
if (cacheDuration.HasValue)
|
||||
if (!noCache && cacheDuration.HasValue)
|
||||
{
|
||||
responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Services;
|
||||
using SocketHttpListener.Net;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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>
|
||||
|
@ -32,12 +43,13 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
/// <param name="url">The URL.</param>
|
||||
/// <param name="endPoint">The end point.</param>
|
||||
/// <param name="duration">The duration.</param>
|
||||
public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration)
|
||||
public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration, QueryParamCollection headers)
|
||||
{
|
||||
var durationMs = duration.TotalMilliseconds;
|
||||
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
|
||||
|
||||
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using MediaBrowser.Model.Cryptography;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Services;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Text;
|
||||
using SocketHttpListener.Primitives;
|
||||
|
||||
|
@ -30,8 +31,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
|||
private readonly IFileSystem _fileSystem;
|
||||
private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
|
||||
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;
|
||||
_certificate = certificate;
|
||||
|
@ -44,6 +46,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
|||
_enableDualMode = enableDualMode;
|
||||
_httpRequestFactory = httpRequestFactory;
|
||||
_fileSystem = fileSystem;
|
||||
_environment = environment;
|
||||
}
|
||||
|
||||
public Action<Exception, IRequest, bool> ErrorHandler { get; set; }
|
||||
|
@ -56,7 +59,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
|||
public void Start(IEnumerable<string> urlPrefixes)
|
||||
{
|
||||
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;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Services;
|
||||
using SocketHttpListener.Net;
|
||||
using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
|
||||
using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
|
||||
|
@ -66,6 +67,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
|
|||
_response.AddHeader(name, value);
|
||||
}
|
||||
|
||||
public QueryParamCollection Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
return _response.Headers;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetHeader(string name)
|
||||
{
|
||||
return _response.Headers[name];
|
||||
|
|
|
@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Images
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -671,12 +671,15 @@ namespace MediaBrowser.Api.Playback
|
|||
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)
|
||||
{
|
||||
Request = request,
|
||||
RequestedUrl = url,
|
||||
UserAgent = Request.UserAgent,
|
||||
EnableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params)
|
||||
EnableDlnaHeaders = enableDlnaHeaders
|
||||
};
|
||||
|
||||
var auth = AuthorizationContext.GetAuthorizationInfo(Request);
|
||||
|
|
|
@ -55,6 +55,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// </summary>
|
||||
/// <value>The value pointing to the file system where the ssl certiifcate is located..</value>
|
||||
public string CertificatePath { get; set; }
|
||||
public string CertificatePassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is port authorized.
|
||||
|
|
|
@ -108,6 +108,8 @@ namespace MediaBrowser.Model.IO
|
|||
/// <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, FileOpenOptions fileOpenOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Opens the read.
|
||||
/// </summary>
|
||||
|
@ -402,4 +404,46 @@ namespace MediaBrowser.Model.IO
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,8 @@ namespace MediaBrowser.Model.Services
|
|||
//Add Metadata to Response
|
||||
Dictionary<string, object> Items { get; }
|
||||
|
||||
QueryParamCollection Headers { get; }
|
||||
|
||||
Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,6 +200,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
MergeCriticRating(source, target, lockedFields, replaceData);
|
||||
MergeAwards(source, target, lockedFields, replaceData);
|
||||
MergeTrailers(source, target, lockedFields, replaceData);
|
||||
MergeVideoInfo(source, target, lockedFields, replaceData);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Net", "Emby.Dr
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Skia", "Emby.Drawing.Skia\Emby.Drawing.Skia.csproj", "{2312DA6D-FF86-4597-9777-BCEEC32D96DD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Text;
|
||||
using SocketHttpListener.Primitives;
|
||||
|
||||
|
@ -33,8 +34,9 @@ namespace SocketHttpListener.Net
|
|||
private readonly ITextEncoding _textEncoding;
|
||||
private readonly IMemoryStreamFactory _memoryStreamFactory;
|
||||
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;
|
||||
_logger = logger;
|
||||
|
@ -44,6 +46,7 @@ namespace SocketHttpListener.Net
|
|||
_memoryStreamFactory = memoryStreamFactory;
|
||||
_textEncoding = textEncoding;
|
||||
_fileSystem = fileSystem;
|
||||
_environment = environment;
|
||||
|
||||
this.secure = secure;
|
||||
this.cert = cert;
|
||||
|
@ -109,7 +112,7 @@ namespace SocketHttpListener.Net
|
|||
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);
|
||||
lock (listener.unregistered)
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace SocketHttpListener.Net
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ using MediaBrowser.Model.Cryptography;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Text;
|
||||
using SocketHttpListener.Primitives;
|
||||
|
||||
|
@ -41,8 +42,9 @@ namespace SocketHttpListener.Net
|
|||
private readonly ITextEncoding _textEncoding;
|
||||
private readonly IStreamFactory _streamFactory;
|
||||
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;
|
||||
this.sock = sock;
|
||||
|
@ -53,6 +55,7 @@ namespace SocketHttpListener.Net
|
|||
_memoryStreamFactory = memoryStreamFactory;
|
||||
_textEncoding = textEncoding;
|
||||
_fileSystem = fileSystem;
|
||||
_environment = environment;
|
||||
_streamFactory = streamFactory;
|
||||
}
|
||||
|
||||
|
@ -84,9 +87,9 @@ namespace SocketHttpListener.Net
|
|||
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);
|
||||
|
||||
|
@ -217,7 +220,7 @@ namespace SocketHttpListener.Net
|
|||
{
|
||||
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
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Text;
|
||||
using SocketHttpListener.Primitives;
|
||||
|
||||
|
@ -22,6 +23,7 @@ namespace SocketHttpListener.Net
|
|||
internal ITextEncoding TextEncoding { get; private set; }
|
||||
internal IMemoryStreamFactory MemoryStreamFactory { get; private set; }
|
||||
internal INetworkManager NetworkManager { get; private set; }
|
||||
internal IEnvironmentInfo EnvironmentInfo { get; private set; }
|
||||
|
||||
public bool EnableDualMode { get; set; }
|
||||
|
||||
|
@ -40,7 +42,7 @@ namespace SocketHttpListener.Net
|
|||
|
||||
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;
|
||||
CryptoProvider = cryptoProvider;
|
||||
|
@ -50,19 +52,20 @@ namespace SocketHttpListener.Net
|
|||
TextEncoding = textEncoding;
|
||||
MemoryStreamFactory = memoryStreamFactory;
|
||||
FileSystem = fileSystem;
|
||||
EnvironmentInfo = environmentInfo;
|
||||
prefixes = new HttpListenerPrefixCollection(logger, this);
|
||||
registry = new Dictionary<HttpListenerContext, HttpListenerContext>();
|
||||
connections = new Dictionary<HttpConnection, HttpConnection>();
|
||||
auth_schemes = AuthenticationSchemes.Anonymous;
|
||||
}
|
||||
|
||||
public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem)
|
||||
:this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, 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, environmentInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem)
|
||||
: this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, 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, environmentInfo)
|
||||
{
|
||||
_certificate = certificate;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Text;
|
||||
using SocketHttpListener.Primitives;
|
||||
|
||||
|
@ -28,8 +29,9 @@ namespace SocketHttpListener.Net
|
|||
private readonly IAcceptSocket _socket;
|
||||
private readonly bool _supportsDirectSocketAccess;
|
||||
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;
|
||||
_memoryStreamFactory = memoryStreamFactory;
|
||||
|
@ -38,6 +40,7 @@ namespace SocketHttpListener.Net
|
|||
_socket = socket;
|
||||
_supportsDirectSocketAccess = supportsDirectSocketAccess;
|
||||
_logger = logger;
|
||||
_environment = environment;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
|
@ -344,7 +347,20 @@ namespace SocketHttpListener.Net
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -355,11 +371,53 @@ namespace SocketHttpListener.Net
|
|||
|
||||
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
|
||||
{
|
||||
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];
|
||||
int bytesRead;
|
||||
|
||||
|
||||
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
if (bytesRead == 0)
|
||||
|
|
Loading…
Reference in New Issue
Block a user