VMOD BLOB-用于VCL BLOB类型、编码和解码的实用程序¶
SYNOPSIS¶
import blob [as name] [from "path"] BLOB解码(ENUM解码,整型长度,字符串编码) 字符串编码(ENUM编码、ENUM大小写、BLOB BLOB) 字符串转码(ENUM解码、ENUM编码、ENUM大小写、整型长度、字符串编码) 布尔相同(斑点,斑点) 布尔值相等(斑点,斑点) 整数长度(BLOB) BLOB SUB(BLOB,字节长度,字节偏移量=0) New xblob=blob.blob(ENUM解码,字符串编码) BLOB xblob.get() 字符串xblob.encode(ENUM编码,ENUM大小写)
DESCRIPTION¶
此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);
}
编码方案¶
二进制到文本编码方案由VMOD的构造函数、方法和函数中的ENUM指定。解码将(可能连接的)字符串转换为BLOB,而编码将BLOB转换为字符串。
编码方案的ENUM值可以是以下值之一:
IDENTITY
BASE64
BASE64URL
BASE64URLNOPAD
BASE64CF
HEX
URL
空字符串被解码为“NULL BLOB”(长度为0),反过来,NULL BLOB被编码为空字符串。
对于使用 HEX
或 URL
,您还可以指定一个 case 使用以下其中一个值进行ENUM LOWER
, UPPER
或 DEFAULT
生成具有小写或大写十六进制数字的字符串(在 [a-f]
或 [A-F]
)。的缺省值 case 是 DEFAULT
,这是为了 HEX
和 URL
意思与 LOWER
。
这个 case ENUM与解码无关; HEX
或 URL
要解码为BLOB的字符串可以是十六进制数字,无论是哪种情况,也可以是大小写混合的情况。
这个 case ENUM必须设置为 DEFAULT
对于其他编码 (BASE64*
和 IDENTITY
)。属性生成大写字符串。 IDENTITY
使用以下方案 case=UPPER
。若要更改字符串的大小写,请使用 std.toupper()
或 std.tolower()
函数来自 VMOD标准-Varnish标准模块 。
IDENTITY¶
最简单的编码在BLOB和字符串数据类型之间进行转换,使内容字节相同。
请注意,BLOB可以在其末尾之前的任何位置包含空字节;如果使用 IDENTITY
,则得到的字符串在该位置将有一个空字节。由于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 ENUM必须设置为 DEFAULT
为 IDENTITY
编码。
Base64*¶
Base64编码方案使用4个字符来编码3个字节。没有换行符或最大行长--不允许使用空格。
这个 BASE64
encoding uses the alphanumeric characters, +
and /
; and encoded strings are padded with the `` =``字符,因此它们的长度始终是四的倍数。
这个 BASE64URL
encoding also uses the alphanumeric characters, but -
and _
instead of +
and /
, so that an encoded string can be used safely in a URL. This scheme also uses the padding character `` =``。
这个 BASE64URLNOPAD
编码使用的字母表与 BASE6URL
,但省略了填充。因此,使用该方案的编码的长度不必是四的倍数。
这个 BASE64CF` is similar to ``BASE64URL
, with the following changes to BASE64
: +
replaced with -
, /
replaced with `` ~``和 _
作为填充字符。它被某个CDN提供商使用,他也是这个名字的灵感来源。
这个 case ENUM必须设置为 DEFAULT
因为对于所有的 BASE64*
编码。
HEX¶
这个 HEX
编码方案将十六进制字符串转换为BLOB,反之亦然。对于编码,您可以使用 case ENUM用于指定大写或小写十六进制数字 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 ENUM确定十六进制数字的大小写,但不影响非百分比编码的字母字符。
BLOB解码(ENUM解码,整型长度,字符串编码)¶
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");
字符串编码(ENUM编码、ENUM大小写、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"));
字符串转码(ENUM解码、ENUM编码、ENUM大小写、整型长度、字符串编码)¶
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 ,然后根据该方案返回结果斑点的编码 encoding 。 case 属性的十六进制数字的大小写。 HEX
和 URL
编码,并且对于其他编码将被忽略。
和以前一样 blob.decode() :如果 length >0,只解码第一个 length 字符,否则将对整个字符串进行解码。的默认值为 length 为0。
decoding 和 encoding 默认为标识,并且 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);
布尔相同(斑点,斑点)¶
退货 true
当且仅当两个BLOB参数是相同的对象,即它们指定完全相同的内存区域,或者两者都为空。
如果Blob都为空(长度为0和/或内部指针为 NULL
),然后 blob.same() 退货 true
。如果将任何非空斑点与空斑点进行比较,则 blob.same() 退货 false
。
布尔值相等(斑点,斑点)¶
当且仅当两个BLOB参数具有相同的内容(可能位于不同的内存区域)时才返回TRUE。
和以前一样 blob.same() :如果斑点都是空的,则 blob.equal() 退货 true
。如果将任何非空斑点与空斑点进行比较,则 blob.equal() 退货 false
。
整数长度(BLOB)¶
返回斑点的长度。
BLOB SUB(BLOB,字节长度,字节偏移量=0)¶
返回一个新的Blob,从 length 从开始的BLOB参数的字节 offset 从其内存区开始的字节数。的默认值为 offset 是 0B
。
blob.sub() 如果BLOB参数为空,则失败并返回NULL offset + length
所需的字节数超过Blob中的可用字节数。
New xblob=blob.blob(ENUM解码,字符串编码)¶
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());
字符串xblob.encode(ENUM编码,ENUM大小写)¶
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 and case, encodings via the 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的函数应该用于直到运行时才知道的数据。
ERRORS¶
编码器、解码器和 blob.sub() 如果没有足够的空间来创建新的Blob或字符串,则可能失败。如果编码的字符串是解码方案的非法格式,则解码器也可能失败。编码器将在 IDENTITY
和 BASE64*
编码方案,如果 case ENUM未设置为 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
消息将写入日志。
LIMITATIONS¶
VMOD以各种方式为新的Blob和字符串分配内存。这个 blob.blob() 对象及其方法从堆中分配内存,因此它们只受可用虚拟内存的限制。
这个 blob.encode() , blob.decode() 和 blob.transcode() 函数分配Varnish工作空间,也是如此 blob.sub() 用于新创建的BLOB。如果这些函数出现故障,如Varnish日志中的“Out of space”消息所示(带有 VCL_Error
标记),则需要增加varnishd参数 workspace_client
和/或 workspace_backend
。
这个 blob.transcode() 函数还为临时Blob分配堆栈上的空间。如果此函数导致堆栈溢出,则可能需要增加varnishd参数 thread_pool_stack
。
另请参阅¶
COPYRIGHT¶
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>