As a part of making the deployment process easy, I was involved in a project where our software needed to be prefilled with authentication credentials per customer basis. All this functionality had to be implemented at the view level which required the file to be unzipped into a memory buffer, modified and zipped back. This needed 2 iterations
Python has a very usefulzipfile library for this purpose to read/write zipped files in memory.
zipped_file # This contains the zipped file
file_content_buffer = StringIO() # in_memory buffer
config_filepath = '/sample.conf'
with ZipFile(zipped_file, 'r') as zipread:
with ZipFile(file_content_buffer, 'w', ZIP_DEFLATED) as zipwrite:
for item in zipread.infolist():
if item.filename.endswith(config_filepath):
credentials = 'xxxxx-top-secret'
zipwrite.writestr(item.filename, credentials)
else:
# copy the data over as is
data = zipread.read(item.filename)
zipwrite.writestr(item.filename, data)
file_content_buffer.seek(0)
response = HttpResponse(file_content_buffer.getvalue())
response['Content-Disposition'] = ('attachment;
filename=custom_zipped_file.zip')
response['Content-Type'] = 'application/x-zip'
return response
This worked well until I tested it out, only to find out that several of the symlinks within the zipped file dont get copied over. They appear as broken files with 0kb size. After a lot of research, it looks like the file properites dont get preserved hence rendering the file broken. This also manifests in the created timestamp where it's set to epoch 0. So, the following changes had to keep the file in tact.
with ZipFile(zipped_file, 'r') as zipread:
with ZipFile(file_content_buffer, 'w', ZIP_DEFLATED) as zipwrite:
for item in zipread.infolist():
# Copy all ZipInfo attributes for each file since by
# default the properties are not preserved.
dest = ZipInfo(item.filename)
dest.CRC = item.CRC
dest.date_time = item.date_time #sets the date modified correctly
dest.create_system = item.create_system
dest.compress_type = item.compress_type
dest.external_attr = item.external_attr # preserves symlinks
dest.compress_size = item.compress_size
dest.file_size = item.file_size
dest.header_offset = item.header_offset
if item.filename.endswith(config_filepath):
# Sets up config file with valid credentials
zipwrite.writestr(dest, credentials)
else:
data = zipread.read(item.filename)
zipwrite.writestr(dest, data)
file_content_buffer.seek(0)