Dies ist eine Implementierung des Hypertext Transfer Protocol Version 2 in C.
Die Framing-Schicht von HTTP/2 ist als wiederverwendbare C-Bibliothek implementiert. Darüber hinaus haben wir einen HTTP/2-Client, -Server und -Proxy implementiert. Wir haben auch Lasttest- und Benchmarking-Tools für HTTP/2 entwickelt.
Ein HPACK-Encoder und -Decoder sind als öffentliche API verfügbar.
nghttp2 wurde ursprünglich auf Basis von RFC 7540 HTTP/2 und RFC 7541 HPACK – Header-Komprimierung für HTTP/2 entwickelt. Jetzt aktualisieren wir unseren Code, um RFC 9113 zu implementieren.
Die nghttp2-Codebasis wurde aus dem spdylay-Projekt (https://github.com/tatsuhiro-t/spdylay) abgeleitet.
Die folgenden Endpunkte stehen zum Ausprobieren unserer nghttp2-Implementierung zur Verfügung.
https://nghttp2.org/ (TLS + ALPN und HTTP/3)
Dieser Endpunkt unterstützt h2
, h2-16
, h2-14
und http/1.1
über ALPN und erfordert TLSv1.2 für die HTTP/2-Verbindung.
Es unterstützt auch HTTP/3.
http://nghttp2.org/ (HTTP-Upgrade und HTTP/2 Direct)
h2c
und http/1.1
.
Zum Erstellen der libnghttp2-Bibliothek ist das folgende Paket erforderlich:
Um die Dokumentation zu erstellen, müssen Sie Folgendes installieren:
Wenn Sie nur libnghttp2 (C-Bibliothek) benötigen, sind die oben genannten Pakete alles, was Sie brauchen. Verwenden Sie --enable-lib-only
um sicherzustellen, dass nur libnghttp2 erstellt wird. Dies vermeidet potenzielle Buildfehler im Zusammenhang mit der Erstellung gebündelter Anwendungen.
Um die Anwendungsprogramme ( nghttp
, nghttpd
, nghttpx
und h2load
) im src
Verzeichnis zu erstellen und auszuführen, sind die folgenden Pakete erforderlich:
Um die Option -a
(verknüpfte Assets von der heruntergeladenen Ressource abzurufen) in nghttp
zu aktivieren, ist das folgende Paket erforderlich:
Um die Systemd-Unterstützung in nghttpx zu aktivieren, ist das folgende Paket erforderlich:
Die HPACK-Tools erfordern das folgende Paket:
Um Quellen im Beispielverzeichnis zu erstellen, ist libevent erforderlich:
Um die Heap-Fragmentierung in Serverprogrammen mit langer Laufzeit ( nghttpd
und nghttpx
) zu verringern, wird jemalloc empfohlen:
jemalloc
Notiz
Alpine Linux unterstützt derzeit aufgrund von Musl-Einschränkungen keinen Malloc-Ersatz. Einzelheiten finden Sie in Ausgabe Nr. 762.
Für den BoringSSL- oder aws-lc-Build ist die folgende Bibliothek erforderlich, um die RFC 8879 TLS-Zertifikatkomprimierung in Anwendungen zu aktivieren:
Um die Mruby-Unterstützung für nghttpx zu aktivieren, ist mruby erforderlich. Wir müssen mruby mit explizit aktivierter C++-ABI erstellen und benötigen wahrscheinlich andere mrgems. mruby wird vom Git-Submodul im Verzeichnis Third-Party/mruby verwaltet. Derzeit ist die Mruby-Unterstützung für nghttpx standardmäßig deaktiviert. Um die Mruby-Unterstützung zu aktivieren, verwenden Sie die Konfigurationsoption --with-mruby
. Beachten Sie, dass zum Zeitpunkt des Schreibens dieses Artikels die Pakete libmruby-dev und mruby in Debian/Ubuntu nicht für nghttp2 verwendbar sind, da sie C++ ABI nicht aktivieren. Um mruby zu erstellen, sind die folgenden Pakete erforderlich:
nghttpx unterstützt neverbleed, Privilege Separation Engine für OpenSSL. Kurz gesagt, es minimiert das Risiko eines Verlusts privater Schlüssel, wenn schwerwiegende Fehler wie Heartbleed ausgenutzt werden. Der Neverbleed ist standardmäßig deaktiviert. Um es zu aktivieren, verwenden Sie die Konfigurationsoption --with-neverbleed
.
Um die experimentelle HTTP/3-Unterstützung für h2load und nghttpx zu aktivieren, sind die folgenden Bibliotheken erforderlich:
Verwenden Sie die Konfigurationsoption --enable-http3
, um die HTTP/3-Funktion für h2load und nghttpx zu aktivieren.
Um ein optionales eBPF-Programm zu erstellen, um ein eingehendes QUIC-UDP-Datagramm an einen korrekten Socket für nghttpx weiterzuleiten, sind die folgenden Bibliotheken erforderlich:
Verwenden Sie die Konfigurationsoption --with-libbpf
um ein eBPF-Programm zu erstellen. libelf-dev wird benötigt, um libbpf zu erstellen.
Für Ubuntu 20.04 können Sie libbpf aus dem Quellcode erstellen. nghttpx erfordert das eBPF-Programm zum Neuladen seiner Konfiguration und zum Hot-Swapping seiner ausführbaren Datei.
Zum Kompilieren des C-Quellcodes von libnghttp2 ist ein C99-Compiler erforderlich. gcc 4.8 ist bekanntermaßen ausreichend. Um den C++-Quellcode zu kompilieren, ist ein C++20-kompatibler Compiler erforderlich. Es ist bekannt, dass mindestens g++ >= 12 und clang++ >= 15 funktionieren.
Notiz
Um die Mruby-Unterstützung in nghttpx zu aktivieren und die Konfigurationsoption --with-mruby
zu verwenden.
Notiz
--disable-threads
von Mac OS Ein Patch ist willkommen, um Multi-Threading auf der Mac OS X-Plattform zum Laufen zu bringen.
Notiz
Um die zugehörigen Anwendungen (nghttp, nghttpd, nghttpx und h2load) zu kompilieren, müssen Sie die Konfigurationsoption --enable-app
verwenden und sicherstellen, dass die oben angegebenen Anforderungen erfüllt sind. Normalerweise konfigurieren Sie Skriptprüfungen, um die erforderlichen Abhängigkeiten zum Erstellen dieser Anwendungen zu konfigurieren, und aktivieren Sie --enable-app
automatisch, sodass Sie es nicht explizit verwenden müssen. Wenn Sie jedoch feststellen, dass Anwendungen nicht erstellt wurden, kann die Verwendung von --enable-app
die Ursache finden, beispielsweise die fehlende Abhängigkeit.
Notiz
Um Bibliotheken von Drittanbietern zu erkennen, wird pkg-config verwendet (wir verwenden pkg-config jedoch nicht für einige Bibliotheken (z. B. libev)). Standardmäßig durchsucht pkg-config *.pc
Datei an den Standardspeicherorten (z. B. /usr/lib/pkgconfig). Wenn die *.pc
Datei am benutzerdefinierten Speicherort verwendet werden muss, geben Sie Pfade zur Umgebungsvariablen PKG_CONFIG_PATH
an und übergeben Sie sie wie folgt an das Konfigurationsskript:
$ ./configure PKG_CONFIG_PATH=/path/to/pkgconfig
Für von pkg-config verwaltete Bibliotheken sind die Umgebungsvariablen *_CFLAG
und *_LIBS
definiert (z. B. OPENSSL_CFLAGS
, OPENSSL_LIBS
). Die Angabe einer nicht leeren Zeichenfolge für diese Variablen überschreibt pkg-config vollständig. Mit anderen Worten: Wenn sie angegeben werden, wird pkg-config nicht zur Erkennung verwendet und der Benutzer ist dafür verantwortlich, die richtigen Werte für diese Variablen anzugeben. Für eine vollständige Liste dieser Variablen führen Sie ./configure -h
aus.
Wenn Sie Ubuntu 22.04 LTS verwenden, führen Sie Folgendes aus, um die erforderlichen Pakete zu installieren:
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
Das nghttp2-Projekt veröffentlicht regelmäßig TAR-Archive, die den nghttp2-Quellcode und generierte Build-Dateien enthalten. Sie können von der Seite „Releases“ heruntergeladen werden.
Für die Erstellung von nghttp2 aus Git sind Autotools-Entwicklungspakete erforderlich. Für den Aufbau aus TAR-Archiven sind diese nicht erforderlich und daher viel einfacher. Der übliche Build-Schritt ist wie folgt:
$ tar xf nghttp2-XYZtar.bz2
$ cd nghttp2-XYZ
$ ./configure
$ machen
Das Erstellen aus Git ist einfach, aber bitte stellen Sie sicher, dass mindestens Autoconf 2.68 verwendet wird:
$ git submodule update --init
$ autoreconf -i
$ automake
$ autoconf
$ ./configure
$ machen
Der einfachste Weg, eine native Windows nghttp2-DLL zu erstellen, ist die Verwendung von cmake. Die kostenlose Version von Visual C++ Build Tools funktioniert einwandfrei.
cmake
aus.cmake --build
aus, um die Bibliothek zu erstellen.Beachten Sie, dass die oben genannten Schritte höchstwahrscheinlich nur die nghttp2-Bibliothek erzeugen. Es werden keine gebündelten Anwendungen kompiliert.
In der Mingw-Umgebung können Sie nur die Bibliothek kompilieren, nämlich libnghttp2-X.dll
und libnghttp2.a
.
Wenn Sie die Anwendungen ( h2load
, nghttp
, nghttpx
, nghttpd
) kompilieren möchten, müssen Sie die Cygwin-Umgebung verwenden.
In der Cygwin-Umgebung müssen Sie zum Kompilieren der Anwendungen zuerst libev kompilieren und installieren.
Zweitens müssen Sie die Definition des Makros __STRICT_ANSI__
aufheben. Andernfalls sind die Funktionen fdopen
, fileno
und strptime
nicht verfügbar.
Der Beispielbefehl sieht folgendermaßen aus:
$ export CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
$ export CXXFLAGS=$CFLAGS
$ ./configure
$ machen
Wenn Sie die Anwendungen unter examples/
kompilieren möchten, müssen Sie die event.h
aus der Installation von libev entfernen oder umbenennen, da sie mit der Installation von libevent in Konflikt steht.
Nach der Installation der nghttp2-Tool-Suite mit make install
kann ein ähnlicher Fehler auftreten:
nghttpx: Fehler beim Laden gemeinsam genutzter Bibliotheken: libnghttp2.so.14: Gemeinsam genutzte Objektdatei kann nicht geöffnet werden: Keine solche Datei oder kein solches Verzeichnis
Dies bedeutet, dass das Tool die gemeinsam genutzte Bibliothek libnghttp2.so
nicht finden kann.
Um den Cache der gemeinsam genutzten Bibliothek zu aktualisieren, führen Sie sudo ldconfig
aus.
Notiz
Die Dokumentation ist noch unvollständig.
Führen Sie zum Erstellen der Dokumentation Folgendes aus:
$ HTML erstellen
Die Dokumente werden unter doc/manual/html/
generiert.
Die generierten Dokumente werden nicht mit make install
installiert.
Die Online-Dokumentation ist verfügbar unter https://nghttp2.org/documentation/
Um h2load und nghttpx mit aktivierter HTTP/3-Funktion zu erstellen, führen Sie das Konfigurationsskript mit --enable-http3
aus.
Damit nghttpx Konfigurationen neu lädt und seine ausführbare Datei austauscht und gleichzeitig alte Arbeitsprozesse ordnungsgemäß beendet, ist eBPF erforderlich. Führen Sie das Konfigurationsskript mit --enable-http3 --with-libbpf
aus, um das eBPF-Programm zu erstellen. Das QUIC-Schlüsselmaterial muss mit --frontend-quic-secret-file
festgelegt werden, um die bestehenden Verbindungen während des Neuladens aufrechtzuerhalten.
Es folgen die detaillierten Schritte zum Erstellen von HTTP/3-fähigem h2load und nghttpx.
Erstellen Sie aws-lc:
$ git clone -- Depth 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 build
$ cmake --install build
$cd ..
Erstellen Sie nghttp3:
$ git clone -- Depth 1 -b v1.6.0 https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ git submodule update --init -- Depth 1
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc)
$ make install
$cd ..
Erstellen Sie ngtcp2:
$ git clone -- Depth 1 -b v1.9.1 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ git submodule update --init -- Depth 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"
$ make -j$(nproc)
$ make install
$cd ..
Wenn Ihre Linux-Distribution nicht über libbpf-dev >= 0.7.0 verfügt, erstellen Sie aus dem Quellcode:
$ git clone -- Depth 1 -b v1.4.6 https://github.com/libbpf/libbpf
$ cd libbpf
$ PREFIX=$PWD/build make -C src install
$cd ..
Erstellen Sie nghttp2:
$ Git-Klon https://github.com/nghttp2/nghttp2
$ cd nghttp2
$ git submodule update --init
$ autoreconf -i
$ ./configure --with-mruby --enable-http3 --with-libbpf
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/ ../libbpf/build/lib64/pkgconfig"
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../aws-lc/opt/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
$ make -j$(nproc)
Das eBPF-Programm reuseport_kern.o
sollte im BPF-Verzeichnis zu finden sein. Übergeben Sie die Option --quic-bpf-program-file=bpf/reuseport_kern.o
an nghttpx, um sie zu laden. Siehe auch den Abschnitt HTTP/3 in nghttpx – HTTP/2-Proxy – HOW-TO.
Unit-Tests werden durch einfaches Ausführen von make check
durchgeführt.
Wir haben die Integrationstests für den nghttpx-Proxyserver. Die Tests sind in der Programmiersprache Go geschrieben und nutzen deren Test-Framework. Wir sind auf folgende Bibliotheken angewiesen:
Go-Module laden diese Abhängigkeiten automatisch herunter.
Um die Tests auszuführen, führen Sie den folgenden Befehl im Verzeichnis integration-tests
aus:
$ mach es
Innerhalb der Tests verwenden wir Port 3009, um den Testsubjektserver auszuführen.
nghttp2 v1.0.0 führte mehrere abwärtsinkompatible Änderungen ein. In diesem Abschnitt beschreiben wir diese Änderungen und die Migration auf Version 1.0.0.
h2
und h2c
Zuvor haben wir h2-14
und h2c-14
angekündigt. v1.0.0 implementiert die endgültige Protokollversion und wir haben die ALPN-ID in h2
und h2c
geändert. Die Makros NGHTTP2_PROTO_VERSION_ID
, NGHTTP2_PROTO_VERSION_ID_LEN
, NGHTTP2_CLEARTEXT_PROTO_VERSION_ID
und NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN
wurden aktualisiert, um diese Änderung widerzuspiegeln.
Grundsätzlich müssen bestehende Anwendungen nichts tun, für diese Änderung reicht lediglich eine Neukompilierung.
Mit „Client-Verbindungsvorwort“ bezeichnen wir die ersten 24 Bytes des Client-Verbindungsvorworts. Dies ist technisch gesehen nicht korrekt, da das Client-Verbindungsvorwort aus einer 24-Byte-Client-Magic-Byte-Zeichenfolge gefolgt von einem SETTINGS-Frame besteht. Zur Verdeutlichung nennen wir diesen 24-Byte-Byte-String und die aktualisierte API „Client Magic“.
NGHTTP2_CLIENT_CONNECTION_PREFACE
wurde durch NGHTTP2_CLIENT_MAGIC
ersetzt.NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
wurde durch NGHTTP2_CLIENT_MAGIC_LEN
ersetzt.NGHTTP2_BAD_PREFACE
wurde in NGHTTP2_BAD_CLIENT_MAGIC
umbenannt Die bereits veralteten NGHTTP2_CLIENT_CONNECTION_HEADER
und NGHTTP2_CLIENT_CONNECTION_HEADER_LEN
wurden entfernt.
Wenn die Anwendung diese Makros verwendet, ersetzen Sie einfach die alten durch neue. Seit Version 1.0.0 wird Client-Magic von der Bibliothek gesendet (siehe nächster Unterabschnitt), sodass die Client-Anwendung diese Makroverwendung möglicherweise einfach entfernen kann.
Bisher hat die nghttp2-Bibliothek keine Client-Magic gesendet, bei der es sich um die erste 24-Byte-Byte-Zeichenfolge des Client-Verbindungsvorworts handelt, und Client-Anwendungen müssen sie selbst senden. Seit v1.0.0 wird Client-Magic von der Bibliothek über den ersten Aufruf von nghttp2_session_send()
oder nghttp2_session_mem_send2()
gesendet.
Die Clientanwendungen, die Clientmagie senden, müssen den entsprechenden Code entfernen.
Die Alt-Svc-Spezifikation ist noch nicht finalisiert. Um unsere API stabil zu machen, haben wir beschlossen, alle Alt-Svc-bezogenen APIs aus nghttp2 zu entfernen.
NGHTTP2_EXT_ALTSVC
wurde entfernt.nghttp2_ext_altsvc
wurde entfernt.Wir haben die Funktionalität von Alt-Svc bereits in der v0.7-Serie entfernt und sie waren im Wesentlichen noop. Die Anwendung, die dieses Makro und diese Struktur verwendet, entfernt diese Zeilen.
Bisher verwendete nghttp2_on_invalid_frame_recv_cb_called
den in nghttp2_error_code
definierten error_code
als Parameter. Sie sind jedoch nicht detailliert genug, um sie zu debuggen. Daher haben wir uns entschieden, stattdessen detailliertere nghttp2_error
-Werte zu verwenden.
Die Anwendung, die diesen Rückruf verwendet, sollte die Rückrufsignatur aktualisieren. Wenn error_code
als HTTP/2-Fehlercode behandelt wird, aktualisieren Sie den Code, sodass er als nghttp2_error
behandelt wird.
Zuvor verarbeitete nghttp2 keine Client-Magie (24-Byte-Byte-String). Um damit klarzukommen, mussten wir nghttp2_option_set_recv_client_preface()
verwenden. Seit Version 1.0.0 verarbeitet nghttp2 standardmäßig Client-Magie und nghttp2_option_set_recv_client_preface()
wurde entfernt.
Einige Anwendungen möchten dieses Verhalten möglicherweise deaktivieren, daher haben wir nghttp2_option_set_no_recv_client_magic()
hinzugefügt, um dies zu erreichen.
Die Anwendung, nghttp2_option_set_recv_client_preface()
mit einem Wert ungleich Null verwendet, entfernen Sie ihn einfach.
Die Anwendung, nghttp2_option_set_recv_client_preface()
mit einem Nullwert verwendet oder nicht verwendet, muss nghttp2_option_set_no_recv_client_magic()
mit einem Wert ungleich Null verwenden.
Das Verzeichnis src
enthält die HTTP/2-Client-, Server- und Proxy-Programme.
nghttp
ist ein HTTP/2-Client. Es kann mit Vorkenntnissen, HTTP-Upgrade und ALPN-TLS-Erweiterung eine Verbindung zum HTTP/2-Server herstellen.
Es verfügt über einen ausführlichen Ausgabemodus für Rahmeninformationen. Hier ist eine Beispielausgabe des nghttp
Clients:
$ nghttp -nv https://nghttp2.org
[ 0,190] Verbunden
Das ausgehandelte Protokoll: h2
[ 0,212] recv SETTINGS Frame
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0,212] SETTINGS-Frame senden
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0,212] SETTINGS-Frame senden
; ACK
(niv=0)
[ 0,212] PRIORITY-Frame senden
(dep_stream_id=0, Gewichtung=201, exklusiv=0)
[ 0,212] PRIORITY-Frame senden
(dep_stream_id=0, Gewichtung=101, exklusiv=0)
[ 0,212] PRIORITY-Frame senden
(dep_stream_id=0, Gewichtung=1, exklusiv=0)
[ 0,212] PRIORITY-Frame senden
(dep_stream_id=7, Gewichtung=1, exklusiv=0)
[ 0,212] PRIORITY-Frame senden
(dep_stream_id=3, Gewichtung=1, exklusiv=0)
[ 0,212] Sende HEADERS-Frame
; END_STREAM | END_HEADERS | PRIORITÄT
(padlen=0, dep_stream_id=11, Gewicht=16, exklusiv=0)
; Neuen Stream öffnen
:Methode: GET
:Weg: /
:schema: https
:authority: nghttp2.org
akzeptieren: */*
Accept-Encoding: gzip, deflate
Benutzeragent: nghttp2/1.0.1-DEV
[ 0,221] recv SETTINGS Frame
; ACK
(niv=0)
[ 0,221] recv (stream_id=13): Methode: GET
[ 0,221] recv (stream_id=13):scheme: https
[ 0,221] recv (stream_id=13) :path: /stylesheets/screen.css
[ 0,221] recv (stream_id=13):authority: nghttp2.org
[ 0,221] recv (stream_id=13) Accept-Encoding: gzip, deflate
[ 0,222] recv (stream_id=13) Benutzeragent: nghttp2/1.0.1-DEV
[ 0,222] recv PUSH_PROMISE Frame
; END_HEADERS
(padlen=0, versprochen_stream_id=2)
[ 0,222] recv (stream_id=13):status: 200
[ 0,222] recv (stream_id=13) Datum: Do, 21. Mai 2015 16:38:14 GMT
[ 0,222] recv (stream_id=13) Inhaltstyp: text/html
[ 0,222] recv (stream_id=13) zuletzt geändert: Fr, 15. Mai 2015 15:38:06 GMT
[ 0,222] recv (stream_id=13) etag: W/"555612de-19f6"
[ 0,222] recv (stream_id=13) Link: ; rel=vorladen; as=Stylesheet
[ 0,222] recv (stream_id=13) Inhaltskodierung: gzip
[ 0,222] recv (stream_id=13) Server: nghttpx nghttp2/1.0.1-DEV
[ 0,222] recv (stream_id=13) über: 1,1 nghttpx
[ 0,222] recv (stream_id=13) strict-transport-security: max-age=31536000
[ 0,222] recv HEADERS Frame
; END_HEADERS
(padlen=0)
; Erster Antwortheader
[ 0,222] recv DATA Frame
; END_STREAM
[ 0,222] recv (stream_id=2):status: 200
[ 0,222] recv (stream_id=2) Datum: Do, 21. Mai 2015 16:38:14 GMT
[ 0,222] recv (stream_id=2) Inhaltstyp: Text/CSS
[ 0,222] recv (stream_id=2) zuletzt geändert: Fr, 15. Mai 2015 15:38:06 GMT
[ 0,222] recv (stream_id=2) etag: W/"555612de-9845"
[ 0,222] recv (stream_id=2) Inhaltskodierung: gzip
[ 0,222] recv (stream_id=2) Server: nghttpx nghttp2/1.0.1-DEV
[ 0,222] recv (stream_id=2) über: 1,1 nghttpx
[ 0,222] recv (stream_id=2) strict-transport-security: max-age=31536000
[ 0,222] recv HEADERS Frame
; END_HEADERS
(padlen=0)
; Erster Push-Antwort-Header
[ 0,228] recv DATA Frame
; END_STREAM
[ 0,228] Sende GOAWAY-Frame
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
Das HTTP-Upgrade wird wie folgt durchgeführt:
$ nghttp -nvu http://nghttp2.org
[ 0,011] Verbunden
[ 0.011] HTTP-Upgrade-Anfrage
GET / HTTP/1.1
Host: nghttp2.org
Verbindung: Upgrade, HTTP2-Einstellungen
Upgrade: h2c
HTTP2-Einstellungen: AAMAAABkAAQAAP__
Akzeptieren: */*
Benutzeragent: nghttp2/1.0.1-DEV
[ 0,018] HTTP-Upgrade-Antwort
HTTP/1.1 101 Switching-Protokolle
Verbindung: Upgrade
Upgrade: h2c
[ 0,018] HTTP-Upgrade erfolgreich
[ 0,018] recv SETTINGS Frame
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0,018] SETTINGS-Frame senden
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0,018] SETTINGS-Frame senden
; ACK
(niv=0)
[ 0,018] PRIORITY-Frame senden
(dep_stream_id=0, Gewichtung=201, exklusiv=0)
[ 0,018] PRIORITY-Frame senden
(dep_stream_id=0, Gewichtung=101, exklusiv=0)
[ 0,018] PRIORITY-Frame senden
(dep_stream_id=0, Gewichtung=1, exklusiv=0)
[ 0,018] PRIORITY-Frame senden
(dep_stream_id=7, Gewichtung=1, exklusiv=0)
[ 0,018] PRIORITY-Frame senden
(dep_stream_id=3, Gewichtung=1, exklusiv=0)
[ 0,018] PRIORITY-Frame senden
(dep_stream_id=11, Gewichtung=16, exklusiv=0)
[ 0,019] recv (stream_id=1): Methode: GET
[ 0,019] recv (stream_id=1):scheme: http
[ 0,019] recv (stream_id=1) :path: /stylesheets/screen.css
[ 0,019] recv (stream_id=1) Host: nghttp2.org
[ 0,019] recv (stream_id=1) Benutzeragent: nghttp2/1.0.1-DEV
[ 0,019] recv PUSH_PROMISE Frame
; END_HEADERS
(padlen=0, versprochen_stream_id=2)
[ 0,019] recv (stream_id=1):status: 200
[ 0,019] recv (stream_id=1) Datum: Do, 21. Mai 2015 16:39:16 GMT
[ 0,019] recv (stream_id=1) Inhaltstyp: text/html
[ 0,019] recv (stream_id=1) Inhaltslänge: 6646
[ 0,019] recv (stream_id=1) zuletzt geändert: Fr, 15. Mai 2015 15:38:06 GMT
[ 0,019] recv (stream_id=1) etag: „555612de-19f6“
[ 0,019] recv (stream_id=1) Link: ; rel=vorladen; as=Stylesheet
[ 0,019] recv (stream_id=1) Accept-Ranges: Bytes
[ 0,019] recv (stream_id=1) Server: nghttpx nghttp2/1.0.1-DEV
[ 0,019] recv (stream_id=1) über: 1,1 nghttpx
[ 0,019] recv HEADERS Frame
; END_HEADERS
(padlen=0)
; Header der ersten Antwort
[ 0,019] recv DATA Frame
; END_STREAM
[ 0,019] recv (stream_id=2):status: 200
[ 0,019] recv (stream_id=2) Datum: Do, 21. Mai 2015 16:39:16 GMT
[ 0,019] recv (stream_id=2) Inhaltstyp: Text/CSS
[ 0,019] recv (stream_id=2) Inhaltslänge: 38981
[ 0,019] recv (stream_id=2) zuletzt geändert: Fr, 15. Mai 2015 15:38:06 GMT
[ 0,019] recv (stream_id=2) etag: „555612de-9845“
[ 0,019] recv (stream_id=2) Accept-Ranges: Bytes
[ 0,019] recv (stream_id=2) Server: nghttpx nghttp2/1.0.1-DEV
[ 0,019] recv (stream_id=2) über: 1,1 nghttpx
[ 0,019] recv HEADERS Frame
; END_HEADERS
(padlen=0)
; Erster Push-Antwort-Header
[ 0,026] recv DATA Frame
[ 0,027] recv DATA Frame
[ 0,027] WINDOW_UPDATE-Frame senden
(window_size_increment=33343)
[ 0,032] WINDOW_UPDATE-Frame senden
(window_size_increment=33707)
[ 0,032] recv DATA-Frame
; END_STREAM
[ 0,032] recv SETTINGS Frame
; ACK
(niv=0)
[ 0,032] GOAWAY-Frame senden
(last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
Mit der Option -s
gibt nghttp
einige Zeitinformationen für Anfragen aus, sortiert nach Abschlusszeit:
$ nghttp -nas https://nghttp2.org/
***** Statistiken *****
Zeitpunkt der Anfrage:
ResponseEnd: Der Zeitpunkt, zu dem das letzte Byte der Antwort empfangen wurde
relativ zu connectEnd
requestStart: die Zeit kurz bevor das erste Byte der Anfrage gesendet wurde
relativ zu connectEnd. Wenn '*' angezeigt wird, war dies
Vom Server gepusht.
Prozess: ResponseEnd – RequestStart
Code: HTTP-Statuscode
Größe: Anzahl der Bytes, die als Antworttext ohne empfangen wurden
Inflation.
URI: Anforderungs-URI
siehe http://www.w3.org/TR/resource-timing/#processing-model
sortiert nach „vollständig“
ID-ResponseEnd-RequestStart-Prozesscode-Größenanforderungspfad
13 +37,19 ms +280us 36,91 ms 200 2K /
2 +72,65 ms * +36,38 ms 36,26 ms 200 8K /stylesheets/screen.css
17 +77,43 ms +38,67 ms 38,75 ms 200 3K /javascripts/octopress.js
15 +78,12 ms +38,66 ms 39,46 ms 200 3K /javascripts/modernizr-2.0.js
Mit der Option -r
schreibt nghttp
detailliertere Timing-Daten in die angegebene Datei im HAR-Format.
nghttpd
ist ein statischer Multithread-Webserver.
Standardmäßig wird eine SSL/TLS-Verbindung verwendet. Verwenden Sie die Option --no-tls
um es zu deaktivieren.
nghttpd
akzeptiert nur HTTP/2-Verbindungen über ALPN oder direkte HTTP/2-Verbindungen. Es wird kein HTTP-Upgrade unterstützt.
Mit der Option -p
können Benutzer Server-Push konfigurieren.
Genau wie nghttp
verfügt es über einen ausführlichen Ausgabemodus zum Einrahmen von Informationen. Hier ist eine Beispielausgabe von nghttpd
:
$ nghttpd --no-tls -v 8080
IPv4: Hören Sie 0.0.0.0:8080
IPv6: hören Sie :::8080
[id=1] [ 1.521] SETTINGS-Frame senden
(niv=1)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=1] [ 1.521] recv SETTINGS Frame
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[id=1] [ 1.521] recv SETTINGS Frame
; ACK
(niv=0)
[id=1] [ 1.521] recv PRIORITY Frame
(dep_stream_id=0, Gewicht=201, exklusiv=0)
[id=1] [ 1.521] recv PRIORITY Frame
(dep_stream_id=0, Gewichtung=101, exklusiv=0)
[id=1] [ 1.521] recv PRIORITY Frame
(dep_stream_id=0, Gewichtung=1, exklusiv=0)
[id=1] [ 1.521] recv PRIORITY Frame
(dep_stream_id=7, Gewichtung=1, exklusiv=0)
[id=1] [ 1.521] recv PRIORITY Frame
(dep_stream_id=3, Gewichtung=1, exklusiv=0)
[id=1] [ 1.521] recv (stream_id=13): Methode: GET
[id=1] [ 1.521] recv (stream_id=13) :path: /
[id=1] [ 1.521] recv (stream_id=13):scheme: http
[id=1] [ 1.521] recv (stream_id=13):authority: localhost:8080
[id=1] [ 1.521] recv (stream_id=13) akzeptieren: */*
[id=1] [ 1.521] recv (stream_id=13) Accept-Encoding: gzip, deflate
[id=1] [ 1.521] recv (stream_id=13) Benutzeragent: nghttp2/1.0.0-DEV
[id=1] [ 1.521] recv HEADERS Frame
; END_STREAM | END_HEADERS | PRIORITÄT
(padlen=0, dep_stream_id=11, Gewicht=16, exklusiv=0)
; Neuen Stream öffnen
[id=1] [ 1.521] SETTINGS-Frame senden
; ACK
(niv=0)
[id=1] [ 1.521] HEADERS-Frame senden
; END_HEADERS
(padlen=0)
; Erster Antwortheader
:Status: 200
Server: nghttpd nghttp2/1.0.0-DEV
Inhaltslänge: 10
Cache-Kontrolle: max-age=3600
Datum: Fr, 15. Mai 2015 14:49:04 GMT
Letzte Änderung: Dienstag, 30. September 2014, 12:40:52 Uhr GMT
[id=1] [ 1.522] DATA-Frame senden
; END_STREAM
[id=1] [ 1.522] stream_id=13 geschlossen
[id=1] [ 1.522] recv GOAWAY Frame
(last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])
[id=1] [ 1.522] geschlossen
nghttpx
ist ein Multithread-Reverse-Proxy für HTTP/3, HTTP/2 und HTTP/1.1, betreibt http://nghttp2.org und unterstützt HTTP/2-Server-Push.
Wir haben nghttpx
-Befehlszeilenschnittstelle überarbeitet und daher gibt es mehrere Inkompatibilitäten mit 1.8.0 oder früher. Dies ist notwendig, um die Funktionalität zu erweitern und die weiteren Funktionserweiterungen in der zukünftigen Version sicherzustellen. Bitte lesen Sie Migration von nghttpx v1.8.0 oder früher, um zu erfahren, wie Sie von früheren Versionen migrieren.
nghttpx
implementiert wichtige leistungsorientierte Funktionen in TLS, wie Sitzungs-IDs, Sitzungstickets (mit automatischer Schlüsselrotation), OCSP-Stapling, dynamische Datensatzgröße, ALPN, Forward Secrecy und HTTP/2. nghttpx
bietet auch die Funktionalität, Sitzungscache und Ticketschlüssel über memcached zwischen mehreren nghttpx
Instanzen zu teilen.
nghttpx
verfügt über zwei Betriebsmodi:
Modusoption | Frontend | Backend | Notiz |
---|---|---|---|
Standardmodus | HTTP/3, HTTP/2, HTTP/1.1 | HTTP/1.1, HTTP/2 | Reverse-Proxy |
--http2-proxy | HTTP/3, HTTP/2, HTTP/1.1 | HTTP/1.1, HTTP/2 | Weiterleitungs-Proxy |
Der derzeit interessante Modus ist der Standardmodus. Es funktioniert wie ein Reverse-Proxy und lauscht auf HTTP/3, HTTP/2 und HTTP/1.1 und kann als SSL/TLS-Terminator für vorhandene Webserver eingesetzt werden.
In allen Modi werden die Frontend-Verbindungen standardmäßig per SSL/TLS verschlüsselt. Um die Verschlüsselung zu deaktivieren, verwenden Sie das Schlüsselwort no-tls
in der Option --frontend
. Wenn die Verschlüsselung deaktiviert ist, können eingehende HTTP/1.1-Verbindungen über HTTP Upgrade auf HTTP/2 aktualisiert werden. Auf der anderen Seite sind Backend-Verbindungen standardmäßig nicht verschlüsselt. Um Backend-Verbindungen zu verschlüsseln, verwenden Sie das Schlüsselwort tls
in der Option --backend
.
nghttpx
unterstützt eine Konfigurationsdatei. Sehen Sie sich die Option --conf
und die Beispielkonfigurationsdatei nghttpx.conf.sample
an.
Im Standardmodus fungiert nghttpx
als Reverse-Proxy zum Backend-Server:
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Webserver
[Reverse-Proxy]
Mit der Option --http2-proxy
fungiert es als Forward-Proxy und ist ein sogenannter sicherer HTTP/2-Proxy:
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
[sicherer Proxy] (z. B. Squid, ATS)
Der Client
im obigen Beispiel muss für die Verwendung nghttpx
als sicheren Proxy konfiguriert werden.
Zum Zeitpunkt des Verfassens dieses Artikels unterstützen sowohl Chrome als auch Firefox den sicheren HTTP/2-Proxy. Eine Möglichkeit, Chrome für die Verwendung eines sicheren Proxys zu konfigurieren, besteht darin, ein Proxy.pac-Skript wie dieses zu erstellen:
function FindProxyForURL ( url , host ) {
return "HTTPS SERVERADDR:PORT" ;
}
SERVERADDR
und PORT
sind der Hostname/die Adresse und der Port des Computers, auf dem nghttpx ausgeführt wird. Bitte beachten Sie, dass Chrome für den sicheren Proxy ein gültiges Zertifikat benötigt.
Führen Sie dann Chrome mit den folgenden Argumenten aus:
$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
Die Backend-HTTP/2-Verbindungen können über einen HTTP-Proxy getunnelt werden. Der Proxy wird mit --backend-http-proxy-uri
angegeben. Die folgende Abbildung zeigt, wie nghttpx über einen HTTP-Proxy mit dem externen HTTP/2-Proxy kommuniziert:
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
--===================---> HTTP/2-Proxy
(HTTP-Proxy-Tunnel) (z. B. nghttpx -s)
Das h2load
-Programm ist ein Benchmarking-Tool für HTTP/3, HTTP/2 und HTTP/1.1. Die Benutzeroberfläche von h2load
ist stark von weighttp
inspiriert (https://github.com/lighttpd/weighttp). Die typische Verwendung ist wie folgt:
$ h2load -n100000 -c100 -m100 https://localhost:8443/
Start-Benchmark...
Spawning-Thread Nr. 0: 100 gleichzeitige Clients, insgesamt 100.000 Anfragen
Protokoll: TLSv1.2
Chiffre: ECDHE-RSA-AES128-GCM-SHA256
Temporärer Serverschlüssel: ECDH P-256 256 Bit
Fortschritt: 10 % erledigt
Fortschritt: 20 % erledigt
Fortschritt: 30 % erledigt
Fortschritt: 40 % erledigt
Fortschritt: 50 % erledigt
Fortschritt: 60 % erledigt
Fortschritt: 70 % erledigt
Fortschritt: 80 % erledigt
Fortschritt: 90 % erledigt
Fortschritt: 100 % erledigt
abgeschlossen in 771,26 ms, 129658 req/s, 4,71 MB/s
Anfragen: insgesamt 100.000, 100.000 gestartet, 100.000 erledigt, 100.000 erfolgreich, 0 fehlgeschlagen, 0 fehlerhaft
Statuscodes: 100000 2xx, 0 3xx, 0 4xx, 0 5xx
Datenverkehr: 3812300 Byte insgesamt, 1009900 Byte Header, 1000000 Byte Daten
Min. Max. Mittelwert SD +/- SD
Zeit für Anfrage: 25,12 ms 124,55 ms 51,07 ms 15,36 ms 84,87 %
Zeit für die Verbindung: 208,94 ms 254,67 ms 241,38 ms 7,95 ms 63,00 %
Zeit bis zum 1. Byte: 209,11 ms 254,80 ms 241,51 ms 7,94 ms 63,00 %
Im obigen Beispiel wurden insgesamt 100.000 Anfragen ausgegeben, wobei 100 gleichzeitige Clients (also 100 HTTP/2-Sitzungen) und maximal 100 Streams pro Client verwendet wurden. Mit der Option -t
verwendet h2load
mehrere native Threads, um eine Überlastung eines einzelnen Kerns auf der Clientseite zu vermeiden.
Warnung
Verwenden Sie dieses Tool nicht gegen öffentlich zugängliche Server. Das wird als DOS-Angriff angesehen. Bitte verwenden Sie es nur für Ihre privaten Server.
Wenn das experimentelle HTTP/3 aktiviert ist, kann h2load Anfragen an den HTTP/3-Server senden. Geben Sie dazu h3
für die Option --alpn-list
wie folgt an:
$ h2load --alpn-list h3 https://127.0.0.1:4433
Verwenden Sie für nghttp2 v1.58 oder früher --npn-list
anstelle von --alpn-list
.
Das Verzeichnis src
enthält die HPACK-Tools. Das deflatehd
-Programm ist ein Befehlszeilen-Header-Komprimierungstool. Das inflatehd
-Programm ist ein Befehlszeilen-Header-Dekomprimierungstool. Beide Tools lesen Eingaben von stdin und schreiben Ausgaben nach stdout. Fehler werden in stderr geschrieben. Sie verwenden JSON als Eingabe und Ausgabe. Wir verwenden (meistens) dasselbe JSON-Datenformat, das unter https://github.com/http2jp/hpack-test-case beschrieben ist.
Das deflatehd
-Programm liest JSON-Daten oder HTTP/1-Header-Felder aus Stdin und gibt den komprimierten Header-Block in JSON aus.
Für die JSON -Eingabe muss das Root JSON -Objekt einen cases
enthalten. Sein Wert muss die Abfolge des Eingangs -Header -Satzes enthalten. Sie teilen den gleichen Komprimierungskontext und werden in der Reihenfolge verarbeitet, die sie erscheinen. Jedes Element in der Sequenz ist ein JSON -Objekt und muss einen headers
-Schlüssel enthalten. Sein Wert ist ein Array von JSON -Objekten, das genau einen Namen/Wert -Paar enthält.
Beispiel:
{
"cases" :
[
{
"headers" : [
{ ":method" : " GET " },
{ ":path" : " / " }
]
},
{
"headers" : [
{ ":method" : " POST " },
{ ":path" : " / " }
]
}
]
}
Mit der Option -t
kann das Programm mehr vertraute HTTP/1 -Style -Header -Feldblöcke akzeptieren. Jeder Header -Set wird durch eine leere Linie abgegrenzt:
Beispiel:
: Methode: Get
: Schema: https
:Weg: /
: Methode: Post
Benutzer-Agent: nghttp2
Die Ausgabe ist im JSON -Objekt. Es sollte einen cases
enthalten und sein Wert ist ein Array von JSON -Objekten, das mindestens die folgenden Schlüssel enthält:
output_length
/ input_length
* 100Beispiele:
{
"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
}
]
}
Der Ausgang kann als Eingang für inflatehd
und deflatehd
verwendet werden.
Mit der Option -d
wird der zusätzliche header_table
-Schlüssel hinzugefügt und sein zugeordneter Wert enthält den Status der dynamischen Header -Tabelle, nachdem der entsprechende Header -Set verarbeitet wurde. Der Wert beinhaltet mindestens die folgenden Schlüssel:
referenced
true
, ist es im Referenzsatz. Die size
umfasst den Overhead (32 Bytes). Der index
entspricht dem Index der Header -Tabelle. Der name
ist der Name des Headerfeldes und der value
ist der Kopfzeilenfeld.max_deflate_size
besetzt sind.max_size
. In diesem Fall verwendet der Encoder nur bis zum ersten max_deflate_size
-Puffer. Da die Header -Tabellengröße noch max_size
ist, muss der Encoder die Einträge außerhalb der max_deflate_size
im Auge behalten, jedoch innerhalb der max_size
und sicherstellen, dass sie nicht mehr verwiesen werden.Beispiel:
{
"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
}