Можно ли узнать содержимое 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 был запрошен методом HTTP GET.

Другими словами, если вы выполняете запрос 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]

Наконец-то закончилась теория, необходимая для понимания алгоритма 🎉

Алгоритм

  1. Во-первых, вам нужно знать размер файла. Его можно получить, отправив запрос HEAD и прочитав заголовок ответа Content-Length.
  2. Затем вы можете получить запись EOCD, отправив запрос GET с заголовком запроса Range. EOCD всегда находится в конце ZIP-файла и имеет размер 22 байта.
  3. Из записи 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.