2

I've been trying to study the nginx source code for a while. Recently, Nginx 1.9.12 was released and with that they implemented "Huffman encoding of response headers in HTTP/2".

In this release, I'm unable to understand the this one line,

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

Alternatively, you can browse the source code here: https://trac.nginx.org/nginx/browser/nginx/src/http/v2/ngx_http_v2_filter_module.c#L146

This line is what Nginx uses to insert header "Server: nginx".

What if I want to change it to "Apache"? I've tried converting the string "apache" to hex and then replace the resulting hex in the file with \xhh notation and changing nginx[5] to nginx[6] because the string apache is 6 characters long.

But the output seems unpredictable. I've searched a lot before asking this question here.

Can someone help me how this code works and how can I replace the text? Any script or online web app to make it easier?

2 Answers 2

2

I wrote simple Go script for converting from/to HPACK compressed strings:

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)
}

// ////////////////////////////////////////////////////////////////////////////////// //
1
  • Thanks Andy. Thanks a lot.
    – user3418870
    Apr 28, 2016 at 18:28
2

What you see here is the representation of the string "nginx" compressed with HPACK's Huffman encoding.

In this case the first byte indicates the length and encoding of the string. The top bit indicates if it is compressed using Huffman, the remaining 7 bits indicate the length of the string (after compression if Huffman is used).

In this case the first byte is 0x84. The top bit is set, meaning Huffman is used. The length is 4.

In your case the trivial fix would be to encode the string without Huffman. You would put the length of the string in the first byte, in the case of "nginx" 0x05, in the case of Apache, 0x06. After that the ASCII representation of the string. That will work for all strings up to 63 bytes. Longer strings require more bytes for length encoding.

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

Apache[] = {0x06, 'A', 'p', 'a', 'c', 'h', 'e'};
5
  • Thanks Vlad. I've changed the line to static const u_char nginx[] = {0x06, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65}; And compiled. And server responds "Apache" in the server header. That's what I wanted. However, I just want to know if there's any performance impact or security issue, if I encode the string with HPACK's Huffman encoding (the way it is in the source code) and the way you've told me to do (without huffman). I'd prefer your way of doing i.e. encoding the string with HPACK's Huffman encoding. At least, just to learn how it works.
    – user3418870
    Feb 29, 2016 at 19:11
  • In that case you should call ngx_http_v2_write_value. It will encode the string in the shortest form. Feb 29, 2016 at 22:53
  • OK. Thanks Vlad. What's the proper way to call ngx_http_v2_write_value? In nginx source, it has 4 parameters (dst, src, len, tmp). I'm confused because I only have a string as input. Instead of making another call in the source code, I'd prefer to directly know the Huffman encoded hex values for a string so that I can do the way you did. Any sample code (apart from nginxs') in C/C++ to do that? I'm not good like you at C. Just a college student learning from experts like you. Thanks again Vlad.
    – user3418870
    Mar 1, 2016 at 7:48
  • You could copy the relevant code, compile it as a standalone application, run it, and see what the result is. Mar 1, 2016 at 19:12
  • Vlad, I've been trying from past few weeks. I'm unable to get working code. Do you have any script or something like that? I'm feeling miserable.
    – user3418870
    Apr 10, 2016 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.