Как я могу накачать эту байтовую строку zlib в python? - PullRequest
1 голос
/ 12 апреля 2020

Я пишу инструмент для взаимодействия с популярным хранилищем данных SaaS. Их онлайн-редактор sql сериализует sql рабочих таблиц до JSON, но тело рабочей таблицы SQL выкачивается zlib с использованием pako. js. Я пытаюсь прочитать и раздуть эти строки zlib из python, но я могу декодировать только строки, содержащие короткие

Примером с текстом sql была буква a:

bytestring = b'x\xef\xbf\xbdK\x04\x00\x00b\x00b\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
>>> "a"

Если я добавлю точку с запятой a;, это не сможет распаковать:

bytestring = b'x\xef\xbf\xbdK\xef\xbf\xbd\x06\x00\x00\xef\xbf\xbd\x00\xef\xbf\xbd\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
*** UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8f in position 1: invalid start byte

Примечание: я также пробовал эти примеры декодирования с помощью 'punycode', ссылки на которые я нашел в реализация javascript.

Мое понимание zlib довольно ограничено, но я понял, что первые два и последние четыре байта строки zlib являются верхними и нижними колонтитулами и могут быть обрезаны, если мы запустим zlib с волхвами c число -15. Вполне возможно, что существует число zlib magi c, которое распаковывает эти строки без необходимости убирать верхний и нижний колонтитулы, но я не смог заставить работать какую-либо комбинацию при цикле от -64 до 64.

Я остановился на функциях сохранения и загрузки онлайн-редактора sql и обнаружил, что они используют библиотеку pako zlib pako.deflate(a, {to: 'string'}) и pako.inflate(b['body'], {to: 'string'}). И я могу раздувать / выкачивать строки sql в браузер, использующий библиотеку pako, но не смог воспроизвести те же результаты в python.

Ответы [ 2 ]

2 голосов
/ 26 апреля 2020

Я согласен, что это проблема повреждения данных. zlib и pako должны иметь возможность считывать данные друг друга без вычеркивания полей или добавления магических c чисел.

Чтобы доказать это, вот пара демонстрационных сценариев, которые я создал вместе, один используя pako для дефлятирования данных и один используя zlib для его инфляции:

// deflate.js
var pako = require("./pako.js");
console.log(escape(pako.deflate(process.argv[2], {to: "string"})));
# inflate.py
import urllib.parse, zlib, sys
print(zlib.decompress(urllib.parse.unquote_to_bytes(sys.stdin.read())).decode("utf-8"))

Запустите их в командной строке, используя node deflate.js "Here is some example text" | inflate.py. Ожидаемый результат - это аргумент, передаваемый node deflate.js.

Одна вещь, на которую стоит обратить внимание в pako, - это поведение при использовании опции to: "string". Документация для этой опции выглядит следующим образом:

to (String) - если равно 'string', то результатом будет "двоичная строка" (каждый код символа) [0..255])

Именно по этой причине я использую escape в функции JavaScript выше. Использование escape гарантирует, что строка, переданная между JavaScript и Python, не содержит никаких символов, не входящих в ASCII. (Обратите внимание, что encodeURIComponent не работает, потому что строка содержит двоичные данные.) Затем я использую urllib.parse.unquote_to_bytes в Python, чтобы отменить это экранирование.

Если вы можете escape pako -детализированные данные в браузере, вы можете передать их в Python, чтобы снова их раздувать.

2 голосов
/ 25 апреля 2020

Каждая последовательность \xef\xbf\xbd представляет случай искажения исходных данных.

В вашем первом примере первый и единственный \xef\xbf\xbd должен быть одним байтом, который является вторым байтом заголовок zlib. Во втором примере первый \xef\xbf\xbd должен быть вторым байтом заголовка zlib, второй экземпляр должен быть \b4, третий экземпляр должен быть \ff, а четвертый экземпляр должен быть \9b.

Где-то по пути есть некоторая обработка UTF-8, которую не должно происходить . Он терпит неудачу каждый раз, когда сталкивается с байтом с установленным старшим битом. В этих случаях он заменяет байт этой трехбайтовой последовательностью UTF-8 U+FFFD, которая является символом «замены», используемым для представления неизвестного символа.

Суть в том, что ваши данные безвозвратно возвращаются поврежден. Вы должны исправить все, что происходит оттуда. Вы пытаетесь использовать копирование и вставку для получения данных? Если вы видите знак вопроса в черном ромбе, это символ UTF-8.

...