Это реализация протокола передачи гипертекста версии 2 на языке C.
Уровень кадрирования HTTP/2 реализован как повторно используемая библиотека C. Кроме того, мы реализовали клиент, сервер и прокси HTTP/2. Мы также разработали инструменты нагрузочного тестирования и сравнительного анализа для HTTP/2.
Кодер и декодер HPACK доступны в виде общедоступного API.
nghttp2 изначально был разработан на основе RFC 7540 HTTP/2 и RFC 7541 HPACK — сжатие заголовка для HTTP/2. Сейчас мы обновляем наш код для реализации RFC 9113.
База кода nghttp2 была создана из проекта spdylay (https://github.com/tatsuhiro-t/spdylay).
Следующие конечные точки доступны для тестирования нашей реализации nghttp2.
https://nghttp2.org/ (TLS + ALPN и HTTP/3)
Эта конечная точка поддерживает h2
, h2-16
, h2-14
и http/1.1
через ALPN и требует TLSv1.2 для соединения HTTP/2.
Он также поддерживает HTTP/3.
http://nghttp2.org/ (обновление HTTP и прямой HTTP/2)
h2c
и http/1.1
.
Для сборки библиотеки libnghttp2 необходим следующий пакет:
Для сборки документации вам необходимо установить:
Если вам нужен только libnghttp2 (библиотека C), то вышеперечисленные пакеты — это все, что вам нужно. Используйте --enable-lib-only
, чтобы гарантировать сборку только libnghttp2. Это позволяет избежать потенциальной ошибки сборки, связанной со сборкой связанных приложений.
Для сборки и запуска прикладных программ ( nghttp
, nghttpd
, nghttpx
и h2load
) в каталоге src
требуются следующие пакеты:
Чтобы включить опцию -a
(получение связанных ресурсов из загруженного ресурса) в nghttp
, необходим следующий пакет:
Чтобы включить поддержку systemd в nghttpx, необходим следующий пакет:
Для инструментов HPACK требуется следующий пакет:
Для сборки исходников в каталоге примеров требуется libevent:
Чтобы уменьшить фрагментацию кучи в долго работающих серверных программах ( nghttpd
и nghttpx
), рекомендуется использовать jemalloc:
Джемаллок
Примечание
Alpine Linux в настоящее время не поддерживает замену malloc из-за ограничений musl. Подробности смотрите в выпуске №762.
Для сборки BoringSSL или aws-lc, чтобы включить сжатие сертификатов TLS RFC 8879 в приложениях, требуется следующая библиотека:
Чтобы включить поддержку mruby для nghttpx, требуется mruby. Нам нужно собрать mruby с явно включенным C++ ABI и, возможно, потребуются другие mrgems, mruby управляется подмодулем git в каталоге Third-Party/mruby. В настоящее время поддержка mruby для nghttpx отключена по умолчанию. Чтобы включить поддержку mruby, используйте параметр конфигурации --with-mruby
. Обратите внимание, что на момент написания этой статьи пакеты libmruby-dev и mruby в Debian/Ubuntu нельзя было использовать для nghttp2, поскольку они не поддерживают C++ ABI. Для сборки mruby требуются следующие пакеты:
nghttpx поддерживает Neverbleed, механизм разделения привилегий для OpenSSL. Короче говоря, это сводит к минимуму риск утечки закрытого ключа при использовании серьезной ошибки, такой как Heartbleed. По умолчанию функция Neverbleed отключена. Чтобы включить его, используйте параметр конфигурации --with-neverbleed
.
Чтобы включить экспериментальную поддержку HTTP/3 для h2load и nghttpx, необходимы следующие библиотеки:
Используйте параметр конфигурации --enable-http3
, чтобы включить функцию HTTP/3 для h2load и nghttpx.
Чтобы создать дополнительную программу eBPF для направления входящей датаграммы QUIC UDP в правильный сокет для nghttpx, необходимы следующие библиотеки:
Используйте параметр конфигурации --with-libbpf
для сборки программы eBPF. libelf-dev необходим для сборки libbpf.
Для Ubuntu 20.04 вы можете собрать libbpf из исходного кода. nghttpx требует наличия программы eBPF для перезагрузки конфигурации и горячей замены исполняемого файла.
Для компиляции исходного кода libnghttp2 C требуется компилятор C99. Известно, что gcc 4.8 подходит. Для компиляции исходного кода C++ требуется компилятор, совместимый с C++20. Известно, что как минимум g++ >= 12 и clang++ >= 15 работают.
Примечание
Чтобы включить поддержку mruby в nghttpx, используйте параметр конфигурации --with-mruby
.
Примечание
Пользователям Mac OS X может потребоваться опция конфигурации --disable-threads
, чтобы отключить многопоточность в nghttpd, nghttpx и h2load и предотвратить их сбой. Приветствуется патч, позволяющий работать с многопоточностью на платформе Mac OS X.
Примечание
Чтобы скомпилировать связанные приложения (nghttp, nghttpd, nghttpx и h2load), необходимо использовать параметр конфигурации --enable-app
и убедиться, что указанные выше требования выполняются. Обычно скрипт configure проверяет необходимые зависимости для создания этих приложений и автоматически включает --enable-app
, поэтому вам не нужно использовать его явно. Но если вы обнаружили, что приложения не были собраны, то использование --enable-app
может обнаружить эту причину, например отсутствие зависимости.
Примечание
Для обнаружения сторонних библиотек используется pkg-config (однако мы не используем pkg-config для некоторых библиотек (например, libev)). По умолчанию pkg-config ищет файл *.pc
в стандартных местах (например, /usr/lib/pkgconfig). Если необходимо использовать файл *.pc
в произвольном расположении, укажите пути к переменной среды PKG_CONFIG_PATH
и передайте ее для настройки скрипта, например:
$ ./configure PKG_CONFIG_PATH=/путь/к/pkgconfig
Для управляемых библиотек pkg-config определены переменные среды *_CFLAG
и *_LIBS
(например, OPENSSL_CFLAGS
, OPENSSL_LIBS
). Указание непустой строки для этих переменных полностью переопределяет pkg-config. Другими словами, если они указаны, pkg-config не используется для обнаружения, и пользователь несет ответственность за указание правильных значений для этих переменных. Чтобы получить полный список этих переменных, запустите ./configure -h
.
Если вы используете Ubuntu 22.04 LTS, выполните следующую команду, чтобы установить необходимые пакеты:
sudo apt-get install g++ clang make binutils autoconf automake
autotools-dev libtool pkg-config
zlib1g-dev libssl-dev libxml2-dev libev-dev
libevent-dev libjansson-dev
libc-ares-dev libjemalloc-dev libsystemd-dev
Ruby-dev Bison Libelf-dev
Проект nghttp2 регулярно выпускает tar-архивы, которые включают исходный код nghttp2 и сгенерированные файлы сборки. Их можно скачать на странице «Релизы».
Для сборки nghttp2 из git требуются пакеты разработки autotools. Для сборки из tar-архивов они не требуются, поэтому это намного проще. Обычный этап сборки выглядит следующим образом:
$ tar xf nghttp2-XYZtar.bz2
$ cd nghttp2-XYZ
$ ./настроить
$ сделать
Сборка из git проста, но убедитесь, что используется как минимум autoconf 2.68:
$ git обновление подмодуля --init
$ автореконф -я
$ автопроизводитель
$ автоконф
$ ./настроить
$ сделать
Самый простой способ создать собственную библиотеку Windows nghttp2 — использовать cmake. Бесплатная версия Visual C++ Build Tools работает нормально.
cmake
.cmake --build
для сборки библиотеки.Обратите внимание, что приведенные выше шаги, скорее всего, создают только библиотеку nghttp2. Никакие связанные приложения не компилируются.
В среде Mingw вы можете скомпилировать только библиотеки: libnghttp2-X.dll
и libnghttp2.a
.
Если вы хотите скомпилировать приложения ( h2load
, nghttp
, nghttpx
, nghttpd
), вам необходимо использовать среду Cygwin.
В среде Cygwin для компиляции приложений необходимо сначала скомпилировать и установить libev.
Во-вторых, вам необходимо отменить определение макроса __STRICT_ANSI__
, иначе функции fdopen
, fileno
и strptime
будут недоступны.
пример команды такой:
$ экспорт CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
$ экспорт CXXFLAGS=$CFLAGS
$ ./настроить
$ сделать
Если вы хотите скомпилировать приложения в разделе examples/
, вам необходимо удалить или переименовать файл event.h
из установки libev, поскольку он конфликтует с установкой libevent.
После установки набора инструментов nghttp2 с помощью make install
может возникнуть аналогичная ошибка:
nghttpx: ошибка при загрузке общих библиотек: libnghttp2.so.14: невозможно открыть файл общего объекта: нет такого файла или каталога
Это означает, что инструмент не может найти общую библиотеку libnghttp2.so
.
Чтобы обновить кеш общей библиотеки, запустите sudo ldconfig
.
Примечание
Документация все еще неполная.
Чтобы создать документацию, запустите:
$ сделать HTML
Документы будут созданы в doc/manual/html/
.
Сгенерированные документы не будут установлены с помощью make install
.
Онлайн-документация доступна по адресу https://nghttp2.org/documentation/.
Чтобы собрать h2load и nghttpx с включенной функцией HTTP/3, запустите сценарий настройки с --enable-http3
.
Чтобы nghttpx мог перезагрузить конфигурации и заменить свой исполняемый файл, одновременно корректно завершая старые рабочие процессы, требуется eBPF. Запустите сценарий настройки с --enable-http3 --with-libbpf
для сборки программы eBPF. Материал ключа QUIC должен быть установлен с помощью --frontend-quic-secret-file
, чтобы сохранить существующие соединения активными во время перезагрузки.
Ниже приведены подробные инструкции по созданию h2load и nghttpx с поддержкой HTTP/3.
Сборка aws-lc:
$ git clone --глубина 1 -b v1.39.0 https://github.com/aws/aws-lc
$ cd aws-lc
$ cmake -B build -DDISABLE_GO=ON --install-prefix=$PWD/opt
$ make -j$(nproc) -C построить
$ cmake --install сборка
$ компакт-диск ..
Сборка nghttp3:
$ git clone --глубина 1 -b v1.6.0 https://github.com/ngtcp2/nghttp3
$ компакт-диск nghttp3
$ git обновление подмодуля --init --глубина 1
$ автореконф -я
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc)
$ сделать установку
$ компакт-диск ..
Сборка ngtcp2:
$ git clone --глубина 1 -b v1.9.1 https://github.com/ngtcp2/ngtcp2
$ компакт-диск ngtcp2
$ git обновление подмодуля --init --глубина 1
$ автореконф -я
$ ./configure --prefix=$PWD/build --enable-lib-only --with-boringssl
BORINGSSL_CFLAGS="-I$PWD/../aws-lc/opt/include"
BORINGSSL_LIBS="-L$PWD/../aws-lc/opt/lib -lssl -lcrypto"
$ make -j$(nproc)
$ сделать установку
$ компакт-диск ..
Если в вашем дистрибутиве Linux нет libbpf-dev >= 0.7.0, выполните сборку из исходного кода:
$ git clone --глубина 1 -b v1.4.6 https://github.com/libbpf/libbpf
$ cd libbpf
$ PREFIX=$PWD/build make -C src install
$ компакт-диск ..
Сборка nghttp2:
$ git клон https://github.com/nghttp2/nghttp2
$ компакт-диск nghttp2
$ git обновление подмодуля --init
$ автореконф -я
$ ./configure --with-mruby --enable-http3 --with-libpf
CC=clang-15 CXX=clang++-15
PKG_CONFIG_PATH="$PWD/../aws-lc/opt/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/ ../libpf/build/lib64/pkgconfig"
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../aws-lc/opt/lib -Wl,-rpath,$PWD/../libpf/build/lib64"
$ make -j$(nproc)
Программа eBPF reuseport_kern.o
должна находиться в каталоге bpf. Передайте параметр --quic-bpf-program-file=bpf/reuseport_kern.o
в nghttpx, чтобы загрузить его. См. также раздел HTTP/3 в документе nghttpx — HTTP/2 proxy — HOW-TO.
Модульные тесты выполняются простым запуском make check
.
У нас есть интеграционные тесты для прокси-сервера nghttpx. Тесты написаны на языке программирования Go и используют его среду тестирования. Мы зависим от следующих библиотек:
Модули Go автоматически загрузят эти зависимости.
Чтобы запустить тесты, выполните следующую команду в каталоге integration-tests
:
$ сделай это
Внутри тестов мы используем порт 3009 для запуска сервера тестируемого объекта.
В nghttp2 v1.0.0 внесено несколько изменений, несовместимых с предыдущими версиями. В этом разделе мы опишем эти изменения и способы перехода на версию 1.0.0.
h2
и h2c
Ранее мы анонсировали h2-14
и h2c-14
. Версия 1.0.0 реализует окончательную версию протокола, и мы изменили идентификатор ALPN на h2
и h2c
. Макросы NGHTTP2_PROTO_VERSION_ID
, NGHTTP2_PROTO_VERSION_ID_LEN
, NGHTTP2_CLEARTEXT_PROTO_VERSION_ID
и NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN
были обновлены, чтобы отразить это изменение.
По сути, с существующими приложениями ничего делать не нужно, для этого изменения достаточно просто перекомпилировать.
Мы используем «предисловие к клиентскому соединению» для обозначения первых 24 байтов предисловия к клиентскому соединению. Технически это неправильно, поскольку предисловие к соединению клиента состоит из 24-байтовой строки магических байтов клиента, за которой следует кадр НАСТРОЙКИ. Для пояснения мы называем «клиентской магией» эту 24-байтовую строку и обновленный API.
NGHTTP2_CLIENT_CONNECTION_PREFACE
был заменен на NGHTTP2_CLIENT_MAGIC
.NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
заменен на NGHTTP2_CLIENT_MAGIC_LEN
.NGHTTP2_BAD_PREFACE
переименован в NGHTTP2_BAD_CLIENT_MAGIC
Уже устаревшие NGHTTP2_CLIENT_CONNECTION_HEADER
и NGHTTP2_CLIENT_CONNECTION_HEADER_LEN
были удалены.
Если приложение использует эти макросы, просто замените старые на новые. Начиная с версии 1.0.0, клиентская магия отправляется библиотекой (см. следующий подраздел), поэтому клиентское приложение может просто исключить использование этих макросов.
Ранее библиотека nghttp2 не отправляла клиентскую магию, которая представляет собой первую 24-байтовую строку предисловия к клиентскому соединению, и клиентским приложениям приходилось отправлять ее самостоятельно. Начиная с версии 1.0.0, клиентская магия отправляется библиотекой посредством первого вызова nghttp2_session_send()
или nghttp2_session_mem_send2()
.
Клиентские приложения, отправляющие клиентскую магию, должны удалить соответствующий код.
Спецификация Alt-Svc еще не доработана. Чтобы сделать наш API стабильным, мы решили удалить все API, связанные с Alt-Svc, из nghttp2.
NGHTTP2_EXT_ALTSVC
был удален.nghttp2_ext_altsvc
был удален.Мы уже удалили функциональность Alt-Svc в серии v0.7, и они, по сути, были бесполезными. Приложение, использующее этот макрос и структуру, удаляет эти строки.
Ранее nghttp2_on_invalid_frame_recv_cb_called
принимал error_code
, определенный в nghttp2_error_code
, в качестве параметра. Но они недостаточно подробны для отладки. Поэтому мы решили вместо этого использовать более подробные значения nghttp2_error
.
Приложение, использующее этот обратный вызов, должно обновить подпись обратного вызова. Если он воспринимает error_code
как код ошибки HTTP/2, обновите код, чтобы он обрабатывался как nghttp2_error
.
Раньше nghttp2 не обрабатывал магию клиента (строку 24 байта). Чтобы справиться с этим, нам пришлось использовать nghttp2_option_set_recv_client_preface()
. Начиная с версии 1.0.0, nghttp2 по умолчанию обрабатывает магию клиента, а nghttp2_option_set_recv_client_preface()
был удален.
Некоторым приложениям может потребоваться отключить это поведение, поэтому для достижения этой цели мы добавили nghttp2_option_set_no_recv_client_magic()
.
Приложение использует nghttp2_option_set_recv_client_preface()
с ненулевым значением, просто удалите его.
Приложение, использующее nghttp2_option_set_recv_client_preface()
с нулевым значением или не использующее его, должно использовать nghttp2_option_set_no_recv_client_magic()
с ненулевым значением.
Каталог src
содержит клиентские, серверные и прокси-программы HTTP/2.
nghttp
— клиент HTTP/2. Он может подключаться к серверу HTTP/2 с предварительным знанием, обновлением HTTP и расширением ALPN TLS.
Он имеет режим подробного вывода для формирования информации. Вот пример вывода клиента nghttp
:
$ nghttp -nv https://nghttp2.org
[ 0.190] Подключено
Протокол переговоров: h2
[0.212] кадр Recv SETTINGS <длина=12, flags=0x00,stream_id=0>
(нив=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.212] отправить кадр SETTINGS <длина=12, flags=0x00,stream_id=0>
(нив=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.212] отправить кадр SETTINGS <длина=0, flags=0x01,stream_id=0>
; ПОДТВЕРЖДЕНИЕ
(нив=0)
[0.212] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=3>
(dep_stream_id=0, вес=201, эксклюзив=0)
[0.212] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=5>
(dep_stream_id=0, вес=101, эксклюзив=0)
[0.212] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=7>
(dep_stream_id=0, вес=1, эксклюзив=0)
[0.212] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=9>
(dep_stream_id=7, вес=1, эксклюзив=0)
[0.212] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=11>
(dep_stream_id=3, вес=1, эксклюзив=0)
[0.212] отправить кадр HEADERS <длина=39, flags=0x25,stream_id=13>
; END_STREAM | END_HEADERS | ПРИОРИТЕТ
(padlen=0, dep_stream_id=11, вес=16, эксклюзив=0)
; Открыть новый поток
:метод: ПОЛУЧИТЬ
:путь: /
:схема: https
:authority: nghttp2.org
принимать: */*
принять-кодировку: gzip, deflate
пользовательский агент: nghttp2/1.0.1-DEV
[0.221] кадр Recv SETTINGS <длина=0, флаги=0x01,stream_id=0>
; ПОДТВЕРЖДЕНИЕ
(нив=0)
[0.221] получение (stream_id=13): метод: GET
[0.221] получение (stream_id=13) :scheme: https
[0.221] получение (stream_id=13): путь: /stylesheets/screen.css
[0.221] получение (stream_id=13) :authority: nghttp2.org
[0.221] Recv (stream_id=13) принять кодировку: gzip, deflate
[0.222] получение (stream_id=13) пользовательский агент: nghttp2/1.0.1-DEV
[0.222] Получен кадр PUSH_PROMISE <длина=50, флаги=0x04,stream_id=13>
; END_HEADERS
(падлен=0, обещанный_поток_id=2)
[0.222] получение (stream_id=13): статус: 200
[0.222] дата получения (stream_id=13): четверг, 21 мая 2015 г., 16:38:14 по Гринвичу
[ 0.222] Recv (stream_id=13) тип контента: text/html
[0.222] Recv (stream_id=13) последнее изменение: пятница, 15 мая 2015 г., 15:38:06 GMT
[ 0.222] получение (stream_id=13) etag: W/"555612de-19f6"
[ 0.222] ссылка Recv (stream_id=13): ; отн = предварительная загрузка; as=таблица стилей
[0.222] Recv (stream_id=13) Кодировка контента: gzip
[0.222] сервер получения (stream_id=13): nghttpx nghttp2/1.0.1-DEV
[0.222] получение (stream_id=13) через: 1.1 nghttpx
[0.222] Recv (stream_id=13) строгая транспортная безопасность: max-age=31536000
[0.222] кадр получения HEADERS <длина=166, flags=0x04,stream_id=13>
; END_HEADERS
(падлен=0)
; Заголовок первого ответа
[0,222] кадр полученных данных <длина=2601, флаги=0x01,stream_id=13>
; END_STREAM
[0.222] получение (stream_id=2): статус: 200
[ 0.222] дата получения (stream_id=2): четверг, 21 мая 2015 г., 16:38:14 по Гринвичу
[0.222] Recv (stream_id=2) тип контента: text/css
[0.222] Recv (stream_id=2) последнее изменение: пятница, 15 мая 2015 г., 15:38:06 GMT
[ 0.222] получение (stream_id=2) etag: W/"555612de-9845"
[0.222] Recv (stream_id=2) кодировка контента: gzip
[0.222] сервер получения (stream_id=2): nghttpx nghttp2/1.0.1-DEV
[0.222] получение (stream_id=2) через: 1.1 nghttpx
[0.222] Recv (stream_id=2) строгая транспортная безопасность: max-age=31536000
[0.222] кадр получения HEADERS <длина=32, flags=0x04,stream_id=2>
; END_HEADERS
(падлен=0)
; Первый заголовок ответа на нажатие
[0,228] кадр полученного ДАННОГО <длина=8715, флаги=0x01,stream_id=2>
; END_STREAM
[0.228] отправить кадр GOAWAY <длина=8, флаги=0x00,stream_id=0>
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
Обновление HTTP выполняется следующим образом:
$ nghttp -nvu http://nghttp2.org
[ 0.011] Подключено
[0.011] Запрос на обновление HTTP
ПОЛУЧИТЬ/HTTP/1.1
Хост: nghttp2.org
Соединение: Обновление, настройки HTTP2
Обновление: h2c
Настройки HTTP2: AAMAAABkAAQAAP__
Принимать: */*
Пользовательский агент: nghttp2/1.0.1-DEV
[0.018] Ответ на обновление HTTP
HTTP/1.1 101 Протоколы коммутации
Подключение: Обновление
Обновление: h2c
[0.018] Успешное обновление HTTP
[0.018] кадр Recv SETTINGS <длина=12, флаги=0x00,stream_id=0>
(нив=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.018] отправить кадр SETTINGS <длина=12, flags=0x00,stream_id=0>
(нив=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.018] отправить кадр SETTINGS <длина=0, flags=0x01,stream_id=0>
; ПОДТВЕРЖДЕНИЕ
(нив=0)
[0.018] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=3>
(dep_stream_id=0, вес=201, эксклюзив=0)
[0.018] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=5>
(dep_stream_id=0, вес=101, эксклюзив=0)
[0.018] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=7>
(dep_stream_id=0, вес=1, эксклюзив=0)
[0.018] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=9>
(dep_stream_id=7, вес=1, эксклюзив=0)
[0.018] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=11>
(dep_stream_id=3, вес=1, эксклюзив=0)
[0.018] отправить кадр PRIORITY <длина=5, flags=0x00,stream_id=1>
(dep_stream_id=11, вес=16, эксклюзив=0)
[0.019] получение (stream_id=1): метод: GET
[0.019] получение (stream_id=1) :scheme: http
[0.019] получение (stream_id=1): путь: /stylesheets/screen.css
[0.019] хост приема (stream_id=1): nghttp2.org
[0.019] получение (stream_id=1) пользовательский агент: nghttp2/1.0.1-DEV
[0.019] Получен кадр PUSH_PROMISE <длина=49, флаги=0x04,stream_id=1>
; END_HEADERS
(падлен=0, обещанный_поток_id=2)
[0.019] получение (stream_id=1): статус: 200
[ 0.019] дата получения (stream_id=1): четверг, 21 мая 2015 г., 16:39:16 по Гринвичу
[ 0.019] Recv (stream_id=1) тип контента: text/html
[0.019] получение (stream_id=1) длина содержимого: 6646
[0.019] Recv (stream_id=1) последнее изменение: пятница, 15 мая 2015 г., 15:38:06 GMT
[0.019] получение (stream_id=1) etag: "555612de-19f6"
[ 0.019] ссылка Recv (stream_id=1): ; отн = предварительная загрузка; as=таблица стилей
[0.019] Recv (stream_id=1) диапазоны приема: байты
[0.019] сервер получения (stream_id=1): nghttpx nghttp2/1.0.1-DEV
[0.019] получение (stream_id=1) через: 1.1 nghttpx
[0.019] кадр получения HEADERS <длина=157, флаги=0x04,stream_id=1>
; END_HEADERS
(падлен=0)
; Заголовок первого ответа
[0,019] кадр полученных данных <длина=6646, флаги=0x01,stream_id=1>
; END_STREAM
[0.019] получение (stream_id=2): статус: 200
[ 0.019] дата получения (stream_id=2): четверг, 21 мая 2015 г., 16:39:16 по Гринвичу
[0.019] Recv (stream_id=2) тип контента: text/css
[0.019] получение (stream_id=2) длина содержимого: 38981
[0.019] Recv (stream_id=2) последнее изменение: пятница, 15 мая 2015 г., 15:38:06 GMT
[0,019] получение (stream_id=2) etag: "555612de-9845"
[0.019] Recv (stream_id=2) диапазоны приема: байты
[0.019] сервер получения (stream_id=2): nghttpx nghttp2/1.0.1-DEV
[0.019] получение (stream_id=2) через: 1.1 nghttpx
[0.019] кадр получения HEADERS <длина=36, флаги=0x04,stream_id=2>
; END_HEADERS
(падлен=0)
; Первый заголовок ответа на нажатие
[0,026] кадр полученного ДАННОГО <длина=16384, флаги=0x00,stream_id=2>
[0,027] кадр полученных данных <длина=7952, флаги=0x00,stream_id=2>
[0.027] отправить кадр WINDOW_UPDATE <длина=4, флаги=0x00,stream_id=0>
(window_size_increment=33343)
[0.032] отправить кадр WINDOW_UPDATE <длина=4, флаги=0x00,stream_id=2>
(window_size_increment=33707)
[0,032] кадр полученных данных <длина=14645, флаги=0x01,stream_id=2>
; END_STREAM
[0.032] кадр Recv SETTINGS <длина=0, флаги=0x01,stream_id=0>
; ПОДТВЕРЖДЕНИЕ
(нив=0)
[0.032] отправить кадр GOAWAY <длина=8, флаги=0x00,stream_id=0>
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
Используя опцию -s
, nghttp
выводит некоторую информацию о времени выполнения запросов, отсортированную по времени завершения:
$ nghttp -nas https://nghttp2.org/
***** Статистика *****
Время запроса:
responseEnd: время получения последнего байта ответа.
относительно ConnectEnd
requestStart: время непосредственно перед отправкой первого байта запроса.
относительно ConnectEnd. Если отображается '*', это было
проталкивается сервером.
процесс: responseEnd - requestStart
код: код состояния HTTP
размер: количество байтов, полученных в качестве тела ответа без
инфляция.
URI: запрос URI
см. http://www.w3.org/TR/resource-timing/#processing-model.
отсортировано по «полному»
id responseEnd requestStart путь запроса размера кода процесса
13 +37,19мс +280мс 36,91мс 200 2К /
2 +72,65 мс * +36,38 мс 36,26 мс 200 8K /stylesheets/screen.css
17 +77,43 мс +38,67 мс 38,75 мс 200 3K /javascripts/octopress.js
15 +78,12 мс +38,66 мс 39,46 мс 200 3K /javascripts/modernizr-2.0.js
Используя опцию -r
, nghttp
записывает более подробные данные о времени в данный файл в формате HAR.
nghttpd
— многопоточный статический веб-сервер.
По умолчанию используется соединение SSL/TLS. Используйте параметр --no-tls
чтобы отключить его.
nghttpd
принимает только соединения HTTP/2 через ALPN или прямые соединения HTTP/2. Обновление HTTP не поддерживается.
Опция -p
позволяет пользователям настраивать отправку данных на сервер.
Как и nghttp
, он имеет режим подробного вывода для формирования информации. Вот пример вывода nghttpd
:
$ nghttpd --no-tls -v 8080
IPv4: слушать 0.0.0.0:8080
IPv6: слушать :::8080
[id=1] [1.521] отправить кадр SETTINGS <длина=6, flags=0x00,stream_id=0>
(нив=1)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=1] [ 1.521] кадр Recv SETTINGS <длина=12, flags=0x00,stream_id=0>
(нив=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[id=1] [1.521] кадр Recv SETTINGS <длина=0, flags=0x01,stream_id=0>
; ПОДТВЕРЖДЕНИЕ
(нив=0)
[id=1] [1.521] получен кадр PRIORITY <длина=5, flags=0x00,stream_id=3>
(dep_stream_id=0, вес=201, эксклюзив=0)
[id=1] [1.521] получен кадр PRIORITY <длина=5, flags=0x00,stream_id=5>
(dep_stream_id=0, вес=101, эксклюзив=0)
[id=1] [1.521] получен кадр PRIORITY <длина=5, flags=0x00,stream_id=7>
(dep_stream_id=0, вес=1, эксклюзив=0)
[id=1] [ 1.521] получен кадр PRIORITY <длина=5, flags=0x00,stream_id=9>
(dep_stream_id=7, вес=1, эксклюзив=0)
[id=1] [1.521] получен кадр PRIORITY <длина=5, flags=0x00,stream_id=11>
(dep_stream_id=3, вес=1, эксклюзив=0)
[id=1] [1.521] получение (stream_id=13): метод: GET
[id=1] [1.521] получение (stream_id=13) :path: /
[id=1] [1.521] получение (stream_id=13) :scheme: http
[id=1] [1.521] получение (stream_id=13):authority: localhost:8080
[id=1] [1.521] получение (stream_id=13) принять: */*
[id=1] [1.521] Recv (stream_id=13) принять кодировку: gzip, deflate
[id=1] [1.521] получение (stream_id=13) пользовательский агент: nghttp2/1.0.0-DEV
[id=1] [1.521] кадр получения HEADERS <длина=41, flags=0x25,stream_id=13>
; END_STREAM | END_HEADERS | ПРИОРИТЕТ
(padlen=0, dep_stream_id=11, вес=16, эксклюзив=0)
; Открыть новый поток
[id=1] [1.521] отправить кадр SETTINGS <длина=0, flags=0x01,stream_id=0>
; ПОДТВЕРЖДЕНИЕ
(нив=0)
[id=1] [1.521] отправить кадр HEADERS <длина=86, flags=0x04,stream_id=13>
; END_HEADERS
(падлен=0)
; Заголовок первого ответа
:статус: 200
сервер: nghttpd nghttp2/1.0.0-DEV
длина контента: 10
контроль кэша: max-age=3600
дата: пятница, 15 мая 2015 г., 14:49:04 GMT
последнее изменение: вторник, 30 сентября 2014 г., 12:40:52 GMT
[id=1] [1.522] отправить кадр DATA <длина=10, flags=0x01,stream_id=13>
; END_STREAM
[id=1] [ 1.522]stream_id=13 закрыто
[id=1] [1.522] получен кадр GOAWAY <длина=8, flags=0x00,stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])
[id=1] [ 1.522] закрыто
nghttpx
— это многопоточный обратный прокси-сервер для HTTP/3, HTTP/2 и HTTP/1.1, который поддерживает http://nghttp2.org и поддерживает отправку данных с сервера HTTP/2.
Мы переработали интерфейс командной строки nghttpx
, в результате чего появилось несколько несовместимых с версией 1.8.0 или более ранних версий. Это необходимо для расширения его возможностей и обеспечения дальнейших улучшений функций в будущем выпуске. Пожалуйста, прочтите «Миграция с nghttpx v1.8.0 или более ранней версии», чтобы узнать, как перейти с более ранних версий.
nghttpx
реализует важные функции, ориентированные на производительность, в TLS, такие как идентификаторы сеансов, билеты сеансов (с автоматической ротацией ключей), сшивание OCSP, динамическое определение размера записей, ALPN, прямую секретность и HTTP/2. nghttpx
также предлагает функцию совместного использования кеша сеанса и ключей билетов между несколькими экземплярами nghttpx
через memcached.
nghttpx
имеет 2 режима работы:
Опция режима | Внешний интерфейс | Бэкэнд | Примечание |
---|---|---|---|
режим по умолчанию | HTTP/3, HTTP/2, HTTP/1.1 | HTTP/1.1, HTTP/2 | Обратный прокси |
--http2-proxy | HTTP/3, HTTP/2, HTTP/1.1 | HTTP/1.1, HTTP/2 | Форвард прокси |
Интересный режим на данный момент — это режим по умолчанию. Он работает как обратный прокси-сервер и прослушивает HTTP/3, HTTP/2 и HTTP/1.1 и может быть развернут как терминатор SSL/TLS для существующего веб-сервера.
Во всех режимах внешние соединения по умолчанию шифруются с помощью SSL/TLS. Чтобы отключить шифрование, используйте ключевое слово no-tls
в опции --frontend
. Если шифрование отключено, входящие соединения HTTP/1.1 можно обновить до HTTP/2 с помощью обновления HTTP. На другом жестком диске серверные соединения по умолчанию не шифруются. Чтобы зашифровать внутренние соединения, используйте ключевое слово tls
в опции --backend
.
nghttpx
поддерживает файл конфигурации. См. параметр --conf
и пример файла конфигурации nghttpx.conf.sample
.
В режиме по умолчанию nghttpx
работает как обратный прокси-сервер для внутреннего сервера:
Клиент <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Веб-сервер
[обратный прокси]
С опцией --http2-proxy
он работает как прямой прокси и является так называемым безопасным прокси-сервером HTTP/2:
Клиент <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Прокси
[безопасный прокси] (например, Squid, ATS)
Client
в приведенном выше примере необходимо настроить на использование nghttpx
в качестве безопасного прокси-сервера.
На момент написания этой статьи и Chrome, и Firefox поддерживали безопасный прокси-сервер HTTP/2. Один из способов настроить Chrome на использование безопасного прокси-сервера — создать такой скрипт proxy.pac:
function FindProxyForURL ( url , host ) {
return "HTTPS SERVERADDR:PORT" ;
}
SERVERADDR
и PORT
— это имя хоста/адрес и порт компьютера, на котором работает nghttpx. Обратите внимание, что Chrome требует действительный сертификат для безопасного прокси.
Затем запустите Chrome со следующими аргументами:
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
Внутренние соединения HTTP/2 можно туннелировать через HTTP-прокси. Прокси указывается с помощью --backend-http-proxy-uri
. На следующем рисунке показано, как nghttpx взаимодействует с внешним прокси-сервером HTTP/2 через прокси-сервер HTTP:
Клиент <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
--===================---> HTTP/2-прокси
(HTTP-прокси-туннель) (например, nghttpx -s)
Программа h2load
— это инструмент для сравнительного анализа HTTP/3, HTTP/2 и HTTP/1.1. Пользовательский интерфейс h2load
во многом вдохновлен weighttp
(https://github.com/lighttpd/weighttp). Типичное использование следующее:
$ h2load -n100000 -c100 -m100 https://localhost:8443/
стартовый тест...
порождающий поток № 0: 100 одновременных клиентов, общее количество запросов 100 000.
Протокол: TLSv1.2
Шифр: ECDHE-RSA-AES128-GCM-SHA256.
Временной ключ сервера: ECDH P-256, 256 бит.
прогресс: выполнено 10%
прогресс: выполнено 20%
прогресс: выполнено 30%
прогресс: выполнено 40%
прогресс: выполнено 50%
прогресс: выполнено 60%
прогресс: выполнено 70%
прогресс: выполнено 80%
прогресс: 90% выполнено
прогресс: выполнено на 100%
завершено за 771,26 мс, 129658 запросов/с, 4,71 МБ/с
запросов: всего 100 000, 100 000 запущено, 100 000 выполнено, 100 000 выполнено успешно, 0 неудачно, 0 ошибок
коды состояния: 100000 2xx, 0 3xx, 0 4xx, 0 5xx
трафик: всего 3812300 байт, заголовки 1009900 байт, данные 1000000 байт
мин. макс. среднее стандартное отклонение +/- стандартное отклонение
время запроса: 25,12мс 124,55мс 51,07мс 15,36мс 84,87%
время подключения: 208,94 мс 254,67 мс 241,38 мс 7,95 мс 63,00%
время до 1-го байта: 209,11 мс 254,80 мс 241,51 мс 7,94 мс 63,00%
В приведенном выше примере было выдано всего 100 000 запросов с использованием 100 одновременных клиентов (другими словами, 100 сеансов HTTP/2) и максимум 100 потоков на каждого клиента. С опцией -t
h2load
будет использовать несколько собственных потоков, чтобы избежать перегрузки одного ядра на стороне клиента.
Предупреждение
Не используйте этот инструмент против общедоступных серверов. Это считается атакой DOS. Пожалуйста, используйте его только против ваших частных серверов.
Если экспериментальный HTTP/3 включен, h2load может отправлять запросы на сервер HTTP/3. Для этого укажите параметр h3
в --alpn-list
следующим образом:
$ h2load --alpn-list h3 https://127.0.0.1:4433
Для nghttp2 v1.58 или более ранней версии используйте --npn-list
вместо --alpn-list
.
Каталог src
содержит инструменты HPACK. Программа deflatehd
— это инструмент сжатия заголовков командной строки. Программа inflatehd
— это инструмент распаковки заголовков командной строки. Оба инструмента считывают ввод со стандартного ввода и записывают вывод на стандартный вывод. Ошибки записываются в stderr. Они принимают JSON в качестве входных и выходных данных. Мы (в основном) используем тот же формат данных JSON, который описан на https://github.com/http2jp/hpack-test-case.
Программа deflatehd
считывает данные JSON или поля заголовка в стиле HTTP/1 из STDIN и выходы сжатого блока заголовка в JSON.
Для ввода JSON объект root json должен включать ключ cases
. Его значение должно включать последовательность набора заголовков ввода. Они разделяют тот же контекст сжатия и обрабатываются в порядке, в котором они появляются. Каждый элемент в последовательности представляет собой объект JSON, и он должен включать ключ headers
. Его значение представляет собой массив объектов JSON, который включает в себя ровную пару имен/пара.
Пример:
{
"cases" :
[
{
"headers" : [
{ ":method" : " GET " },
{ ":path" : " / " }
]
},
{
"headers" : [
{ ":method" : " POST " },
{ ":path" : " / " }
]
}
]
}
С помощью -t
программа может принять более знакомые полевые блоки HTTP/1. Каждый набор заголовков разграничен пустой линией:
Пример:
: Метод: получить
: Схема: https
:путь: /
: Метод: Пост
Пользовательский агент: NGHTTP2
Вывод находится в объекте JSON. Он должен включать ключ cases
, а его значение - это массив объектов JSON, который имеет по крайней мере следующие ключи:
output_length
/ input_length
* 100Примеры:
{
"cases" :
[
{
"seq" : 0 ,
"input_length" : 66 ,
"output_length" : 20 ,
"percentage_of_original_size" : 30.303030303030305 ,
"wire" : " 01881f3468e5891afcbf83868a3d856659c62e3f " ,
"headers" : [
{
":authority" : " example.org "
},
{
":method" : " GET "
},
{
":path" : " / "
},
{
":scheme" : " https "
},
{
"user-agent" : " nghttp2 "
}
],
"header_table_size" : 4096
}
,
{
"seq" : 1 ,
"input_length" : 74 ,
"output_length" : 10 ,
"percentage_of_original_size" : 13.513513513513514 ,
"wire" : " 88448504252dd5918485 " ,
"headers" : [
{
":authority" : " example.org "
},
{
":method" : " POST "
},
{
":path" : " /account "
},
{
":scheme" : " https "
},
{
"user-agent" : " nghttp2 "
}
],
"header_table_size" : 4096
}
]
}
Выход может использоваться в качестве входа для inflatehd
и deflatehd
.
С помощью опции -d
добавляется дополнительная клавиша header_table
, и его связанное значение включает в себя состояние таблицы динамических заголовков после обработки соответствующего набора заголовков. Значение включает в себя как минимум следующие ключи:
referenced
это true
, он находится в ссылке. size
включает в себя накладные расходы (32 байта). index
соответствует индексу таблицы заголовков. name
- имя поля заголовка, а value
- значение поля заголовка.max_deflate_size
.max_size
. В этом случае энкодер использует только для первого буфера max_deflate_size
. Поскольку размер таблицы заголовков по -прежнему остается max_size
, энкодер должен отслеживать записи за пределами max_deflate_size
, но внутри max_size
и убедиться, что они больше не ссылаются.Пример:
{
"cases" :
[
{
"seq" : 0 ,
"input_length" : 66 ,
"output_length" : 20 ,
"percentage_of_original_size" : 30.303030303030305 ,
"wire" : " 01881f3468e5891afcbf83868a3d856659c62e3f " ,
"headers" : [
{
":authority" : " example.org "
},
{
":method" : " GET "
},
{
":path" : " / "
},
{
":scheme" : " https "
},
{
"user-agent" : " nghttp2 "
}
],
"header_table_size" : 4096 ,
"header_table" : {
"entries" : [
{
"index" : 1 ,
"name" : " user-agent " ,
"value" : " nghttp2 " ,
"referenced" : true ,
"size" : 49
},
{
"index" : 2 ,
"name" : " :scheme " ,
"value" : " https " ,
"referenced" : true ,
"size" : 44
},
{
"index" : 3 ,
"name" : " :path " ,
"value" : " / " ,
"referenced" : true ,
"size" : 38
},
{
"index" : 4 ,
"name" : " :method " ,
"value" : " GET " ,
"referenced" : true ,
"size" : 42
},
{
"index" : 5 ,
"name" : " :authority " ,
"value" : " example.org " ,
"referenced" : true ,
"size" : 53
}
],
"size" : 226 ,
"max_size" : 4096 ,
"deflate_size" : 226 ,
"max_deflate_size" : 4096
}
}
,
{
"seq" : 1 ,
"input_length" : 74 ,
"output_length" : 10 ,
"percentage_of_original_size" : 13.513513513513514 ,
"wire" : " 88448504252dd5918485 " ,
"headers" : [
{
":authority" : " example.org "
},
{
":method" : " POST "
},
{
":path" : " /account "
},
{
":scheme" : " https "
},
{
"user-agent" : " nghttp2 "
}
],
"header_table_size" : 4096 ,
"header_table" : {
"entries" : [
{
"index" : 1 ,
"name" : " :method " ,
"value" : " POST " ,
"referenced" : true ,
"size" : 43
},
{
"index" : 2 ,
"name" : " user-agent " ,
"value" : " nghttp2 " ,
"referenced" : true ,
"size" : 49
},
{
"index" : 3 ,
"name" : " :scheme " ,
"value" : " https " ,
"referenced" : true ,
"size" : 44
},
{
"index" : 4 ,
"name" : " :path " ,
"value" : " / " ,
"referenced" : false ,
"size" : 38
},
{
"index" : 5 ,
"name" : " :method " ,
"value" : " GET " ,
"referenced" : false ,
"size" : 42
},
{
"index" : 6 ,
"name" : " :authority " ,
"value" : " example.org " ,
"referenced" : true ,
"size" : 53
}