@@ -609,3 +609,58 @@ func TestDownloadWithRetry_RemovaPartialFileOnError(t *testing.T) {
609609 t .Fatalf ("expected partial file to be removed, statErr=%v" , statErr )
610610 }
611611}
612+
613+ // TestFetchPackages_PlusEncodedAsPercentTwoBInURL verifies that FetchPackages
614+ // encodes '+' as '%2B' in the HTTP request URL (S3/CloudFront treats literal
615+ // '+' as space), while the destination filename retains the original '+'.
616+ func TestFetchPackages_PlusEncodedAsPercentTwoBInURL (t * testing.T ) {
617+ tempDir , err := os .MkdirTemp ("" , "pkgfetcher_test" )
618+ if err != nil {
619+ t .Fatalf ("Failed to create temp dir: %v" , err )
620+ }
621+ defer os .RemoveAll (tempDir )
622+
623+ var receivedPath string
624+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
625+ receivedPath = r .URL .RawPath
626+ if receivedPath == "" {
627+ // RawPath is empty when the path has no encoded characters after Go
628+ // normalisation, so fall back to RequestURI which preserves encoding.
629+ receivedPath = r .RequestURI
630+ }
631+ w .WriteHeader (http .StatusOK )
632+ _ , _ = w .Write ([]byte ("eci-package-content" ))
633+ }))
634+ defer server .Close ()
635+
636+ // Simulate an ECI package filename containing '+' characters.
637+ filename := "systemd_255.4-1ubuntu8.12-ecir8+etf+taprio_amd64.deb"
638+ inputURL := server .URL + "/pool/main/s/systemd/" + filename
639+
640+ err = FetchPackages ([]string {inputURL }, tempDir , 1 )
641+ if err != nil {
642+ t .Fatalf ("FetchPackages failed: %v" , err )
643+ }
644+
645+ // The server must have received '%2B' instead of '+'.
646+ if ! strings .Contains (receivedPath , "%2B" ) {
647+ t .Errorf ("server received path with literal '+' instead of '%%2B': %s" , receivedPath )
648+ }
649+ if strings .Contains (receivedPath , "+" ) {
650+ t .Errorf ("server path still contains literal '+': %s" , receivedPath )
651+ }
652+
653+ // The destination file must retain the original '+' in its name.
654+ destPath := filepath .Join (tempDir , filename )
655+ if _ , statErr := os .Stat (destPath ); os .IsNotExist (statErr ) {
656+ t .Fatalf ("expected destination file with '+' in name to exist: %s" , destPath )
657+ }
658+
659+ content , readErr := os .ReadFile (destPath )
660+ if readErr != nil {
661+ t .Fatalf ("failed to read downloaded file: %v" , readErr )
662+ }
663+ if string (content ) != "eci-package-content" {
664+ t .Fatalf ("unexpected file content: %q" , string (content ))
665+ }
666+ }
0 commit comments