mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-06 13:26:38 +08:00
4
This commit is contained in:
@@ -5,6 +5,8 @@ package cloud115
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -181,6 +183,24 @@ func (u *OSSMultipartUploader) UploadFileWithResult(ctx context.Context, input O
|
|||||||
return completeParts[i].PartNumber < completeParts[j].PartNumber
|
return completeParts[i].PartNumber < completeParts[j].PartNumber
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 115 下发的 callback / callback_var 是 JSON 字符串,而 OSS CompleteMultipartUpload
|
||||||
|
// 要求 callback 参数为 Base64 编码后的 JSON,否则报 "The callback configuration is
|
||||||
|
// not base64 encoded"。这里把两者转为 Base64 后再提交(参考 QMediaSync 的
|
||||||
|
// BuildOSSCallbackHeaders)。
|
||||||
|
cb := input.Callback
|
||||||
|
cbVar := input.CallbackVar
|
||||||
|
if cb == "" {
|
||||||
|
return OSSMultipartUploadResult{}, errors.New("OSS callback 为空")
|
||||||
|
}
|
||||||
|
if !json.Valid([]byte(cb)) {
|
||||||
|
return OSSMultipartUploadResult{}, errors.New("解析 callback 失败:不是合法 JSON")
|
||||||
|
}
|
||||||
|
if cbVar == "" {
|
||||||
|
cbVar = "{}"
|
||||||
|
}
|
||||||
|
if !json.Valid([]byte(cbVar)) {
|
||||||
|
return OSSMultipartUploadResult{}, errors.New("解析 callback_var 失败:不是合法 JSON")
|
||||||
|
}
|
||||||
completeResult, err := u.client.CompleteMultipartUpload(ctx, &oss.CompleteMultipartUploadRequest{
|
completeResult, err := u.client.CompleteMultipartUpload(ctx, &oss.CompleteMultipartUploadRequest{
|
||||||
Bucket: oss.Ptr(input.Bucket),
|
Bucket: oss.Ptr(input.Bucket),
|
||||||
Key: oss.Ptr(input.Object),
|
Key: oss.Ptr(input.Object),
|
||||||
@@ -188,8 +208,8 @@ func (u *OSSMultipartUploader) UploadFileWithResult(ctx context.Context, input O
|
|||||||
CompleteMultipartUpload: &oss.CompleteMultipartUpload{
|
CompleteMultipartUpload: &oss.CompleteMultipartUpload{
|
||||||
Parts: completeParts,
|
Parts: completeParts,
|
||||||
},
|
},
|
||||||
Callback: oss.Ptr(input.Callback),
|
Callback: oss.Ptr(base64.StdEncoding.EncodeToString([]byte(cb))),
|
||||||
CallbackVar: oss.Ptr(input.CallbackVar),
|
CallbackVar: oss.Ptr(base64.StdEncoding.EncodeToString([]byte(cbVar))),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return OSSMultipartUploadResult{}, fmt.Errorf("完成 OSS multipart 失败:%w", err)
|
return OSSMultipartUploadResult{}, fmt.Errorf("完成 OSS multipart 失败:%w", err)
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
package cloud115
|
package cloud115
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileSHA1(t *testing.T) {
|
func TestFileSHA1(t *testing.T) {
|
||||||
@@ -112,3 +117,81 @@ func TestBaseNameOf(t *testing.T) {
|
|||||||
t.Errorf("got %s", got)
|
t.Errorf("got %s", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fakeCallbackOSSClient 捕获 CompleteMultipartUpload 收到的 callback / callback_var,
|
||||||
|
// 用于断言已经 Base64 编码(116 要求 callback 必须是 Base64 后的 JSON,否则报
|
||||||
|
// "The callback configuration is not base64 encoded")。
|
||||||
|
type fakeCallbackOSSClient struct {
|
||||||
|
capturedCallback string
|
||||||
|
capturedCallbackVar string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeCallbackOSSClient) InitiateMultipartUpload(_ context.Context, _ *oss.InitiateMultipartUploadRequest, _ ...func(*oss.Options)) (*oss.InitiateMultipartUploadResult, error) {
|
||||||
|
return &oss.InitiateMultipartUploadResult{UploadId: oss.Ptr("upload-new")}, nil
|
||||||
|
}
|
||||||
|
func (c *fakeCallbackOSSClient) UploadPart(_ context.Context, r *oss.UploadPartRequest, _ ...func(*oss.Options)) (*oss.UploadPartResult, error) {
|
||||||
|
if r.Body != nil {
|
||||||
|
_, _ = io.Copy(io.Discard, r.Body)
|
||||||
|
}
|
||||||
|
return &oss.UploadPartResult{ETag: oss.Ptr("etag-1")}, nil
|
||||||
|
}
|
||||||
|
func (c *fakeCallbackOSSClient) ListParts(context.Context, *oss.ListPartsRequest, ...func(*oss.Options)) (*oss.ListPartsResult, error) {
|
||||||
|
return &oss.ListPartsResult{}, nil
|
||||||
|
}
|
||||||
|
func (c *fakeCallbackOSSClient) CompleteMultipartUpload(_ context.Context, r *oss.CompleteMultipartUploadRequest, _ ...func(*oss.Options)) (*oss.CompleteMultipartUploadResult, error) {
|
||||||
|
c.capturedCallback = *r.Callback
|
||||||
|
c.capturedCallbackVar = *r.CallbackVar
|
||||||
|
return &oss.CompleteMultipartUploadResult{
|
||||||
|
CallbackResult: map[string]any{
|
||||||
|
"state": true,
|
||||||
|
"data": map[string]any{"file_id": "file-1", "pick_code": "pick-1"},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
func (c *fakeCallbackOSSClient) AbortMultipartUpload(context.Context, *oss.AbortMultipartUploadRequest, ...func(*oss.Options)) (*oss.AbortMultipartUploadResult, error) {
|
||||||
|
return &oss.AbortMultipartUploadResult{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCompleteMultipartUploadCallbackBase64 回归测试:OSS CompleteMultipartUpload 的
|
||||||
|
// callback 必须 Base64 编码,否则报 "The callback configuration is not base64 encoded",
|
||||||
|
// 导致大于 128 KiB 的元数据文件上传失败。
|
||||||
|
func TestCompleteMultipartUploadCallbackBase64(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "big.bin")
|
||||||
|
data := make([]byte, 8) // 8 字节,PartSize=8 → 1 part
|
||||||
|
if err := os.WriteFile(path, data, 0o644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fake := &fakeCallbackOSSClient{}
|
||||||
|
uploader := &OSSMultipartUploader{client: fake}
|
||||||
|
|
||||||
|
callback := `{"callbackUrl":"http://uplb.115.com/3.0/completeupload.php"}`
|
||||||
|
callbackVar := `{"x:pick_code":"abc"}`
|
||||||
|
_, err := uploader.UploadFileWithResult(context.Background(), OSSMultipartUploadInput{
|
||||||
|
Bucket: "bucket-1",
|
||||||
|
Object: "object-1",
|
||||||
|
Callback: callback,
|
||||||
|
CallbackVar: callbackVar,
|
||||||
|
FilePath: path,
|
||||||
|
FileSize: int64(len(data)),
|
||||||
|
PartSize: 8,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("multipart 上传失败:%v", err)
|
||||||
|
}
|
||||||
|
// 捕获的 callback 必须是合法 Base64,且解码后与原 JSON 一致
|
||||||
|
cbBytes, err := base64.StdEncoding.DecodeString(fake.capturedCallback)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("callback 未 Base64 编码:%v (raw=%q)", err, fake.capturedCallback)
|
||||||
|
}
|
||||||
|
if string(cbBytes) != callback {
|
||||||
|
t.Errorf("callback 解码后 = %s,期望 %s", cbBytes, callback)
|
||||||
|
}
|
||||||
|
cbvBytes, err := base64.StdEncoding.DecodeString(fake.capturedCallbackVar)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("callback_var 未 Base64 编码:%v (raw=%q)", err, fake.capturedCallbackVar)
|
||||||
|
}
|
||||||
|
if string(cbvBytes) != callbackVar {
|
||||||
|
t.Errorf("callback_var 解码后 = %s,期望 %s", cbvBytes, callbackVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user