此代码如何生成字符串 "nginx"?

How does this code result in the string "nginx"?

最近一段时间一直在努力研究nginx源码。最近,Nginx 1.9.12 发布并实现了 "Huffman encoding of response headers in HTTP/2".

在这个版本中,我无法理解这一行,

static const u_char nginx[5] = "\x84\xaa\x63\x55\xe7";

或者,您可以在此处浏览源代码:https://trac.nginx.org/nginx/browser/nginx/src/http/v2/ngx_http_v2_filter_module.c#L146

这一行是Nginx用来插入的 header "Server: nginx".

如果我想把它改成"Apache"怎么办?我尝试将字符串 "apache" 转换为十六进制,然后用 \xhh 符号替换文件中生成的十六进制并将 nginx[5] 更改为 nginx[6] 因为字符串 apache 的长度为 6 个字符。

但输出似乎不可预测。在这里问这个问题之前,我已经搜索了很多。

有人可以帮助我了解这段代码的工作原理以及如何替换文本吗?任何脚本或在线网络应用程序可以使它更容易?

您在这里看到的是用 HPACK 的霍夫曼编码压缩的字符串 "nginx" 的表示形式。

在这种情况下,第一个字节表示字符串的长度和编码。 最高位表示是否使用哈夫曼压缩,其余7位表示字符串的长度(如果使用哈夫曼压缩后)。

在这种情况下,第一个字节是 0x84。设置了最高位,意味着使用了霍夫曼。长度为 4.

在你的情况下,简单的解决方法是在没有霍夫曼的情况下对字符串进行编码。您可以将字符串的长度放在第一个字节中,在 "nginx" 的情况下为 0x05,在 Apache 的情况下为 0x06。之后是字符串的 ASCII 表示。这将适用于最多 63 个字节的所有字符串。较长的字符串需要更多的字节来进行长度编码。

nginx[] = {0x05, 'n', 'g', 'i', 'n', 'x'};

Apache[] = {0x06, 'A', 'p', 'a', 'c', 'h', 'e'};

我编写了简单的 Go 脚本来转换 from/to HPACK 压缩字符串:

package main

// ////////////////////////////////////////////////////////////////////////////////// //

import (
    "fmt"
    "golang.org/x/net/http2/hpack"
)

// ////////////////////////////////////////////////////////////////////////////////// //

func main() {
    fmt.Println("nginx", "→", Encode("nginx"))
    fmt.Println("apache", "→", Encode("apache"))
    fmt.Println("-----")
    fmt.Println("\x84\xaa\x63\x55\xe7", "→", Decode("\x84\xaa\x63\x55\xe7"))
    fmt.Println("\x84\x1d\x63\x24\xe5", "→", Decode("\x84\x1d\x63\x24\xe5"))
}

func Encode(s string) string {
    var result string

    hd := hpack.AppendHuffmanString(nil, s)
    hl := hpack.HuffmanEncodeLength(s) | 0x80

    result += RenderByte(byte(hl))

    for _, b := range hd {
        result += RenderByte(b)
    }

    return result
}

func Decode(s string) string {
    data := []byte(s)
    result, _ := hpack.HuffmanDecodeToString(data[1:])
    return result
}

func RenderByte(b byte) string {
    return fmt.Sprintf("\x%x", b)
}

// ////////////////////////////////////////////////////////////////////////////////// //