Можно ли узнать содержимое ZIP-файла перед его загрузкой? Всего 52 строки кода, и волшебство может произойти! 🔮
Давайте представим следующий сценарий:
Некоторое время назад вы очистили место на жестком диске вашего ноутбука и загрузили в облако три больших ZIP-файла (каждый из них по 8 ГБ). Теперь вы хотите посмотреть свой любимый фильм, и знаете, что он есть в одном из загруженных архивов. Но вы находитесь в отпуске и используете передачу данных со своего мобильного, поэтому ваше соединение медленное, и вам приходится доплачивать, когда вы превышаете 10 ГБ передачи. Эти три файла называются:
backup1.zip
,backup2.zip
,backup3.zip
. Какой из них вы должны скачать?
Если вам интересно, как решить такую проблему, и вы хотите узнать что-то об AWS, формате ZIP-файла и HTTP-запросах, продолжайте читать!
Веб-сервисы Amazon (AWS)
Serverless — действительно отличная технология. Это позволяет нам писать и развертывать исполняемый код без решения всех проблем базовой инфраструктуры.
В этой статье вы узнаете, как использовать немного мощности двух бессерверных сервисов, предоставляемых AWS: S3 и Lambda.
- Amazon Simple Storage Service (Amazon S3) — сервис хранения объектов, созданный для извлечения любых данных из любого места,
- AWS Lambda — служба вычислений, управляемая событиями, которая запускает код.
Оба сервиса бессерверные, а это значит, что вам не нужно даже думать о серверах или кластерах, потому что всем управляет AWS ☁️
HTTP-метод HEAD
Бьюсь об заклад, вы уже знаете некоторые методы HTTP-запросов, такие как:
- ПОЛУЧАТЬ,
- ПОЧТА,
- ПОМЕЩАТЬ,
- УДАЛИТЬ.
Но слышали ли вы когда-нибудь о методе HTTP HEAD
? Он делает то же самое, что и GET
, но без фактической загрузки данных. Чтобы быть более конкретным, давайте взглянем на Веб-документы MDN:
Метод HTTP
HEAD
запрашивает заголовки, которые были бы возвращены, если бы URL-адрес запросаHEAD
был запрошен методом HTTPGET
.
Другими словами, если вы выполняете запрос HEAD
, вы получаете только заголовки ответа. Одним из заголовков является заголовок Content-Length
, который указывает размер тела сообщения.
Заголовок запроса диапазона HTTP
Вы только что узнали о методе запроса HEAD
, но есть и кое-что новое в известном методе GET
— заголовок HTTP-запроса Range
.
Этот заголовок запроса указывает часть документа, которую должен вернуть сервер. Например, вы можете отправить запрос GET
с заголовком Range: bytes=100–199
и получить байты из указанного диапазона запроса (в этом случае вы получите 100 байт, начиная со 100-го байта файла).
Формат ZIP-файла
ZIP — это формат файла архива. Здесь — исчерпывающая спецификация формата файла .ZIP. Спецификация очень техническая — я прочитал ее, так что вам не нужно.
Для наших целей достаточно знать, что ZIP-файлы имеют четко определенную структуру. Каждый ZIP-файл правильно идентифицируется end of central directory record
(запись EOCD). Запись EOCD располагается в конце структуры архива. ZIP-файл также содержит central directory entry
(запись компакт-диска), в которой указывается имя каждого файла или каталога в архиве вместе с другими метаданными о записи и смещение, указывающее на фактические данные записи.
Стандартный формат файла ZIP имеет ограничение в 4 ГБ. Если файл имеет размер более 4 ГБ, он заархивирован в более новой версии формата файла ZIP — ZIP64
. Есть пара отличий в форматах, для нас наиболее важными являются дополнительная запись ZIP64 EOCD и локатор:
[local file header 1..n] [encryption header 1..n] [file data 1..n] [data descriptor 1..n] ... [central directory header 1..n] [zip64 end of central directory record] [zip64 end of central directory locator] [end of central directory record]
Наконец-то закончилась теория, необходимая для понимания алгоритма 🎉
Алгоритм
- Во-первых, вам нужно знать размер файла. Его можно получить, отправив запрос
HEAD
и прочитав заголовок ответаContent-Length
. - Затем вы можете получить запись EOCD, отправив запрос
GET
с заголовком запросаRange
. EOCD всегда находится в конце ZIP-файла и имеет размер 22 байта. - Из записи EOCD вы можете получить метаданные CD. Необходимая информация - это размер компакт-диска и смещение до его начала. Они всегда занимают байты с 12 по 20. Что касается EOCD, то можно отправить запрос
GET
с указаннымRange
. Не забудьте проанализировать полученные данные, потому что согласно спецификации "Все значения ДОЛЖНЫ храниться в байтах с прямым порядком байтов", но вам требуетсяint
.
Offset | Bytes | Description 12 | 4 | Size of central directory 16 | 4 | Offset of start of CD, relative to start of archive
4. Имея метаданные компакт-диска (его начало и размер), можно получить сам компакт-диск. Опять же, это можно сделать, отправив запрос GET
с заголовком запроса Range
.
5. На предпоследнем шаге можно просто прочитать поток байтов. CD и EOCD расположены непосредственно друг за другом, поэтому их наличие позволяет читать блок байтов.
6. В конце концов, есть еще одна хитрость. Байты CD+EOCD можно открыть в виде ZIP-файла. С ним можно делать что угодно, например перебирать файлы в списке файлов и печатать все имена файлов.
ZIP64
Как уже упоминалось, структура ZIP и ZIP64 немного отличается. Для последнего алгоритм выглядит так же. Единственное отличие состоит в том, что вам нужно получить дополнительную запись ZIP64 EOCD и локатор ZIP64 EOCD. Затем блоки из четырех байтов (запись CD+EOCD64+локатор EOCD64+EOCD) можно прочитать и открыть в виде ZIP-файла.
Offset | Bytes | Description 40 | 8 | Size of central directory 48 | 8 | Offset of start of CD, relative to start of archive
Код
Ниже вы можете найти рабочий пример кода для печати содержимого ZIP-файла без загрузки полного файла.
Следующий код работает с файлами, расположенными в корзине S3. Функция Lambda вызывается в уведомлении о событии S3.
Распечатав все файлы, вы сможете найти свой любимый фильм и скачать только один ZIP-файл, будучи на 100% уверенным, что выбрали правильный архив!
Краткое содержание
В статье я показал вам, как просмотреть содержимое ZIP-файла, не загружая его. Это стало возможным благодаря использованию методов и заголовков HTTP-запросов и знанию структуры формата файла ZIP.