Esta é uma implementação do Hypertext Transfer Protocol versão 2 em C.
A camada de enquadramento do HTTP/2 é implementada como uma biblioteca C reutilizável. Além disso, implementamos um cliente, servidor e proxy HTTP/2. Também desenvolvemos ferramentas de teste de carga e benchmarking para HTTP/2.
Um codificador e decodificador HPACK estão disponíveis como uma API pública.
nghttp2 foi originalmente desenvolvido com base em RFC 7540 HTTP/2 e RFC 7541 HPACK - Header Compression for HTTP/2. Agora estamos atualizando nosso código para implementar o RFC 9113.
A base de código nghttp2 foi bifurcada do projeto spdylay (https://github.com/tatsuhiro-t/spdylay).
Os seguintes endpoints estão disponíveis para testar nossa implementação nghttp2.
https://nghttp2.org/ (TLS + ALPN e HTTP/3)
Este endpoint suporta h2
, h2-16
, h2-14
e http/1.1
via ALPN e requer TLSv1.2 para conexão HTTP/2.
Ele também suporta HTTP/3.
http://nghttp2.org/ (atualização HTTP e HTTP/2 direto)
h2c
e http/1.1
.
O seguinte pacote é necessário para construir a biblioteca libnghttp2:
Para construir a documentação, você precisa instalar:
Se você precisar apenas da libnghttp2 (biblioteca C), os pacotes acima são tudo que você precisa. Use --enable-lib-only
para garantir que apenas libnghttp2 seja compilado. Isso evita possíveis erros de compilação relacionados à criação de aplicativos agrupados.
Para construir e executar os programas aplicativos ( nghttp
, nghttpd
, nghttpx
e h2load
) no diretório src
, os seguintes pacotes são necessários:
Para ativar a opção -a
(obter ativos vinculados do recurso baixado) em nghttp
, o seguinte pacote é necessário:
Para habilitar o suporte do systemd no nghttpx, o seguinte pacote é necessário:
As ferramentas HPACK requerem o seguinte pacote:
Para construir fontes no diretório de exemplos, libevent é necessário:
Para mitigar a fragmentação de heap em programas de servidor de longa execução ( nghttpd
e nghttpx
), jemalloc é recomendado:
jemalloc
Observação
Alpine Linux atualmente não oferece suporte à substituição de malloc devido a limitações musl. Veja detalhes na edição nº 762.
Para BoringSSL ou aws-lc build, para habilitar a compactação de certificado TLS RFC 8879 em aplicativos, a seguinte biblioteca é necessária:
Para ativar o suporte mruby para nghttpx, é necessário mruby. Precisamos construir mruby com C++ ABI explicitamente ativado e provavelmente precisaremos de outros mrgems, mruby é gerenciado pelo submódulo git no diretório third-party/mruby. Atualmente, o suporte mruby para nghttpx está desabilitado por padrão. Para ativar o suporte mruby, use a opção de configuração --with-mruby
. Observe que no momento em que este livro foi escrito, os pacotes libmruby-dev e mruby no Debian/Ubuntu não eram utilizáveis para nghttp2, pois não habilitam C++ ABI. Para construir o mruby, são necessários os seguintes pacotes:
nghttpx suporta mecanismo de separação de privilégios neverbleed para OpenSSL. Resumindo, minimiza o risco de vazamento de chave privada quando um bug grave como o Heartbleed é explorado. O Neverbleed está desabilitado por padrão. Para habilitá-lo, use a opção de configuração --with-neverbleed
.
Para ativar o suporte experimental HTTP/3 para h2load e nghttpx, as seguintes bibliotecas são necessárias:
Use a opção de configuração --enable-http3
para ativar o recurso HTTP/3 para h2load e nghttpx.
Para construir um programa eBPF opcional para direcionar um datagrama QUIC UDP de entrada para um soquete correto para nghttpx, as seguintes bibliotecas são necessárias:
Use a opção de configuração --with-libbpf
para construir o programa eBPF. libelf-dev é necessário para construir o libbpf.
Para Ubuntu 20.04, você pode construir libbpf a partir do código-fonte. nghttpx requer o programa eBPF para recarregar sua configuração e trocar a quente seu executável.
A compilação do código-fonte libnghttp2 C requer um compilador C99. O gcc 4.8 é conhecido por ser adequado. Para compilar o código-fonte C++, é necessário um compilador compatível com C++20. Sabe-se que pelo menos g++ >= 12 e clang++ >= 15 funcionam.
Observação
Para ativar o suporte mruby no nghttpx e use a opção de configuração --with-mruby
.
Observação
Os usuários do Mac OS X podem precisar da opção de configuração --disable-threads
para desabilitar o multi-threading em nghttpd, nghttpx e h2load para evitar que eles travem. Um patch é bem-vindo para fazer o multi threading funcionar na plataforma Mac OS X.
Observação
Para compilar os aplicativos associados (nghttp, nghttpd, nghttpx e h2load), você deve usar a opção de configuração --enable-app
e garantir que os requisitos especificados acima sejam atendidos. Normalmente, o script de configuração verifica as dependências necessárias para construir esses aplicativos e habilita --enable-app
automaticamente, para que você não precise usá-lo explicitamente. Mas se você descobriu que os aplicativos não foram criados, o uso de --enable-app
pode encontrar essa causa, como a dependência ausente.
Observação
Para detectar bibliotecas de terceiros, o pkg-config é usado (no entanto, não usamos o pkg-config para algumas bibliotecas (por exemplo, libev)). Por padrão, o pkg-config pesquisa o arquivo *.pc
nos locais padrão (por exemplo, /usr/lib/pkgconfig). Se for necessário usar o arquivo *.pc
no local personalizado, especifique os caminhos para a variável de ambiente PKG_CONFIG_PATH
e passe-o para o script de configuração, assim:
$ ./configure PKG_CONFIG_PATH=/caminho/para/pkgconfig
Para bibliotecas gerenciadas pkg-config, as variáveis de ambiente *_CFLAG
e *_LIBS
são definidas (por exemplo, OPENSSL_CFLAGS
, OPENSSL_LIBS
). A especificação de uma string não vazia para essas variáveis substitui completamente o pkg-config. Em outras palavras, se forem especificadas, pkg-config não será usado para detecção e o usuário será responsável por especificar os valores corretos para essas variáveis. Para obter uma lista completa dessas variáveis, execute ./configure -h
.
Se você estiver usando Ubuntu 22.04 LTS, execute o seguinte para instalar os pacotes necessários:
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
O projeto nghttp2 lança regularmente arquivos tar que incluem código-fonte nghttp2 e arquivos de construção gerados. Eles podem ser baixados na página de lançamentos.
Construir nghttp2 a partir do git requer pacotes de desenvolvimento de autotools. Construir a partir de arquivos tar não exige isso e, portanto, é muito mais fácil. A etapa de construção usual é a seguinte:
$ tar xf nghttp2-XYZtar.bz2
$ cd nghttp2-XYZ
$ ./configure
$ fazer
Construir a partir do git é fácil, mas certifique-se de usar pelo menos o autoconf 2.68:
$ git atualização do submódulo --init
$ autoreconf -i
$ automake
$ autoconf
$ ./configure
$ fazer
A maneira mais fácil de criar dll nghttp2 nativa do Windows é usar cmake. A versão gratuita do Visual C++ Build Tools funciona bem.
cmake
.cmake --build
para construir a biblioteca.Observe que as etapas acima provavelmente produzem apenas a biblioteca nghttp2. Nenhum aplicativo incluído é compilado.
No ambiente Mingw, você só pode compilar a biblioteca, é libnghttp2-X.dll
e libnghttp2.a
.
Se você deseja compilar os aplicativos ( h2load
, nghttp
, nghttpx
, nghttpd
), você precisa usar o ambiente Cygwin.
No ambiente Cygwin, para compilar os aplicativos você precisa primeiro compilar e instalar o libev.
Em segundo lugar, você precisa indefinir a macro __STRICT_ANSI__
, caso contrário, as funções fdopen
, fileno
e strptime
não estarão disponíveis.
o comando de exemplo assim:
$ export CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
$ exportar CXXFLAGS=$CFLAGS
$ ./configure
$ fazer
Se você deseja compilar os aplicativos em examples/
, você precisa remover ou renomear o event.h
da instalação do libev, porque ele entra em conflito com a instalação do libevent.
Depois de instalar o conjunto de ferramentas nghttp2 com make install
pode ocorrer um erro semelhante:
nghttpx: erro ao carregar bibliotecas compartilhadas: libnghttp2.so.14: não é possível abrir o arquivo de objeto compartilhado: esse arquivo ou diretório não existe
Isso significa que a ferramenta não consegue localizar a biblioteca compartilhada libnghttp2.so
.
Para atualizar o cache da biblioteca compartilhada, execute sudo ldconfig
.
Observação
A documentação ainda está incompleta.
Para construir a documentação, execute:
$ fazer HTML
Os documentos serão gerados em doc/manual/html/
.
Os documentos gerados não serão instalados com make install
.
A documentação on-line está disponível em https://nghttp2.org/documentation/
Para construir h2load e nghttpx com o recurso HTTP/3 habilitado, execute o script configure com --enable-http3
.
Para que o nghttpx recarregue as configurações e troque seu executável enquanto encerra normalmente os processos de trabalho antigos, o eBPF é necessário. Execute o script de configuração com --enable-http3 --with-libbpf
para construir o programa eBPF. O material de chaveamento QUIC deve ser definido com --frontend-quic-secret-file
para manter as conexões existentes ativas durante o recarregamento.
As etapas detalhadas para construir h2load e nghttpx habilitados para HTTP/3 são a seguir.
Construir aws-lc:
$ git clone --profundidade 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 compilação
$ cmake --instalar compilação
$cd..
Construa nghttp3:
$ git clone --profundidade 1 -b v1.6.0 https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ git submódulo atualização --init --profundidade 1
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$faça-j$(nproc)
$ fazer instalação
$cd..
Construa ngtcp2:
$ git clone --profundidade 1 -b v1.9.1 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ git submódulo atualização --init --profundidade 1
$ autoreconf -i
$ ./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"
$faça -j$(nproc)
$ fazer instalação
$cd..
Se sua distribuição Linux não tiver libbpf-dev >= 0.7.0, construa a partir do código-fonte:
$ git clone --profundidade 1 -b v1.4.6 https://github.com/libbpf/libbpf
$cd libbpf
$ PREFIX=$PWD/build make -C src install
$cd..
Construa nghttp2:
$ git clone https://github.com/nghttp2/nghttp2
$ cd nghttp2
$ git atualização do submódulo --init
$ autoreconf -i
$ ./configure --with-mruby --enable-http3 --with-libbbpf
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/ ../libbbpf/build/lib64/pkgconfig"
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../aws-lc/opt/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
$faça -j$(nproc)
O programa eBPF reuseport_kern.o
deve ser encontrado no diretório bpf. Passe a opção --quic-bpf-program-file=bpf/reuseport_kern.o
para nghttpx para carregá-lo. Consulte também a seção HTTP/3 em nghttpx - proxy HTTP/2 - COMO FAZER.
Os testes unitários são feitos simplesmente executando make check
.
Temos os testes de integração para o servidor proxy nghttpx. Os testes são escritos na linguagem de programação Go e utilizam sua estrutura de testes. Dependemos das seguintes bibliotecas:
Os módulos Go baixarão essas dependências automaticamente.
Para executar os testes, execute o seguinte comando no diretório integration-tests
:
$ faça isso
Dentro dos testes, usamos a porta 3009 para executar o servidor da cobaia do teste.
nghttp2 v1.0.0 introduziu várias alterações incompatíveis com versões anteriores. Nesta seção, descrevemos essas mudanças e como migrar para a v1.0.0.
h2
e h2c
Anteriormente anunciamos h2-14
e h2c-14
. v1.0.0 implementa a versão final do protocolo e alteramos o ALPN ID para h2
e h2c
. As macros NGHTTP2_PROTO_VERSION_ID
, NGHTTP2_PROTO_VERSION_ID_LEN
, NGHTTP2_CLEARTEXT_PROTO_VERSION_ID
e NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN
foram atualizadas para refletir essa alteração.
Basicamente, as aplicações existentes não precisam fazer nada, basta recompilar para essa mudança.
Usamos "prefácio de conexão do cliente" para significar os primeiros 24 bytes do prefácio de conexão do cliente. Tecnicamente, isso não é correto, pois o prefácio da conexão do cliente é composto por uma sequência de bytes mágicos do cliente de 24 bytes seguida pelo quadro SETTINGS. Para esclarecimento, chamamos de "mágica do cliente" para esta string de 24 bytes e API atualizada.
NGHTTP2_CLIENT_CONNECTION_PREFACE
foi substituído por NGHTTP2_CLIENT_MAGIC
.NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
foi substituído por NGHTTP2_CLIENT_MAGIC_LEN
.NGHTTP2_BAD_PREFACE
foi renomeado como NGHTTP2_BAD_CLIENT_MAGIC
Os já obsoletos NGHTTP2_CLIENT_CONNECTION_HEADER
e NGHTTP2_CLIENT_CONNECTION_HEADER_LEN
foram removidos.
Se o aplicativo usar essas macros, basta substituir as antigas por novas. Desde a v1.0.0, a magia do cliente é enviada pela biblioteca (veja a próxima subseção), então o aplicativo cliente pode simplesmente remover o uso dessas macros.
Anteriormente, a biblioteca nghttp2 não enviava magia do cliente, que é a primeira string de 24 bytes do prefácio de conexão do cliente, e os aplicativos clientes tinham que enviá-la por conta própria. Desde a v1.0.0, a magia do cliente é enviada pela biblioteca por meio da primeira chamada de nghttp2_session_send()
ou nghttp2_session_mem_send2()
.
Os aplicativos clientes que enviam magia do cliente devem remover o código relevante.
A especificação Alt-Svc ainda não foi finalizada. Para tornar nossa API estável, decidimos remover todas as APIs relacionadas ao Alt-Svc do nghttp2.
NGHTTP2_EXT_ALTSVC
foi removido.nghttp2_ext_altsvc
foi removido.Já removemos a funcionalidade do Alt-Svc na série v0.7 e eles foram essencialmente noop. O aplicativo que usa essas macro e estrutura remove essas linhas.
Anteriormente, nghttp2_on_invalid_frame_recv_cb_called
pegava o error_code
, definido em nghttp2_error_code
, como parâmetro. Mas eles não são detalhados o suficiente para serem depurados. Portanto, decidimos usar valores nghttp2_error
mais detalhados.
O aplicativo que usa esse retorno de chamada deve atualizar a assinatura do retorno de chamada. Se tratar error_code
como código de erro HTTP/2, atualize o código para que seja tratado como nghttp2_error
.
Anteriormente, o nghttp2 não processava a magia do cliente (sequência de bytes de 24 bytes). Para lidar com isso, tivemos que usar nghttp2_option_set_recv_client_preface()
. Desde a v1.0.0, o nghttp2 processa a magia do cliente por padrão e nghttp2_option_set_recv_client_preface()
foi removido.
Alguns aplicativos podem querer desabilitar esse comportamento, então adicionamos nghttp2_option_set_no_recv_client_magic()
para conseguir isso.
O aplicativo usando nghttp2_option_set_recv_client_preface()
com valor diferente de zero, basta removê-lo.
O aplicativo que usa nghttp2_option_set_recv_client_preface()
com valor zero ou não o usa deve usar nghttp2_option_set_no_recv_client_magic()
com valor diferente de zero.
O diretório src
contém os programas cliente, servidor e proxy HTTP/2.
nghttp
é um cliente HTTP/2. Ele pode se conectar ao servidor HTTP/2 com conhecimento prévio, atualização HTTP e extensão ALPN TLS.
Possui modo de saída detalhado para enquadrar informações. Aqui está um exemplo de saída do cliente nghttp
:
$ nghttp -nvhttps://nghttp2.org
[0,190] Conectado
O protocolo negociado: h2
[0.212] quadro recv SETTINGS
(niv = 2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.212] enviar quadro SETTINGS
(niv = 2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0.212] enviar quadro SETTINGS
; CONFIRMAR
(niv=0)
[0.212] enviar quadro PRIORITY
(dep_stream_id=0, peso=201, exclusivo=0)
[0.212] enviar quadro PRIORITY
(dep_stream_id=0, peso=101, exclusivo=0)
[0.212] enviar quadro PRIORITY
(dep_stream_id=0, peso=1, exclusivo=0)
[0.212] enviar quadro PRIORITY
(dep_stream_id=7, peso=1, exclusivo=0)
[0.212] enviar quadro PRIORITY
(dep_stream_id=3, peso=1, exclusivo=0)
[0.212] enviar quadro HEADERS
; END_STREAM | END_HEADERS | PRIORIDADE
(padlen=0, dep_stream_id=11, peso=16, exclusivo=0)
; Abrir novo fluxo
:método: GET
:caminho: /
:esquema: https
:autoridade: nghttp2.org
aceitar: */*
codificação de aceitação: gzip, deflate
agente do usuário: nghttp2/1.0.1-DEV
[0.221] quadro recv SETTINGS
; CONFIRMAR
(niv=0)
[0,221] recv (stream_id = 13): método: GET
[0,221] recv (stream_id = 13): esquema: https
[0.221] recv (stream_id = 13): caminho: /stylesheets/screen.css
[0.221] recv (stream_id = 13): autoridade: nghttp2.org
[0,221] recv (stream_id = 13) codificação de aceitação: gzip, deflate
[0.222] recv (stream_id = 13) agente do usuário: nghttp2/1.0.1-DEV
[0.222] recv quadro PUSH_PROMISE
; END_HEADERS
(padlen=0, prometido_stream_id=2)
[0,222] recv (stream_id = 13): status: 200
[0,222] recv (stream_id = 13) data: qui, 21 de maio de 2015 16:38:14 GMT
[0,222] recv (stream_id = 13) tipo de conteúdo: texto/html
[0,222] recv (stream_id = 13) última modificação: sexta-feira, 15 de maio de 2015, 15:38:06 GMT
[0,222] recv (stream_id=13) etag: W/"555612de-19f6"
[0.222] recv (stream_id=13) link: ; rel=pré-carregamento; como = folha de estilo
[0,222] recv (stream_id = 13) codificação de conteúdo: gzip
[0.222] recv (stream_id=13) servidor: nghttpx nghttp2/1.0.1-DEV
[0,222] recv (stream_id = 13) via: 1,1 nghttpx
[0,222] recv (stream_id = 13) segurança de transporte estrito: idade máxima = 31536000
[0,222] quadro recv HEADERS
; END_HEADERS
(padlen=0)
; Cabeçalho da primeira resposta
[0,222] quadro recv DATA
; END_STREAM
[0,222] recv (stream_id = 2): status: 200
[0,222] recv (stream_id = 2) data: qui, 21 de maio de 2015 16:38:14 GMT
[0,222] recv (stream_id = 2) tipo de conteúdo: texto/css
[0,222] recv (stream_id = 2) última modificação: sexta-feira, 15 de maio de 2015, 15:38:06 GMT
[0,222] recv (stream_id=2) e-tag: W/"555612de-9845"
[0,222] recv (stream_id = 2) codificação de conteúdo: gzip
[0.222] recv (stream_id=2) servidor: nghttpx nghttp2/1.0.1-DEV
[0,222] recv (stream_id = 2) via: 1,1 nghttpx
[0,222] recv (stream_id = 2) segurança de transporte estrito: idade máxima = 31536000
[0,222] quadro recv HEADERS
; END_HEADERS
(padlen=0)
; Primeiro cabeçalho de resposta push
[0,228] quadro recv DATA
; END_STREAM
[0,228] enviar quadro GOAWAY
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
A atualização HTTP é realizada da seguinte forma:
$ nghttp -nvu http://nghttp2.org
[0,011] Conectado
[0.011] Solicitação de atualização HTTP
OBTER/HTTP/1.1
Anfitrião: nghttp2.org
Conexão: atualização, configurações HTTP2
Atualização: h2c
Configurações HTTP2: AAMAAABkAAQAAP__
Aceitar: */*
Agente do usuário: nghttp2/1.0.1-DEV
[0,018] Resposta de atualização HTTP
Protocolos de comutação HTTP/1.1 101
Conexão: Atualização
Atualização: h2c
[0,018] Atualização HTTP bem-sucedida
[0,018] quadro recv SETTINGS
(niv = 2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0,018] enviar quadro SETTINGS
(niv = 2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[0,018] enviar quadro SETTINGS
; CONFIRMAR
(niv=0)
[0,018] enviar quadro PRIORITY
(dep_stream_id=0, peso=201, exclusivo=0)
[0,018] enviar quadro PRIORITY
(dep_stream_id=0, peso=101, exclusivo=0)
[0,018] enviar quadro PRIORITY
(dep_stream_id=0, peso=1, exclusivo=0)
[0,018] enviar quadro PRIORITY
(dep_stream_id=7, peso=1, exclusivo=0)
[0,018] enviar quadro PRIORITY
(dep_stream_id=3, peso=1, exclusivo=0)
[0,018] enviar quadro PRIORITY
(dep_stream_id=11, peso=16, exclusivo=0)
[0,019] recv (stream_id = 1): método: GET
[0,019] recv (stream_id = 1): esquema: http
[0,019] recv (stream_id = 1): caminho: /stylesheets/screen.css
[0,019] recv (stream_id = 1) host: nghttp2.org
[0,019] recv (stream_id = 1) agente do usuário: nghttp2/1.0.1-DEV
[0,019] recv quadro PUSH_PROMISE
; END_HEADERS
(padlen=0, prometido_stream_id=2)
[0,019] recv (stream_id = 1): status: 200
[0,019] recv (stream_id = 1) data: qui, 21 de maio de 2015 16:39:16 GMT
[0,019] recv (stream_id = 1) tipo de conteúdo: texto/html
[0,019] recv (stream_id = 1) comprimento do conteúdo: 6646
[0,019] recv (stream_id = 1) última modificação: sexta-feira, 15 de maio de 2015, 15:38:06 GMT
[0,019] recv (stream_id = 1) e-tag: "555612de-19f6"
[0,019] recv (stream_id=1) link: ; rel=pré-carregamento; como = folha de estilo
[0,019] recv (stream_id = 1) intervalos de aceitação: bytes
[0,019] recv (stream_id=1) servidor: nghttpx nghttp2/1.0.1-DEV
[0,019] recv (stream_id = 1) via: 1,1 nghttpx
[0,019] quadro recv HEADERS
; END_HEADERS
(padlen=0)
; Cabeçalho da primeira resposta
[0,019] quadro recv DATA
; END_STREAM
[0,019] recv (stream_id = 2): status: 200
[0,019] recv (stream_id = 2) data: qui, 21 de maio de 2015 16:39:16 GMT
[0,019] recv (stream_id = 2) tipo de conteúdo: texto/css
[0,019] recv (stream_id = 2) comprimento do conteúdo: 38981
[0,019] recv (stream_id = 2) última modificação: sexta-feira, 15 de maio de 2015, 15:38:06 GMT
[0,019] recv (stream_id = 2) e-tag: "555612de-9845"
[0,019] recv (stream_id = 2) intervalos de aceitação: bytes
[0,019] recv (stream_id=2) servidor: nghttpx nghttp2/1.0.1-DEV
[0,019] recv (stream_id = 2) via: 1,1 nghttpx
[0,019] quadro recv HEADERS
; END_HEADERS
(padlen=0)
; Primeiro cabeçalho de resposta push
[0,026] quadro recv DATA
[0,027] quadro recv DATA
[0,027] enviar quadro WINDOW_UPDATE
(window_size_increment=33343)
[0,032] enviar quadro WINDOW_UPDATE
(window_size_increment=33707)
[0,032] quadro recv DATA
; END_STREAM
[0,032] quadro recv SETTINGS
; CONFIRMAR
(niv=0)
[0,032] enviar quadro GOAWAY
(last_stream_id = 2, código de erro = NO_ERROR (0x00), dados_opacos (0) = [])
Usando a opção -s
, nghttp
imprime algumas informações de tempo para solicitações, classificadas por tempo de conclusão:
$ nghttp -nas https://nghttp2.org/
***** Estatísticas *****
Horário da solicitação:
responseEnd: a hora em que o último byte da resposta foi recebido
relativo a connectEnd
requestStart: o tempo imediatamente antes do envio do primeiro byte da solicitação
relativo a connectEnd. Se '*' for mostrado, isso foi
empurrado pelo servidor.
processo: respostaEnd - requestStart
código: código de status HTTP
tamanho: número de bytes recebidos como corpo de resposta sem
inflação.
URI: solicitar URI
consulte http://www.w3.org/TR/resource-timing/#processing-model
classificado por 'completo'
id responseEnd requestStart código do processo tamanho caminho da solicitação
13 +37,19ms +280us 36,91ms 200 2K /
2 +72,65ms * +36,38ms 36,26ms 200 8K /stylesheets/screen.css
17 +77,43ms +38,67ms 38,75ms 200 3K /javascripts/octopress.js
15 +78,12ms +38,66ms 39,46ms 200 3K /javascripts/modernizr-2.0.js
Usando a opção -r
, nghttp
grava dados de tempo mais detalhados no arquivo fornecido no formato HAR.
nghttpd
é um servidor web estático multithread.
Por padrão, ele usa conexão SSL/TLS. Use a opção --no-tls
para desativá-lo.
nghttpd
aceita apenas conexões HTTP/2 via ALPN ou conexões HTTP/2 diretas. Nenhuma atualização HTTP é suportada.
A opção -p
permite aos usuários configurar o push do servidor.
Assim como nghttp
, ele possui um modo de saída detalhado para enquadrar informações. Aqui está um exemplo de saída de nghttpd
:
$ nghttpd --no-tls -v 8080
IPv4: ouça 0.0.0.0:8080
IPv6: ouça :::8080
[id = 1] [1.521] enviar quadro SETTINGS
(niv = 1)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id = 1] [1.521] quadro recv SETTINGS
(niv = 2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[id = 1] [1.521] quadro recv SETTINGS
; CONFIRMAR
(niv=0)
[id = 1] [1.521] quadro recv PRIORITY
(dep_stream_id=0, peso=201, exclusivo=0)
[id = 1] [1.521] quadro recv PRIORITY
(dep_stream_id=0, peso=101, exclusivo=0)
[id = 1] [1.521] quadro recv PRIORITY
(dep_stream_id=0, peso=1, exclusivo=0)
[id = 1] [1.521] quadro recv PRIORITY
(dep_stream_id=7, peso=1, exclusivo=0)
[id = 1] [1.521] quadro recv PRIORITY
(dep_stream_id=3, peso=1, exclusivo=0)
[id = 1] [1.521] recv (stream_id = 13): método: GET
[id = 1] [1.521] recv (stream_id = 13): caminho: /
[id = 1] [1.521] recv (stream_id = 13): esquema: http
[id = 1] [1.521] recv (stream_id = 13): autoridade: localhost: 8080
[id=1] [1.521] recv (stream_id=13) aceitar: */*
[id = 1] [1.521] recv (stream_id = 13) codificação de aceitação: gzip, deflate
[id=1] [1.521] recv (stream_id=13) agente do usuário: nghttp2/1.0.0-DEV
[id = 1] [1.521] quadro recv HEADERS
; END_STREAM | END_HEADERS | PRIORIDADE
(padlen=0, dep_stream_id=11, peso=16, exclusivo=0)
; Abrir novo fluxo
[id=1] [1.521] enviar quadro SETTINGS
; CONFIRMAR
(niv=0)
[id = 1] [1.521] enviar quadro HEADERS
; END_HEADERS
(padlen=0)
; Cabeçalho da primeira resposta
:status: 200
servidor: nghttpd nghttp2/1.0.0-DEV
comprimento do conteúdo: 10
controle de cache: idade máxima = 3600
data: sexta-feira, 15 de maio de 2015, 14:49:04 GMT
última modificação: terça-feira, 30 de setembro de 2014 12:40:52 GMT
[id = 1] [1.522] enviar quadro de DADOS
; END_STREAM
[id=1] [1.522] stream_id=13 fechado
[id = 1] [1.522] recv quadro GOAWAY
(last_stream_id = 0, código de erro = NO_ERROR (0x00), dados_opacos (0) = [])
[id=1] [1.522] fechado
nghttpx
é um proxy reverso multithread para HTTP/3, HTTP/2 e HTTP/1.1, alimenta http://nghttp2.org e suporta push de servidor HTTP/2.
Reformulamos a interface de linha de comando nghttpx
e, como resultado, existem várias incompatibilidades da versão 1.8.0 ou anterior. Isso é necessário para ampliar sua capacidade e garantir melhorias adicionais de recursos na versão futura. Leia Migração do nghttpx v1.8.0 ou anterior para saber como migrar de versões anteriores.
nghttpx
implementa recursos importantes orientados ao desempenho no TLS, como IDs de sessão, tickets de sessão (com rotação automática de chaves), grampeamento OCSP, dimensionamento dinâmico de registros, ALPN, sigilo de encaminhamento e HTTP/2. nghttpx
também oferece a funcionalidade de compartilhar cache de sessão e chaves de tickets entre várias instâncias nghttpx
via memcached.
nghttpx
possui 2 modos de operação:
Opção de modo | Front-end | Back-end | Observação |
---|---|---|---|
modo padrão | HTTP/3, HTTP/2, HTTP/1.1 | HTTP/1.1, HTTP/2 | Proxy reverso |
--http2-proxy | HTTP/3, HTTP/2, HTTP/1.1 | HTTP/1.1, HTTP/2 | Proxy de encaminhamento |
O modo interessante no momento é o modo padrão. Ele funciona como um proxy reverso e escuta HTTP/3, HTTP/2 e HTTP/1.1 e pode ser implantado como um terminador SSL/TLS para um servidor web existente.
Em todos os modos, as conexões frontend são criptografadas por SSL/TLS por padrão. Para desabilitar a criptografia, use a palavra-chave no-tls
na opção --frontend
. Se a criptografia estiver desabilitada, as conexões HTTP/1.1 de entrada poderão ser atualizadas para HTTP/2 por meio da Atualização HTTP. Por outro lado, as conexões de back-end não são criptografadas por padrão. Para criptografar conexões de back-end, use a palavra-chave tls
na opção --backend
.
nghttpx
suporta um arquivo de configuração. Consulte a opção --conf
e o arquivo de configuração de exemplo nghttpx.conf.sample
.
No modo padrão, nghttpx
funciona como proxy reverso para o servidor backend:
Cliente <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Servidor Web
[proxy reverso]
Com a opção --http2-proxy
, ele funciona como proxy de encaminhamento e é chamado de proxy HTTP/2 seguro:
Cliente <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
[proxy seguro] (por exemplo, Squid, ATS)
O Client
no exemplo acima precisa ser configurado para usar nghttpx
como proxy seguro.
No momento em que este artigo foi escrito, tanto o Chrome quanto o Firefox suportavam proxy HTTP/2 seguro. Uma maneira de configurar o Chrome para usar um proxy seguro é criar um script proxy.pac como este:
function FindProxyForURL ( url , host ) {
return "HTTPS SERVERADDR:PORT" ;
}
SERVERADDR
e PORT
são o nome do host/endereço e a porta da máquina em que o nghttpx está sendo executado. Observe que o Chrome exige um certificado válido para proxy seguro.
Em seguida, execute o Chrome com os seguintes argumentos:
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
As conexões HTTP/2 de back-end podem ser encapsuladas por meio de um proxy HTTP. O proxy é especificado usando --backend-http-proxy-uri
. A figura a seguir ilustra como o nghttpx se comunica com o proxy HTTP/2 externo por meio de um proxy HTTP:
Cliente <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
--===================---> Proxy HTTP/2
(túnel de proxy HTTP) (por exemplo, nghttpx -s)
O programa h2load
é uma ferramenta de benchmarking para HTTP/3, HTTP/2 e HTTP/1.1. A IU do h2load
é fortemente inspirada no weighttp
(https://github.com/lighttpd/weighttp). O uso típico é o seguinte:
$ h2load -n100000 -c100 -m100 https://localhost:8443/
referência inicial...
thread de geração # 0: 100 clientes simultâneos, 100.000 solicitações no total
Protocolo: TLSv1.2
Cifra: ECDHE-RSA-AES128-GCM-SHA256
Chave temporária do servidor: ECDH P-256 256 bits
progresso: 10% concluído
progresso: 20% concluído
progresso: 30% concluído
progresso: 40% concluído
progresso: 50% concluído
progresso: 60% concluído
progresso: 70% concluído
progresso: 80% concluído
progresso: 90% concluído
progresso: 100% concluído
terminou em 771,26 ms, 129.658 req/s, 4,71 MB/s
solicitações: 100.000 no total, 100.000 iniciadas, 100.000 concluídas, 100.000 bem-sucedidas, 0 com falha, 0 com erro
códigos de status: 100000 2xx, 0 3xx, 0 4xx, 0 5xx
tráfego: 3812300 bytes no total, 1009900 bytes de cabeçalhos, 1000000 bytes de dados
min máximo média sd +/- sd
tempo para solicitação: 25,12ms 124,55ms 51,07ms 15,36ms 84,87%
tempo para conexão: 208,94 ms 254,67 ms 241,38 ms 7,95 ms 63,00%
tempo até o 1º byte: 209,11ms 254,80ms 241,51ms 7,94ms 63,00%
O exemplo acima emitiu um total de 100.000 solicitações, usando 100 clientes simultâneos (em outras palavras, 100 sessões HTTP/2) e um máximo de 100 fluxos por cliente. Com a opção -t
, h2load
usará vários threads nativos para evitar a saturação de um único núcleo no lado do cliente.
Aviso
Não use esta ferramenta em servidores disponíveis publicamente. Isso é considerado um ataque DOS. Por favor, use-o apenas em seus servidores privados.
Se o HTTP/3 experimental estiver habilitado, o h2load pode enviar solicitações ao servidor HTTP/3. Para fazer isso, especifique a opção h3
para --alpn-list
assim:
$ h2load --alpn-list h3 https://127.0.0.1:4433
Para nghttp2 v1.58 ou anterior, use --npn-list
em vez de --alpn-list
.
O diretório src
contém as ferramentas HPACK. O programa deflatehd
é uma ferramenta de compactação de cabeçalho de linha de comando. O programa inflatehd
é uma ferramenta de descompactação de cabeçalho de linha de comando. Ambas as ferramentas leem a entrada do stdin e gravam a saída no stdout. Os erros são escritos para Stderr. Eles tomam JSON como entrada e saída. (Principalmente) usamos o mesmo formato de dados JSON descrito em https://github.com/http2jp/hpack-test-case.
O programa deflatehd
lê os dados JSON Data ou HTTP/1 estilo de 1 estilo da Stdin e saídas Bloco de cabeçalho compactado em JSON.
Para a entrada JSON, o objeto JSON root deve incluir uma chave cases
. Seu valor deve incluir a sequência do conjunto de cabeçalho de entrada. Eles compartilham o mesmo contexto de compressão e são processados na ordem em que aparecem. Cada item na sequência é um objeto JSON e deve incluir uma chave headers
. Seu valor é uma matriz de objetos JSON, que inclui exatamente um par de nome/valor.
Exemplo:
{
"cases" :
[
{
"headers" : [
{ ":method" : " GET " },
{ ":path" : " / " }
]
},
{
"headers" : [
{ ":method" : " POST " },
{ ":path" : " / " }
]
}
]
}
Com a opção -t
, o programa pode aceitar blocos de campo de cabeçalho de estilo HTTP/1 mais familiares. Cada conjunto de cabeçalho é delimitado por uma linha vazia:
Exemplo:
: Método: Get
: Esquema: https
:caminho: /
: Método: Post
agente de usuário: nghttp2
A saída está no objeto JSON. Ele deve incluir uma chave cases
e seu valor é uma variedade de objetos JSON, que possui pelo menos as seguintes chaves:
output_length
/ input_length
* 100Exemplos:
{
"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
}
]
}
A saída pode ser usada como entrada para inflatehd
e deflatehd
.
Com a opção -d
, a tecla Extra header_table
é adicionada e seu valor associado inclui o estado da tabela de cabeçalho dinâmico após o processamento do conjunto de cabeçalho correspondente. O valor inclui pelo menos as seguintes chaves:
referenced
for true
, ele está no conjunto de referência. O size
inclui a sobrecarga (32 bytes). O index
corresponde ao índice da tabela de cabeçalho. O name
é o nome do campo do cabeçalho e o value
é o valor do campo do cabeçalho.max_deflate_size
.max_size
. Nesse caso, o codificador usa apenas até o primeiro buffer max_deflate_size
. Como o tamanho da tabela de cabeçalho ainda é max_size
, o codificador deve acompanhar as entradas fora do max_deflate_size
, mas dentro do max_size
e verifique se elas não são mais referenciadas.Exemplo:
{
"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
}