【问题标题】:How does this code result in the string "nginx"?此代码如何生成字符串“nginx”?
【发布时间】:2016-02-26 15:21:28
【问题描述】:

一段时间以来,我一直在尝试研究 nginx 源代码。最近,Nginx 1.9.12 发布,他们实现了“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 用来插入标题“Server: nginx”的内容。

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

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

有人能帮我看看这段代码是如何工作的吗?我该如何替换文本?有什么脚本或在线网络应用可以让它更简单吗?

【问题讨论】:

    标签: nginx hex huffman-code


    【解决方案1】:

    我编写了简单的 Go 脚本来转换 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)
    }
    
    // ////////////////////////////////////////////////////////////////////////////////// //
    

    【讨论】:

    • 谢谢安迪。非常感谢。
    【解决方案2】:

    你在这里看到的是用 HPACK 的 Huffman 编码压缩的字符串“nginx”的表示。

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

    在这种情况下,第一个字节是 0x84。最高位已设置,表示使用 Huffman。长度为 4。

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

    nginx[] = {0x05, 'n', 'g', 'i', 'n', 'x'};
    
    Apache[] = {0x06, 'A', 'p', 'a', 'c', 'h', 'e'};
    

    【讨论】:

    • 谢谢弗拉德。我已将行更改为 static const u_char nginx[] = {0x06, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65};并编译。服务器在服务器标头中响应“Apache”。这就是我想要的。但是,我只想知道是否存在任何性能影响或安全问题,如果我使用 HPACK 的 Huffman 编码(源代码中的方式)以及您告诉我的方式(没有 huffman)对字符串进行编码。我更喜欢您的方式,即使用 HPACK 的 Huffman 编码对字符串进行编码。至少,只是为了了解它是如何工作的。
    • 在这种情况下,您应该调用 ngx_http_v2_write_value。它将以最短的形式对字符串进行编码。
    • 好的。谢谢弗拉德。调用 ngx_http_v2_write_value 的正确方法是什么?在 nginx 源码中,它有 4 个参数(dst、src、len、tmp)。我很困惑,因为我只有一个字符串作为输入。我宁愿直接知道字符串的霍夫曼编码的十六进制值,而不是在源代码中进行另一个调用,以便我可以按照您的方式进行操作。 C/C++ 中的任何示例代码(除了 nginxs')来做到这一点?我在C方面不像你那么好。只是一个向像你这样的专家学习的大学生。再次感谢弗拉德。
    • 您可以复制相关代码,将其编译为独立应用程序,运行它,看看结果如何。
    • 弗拉德,过去几周我一直在尝试。我无法获得工作代码。你有任何脚本或类似的东西吗?我感觉很痛苦。
    猜你喜欢
    • 2011-03-19
    • 1970-01-01
    • 2013-01-26
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    • 1970-01-01
    • 2017-04-02
    相关资源
    最近更新 更多