Skip to content

Commit 282ea1c

Browse files
committed
fix(storage): 自建tgbot分片url地址转发bug
1 parent bd653d7 commit 282ea1c

2 files changed

Lines changed: 74 additions & 61 deletions

File tree

backend/src/constants/proxy.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,29 @@ function buildPublicBaseUrl(request) {
121121
return url;
122122
}
123123

124+
/**
125+
* 把相对路径 URL(以 / 开头)转换为“对外可访问”的绝对 URL。
126+
*
127+
* @param {Request} request
128+
* @param {string} maybeUrl
129+
* @returns {string}
130+
*/
131+
export function toAbsoluteUrlIfRelative(request, maybeUrl) {
132+
if (typeof maybeUrl !== "string" || maybeUrl.length === 0) {
133+
return maybeUrl;
134+
}
135+
if (!maybeUrl.startsWith("/")) {
136+
return maybeUrl;
137+
}
138+
139+
try {
140+
const base = buildPublicBaseUrl(request);
141+
return new URL(maybeUrl, base).toString();
142+
} catch {
143+
return maybeUrl;
144+
}
145+
}
146+
124147
/**
125148
* 构建本地 /api/p 代理URL(仅用于 CloudPaste 内部)
126149
* @param {string} path - 文件路径(挂载视图路径)

backend/src/routes/fs/multipart.js

Lines changed: 51 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { usePolicy } from "../../security/policies/policies.js";
88
import { findUploadSessionById, normalizeUploadSessionUserId, updateUploadSessionById } from "../../utils/uploadSessions.js";
99
import { validateFsItemName } from "../../storage/fs/utils/FsInputValidator.js";
1010
import { StorageQuotaGuard } from "../../storage/usage/StorageQuotaGuard.js";
11+
import { toAbsoluteUrlIfRelative } from "../../constants/proxy.js";
1112

1213
/**
1314
* 分片上传(multipart)
@@ -22,21 +23,10 @@ import { StorageQuotaGuard } from "../../storage/usage/StorageQuotaGuard.js";
2223
*
2324
*/
2425

25-
const toAbsoluteUrlIfRelative = (requestUrl, maybeUrl) => {
26-
if (typeof maybeUrl !== "string" || maybeUrl.length === 0) {
27-
return maybeUrl;
28-
}
29-
if (!maybeUrl.startsWith("/")) {
30-
return maybeUrl;
31-
}
32-
const origin = new URL(requestUrl).origin;
33-
return new URL(maybeUrl, origin).toString();
34-
};
35-
3626
const ensureAbsoluteSessionUploadUrl = (c, payload) => {
3727
const session = payload?.session;
3828
const uploadUrl = session?.uploadUrl;
39-
const absolute = toAbsoluteUrlIfRelative(c.req.url, uploadUrl);
29+
const absolute = toAbsoluteUrlIfRelative(c.req.raw, uploadUrl);
4030
if (!session || absolute === uploadUrl) {
4131
return payload;
4232
}
@@ -138,18 +128,18 @@ export const registerMultipartRoutes = (router, helpers) => {
138128
};
139129

140130
const assertStorageQuota = async ({
141-
mountManager,
142-
fileSystem,
143-
quota,
144-
pathForResolve,
145-
storageConfigId,
146-
targetPath,
147-
userIdOrInfo,
148-
userType,
149-
incomingBytes,
150-
withOldBytes = false,
151-
context,
152-
}) => {
131+
mountManager,
132+
fileSystem,
133+
quota,
134+
pathForResolve,
135+
storageConfigId,
136+
targetPath,
137+
userIdOrInfo,
138+
userType,
139+
incomingBytes,
140+
withOldBytes = false,
141+
context,
142+
}) => {
153143
const normalizedIncoming = Number(incomingBytes) || 0;
154144
if (normalizedIncoming <= 0) return;
155145

@@ -204,14 +194,14 @@ export const registerMultipartRoutes = (router, helpers) => {
204194
});
205195

206196
const result = await fileSystem.initializeFrontendMultipartUpload(
207-
path,
208-
fileName,
209-
fileSize,
210-
userIdOrInfo,
211-
userType,
212-
partSize,
213-
partCount,
214-
{ sha256, contentType },
197+
path,
198+
fileName,
199+
fileSize,
200+
userIdOrInfo,
201+
userType,
202+
partSize,
203+
partCount,
204+
{ sha256, contentType },
215205
);
216206

217207
return jsonOk(c, ensureAbsoluteSessionUploadUrl(c, result), "前端分片上传初始化成功");
@@ -406,9 +396,9 @@ export const registerMultipartRoutes = (router, helpers) => {
406396
}
407397

408398
const { driver, mount } = await fileSystem.mountManager.getDriverByPath(
409-
sessionRow.fs_path,
410-
userIdOrInfo,
411-
userType,
399+
sessionRow.fs_path,
400+
userIdOrInfo,
401+
userType,
412402
);
413403

414404
if (String(driver.getType()) !== String(sessionRow.storage_type)) {
@@ -444,14 +434,14 @@ export const registerMultipartRoutes = (router, helpers) => {
444434
}
445435

446436
return jsonOk(
447-
c,
448-
{
449-
success: true,
450-
done: result?.done === true,
451-
status: result?.status ?? 200,
452-
skipped: result?.skipped === true,
453-
},
454-
"分片上传成功",
437+
c,
438+
{
439+
success: true,
440+
done: result?.done === true,
441+
status: result?.status ?? 200,
442+
skipped: result?.skipped === true,
443+
},
444+
"分片上传成功",
455445
);
456446
});
457447

@@ -508,24 +498,24 @@ export const registerMultipartRoutes = (router, helpers) => {
508498
const fileId = generateFileId();
509499

510500
return jsonOk(
511-
c,
512-
{
513-
presignedUrl: result.uploadUrl,
514-
fileId,
515-
storagePath: result.storagePath,
516-
publicUrl: result.publicUrl || null,
517-
mountId: mount.id,
518-
storageConfigId: mount.storage_config_id,
519-
storageType: mount.storage_type || null,
520-
targetPath,
521-
contentType: result.contentType,
522-
headers: result.headers || undefined,
523-
sha256: result.sha256 || sha256 || null,
524-
repoRelPath: result.repoRelPath || result.storagePath || null,
525-
// 透传:如果上游判定对象已存在(去重),可以跳过 PUT,直接 commit 登记
526-
skipUpload: result.skipUpload === true,
527-
},
528-
{ success: true },
501+
c,
502+
{
503+
presignedUrl: result.uploadUrl,
504+
fileId,
505+
storagePath: result.storagePath,
506+
publicUrl: result.publicUrl || null,
507+
mountId: mount.id,
508+
storageConfigId: mount.storage_config_id,
509+
storageType: mount.storage_type || null,
510+
targetPath,
511+
contentType: result.contentType,
512+
headers: result.headers || undefined,
513+
sha256: result.sha256 || sha256 || null,
514+
repoRelPath: result.repoRelPath || result.storagePath || null,
515+
// 透传:如果上游判定对象已存在(去重),可以跳过 PUT,直接 commit 登记
516+
skipUpload: result.skipUpload === true,
517+
},
518+
{ success: true },
529519
);
530520
});
531521

0 commit comments

Comments
 (0)