此代码如何生成字符串 "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)
}
// ////////////////////////////////////////////////////////////////////////////////// //
最近一段时间一直在努力研究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)
}
// ////////////////////////////////////////////////////////////////////////////////// //