From 218de498fafa6a03e926b4d5aa303fe93060b07f Mon Sep 17 00:00:00 2001 From: Fourier Date: Fri, 20 Mar 2026 09:04:57 +0800 Subject: [PATCH 1/2] refactor(client): use context.WithTimeout for upload instead of mutating httpClient Replace the pattern of temporarily swapping httpClient.Timeout (not concurrency-safe) with context.WithTimeout on the request. This is the idiomatic Go approach and safe for concurrent use. --- internal/client/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/client/client.go b/internal/client/client.go index 3edbf06..469153f 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -2,6 +2,7 @@ package client import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -323,10 +324,9 @@ func (c *Client) UploadFileContent(uploadID, fileName, contentType string, fileB fmt.Printf("→ POST %s (multipart, %d bytes)\n", url, body.Len()) } - origTimeout := c.httpClient.Timeout - c.httpClient.Timeout = UploadTimeout - resp, err := c.httpClient.Do(req) - c.httpClient.Timeout = origTimeout + ctx, cancel := context.WithTimeout(context.Background(), UploadTimeout) + defer cancel() + resp, err := c.httpClient.Do(req.WithContext(ctx)) if err != nil { return nil, fmt.Errorf("upload request failed: %w", err) } From f1d4d119c676d787269e2c59532561b36c2aafad Mon Sep 17 00:00:00 2001 From: Fourier Date: Fri, 20 Mar 2026 11:20:32 +0800 Subject: [PATCH 2/2] fix(client): replace go1.25 multipart.FileContentDisposition with compatible impl multipart.FileContentDisposition was introduced in Go 1.25 but go.mod targets 1.24, causing CI build failures. Replace with manual Content-Disposition header construction with proper quote escaping. --- internal/client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/client/client.go b/internal/client/client.go index 469153f..cf4d250 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -295,7 +295,7 @@ func (c *Client) UploadFileContent(uploadID, fileName, contentType string, fileB body := &bytes.Buffer{} writer := multipart.NewWriter(body) partHeader := make(textproto.MIMEHeader) - partHeader.Set("Content-Disposition", multipart.FileContentDisposition("file", fileName)) + partHeader.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, strings.NewReplacer(`\`, `\\`, `"`, `\"`).Replace(fileName))) if contentType == "" { contentType = "application/octet-stream" }