2016-02-26 7 views
1

Я пытался изучить исходный код nginx некоторое время. Недавно Nginx 1.9.12 был выпущен, и с ними были реализованы «кодировка Huffman заголовков ответов в HTTP/2».Как этот код приводит к строке «nginx»?

В этом выпуске я не могу понять одну строку,

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 для вставки заголовка "Сервер: nginx".

Что делать, если я хочу изменить его на «Apache»? Я попытался преобразовать строку «apache» в шестнадцатеричный, а затем заменить полученный шестнадцатеричный файл в формате с обозначением \ xhh и сменить nginx [5] на nginx [6], потому что строка apache имеет длину 6 символов.

Но выход кажется непредсказуемым. Я много искал, прежде чем задавать этот вопрос здесь.

Может кто-нибудь помочь мне, как работает этот код и как я могу заменить текст? Любой скрипт или онлайн-приложение, чтобы сделать его проще?

ответ

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

// ////////////////////////////////////////////////////////////////////////////////// // 
+0

Спасибо Энди. Большое спасибо. – ASRM

1

То, что вы видите здесь, представляет собой представление строки «nginx», сжатой с помощью кодирования Huffman от HPACK.

В этом случае первый байт указывает длину и кодировку строки. Верхний бит указывает, сжат ли он с помощью Хаффмана, остальные 7 бит указывают длину строки (после сжатия, если используется Хаффман).

В этом случае первый байт равен 0x84. Верхний бит установлен, то есть используется Хаффман. Длина равна 4.

В вашем случае тривиальное исправление будет состоять в кодировке строки без Хаффмана. Вы должны поместить длину строки в первый байт, в случае «nginx» 0x05, в случае Apache, 0x06. После этого ASCII-представление строки. Это будет работать для всех строк до 63 байтов. Для более длинных строк требуется больше байтов для кодирования длины.

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

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

спасибо Влад. Я изменил строку на static const u_char nginx [] = {0x06, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65}; И составлен. И сервер отвечает «Apache» в заголовке сервера. Это то, чего я хотел. Однако я просто хочу знать, есть ли какое-либо влияние на производительность или проблема с безопасностью, если я кодирую строку с помощью кодировки Huffman от HPACK (так, как она есть в исходном коде), и то, как вы мне сказали (без huffman). Я бы предпочел, чтобы вы делали кодирование строки с помощью кодирования Huffman от HPACK. По крайней мере, просто чтобы узнать, как это работает. – ASRM

+0

В этом случае вы должны вызвать ngx_http_v2_write_value. Он будет кодировать строку в кратчайшей форме. –

+0

ОК. Спасибо Владу. Каков правильный способ вызвать ngx_http_v2_write_value? В источнике nginx он имеет 4 параметра (dst, src, len, tmp). Я запутался, потому что у меня есть только строка в качестве входных данных. Вместо того, чтобы делать другой вызов в исходном коде, я бы предпочел напрямую знать закодированные по Хаффману шестнадцатеричные значения для строки, чтобы я мог делать так, как вы делали. Любой пример кода (кроме nginxs) в C/C++ для этого? Я не такой хороший, как вы на C.Просто студент колледжа учится у таких экспертов, как вы. Еще раз спасибо Влад. – ASRM