Merge branch 'release/rc-v1.2.0' of github.com:ONLYOFFICE/AppServer into release/rc-v1.2.0
This commit is contained in:
commit
0f971fc5d3
@ -59,7 +59,7 @@ public static class DbQuotaExtension
|
||||
Tenant = -1,
|
||||
Name = "trial",
|
||||
Description = null,
|
||||
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:100,manager:1",
|
||||
Features = "trial,audit,ldap,sso,whitelabel,thirdparty,audit,restore,total_size:107374182400,file_size:100,manager:1",
|
||||
Price = 0,
|
||||
ProductId = null,
|
||||
Visible = false
|
||||
@ -69,7 +69,7 @@ public static class DbQuotaExtension
|
||||
Tenant = -2,
|
||||
Name = "admin",
|
||||
Description = null,
|
||||
Features = "audit,ldap,sso,whitelabel,thirdparty,restore,total_size:107374182400,file_size:1024,manager:1",
|
||||
Features = "audit,ldap,sso,whitelabel,thirdparty,audit,restore,total_size:107374182400,file_size:1024,manager:1",
|
||||
Price = 30,
|
||||
ProductId = "1002",
|
||||
Visible = true
|
||||
@ -79,7 +79,7 @@ public static class DbQuotaExtension
|
||||
Tenant = -3,
|
||||
Name = "startup",
|
||||
Description = null,
|
||||
Features = "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Features = "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Price = 0,
|
||||
ProductId = null,
|
||||
Visible = false
|
||||
|
@ -149,7 +149,7 @@ public abstract class BaseStorage : IDataStore
|
||||
|
||||
public abstract Task<Stream> GetReadStreamAsync(string domain, string path);
|
||||
|
||||
public abstract Task<Stream> GetReadStreamAsync(string domain, string path, int offset);
|
||||
public abstract Task<Stream> GetReadStreamAsync(string domain, string path, long offset);
|
||||
|
||||
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream);
|
||||
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream, ACL acl);
|
||||
|
@ -110,7 +110,7 @@ public class DiscDataStore : BaseStorage
|
||||
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
|
||||
}
|
||||
|
||||
public override Task<Stream> GetReadStreamAsync(string domain, string path, int offset)
|
||||
public override Task<Stream> GetReadStreamAsync(string domain, string path, long offset)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(path);
|
||||
|
||||
@ -123,6 +123,10 @@ public class DiscDataStore : BaseStorage
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
}
|
||||
else if (0 < offset)
|
||||
{
|
||||
throw new InvalidOperationException("Seek stream is not impossible");
|
||||
}
|
||||
|
||||
return Task.FromResult(stream);
|
||||
}
|
||||
@ -130,7 +134,6 @@ public class DiscDataStore : BaseStorage
|
||||
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
|
||||
}
|
||||
|
||||
|
||||
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType, string contentDisposition)
|
||||
{
|
||||
return SaveAsync(domain, path, stream);
|
||||
|
@ -142,7 +142,7 @@ public class GoogleCloudStorage : BaseStorage
|
||||
return GetReadStreamAsync(domain, path, 0);
|
||||
}
|
||||
|
||||
public override async Task<Stream> GetReadStreamAsync(string domain, string path, int offset)
|
||||
public override async Task<Stream> GetReadStreamAsync(string domain, string path, long offset)
|
||||
{
|
||||
var tempStream = _tempStream.Create();
|
||||
|
||||
|
@ -91,7 +91,7 @@ public interface IDataStore
|
||||
///<param name="domain"></param>
|
||||
///<param name="path"></param>
|
||||
///<returns></returns>
|
||||
Task<Stream> GetReadStreamAsync(string domain, string path, int offset);
|
||||
Task<Stream> GetReadStreamAsync(string domain, string path, long offset);
|
||||
|
||||
///<summary>
|
||||
/// Saves the contents of the stream in the repository.
|
||||
|
@ -162,7 +162,7 @@ public class RackspaceCloudStorage : BaseStorage
|
||||
return GetReadStreamAsync(domain, path, 0);
|
||||
}
|
||||
|
||||
public override Task<Stream> GetReadStreamAsync(string domain, string path, int offset)
|
||||
public override Task<Stream> GetReadStreamAsync(string domain, string path, long offset)
|
||||
{
|
||||
return GetReadStreamAsync(domain, path, offset);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ public class S3Storage : BaseStorage
|
||||
return GetReadStreamAsync(domain, path, 0);
|
||||
}
|
||||
|
||||
public override async Task<Stream> GetReadStreamAsync(string domain, string path, int offset)
|
||||
public override async Task<Stream> GetReadStreamAsync(string domain, string path, long offset)
|
||||
{
|
||||
var request = new GetObjectRequest
|
||||
{
|
||||
|
@ -24,6 +24,13 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using System.IO;
|
||||
|
||||
using ASC.Common.Web;
|
||||
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace ASC.Data.Storage.DiscStorage;
|
||||
|
||||
public class StorageHandler
|
||||
@ -86,8 +93,9 @@ public class StorageHandler
|
||||
var headers = header.Length > 0 ? header.Split('&').Select(HttpUtility.UrlDecode) : Array.Empty<string>();
|
||||
|
||||
const int bigSize = 5 * 1024 * 1024;
|
||||
var fileSize = await storage.GetFileSizeAsync(_domain, path);
|
||||
|
||||
if (storage.IsSupportInternalUri && bigSize < await storage.GetFileSizeAsync(_domain, path))
|
||||
if (storage.IsSupportInternalUri && bigSize < fileSize)
|
||||
{
|
||||
var uri = await storage.GetInternalUriAsync(_domain, path, TimeSpan.FromMinutes(15), headers);
|
||||
|
||||
@ -134,7 +142,7 @@ public class StorageHandler
|
||||
|
||||
context.Response.Headers[toCopy] = h.Substring(toCopy.Length + 1);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
context.Response.ContentType = MimeMapping.GetMimeMapping(path);
|
||||
@ -149,8 +157,18 @@ public class StorageHandler
|
||||
context.Response.Headers["Content-Encoding"] = encoding;
|
||||
}
|
||||
|
||||
using (var stream = await storage.GetReadStreamAsync(_domain, path))
|
||||
{
|
||||
|
||||
long offset = 0;
|
||||
var length = ProcessRangeHeader(context, fileSize, ref offset);
|
||||
|
||||
context.Response.Headers["Connection"] = "Keep-Alive";
|
||||
context.Response.Headers["Content-Length"] = length.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
using (var stream = await storage.GetReadStreamAsync(_domain, path, offset))
|
||||
{
|
||||
var responseBufferingFeature = context.Features.Get<IHttpResponseBodyFeature>();
|
||||
responseBufferingFeature?.DisableBuffering();
|
||||
|
||||
await stream.CopyToAsync(context.Response.Body);
|
||||
}
|
||||
|
||||
@ -158,6 +176,38 @@ public class StorageHandler
|
||||
await context.Response.CompleteAsync();
|
||||
}
|
||||
|
||||
private long ProcessRangeHeader(HttpContext context, long fullLength, ref long offset)
|
||||
{
|
||||
if (context == null) throw new ArgumentNullException();
|
||||
if (context.Request.Headers["Range"] == StringValues.Empty) return fullLength;
|
||||
|
||||
long endOffset = -1;
|
||||
|
||||
var range = context.Request.Headers["Range"][0].Split(new[] { '=', '-' });
|
||||
offset = Convert.ToInt64(range[1]);
|
||||
if (range.Count() > 2 && !string.IsNullOrEmpty(range[2]))
|
||||
{
|
||||
endOffset = Convert.ToInt64(range[2]);
|
||||
}
|
||||
if (endOffset < 0 || endOffset >= fullLength)
|
||||
{
|
||||
endOffset = fullLength - 1;
|
||||
}
|
||||
|
||||
var length = endOffset - offset + 1;
|
||||
|
||||
if (length <= 0) throw new HttpException(HttpStatusCode.BadRequest, "Wrong Range header");
|
||||
|
||||
if (length < fullLength)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.PartialContent;
|
||||
}
|
||||
context.Response.Headers["Accept-Ranges"] = "bytes";
|
||||
context.Response.Headers["Content-Range"] = string.Format(" bytes {0}-{1}/{2}", offset, endOffset, fullLength);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private string GetRouteValue(string name, HttpContext context)
|
||||
{
|
||||
return (context.GetRouteValue(name) ?? "").ToString();
|
||||
|
@ -72,7 +72,7 @@ namespace ASC.Migrations.MySql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -1,
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:100,manager:1",
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:100,manager:1",
|
||||
Name = "trial",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
@ -80,7 +80,7 @@ namespace ASC.Migrations.MySql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -2,
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:1024,manager:1",
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:1024,manager:1",
|
||||
Name = "admin",
|
||||
Price = 30m,
|
||||
ProductId = "1002",
|
||||
@ -89,7 +89,7 @@ namespace ASC.Migrations.MySql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -3,
|
||||
Features = "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Features = "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Name = "startup",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
|
@ -118,17 +118,17 @@ public partial class CoreDbContextMigrate : Migration
|
||||
migrationBuilder.InsertData(
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "description", "features", "name", "product_id" },
|
||||
values: new object[] { -3, null, "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3", "startup", null });
|
||||
values: new object[] { -3, null, "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3", "startup", null });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "description", "features", "name", "price", "product_id", "visible" },
|
||||
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
|
||||
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "description", "features", "name", "product_id" },
|
||||
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:100,manager:1", "trial", null });
|
||||
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:100,manager:1", "trial", null });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "last_modified",
|
||||
|
@ -70,7 +70,7 @@ namespace ASC.Migrations.MySql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -1,
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:100,manager:1",
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:100,manager:1",
|
||||
Name = "trial",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
@ -78,7 +78,7 @@ namespace ASC.Migrations.MySql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -2,
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:1024,manager:1",
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:1024,manager:1",
|
||||
Name = "admin",
|
||||
Price = 30m,
|
||||
ProductId = "1002",
|
||||
@ -87,7 +87,7 @@ namespace ASC.Migrations.MySql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -3,
|
||||
Features = "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Features = "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Name = "startup",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
|
@ -67,7 +67,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -1,
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:100,manager:1",
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:100,manager:1",
|
||||
Name = "trial",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
@ -75,7 +75,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -2,
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:1024,manager:1",
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:1024,manager:1",
|
||||
Name = "admin",
|
||||
Price = 30m,
|
||||
ProductId = "1002",
|
||||
@ -84,7 +84,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -3,
|
||||
Features = "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Features = "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Name = "startup",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
|
@ -111,19 +111,19 @@ public partial class CoreDbContextMigrate : Migration
|
||||
schema: "onlyoffice",
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "description", "features", "name", "visible" },
|
||||
values: new object[] { -3, null, "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3", "startup", false });
|
||||
values: new object[] { -3, null, "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3", "startup", false });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
schema: "onlyoffice",
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "description", "features", "name", "price", "product_id", "visible" },
|
||||
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
|
||||
values: new object[] { -2, null, "audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:1024,manager:1", "admin", 30m, "1002", true });
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
schema: "onlyoffice",
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "description", "features", "name", "visible" },
|
||||
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:100,manager:1", "trial", false });
|
||||
values: new object[] { -1, null, "trial,audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:100,manager:1", "trial", false });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "last_modified_tenants_quotarow",
|
||||
|
@ -65,7 +65,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -1,
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:100,manager:1",
|
||||
Features = "trial,audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:100,manager:1",
|
||||
Name = "trial",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
@ -73,7 +73,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -2,
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,total_size:107374182400,file_size:1024,manager:1",
|
||||
Features = "audit,ldap,sso,whitelabel,restore,thirdparty,audit,total_size:107374182400,file_size:1024,manager:1",
|
||||
Name = "admin",
|
||||
Price = 30m,
|
||||
ProductId = "1002",
|
||||
@ -82,7 +82,7 @@ namespace ASC.Migrations.PostgreSql.Migrations
|
||||
new
|
||||
{
|
||||
Tenant = -3,
|
||||
Features = "free,thirdparty,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Features = "free,thirdparty,audit,total_size:2147483648,manager:1,room:12,usersInRoom:3",
|
||||
Name = "startup",
|
||||
Price = 0m,
|
||||
Visible = false
|
||||
|
@ -366,7 +366,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
|
||||
|
||||
public Task<Stream> GetFileStreamAsync(File<int> file, long offset)
|
||||
{
|
||||
return _globalStore.GetStore().GetReadStreamAsync(string.Empty, GetUniqFilePath(file), (int)offset);
|
||||
return _globalStore.GetStore().GetReadStreamAsync(string.Empty, GetUniqFilePath(file), offset);
|
||||
}
|
||||
|
||||
public Task<Uri> GetPreSignedUriAsync(File<int> file, TimeSpan expires)
|
||||
|
@ -79,7 +79,6 @@ public class FileHandlerService
|
||||
private readonly SocketManager _socketManager;
|
||||
private readonly ILogger<FileHandlerService> _logger;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
private readonly RoomLogoManager _roomLogoManager;
|
||||
|
||||
public FileHandlerService(
|
||||
FilesLinkUtility filesLinkUtility,
|
||||
@ -110,8 +109,7 @@ public class FileHandlerService
|
||||
CompressToArchive compressToArchive,
|
||||
InstanceCrypto instanceCrypto,
|
||||
IHttpClientFactory clientFactory,
|
||||
ThumbnailSettings thumbnailSettings,
|
||||
RoomLogoManager roomLogoManager)
|
||||
ThumbnailSettings thumbnailSettings)
|
||||
{
|
||||
_filesLinkUtility = filesLinkUtility;
|
||||
_tenantExtra = tenantExtra;
|
||||
@ -142,7 +140,6 @@ public class FileHandlerService
|
||||
_logger = logger;
|
||||
_clientFactory = clientFactory;
|
||||
_thumbnailSettings = thumbnailSettings;
|
||||
_roomLogoManager = roomLogoManager;
|
||||
}
|
||||
|
||||
public Task Invoke(HttpContext context)
|
||||
@ -422,7 +419,7 @@ public class FileHandlerService
|
||||
var fullLength = await store.GetFileSizeAsync(string.Empty, mp4Path);
|
||||
|
||||
length = ProcessRangeHeader(context, fullLength, ref offset);
|
||||
fileStream = await store.GetReadStreamAsync(string.Empty, mp4Path, (int)offset);
|
||||
fileStream = await store.GetReadStreamAsync(string.Empty, mp4Path, offset);
|
||||
|
||||
title = FileUtility.ReplaceFileExtension(title, ".mp4");
|
||||
}
|
||||
@ -1064,7 +1061,7 @@ public class FileHandlerService
|
||||
|
||||
if (file.ThumbnailStatus != Thumbnail.Created)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NoContent;
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user