VMOD blob — Утилиты для типа VCL blob, кодирования и декодирования
СИНОПСИС
import blob [as name] [from "path"] BLOB decode(ENUM decoding, INT length, STRING encoded) STRING encode(ENUM encoding, ENUM case, BLOB blob) STRING transcode(ENUM decoding, ENUM encoding, ENUM case, INT length, STRING encoded) BOOL same(BLOB, BLOB) BOOL equal(BLOB, BLOB) INT length(BLOB) BLOB sub(BLOB, BYTES length, BYTES offset=0) new xblob = blob.blob(ENUM decoding, STRING encoded) BLOB xblob.get() STRING xblob.encode(ENUM encoding, ENUM case)
ОПИСАНИЕ
Этот VMOD предоставляет утилиты и объект для типа данных VCL BLOB, который может содержать произвольные данные любой длины.
Примеры:
sub vcl_init {
# Create blob objects from encodings such as base64 or hex.
new myblob = blob.blob(BASE64, "Zm9vYmFy");
new yourblob = blob.blob(encoded="666F6F", decoding=HEX);
}
sub vcl_deliver {
# The .get() method retrieves the BLOB from an object.
set resp.http.MyBlob-As-Hex
= blob.encode(blob=myblob.get(), encoding=HEX);
# The .encode() method efficiently retrieves an encoding.
set resp.http.YourBlob-As-Base64 = yourblob.encode(BASE64);
# decode() and encode() functions convert blobs to text and
# vice versa at runtime.
set resp.http.Base64-Encoded
= blob.encode(BASE64,
blob=blob.decode(HEX,
encoded=req.http.Hex-Encoded));
}
sub vcl_recv {
# transcode() converts from one encoding to another.
# case=UPPER specifies upper-case hex digits A-F.
set req.http.Hex-Encoded
= blob.transcode(decoding=BASE64, encoding=HEX,
case=UPPER, encoded="YmF6");
# transcode() from URL to IDENTITY effects a URL decode.
set req.url = blob.transcode(encoded=req.url, decoding=URL);
# transcode() from IDENTITY to URL effects a URL encode.
set req.http.url_urlcoded
= blob.transcode(encoded=req.url, encoding=URL);
}
СХЕМЫ КОДИРОВАНИЯ
Схемы кодирования «двоично-текстовые» задаются перечислениями (ENUM) в конструкторе, методах и функциях VMOD. Декодирование преобразует (возможно, конкатенированную) строку в blob, а кодирование — blob в строку.
Значения перечислений (ENUM) для схемы кодирования могут быть следующими:
IDENTITYBASE64BASE64URLBASE64URLNOPADBASE64CFHEXURL
Пустые строки декодируются в «нулевой blob» (длины 0), и наоборот, нулевой blob кодируется как пустая строка.
Для кодировок с HEX или URL, вы также можете указать перечисление case со значениями LOWER, UPPER или DEFAULT для получения строки с шестнадцатеричными цифрами в нижнем или верхнем регистре (в [a-f] или [A-F]). Значение по умолчанию для case — DEFAULT, что для HEX и URL означает то же, что и LOWER.
Перечисление case не имеет значения для декодирования; строки HEX или URL для декодирования в BLOB могут содержать шестнадцатеричные цифры в любом регистре или в смешанном регистре.
Перечисление case ДОЛЖНО быть установлено в значение DEFAULT для других кодировок (BASE64* и IDENTITY). Вы не можете, например, получить строку в верхнем регистре, используя схему IDENTITY со значением case=UPPER. Для изменения регистра строки используйте функции std.toupper() или std.tolower() из VMOD std — Модуль стандартных функций Varnish.
IDENTITY
Самая простая кодировка преобразует между типами данных BLOB и STRING, сохраняя содержимое идентичным в байтах.
Обратите внимание, что BLOB может содержать нулевой байт в любой позиции до конца; если такой BLOB декодируется с помощью IDENTITY, результирующая STRING будет иметь нулевой байт в этой позиции. Поскольку строки VCL, как и строки C, представляются с завершающим нулевым байтом, строка будет усечена, и будет казаться, что она содержит меньше данных, чем исходный blob. Например:
# Decode from the hex encoding for "foo\0bar".
# The header will be seen as "foo".
set resp.http.Trunced-Foo1
= blob.encode(IDENTITY, blob=blob.decode(HEX,
encoded="666f6f00626172"));
IDENTITY — это кодировка и декодирование по умолчанию. Таким образом, вышесказанное также можно записать как:
# Decode from the hex encoding for "foo\0bar". # The header will be seen as "foo". set resp.http.Trunced-Foo2 = blob.encode(blob=blob.decode(HEX, encoded="666f6f00626172"));
Перечисление case ДОЛЖНО быть установлено в значение DEFAULT для кодировок IDENTITY.
BASE64*
Схемы кодирования Base64 используют 4 символа для кодирования 3 байт. Нет новых строк или максимальной длины строки — пробелы недопустимы.
Кодировка BASE64 использует алфавитно-цифровые символы + и /; закодированные строки дополняются символом =, чтобы их длина всегда была кратной четырём.
Кодировка BASE64URL также использует алфавитно-цифровые символы, но вместо + и / использует - и _, чтобы закодированная строка могла безопасно использоваться в URL. Эта схема также использует символ заполнения =.
Кодировка BASE64URLNOPAD использует тот же алфавит, что и BASE6URL, но опускает заполнение. Таким образом, длина кодирования с этой схемой не обязательно кратна четырём.
Кодировка BASE64CF` is similar to ``BASE64URL, со следующими изменениями в BASE64: + заменено на -, / заменено на ~, и _ используется как символ заполнения. Она используется определённым поставщиком CDN, чьё имя и вдохновило это название.
Перечисление case ДОЛЖНО быть установлено в DEFAULT для всех кодировок BASE64*.
HEX
Схема кодирования HEX преобразует шестнадцатеричные строки в blob и наоборот. При кодировании вы можете использовать перечисление case для указания шестнадцатеричных цифр в верхнем или нижнем регистре A через f (по умолчанию DEFAULT, что означает то же, что и LOWER). Префикс, такой как 0x, не используется при кодировании и является недопустимым при декодировании.
Если шестнадцатеричная строка, подлежащая декодированию, имеет нечётное количество цифр, она декодируется так, как если бы к ней был добавлен префикс 0; то есть первая цифра интерпретируется как представляющая младший ниббл первого байта. Например:
# The concatenated string is "abcdef0", and is decoded as "0abcdef0".
set resp.http.First = "abc";
set resp.http.Second = "def0";
set resp.http.Hex-Decoded
= blob.encode(HEX, blob=blob.decode(HEX,
encoded=resp.http.First + resp.http.Second));
URL
При декодировании URL любые подстроки %<2-hex-digits> заменяются двоичным значением шестнадцатеричного числа после знака %.
Кодирование URL реализует «кодирование процентов» в соответствии со спецификацией RFC3986. Перечисление case определяет регистр шестнадцатеричных цифр, но не влияет на буквенные символы, которые не закодированы по процентам.
BLOB decode(ENUM decoding, INT length, STRING encoded)
BLOB decode(
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, BASE64CF, HEX, URL} decoding=IDENTITY,
INT length=0,
STRING encoded
)
Возвращает BLOB, полученный из строки encoded согласно схеме, заданной decoding.
Если length > 0, декодируются только первые length символов закодированной строки. Если length ≤ 0 или больше длины строки, декодируется вся строка. Значение по умолчанию для length равно 0.
decoding по умолчанию равно IDENTITY.
Пример:
blob.decode(BASE64, encoded="Zm9vYmFyYmF6"); # same with named parameters blob.decode(encoded="Zm9vYmFyYmF6", decoding=BASE64); # convert string to blob blob.decode(encoded="foo");
STRING encode(ENUM encoding, ENUM case, BLOB blob)
STRING encode(
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, BASE64CF, HEX, URL} encoding=IDENTITY,
ENUM {LOWER, UPPER, DEFAULT} case=DEFAULT,
BLOB blob
)
Возвращает строковое представление BLOB blob, как указано в encoding. case определяет регистр шестнадцатеричных цифр для кодировок HEX и URL, и игнорируется для других кодировок.
encoding по умолчанию равно IDENTITY, а case по умолчанию равно DEFAULT. DEFAULT интерпретируется как LOWER для кодировок HEX и URL, и является требуемым значением для других кодировок.
Пример:
set resp.http.encode1
= blob.encode(HEX,
blob=blob.decode(BASE64, encoded="Zm9vYmFyYmF6"));
# same with named parameters
set resp.http.encode2
= blob.encode(blob=blob.decode(encoded="Zm9vYmFyYmF6",
decoding=BASE64),
encoding=HEX);
# convert blob to string
set resp.http.encode3
= blob.encode(blob=blob.decode(encoded="foo"));
STRING transcode(ENUM decoding, ENUM encoding, ENUM case, INT length, STRING encoded)
STRING transcode(
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, BASE64CF, HEX, URL} decoding=IDENTITY,
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, BASE64CF, HEX, URL} encoding=IDENTITY,
ENUM {LOWER, UPPER, DEFAULT} case=DEFAULT,
INT length=0,
STRING encoded
)
Преобразует из одной кодировки в другую, сначала декодируя строку encoded согласно схеме decoding, а затем возвращая кодирование результирующего blob согласно схеме encoding. case определяет регистр шестнадцатеричных цифр для кодировок HEX и URL, и игнорируется для других кодировок.
Как и в blob.decode(): если length > 0, декодируются только первые length символов закодированной строки, в противном случае декодируется вся строка. Значение по умолчанию для length равно 0.
decoding и encoding по умолчанию равны IDENTITY, а case по умолчанию равно DEFAULT. DEFAULT интерпретируется как LOWER для кодировок HEX и URL, и является требуемым значением для других кодировок.
Пример:
set resp.http.Hex2Base64-1
= blob.transcode(HEX, BASE64, encoded="666f6f");
# same with named parameters
set resp.http.Hex2Base64-2
= blob.transcode(encoded="666f6f",
encoding=BASE64, decoding=HEX);
# URL decode -- recall that IDENTITY is the default encoding.
set resp.http.urldecoded
= blob.transcode(encoded="foo%20bar", decoding=URL);
# URL encode
set resp.http.urlencoded
= blob.transcode(encoded="foo bar", encoding=URL);
BOOL same(BLOB, BLOB)
Возвращает true тогда и только тогда, когда два аргумента BLOB являются одним и тем же объектом, т.е. они указывают на точно один и тот же участок памяти, или оба пустые.
Если оба BLOB пустые (длина 0 и/или внутренний указатель NULL), то blob.same() возвращает true. Если любой непустой BLOB сравнивается с пустым BLOB, то blob.same() возвращает false.
BOOL equal(BLOB, BLOB)
Возвращает true тогда и только тогда, когда два аргумента BLOB имеют одинаковое содержимое (возможно, в разных участках памяти).
Как и в blob.same(): Если оба BLOB пустые, то blob.equal() возвращает true. Если любой непустой BLOB сравнивается с пустым BLOB, то blob.equal() возвращает false.
INT length(BLOB)
Возвращает длину BLOB.
BLOB sub(BLOB, BYTES length, BYTES offset=0)
Возвращает новый BLOB, сформированный из length байт аргумента BLOB, начиная с offset байт от начала его участка памяти. Значение по умолчанию для offset — 0B.
blob.sub() завершается ошибкой и возвращает NULL, если аргумент BLOB пустой или если offset + length требует больше байт, чем доступно в BLOB.
new xblob = blob.blob(ENUM decoding, STRING encoded)
new xblob = blob.blob(
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, BASE64CF, HEX, URL} decoding=IDENTITY,
STRING encoded
)
Создаёт объект, содержащий BLOB, полученный из строки encoded по схеме decoding.
Пример:
new theblob1 = blob.blob(BASE64, encoded="YmxvYg=="); # same with named arguments new theblob2 = blob.blob(encoded="YmxvYg==", decoding=BASE64); # string as a blob new stringblob = blob.blob(encoded="bazz");
BLOB xblob.get()
Возвращает BLOB, созданный конструктором.
Пример:
set resp.http.The-Blob1 =
blob.encode(blob=theblob1.get());
set resp.http.The-Blob2 =
blob.encode(blob=theblob2.get());
set resp.http.The-Stringblob =
blob.encode(blob=stringblob.get());
STRING xblob.encode(ENUM encoding, ENUM case)
STRING xblob.encode(
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, BASE64CF, HEX, URL} encoding=IDENTITY,
ENUM {LOWER, UPPER, DEFAULT} case=DEFAULT
)
Возвращает кодировку BLOB, созданного конструктором, в соответствии со схемой encoding. case определяет регистр шестнадцатеричных цифр для кодировок HEX и URL, и ДОЛЖЕН быть установлен в значение DEFAULT для других кодировок.
Пример:
# blob as text set resp.http.The-Blob = theblob1.encode(); # blob as base64 set resp.http.The-Blob-b64 = theblob1.encode(BASE64);
Для любого объекта blob.blob(), encoding и case, кодировки через метод xblob.encode() и функцию blob.encode() равны:
# Always true: blob.encode(ENC, CASE, blob.get()) == blob.encode(ENC, CASE)
Но метод объекта xblob.encode() более эффективен — кодировка вычисляется один раз и кэшируется (с выделением памяти в куче), а кэшированная кодировка извлекается при каждом последующем вызове. Функция blob.encode() вычисляет кодировку при каждом вызове, выделяя место для строки в рабочих пространствах Varnish.
Поэтому, если данные в BLOB фиксированы во время инициализации VCL, так что их кодировки всегда будут одинаковыми, лучше создать объект blob.blob(). Функции VMOD должны использоваться для данных, которые неизвестны до выполнения.
ОШИБКИ
Кодировщики, декодировщики и blob.sub() могут завершиться ошибкой, если недостаточно места для создания нового BLOB или строки. Декодировщики также могут завершиться ошибкой, если закодированная строка имеет неверный формат для схемы декодирования. Кодировщики завершатся ошибкой для схем кодирования IDENTITY и BASE64*, если перечисление case не установлено в DEFAULT.
Если любой из методов, функций или конструкторов VMOD завершается ошибкой, то происходит сбой VCL, так же, как если бы была вызвана return(fail) в исходном коде VCL. Это означает:
- Если конструктор объекта blob.blob() завершается ошибкой или если какой-либо метод или функция завершается ошибкой во время
vcl_init{}, то программа VCL не загрузится, и компилятор VCC выдаст сообщение об ошибке. - Если метод или функция завершаются ошибкой в любой другой подпрограмме VCL, кроме
vcl_synth{}, то управление передаетсяvcl_synth{}. Статус ответа устанавливается в 503 с текстом причины"VCL failed", а сообщение об ошибке будет записано в VSL с помощью тегаVCL_Error. - Если ошибка произошла во время
vcl_synth{}, тогдаvcl_synth{}прерывается. Возвращается строка ответа"503 VCL failed", и сообщениеVCL_Errorзаписывается в журнал.
ОГРАНИЧЕНИЯ
VMOD выделяет память различными способами для новых BLOB и строк. Объект blob.blob() и его методы выделяют память из кучи, и поэтому они ограничены только доступной виртуальной памятью.
Функции blob.encode(), blob.decode() и blob.transcode() выделяют рабочее пространство Varnish, как и blob.sub() для вновь созданного BLOB. Если эти функции завершаются ошибкой, как указывают сообщения «out of space» в журнале Varnish (с тегом VCL_Error), вам потребуется увеличить параметры varnishd workspace_client и/или workspace_backend.
Функция blob.transcode() также выделяет место в стеке для временного BLOB. Если эта функция вызывает переполнение стека, вам может потребоваться увеличить параметр varnishd thread_pool_stack.
СМОТРИТЕ ТАКЖЕ
АВТОРСКИЕ ПРАВА
This document is licensed under the same conditions as Varnish itself.
See LICENSE for details.
SPDX-License-Identifier: BSD-2-Clause
Authors: Nils Goroll <nils.goroll@uplex.de>
Geoffrey Simmons <geoffrey.simmons@uplex.de>
Copyright © 2006 Verdens Gang AS
Copyright © 2006–2020 Varnish Software AS
Licensed under the BSD-2-Clause License.
https://varnish-cache.org/docs/7.4/reference/vmod_blob.html