File tree Expand file tree Collapse file tree 2 files changed +54
-3
lines changed
Expand file tree Collapse file tree 2 files changed +54
-3
lines changed Original file line number Diff line number Diff line change @@ -95,7 +95,7 @@ def self.parse(string)
9595 in String => remainder , separator , String => subpath unless separator . empty?
9696 components [ :subpath ] = subpath . split ( '/' ) . select do |segment |
9797 !segment . empty? && segment != '.' && segment != '..'
98- end . compact . join ( '/' )
98+ end . map { | segment | URI . decode_www_form_component ( segment ) } . compact . join ( '/' )
9999
100100 string = remainder
101101 else
@@ -160,7 +160,7 @@ def self.parse(string)
160160 case string . partition ( '/' )
161161 in String => type , separator , remainder unless separator . empty?
162162 components [ :type ] = type
163-
163+
164164 string = remainder
165165 else
166166 raise InvalidPackageURL , 'invalid or missing package type'
@@ -344,7 +344,13 @@ def to_s
344344 subpath . delete_prefix ( '/' ) . delete_suffix ( '/' ) . split ( '/' ) . each do |segment |
345345 next if segment . empty? || segment == '.' || segment == '..'
346346
347- segments << URI . encode_www_form_component ( segment )
347+ # Custom encoding for URL fragment segments:
348+ # 1. Explicitly encode % as %25 to prevent double-encoding issues
349+ # 2. Percent-encode special characters according to URL fragment rules
350+ # 3. This ensures proper round-trip encoding/decoding with the parse method
351+ segments << segment . gsub ( /%|[^A-Za-z0-9\- \. _~]/ ) { |m |
352+ m == '%' ? '%25' : "%%%02X" % m . ord
353+ }
348354 end
349355
350356 unless segments . empty?
Original file line number Diff line number Diff line change 188188 it { should have_description 'pkg:rpm/fedora/[email protected] ?arch=i386&distro=fedora-25' } 189189 end
190190
191+ context 'with escaped subpath characters' , url : 'pkg:type/name#path/with/%25/percent' do
192+ it {
193+ should have_attributes type : 'type' ,
194+ namespace : nil ,
195+ name : 'name' ,
196+ version : nil ,
197+ qualifiers : nil ,
198+ subpath : 'path/with/%/percent'
199+ }
200+
201+ it 'should properly round-trip the URL' do
202+ expect ( subject . to_s ) . to eq ( 'pkg:type/name#path/with/%25/percent' )
203+ end
204+ end
205+
206+ context 'with multiple escaped subpath characters' , url : 'pkg:type/name#path/%20space/%3Fquery/%25percent' do
207+ it {
208+ should have_attributes type : 'type' ,
209+ namespace : nil ,
210+ name : 'name' ,
211+ version : nil ,
212+ qualifiers : nil ,
213+ subpath : 'path/ space/?query/%percent'
214+ }
215+
216+ it 'should properly round-trip the URL' do
217+ expect ( subject . to_s ) . to eq ( 'pkg:type/name#path/%20space/%3Fquery/%25percent' )
218+ end
219+ end
220+
221+ context 'with the specific issue case' , url : 'pkg:t/n#%25' do
222+ it {
223+ should have_attributes type : 't' ,
224+ namespace : nil ,
225+ name : 'n' ,
226+ version : nil ,
227+ qualifiers : nil ,
228+ subpath : '%'
229+ }
230+
231+ it 'should properly round-trip the URL' do
232+ expect ( subject . to_s ) . to eq ( 'pkg:t/n#%25' )
233+ end
234+ end
235+
191236 context 'with URLs containing extra slashes after scheme' do
192237 it 'should parse pkg:/type/namespace/name correctly' do
193238 purl = PackageURL . parse ( 'pkg:/maven/org.apache.commons/io' )
You can’t perform that action at this time.
0 commit comments