Merge branch 'release/rc-v1.2.0' of github.com:ONLYOFFICE/AppServer into release/rc-v1.2.0

This commit is contained in:
Vlada Gazizova 2023-01-21 21:32:40 +03:00
commit 0f971fc5d3
16 changed files with 89 additions and 39 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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.

View File

@ -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);
}

View File

@ -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
{

View File

@ -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();

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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)

View File

@ -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;
}