blob: 37624002ce787f29cb7c958ba325fab42bb6cd7b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# frozen_string_literal: true
module Packages
module Nuget
class ExtractRemoteMetadataFileService
include Gitlab::Utils::StrongMemoize
ExtractionError = Class.new(StandardError)
MAX_FILE_SIZE = 4.megabytes.freeze
METADATA_FILE_EXTENSION = '.nuspec'
MAX_FRAGMENTS = 5 # nuspec file is usually in the first 2 fragments but we buffer 5 max
def initialize(remote_url)
@remote_url = remote_url
end
def execute
raise ExtractionError, 'invalid file url' if remote_url.blank?
if nuspec_file_content.blank? || !nuspec_file_content.instance_of?(String)
raise ExtractionError, 'nuspec file not found'
end
ServiceResponse.success(payload: nuspec_file_content)
end
private
attr_reader :remote_url
def nuspec_file_content
fragments = []
Gitlab::HTTP.get(remote_url, stream_body: true, allow_object_storage: true) do |fragment|
break if fragments.size >= MAX_FRAGMENTS
fragments << fragment
joined_fragments = fragments.join
next if joined_fragments.exclude?(METADATA_FILE_EXTENSION)
nuspec_content = extract_nuspec_file(joined_fragments)
break nuspec_content if nuspec_content.present?
end
end
strong_memoize_attr :nuspec_file_content
def extract_nuspec_file(fragments)
StringIO.open(fragments) do |io|
Zip::InputStream.open(io) do |zip|
process_zip_entries(zip)
end
rescue Zip::Error => e
raise ExtractionError, "Error opening zip stream: #{e.message}"
end
end
def process_zip_entries(zip)
while (entry = zip.get_next_entry) # rubocop:disable Lint/AssignmentInCondition
next unless entry.name.end_with?(METADATA_FILE_EXTENSION)
raise ExtractionError, 'nuspec file too big' if entry.size > MAX_FILE_SIZE
return extract_file_content(entry)
end
end
def extract_file_content(entry)
Tempfile.create('extract_remote_metadata_file_service') do |file|
entry.extract(file.path) { true } # allow #extract to overwrite the file
file.read
end
rescue Zip::DecompressionError
'' # Ignore decompression errors and continue reading the next fragment
rescue Zip::EntrySizeError => e
raise ExtractionError, "nuspec file has the wrong entry size: #{e.message}"
end
end
end
end
|