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被编码为空字符串。

对于使用 HEXURL ,您还可以指定一个 case 使用以下其中一个值进行ENUM LOWERUPPERDEFAULT 生成具有小写或大写十六进制数字的字符串(在 [a-f][A-F] )。的缺省值 caseDEFAULT ,这是为了 HEXURL 意思与 LOWER

这个 case ENUM与解码无关; HEXURL 要解码为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必须设置为 DEFAULTIDENTITY 编码。

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 由指定的 encodingcase 属性的十六进制数字的大小写。 HEXURL 编码,并且对于其他编码将被忽略。

encoding 默认为 IDENTITY ,以及 case 默认为 DEFAULTDEFAULT 被解释为 LOWER 对于 HEXURL 编码,并且是其他编码的必需值。

示例::

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 ,然后根据该方案返回结果斑点的编码 encodingcase 属性的十六进制数字的大小写。 HEXURL 编码,并且对于其他编码将被忽略。

和以前一样 blob.decode() :如果 length >0,只解码第一个 length 字符,否则将对整个字符串进行解码。的默认值为 length 为0。

decodingencoding 默认为标识,并且 case 默认为 DEFAULTDEFAULT 被解释为 LOWER 对于 HEXURL 编码,并且是其他编码的必需值。

示例::

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 从其内存区开始的字节数。的默认值为 offset0B

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的编码 encodingcase 属性的十六进制数字的大小写。 HEXURL 编码,并且必须设置为 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或字符串,则可能失败。如果编码的字符串是解码方案的非法格式,则解码器也可能失败。编码器将在 IDENTITYBASE64* 编码方案,如果 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

另请参阅