Repository navigation
fix(knowledge): accept GBK multipart filenames from Windows curl - #4269
Li-john1021 wants to merge 2 commits into
Conversation
Windows curl -F sends Content-Disposition filename= in the active ANSI code page (GBK on zh-CN), so utf8.ValidString rejected valid CJK names. Normalize non-UTF-8 upload names via GBK→UTF-8 before ValidateInput, keep XSS/control checks, and clarify the error when encoding is still invalid. Fixes Tencent#4268.
|
Reporting this issue here — thanks for picking it up, and this matches the root cause I isolated. Confirming the diagnosis from my side: raw UTF-8 bytes in the multipart State check, for whoever picks up the review: If it's useful for test coverage, I can run this branch against my repro matrix on a local Lite build and report back: raw-UTF-8 |
|
Thank you for confirming the root cause and for the careful notes on keeping XSS / control-character checks after re-encoding — that matches the intent of the change. A local Lite run against your repro matrix would be very helpful, especially the Windows Appreciate you taking the time to write this up. |
|
Results of the local Lite run against the repro matrix, as requested. Two builds were compiled on the same machine (Windows, UCRT gcc, Filenames are sent as hand-built multipart bodies, so the exact
1. The fix does what the issue needs. B goes from a misleading rejection to a successful upload with the CJK title preserved, and C now gets an encoding-specific message instead of the generic illegal-character one. The call ordering is right too: 2. One input class changes from "loudly rejected" to "silently wrong name" — worth guarding. 3. Case D is pre-existing and not a write-escape, so I am not filing it as a security problem. Method note in case it saves someone a cycle: each case must also use a distinct document body, because uploads are deduplicated on extracted content before the filename is ever validated — identical bodies make every case after the first return |
|
Thank you for running the full Lite matrix and for writing this up so carefully — the table and the note about distinct document bodies (to avoid On the main path: cases A–C match what this PR intends. B recovering the CJK title instead of the misleading 1010, and C surfacing the encoding-specific message, are exactly the behaviors we wanted. I also appreciate you double-checking that normalize-then- On case E: your diagnosis makes sense. If the multipart stack has already consumed the CP936 trail byte I do not want to land a half-measure that breaks the common Windows On case D: understood — path separators in the title metadata only, opaque on-disk handle, pre-existing Grateful for the thorough local verification. |
|
Answering the open question from your last note — yes, the raw
Three measurements:
Concrete predicate, if useful: extract the For the regression test, the pair worth pinning is B and E in the same run: B must still land with the full CJK title, and E must not land as a shortened title — those two can only both pass if the guard reads the header rather than Say the word when the approach is committed and I'll re-run the whole matrix against the new build the same way (baseline |
|
Thank you — this is exactly the measurement I needed. Confirmed takeaway on my side:
I will update this PR to:
I will ping you here once the follow-up commit is up — grateful again for the concrete predicate and the Lite matrix offer. |
When CP936 trail byte 0x5C is inside a quoted filename=, Go's multipart parser unescapes it and shortens FileHeader.Filename. Prefer the raw Content-Disposition filename= bytes in that case so NormalizeUploadFilename can recover the full CJK title (case E) without regressing common GBK uploads (case B).
|
Follow-up is up: It implements the predicate you sketched — extract raw Whenever you have a moment to re-run the Lite matrix against this head the same way as before, that would be extremely helpful — no rush, and thank you again. |
|
Re-ran the Lite matrix against
Each case's stored |
|
Thank you for re-running the full Lite matrix against Glad to see A–C unchanged, E recovering the full Grateful for the thorough verification and the LGTM from your side. The PR should now be ready for maintainer review whenever bandwidth allows. |
Summary
curl -Foften sendsContent-Dispositionfilename=bytes in the active ANSI code page (GBK/CP936 on zh-CN). Those bytes failutf8.ValidStringinValidateInput, producing a misleading文件名包含非法字符(1010) even though the CJK name is valid once decoded.NormalizeUploadFilename(GBK→UTF-8) before filename validation on create/replace/URL-import paths; keep existing XSS/control-character checks after re-encoding.fileNameform field workaround.Fixes #4268
Test plan
ValidateInputpasses, undecodable bytes unchanged, XSS still rejected after decodego test ./internal/utils/ -run NormalizeUploadFilenamego test ./internal/application/service/ -run 'CreateKnowledgeFromFile|ReplaceKnowledge'fileName=form field