From bde98253c7e4627daa17a8ba921184aee29fbaf9 Mon Sep 17 00:00:00 2001 From: djc Date: Wed, 21 Feb 2024 08:57:06 +0000 Subject: [PATCH] deploy: 614fef62f7e0d6e9b6c36763a339beaab8af4513 --- index.html | 22 ++++----- networking-introduction.html | 22 ++++----- print.html | 94 ++++++++++++++++++------------------ quic.html | 18 +++---- quinn/certificate.html | 14 +++--- quinn/data-transfer.html | 22 ++++----- quinn/set-up-connection.html | 18 +++---- searcher.js | 2 +- 8 files changed, 106 insertions(+), 106 deletions(-) diff --git a/index.html b/index.html index a76469b3d..62b228fe6 100644 --- a/index.html +++ b/index.html @@ -174,12 +174,12 @@

Networking Introduction

-

In this chapter, you will find a very short introduction to various networking concepts. +

In this chapter, you will find a very short introduction to various networking concepts. These concepts are important to understanding when to use QUIC.

1. TCP/IP and UDP Comparison

Let's compare TCP, UDP, and QUIC.

    -
  • unreliable: Transport packets are not assured of arrival and ordering.
  • +
  • unreliable: Transport packets are not assured of arrival and ordering.
  • reliable: Transport packets are assured of arrival and ordering.
@@ -192,22 +192,22 @@ These concepts are important to understanding when to use QUIC.

FeatureTCPUDPQUIC

'a. Unreliable is supported as an extension.
-'b. QUIC control flow/congestion implementations will run in userspace whereas in TCP it's running in kernel space, +'b. QUIC control flow/congestion implementations will run in userspace whereas in TCP it's running in kernel space, however, there might be a kernel implementation for QUIC in the future.

2. Issues with TCP

-

TCP has been around for a long time and was not designed with the modern internet in mind. -It has several difficulties that QUIC tries to resolve.

+

TCP has been around for a long time and was not designed with the modern internet in mind. +It has several difficulties that QUIC tries to resolve.

Head-of-line Blocking

-

One of the biggest issues with TCP is that of Head-of-line blocking. -It is a convenient feature because it ensures that all packages are sent and arrive in order. +

One of the biggest issues with TCP is that of Head-of-line blocking. +It is a convenient feature because it ensures that all packages are sent and arrive in order. However, in cases of high throughput (multiplayer game networking) and big load in a short time (web page load), this can severely impact latency.

The issue is demonstrated in the following animation:

-

Head of line blocking

+

Head of line blocking

This animation shows that if a certain packet drops in transmission, all packets have to wait at the transport layer until it is resent by the other end. Once the delayed packet arrives at its destination, all later packets are passed on to the destination application together.

-

Let's look at two areas where head-of-line blocking causes problems.

+

Let's look at two areas where head-of-line blocking causes problems.

Web Networking

-

As websites increasingly need a larger number of HTTP requests (HTML, CSS, JavaScript, images) to display all content, the impact of head-of-line blocking has also increased. -To improve on this, HTTP 2 introduced request multiplexing within a TCP data stream, which allows servers to stream multiple responses at the same time. +

As websites increasingly need a larger number of HTTP requests (HTML, CSS, JavaScript, images) to display all content, the impact of head-of-line blocking has also increased. +To improve on this, HTTP 2 introduced request multiplexing within a TCP data stream, which allows servers to stream multiple responses at the same time. However, data loss of a single packet will still block all response streams because they exist within the context of a single TCP stream.

Connection Setup Duration

In the usual TCP + TLS + HTTP stack, TCP needs 6 handshake messages to set up a session between server and client. TLS performs its own, sending 4 messages for setting up an initial connection over TLS 1.3. By integrating the transport protocol and TLS handshakes, QUIC can make connection setup more efficient.

diff --git a/networking-introduction.html b/networking-introduction.html index a76469b3d..62b228fe6 100644 --- a/networking-introduction.html +++ b/networking-introduction.html @@ -174,12 +174,12 @@

Networking Introduction

-

In this chapter, you will find a very short introduction to various networking concepts. +

In this chapter, you will find a very short introduction to various networking concepts. These concepts are important to understanding when to use QUIC.

1. TCP/IP and UDP Comparison

Let's compare TCP, UDP, and QUIC.

    -
  • unreliable: Transport packets are not assured of arrival and ordering.
  • +
  • unreliable: Transport packets are not assured of arrival and ordering.
  • reliable: Transport packets are assured of arrival and ordering.
@@ -192,22 +192,22 @@ These concepts are important to understanding when to use QUIC.

FeatureTCPUDPQUIC

'a. Unreliable is supported as an extension.
-'b. QUIC control flow/congestion implementations will run in userspace whereas in TCP it's running in kernel space, +'b. QUIC control flow/congestion implementations will run in userspace whereas in TCP it's running in kernel space, however, there might be a kernel implementation for QUIC in the future.

2. Issues with TCP

-

TCP has been around for a long time and was not designed with the modern internet in mind. -It has several difficulties that QUIC tries to resolve.

+

TCP has been around for a long time and was not designed with the modern internet in mind. +It has several difficulties that QUIC tries to resolve.

Head-of-line Blocking

-

One of the biggest issues with TCP is that of Head-of-line blocking. -It is a convenient feature because it ensures that all packages are sent and arrive in order. +

One of the biggest issues with TCP is that of Head-of-line blocking. +It is a convenient feature because it ensures that all packages are sent and arrive in order. However, in cases of high throughput (multiplayer game networking) and big load in a short time (web page load), this can severely impact latency.

The issue is demonstrated in the following animation:

-

Head of line blocking

+

Head of line blocking

This animation shows that if a certain packet drops in transmission, all packets have to wait at the transport layer until it is resent by the other end. Once the delayed packet arrives at its destination, all later packets are passed on to the destination application together.

-

Let's look at two areas where head-of-line blocking causes problems.

+

Let's look at two areas where head-of-line blocking causes problems.

Web Networking

-

As websites increasingly need a larger number of HTTP requests (HTML, CSS, JavaScript, images) to display all content, the impact of head-of-line blocking has also increased. -To improve on this, HTTP 2 introduced request multiplexing within a TCP data stream, which allows servers to stream multiple responses at the same time. +

As websites increasingly need a larger number of HTTP requests (HTML, CSS, JavaScript, images) to display all content, the impact of head-of-line blocking has also increased. +To improve on this, HTTP 2 introduced request multiplexing within a TCP data stream, which allows servers to stream multiple responses at the same time. However, data loss of a single packet will still block all response streams because they exist within the context of a single TCP stream.

Connection Setup Duration

In the usual TCP + TLS + HTTP stack, TCP needs 6 handshake messages to set up a session between server and client. TLS performs its own, sending 4 messages for setting up an initial connection over TLS 1.3. By integrating the transport protocol and TLS handshakes, QUIC can make connection setup more efficient.

diff --git a/print.html b/print.html index 2acde15af..8b7b2d8a9 100644 --- a/print.html +++ b/print.html @@ -175,12 +175,12 @@

Networking Introduction

-

In this chapter, you will find a very short introduction to various networking concepts. +

In this chapter, you will find a very short introduction to various networking concepts. These concepts are important to understanding when to use QUIC.

1. TCP/IP and UDP Comparison

Let's compare TCP, UDP, and QUIC.

    -
  • unreliable: Transport packets are not assured of arrival and ordering.
  • +
  • unreliable: Transport packets are not assured of arrival and ordering.
  • reliable: Transport packets are assured of arrival and ordering.
@@ -193,44 +193,44 @@ These concepts are important to understanding when to use QUIC.

FeatureTCPUDPQUIC

'a. Unreliable is supported as an extension.
-'b. QUIC control flow/congestion implementations will run in userspace whereas in TCP it's running in kernel space, +'b. QUIC control flow/congestion implementations will run in userspace whereas in TCP it's running in kernel space, however, there might be a kernel implementation for QUIC in the future.

2. Issues with TCP

-

TCP has been around for a long time and was not designed with the modern internet in mind. -It has several difficulties that QUIC tries to resolve.

+

TCP has been around for a long time and was not designed with the modern internet in mind. +It has several difficulties that QUIC tries to resolve.

Head-of-line Blocking

-

One of the biggest issues with TCP is that of Head-of-line blocking. -It is a convenient feature because it ensures that all packages are sent and arrive in order. +

One of the biggest issues with TCP is that of Head-of-line blocking. +It is a convenient feature because it ensures that all packages are sent and arrive in order. However, in cases of high throughput (multiplayer game networking) and big load in a short time (web page load), this can severely impact latency.

The issue is demonstrated in the following animation:

-

Head of line blocking

+

Head of line blocking

This animation shows that if a certain packet drops in transmission, all packets have to wait at the transport layer until it is resent by the other end. Once the delayed packet arrives at its destination, all later packets are passed on to the destination application together.

-

Let's look at two areas where head-of-line blocking causes problems.

+

Let's look at two areas where head-of-line blocking causes problems.

Web Networking

-

As websites increasingly need a larger number of HTTP requests (HTML, CSS, JavaScript, images) to display all content, the impact of head-of-line blocking has also increased. -To improve on this, HTTP 2 introduced request multiplexing within a TCP data stream, which allows servers to stream multiple responses at the same time. +

As websites increasingly need a larger number of HTTP requests (HTML, CSS, JavaScript, images) to display all content, the impact of head-of-line blocking has also increased. +To improve on this, HTTP 2 introduced request multiplexing within a TCP data stream, which allows servers to stream multiple responses at the same time. However, data loss of a single packet will still block all response streams because they exist within the context of a single TCP stream.

Connection Setup Duration

In the usual TCP + TLS + HTTP stack, TCP needs 6 handshake messages to set up a session between server and client. TLS performs its own, sending 4 messages for setting up an initial connection over TLS 1.3. By integrating the transport protocol and TLS handshakes, QUIC can make connection setup more efficient.

The QUIC protocol

QUIC is a general-purpose network protocol built on top of UDP, -and standardized by the IETF. Although QUIC is still relatively new, -the protocol is used for all connections from Chrome web browsers to the Google servers.

-

QUIC solves a number of transport-layer and application-layer problems experienced by modern web applications. -It is very similar to TCP+TLS+HTTP2, but implemented on top of UDP. -Having QUIC as a self-contained protocol allows innovations which aren’t +and standardized by the IETF. Although QUIC is still relatively new, +the protocol is used for all connections from Chrome web browsers to the Google servers.

+

QUIC solves a number of transport-layer and application-layer problems experienced by modern web applications. +It is very similar to TCP+TLS+HTTP2, but implemented on top of UDP. +Having QUIC as a self-contained protocol allows innovations which aren’t possible with existing protocols as they are hampered by legacy clients and middleboxes.

Key advantages of QUIC over TCP+TLS+HTTP2 include:

  • Improved connection establishment speed (0-rtt).
  • Improved congestion control by moving congestion control algorithms into the user space at both endpoints.
  • -
  • Improved bandwidth estimation in each direction to avoid congestion.
  • +
  • Improved bandwidth estimation in each direction to avoid congestion.
  • Improved multiplexing without head-of-line blocking.
  • -
  • Contains forward error correction (FEC).
  • +
  • Contains forward error correction (FEC).

While QUIC's intentions are originally web-oriented, it offers interesting opportunities in other areas like game networking. -One thing is for sure, QUIC has many great potentials and will serve us in the future with HTTP/3.

-

In the upcoming chapter we will be discussing various aspects of QUIC also in relation to Quinn.

+One thing is for sure, QUIC has many great potentials and will serve us in the future with HTTP/3.

+

In the upcoming chapter we will be discussing various aspects of QUIC also in relation to Quinn.

Documentation Crates.io @@ -333,8 +333,8 @@ crates will always be at least 6 months old at the time of release.

For our example use case, the easiest way to allow the client to trust our server is to disable certificate verification (don't do this in production!). When the rustls dangerous_configuration feature flag is enabled, a client can be configured to trust any server.

Start by adding a rustls dependency with the dangerous_configuration feature flag to your Cargo.toml file.

-
quinn = "*"
-rustls = { version = "*", features = ["dangerous_configuration", "quic"] }
+
quinn = "*"
+rustls = { version = "*", features = ["dangerous_configuration", "quic"] }
 

Then, allow the client to skip the certificate validation by implementing ServerCertVerifier and letting it assert verification for any server.

#![allow(unused)]
@@ -388,7 +388,7 @@ This example uses rcgen to generate
 fn main() {
 fn generate_self_signed_cert() -> Result<(rustls::Certificate, rustls::PrivateKey), Box<dyn Error>>
 {
-    let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
+    let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
     let key = rustls::PrivateKey(cert.serialize_private_key_der());
     Ok((rustls::Certificate(cert.serialize_der()?), key))
 }
@@ -411,16 +411,16 @@ These files can then be referenced in code.

pub fn read_certs_from_file( ) -> Result<(Vec<rustls::Certificate>, rustls::PrivateKey), Box<dyn Error>> { - let mut cert_chain_reader = BufReader::new(File::open("./fullchain.pem")?); + let mut cert_chain_reader = BufReader::new(File::open("./fullchain.pem")?); let certs = rustls_pemfile::certs(&mut cert_chain_reader)? .into_iter() .map(rustls::Certificate) .collect(); - let mut key_reader = BufReader::new(File::open("./privkey.pem")?); - // if the file starts with "BEGIN RSA PRIVATE KEY" + let mut key_reader = BufReader::new(File::open("./privkey.pem")?); + // if the file starts with "BEGIN RSA PRIVATE KEY" // let mut keys = rustls_pemfile::rsa_private_keys(&mut key_reader)?; - // if the file starts with "BEGIN PRIVATE KEY" + // if the file starts with "BEGIN PRIVATE KEY" let mut keys = rustls_pemfile::pkcs8_private_keys(&mut key_reader)?; assert_eq!(keys.len(), 1); @@ -448,26 +448,26 @@ After configuring plug the configuration into the Endpoint.

Next, let's have a look at how to set up a connection.

Connection Setup

In the previous chapter we looked at how to configure a certificate. -This aspect is omitted in this chapter to prevent duplication. -But remember that this is required to get your Endpoint up and running. -This chapter explains how to set up a connection and prepare it for data transfer.

-

It all starts with the Endpoint struct, this is the entry point of the library.

+This aspect is omitted in this chapter to prevent duplication. +But remember that this is required to get your Endpoint up and running. +This chapter explains how to set up a connection and prepare it for data transfer.

+

It all starts with the Endpoint struct, this is the entry point of the library.

Example

-

Let's start by defining some constants.

+

Let's start by defining some constants.

#![allow(unused)]
 fn main() {
-static SERVER_NAME: &str = "localhost";
+static SERVER_NAME: &str = "localhost";
 
 fn client_addr() -> SocketAddr {
-    "127.0.0.1:5000".parse::<SocketAddr>().unwrap()
+    "127.0.0.1:5000".parse::<SocketAddr>().unwrap()
 }
 
 fn server_addr() -> SocketAddr {
-    "127.0.0.1:5001".parse::<SocketAddr>().unwrap()
+    "127.0.0.1:5001".parse::<SocketAddr>().unwrap()
 }
 }

Server

-

First, the server endpoint should be bound to a socket. +

First, the server endpoint should be bound to a socket. The server() method, which can be used for this, returns the Endpoint type. Endpoint is used to start outgoing connections and accept incoming connections.

#![allow(unused)]
@@ -511,8 +511,8 @@ The SERVER_NAME argument is the DNS name, matching the certificate
 and then get access to a Connection.
 This chapter continues with the subject of sending data over this connection.

Multiplexing

-

Multiplexing is the act of combining data from multiple streams into a single stream. -This can have a significant positive effect on the performance of the application. +

Multiplexing is the act of combining data from multiple streams into a single stream. +This can have a significant positive effect on the performance of the application. With QUIC, the programmer is in full control over the stream allocation.

Stream Types

QUIC provides support for both stream and message-based communication. @@ -527,7 +527,7 @@ Streams and messages can be initiated both on the client and server.

New streams can be created with Connection's open_bi() and open_uni() methods.

Bidirectional Streams

-

With bidirectional streams, data can be sent in both directions. +

With bidirectional streams, data can be sent in both directions. For example, from the connection initiator to the peer and the other way around.

open bidirectional stream

#![allow(unused)]
@@ -537,7 +537,7 @@ For example, from the connection initiator to the peer and the other way around.
         .open_bi()
         .await?;
 
-    send.write_all(b"test").await?;
+    send.write_all(b"test").await?;
     send.finish().await?;
     
     let received = recv.read_to_end(10).await?;
@@ -551,9 +551,9 @@ For example, from the connection initiator to the peer and the other way around.
 async fn receive_bidirectional_stream(connection: Connection) -> anyhow::Result<()> {
     while let Ok((mut send, recv)) = connection.accept_bi().await {
         // Because it is a bidirectional stream, we can both send and receive.
-        println!("request: {:?}", recv.read_to_end(50).await?);
+        println!("request: {:?}", recv.read_to_end(50).await?);
 
-        send.write_all(b"response").await?;
+        send.write_all(b"response").await?;
         send.finish().await?;
     }
 
@@ -571,7 +571,7 @@ It is possible to get reliability without ordering (so no head-of-line blocking)
         .open_uni()
         .await?;
 
-    send.write_all(b"test").await?;
+    send.write_all(b"test").await?;
     send.finish().await?;
 
     Ok(())
@@ -583,21 +583,21 @@ It is possible to get reliability without ordering (so no head-of-line blocking)
 async fn receive_unidirectional_stream(connection: Connection) -> anyhow::Result<()> {
     while let Ok(recv) = connection.accept_uni().await {
         // Because it is a unidirectional stream, we can only receive not send back.
-        println!("{:?}", recv.read_to_end(50).await?);
+        println!("{:?}", recv.read_to_end(50).await?);
     }
 
     Ok(())
 }
 }

Unreliable Messaging

-

With unreliable messaging, you can transfer data without reliability. +

With unreliable messaging, you can transfer data without reliability. This could be useful if data arrival isn't essential or when high throughput is important.

send datagram

#![allow(unused)]
 fn main() {
 async fn send_unreliable(connection: Connection)-> anyhow::Result<()> {
     connection
-        .send_datagram(b"test".into())
+        .send_datagram(b"test".into())
         .await?;
 
     Ok(())
@@ -609,7 +609,7 @@ This could be useful if data arrival isn't essential or when high throughput is
 async fn receive_datagram(connection: Connection) -> anyhow::Result<()> {
     while let Ok(received_bytes) = connection.read_datagram().await {
         // Because it is a unidirectional stream, we can only receive not send back.
-        println!("request: {:?}", received);
+        println!("request: {:?}", received);
     }
 
     Ok(())
diff --git a/quic.html b/quic.html
index e8d0768e8..6d7d15c34 100644
--- a/quic.html
+++ b/quic.html
@@ -175,23 +175,23 @@
                     

The QUIC protocol

QUIC is a general-purpose network protocol built on top of UDP, -and standardized by the IETF. Although QUIC is still relatively new, -the protocol is used for all connections from Chrome web browsers to the Google servers.

-

QUIC solves a number of transport-layer and application-layer problems experienced by modern web applications. -It is very similar to TCP+TLS+HTTP2, but implemented on top of UDP. -Having QUIC as a self-contained protocol allows innovations which aren’t +and standardized by the IETF. Although QUIC is still relatively new, +the protocol is used for all connections from Chrome web browsers to the Google servers.

+

QUIC solves a number of transport-layer and application-layer problems experienced by modern web applications. +It is very similar to TCP+TLS+HTTP2, but implemented on top of UDP. +Having QUIC as a self-contained protocol allows innovations which aren’t possible with existing protocols as they are hampered by legacy clients and middleboxes.

Key advantages of QUIC over TCP+TLS+HTTP2 include:

  • Improved connection establishment speed (0-rtt).
  • Improved congestion control by moving congestion control algorithms into the user space at both endpoints.
  • -
  • Improved bandwidth estimation in each direction to avoid congestion.
  • +
  • Improved bandwidth estimation in each direction to avoid congestion.
  • Improved multiplexing without head-of-line blocking.
  • -
  • Contains forward error correction (FEC).
  • +
  • Contains forward error correction (FEC).

While QUIC's intentions are originally web-oriented, it offers interesting opportunities in other areas like game networking. -One thing is for sure, QUIC has many great potentials and will serve us in the future with HTTP/3.

-

In the upcoming chapter we will be discussing various aspects of QUIC also in relation to Quinn.

+One thing is for sure, QUIC has many great potentials and will serve us in the future with HTTP/3.

+

In the upcoming chapter we will be discussing various aspects of QUIC also in relation to Quinn.

diff --git a/quinn/certificate.html b/quinn/certificate.html index 246a1ac6e..2f4fb7f00 100644 --- a/quinn/certificate.html +++ b/quinn/certificate.html @@ -180,8 +180,8 @@

For our example use case, the easiest way to allow the client to trust our server is to disable certificate verification (don't do this in production!). When the rustls dangerous_configuration feature flag is enabled, a client can be configured to trust any server.

Start by adding a rustls dependency with the dangerous_configuration feature flag to your Cargo.toml file.

-
quinn = "*"
-rustls = { version = "*", features = ["dangerous_configuration", "quic"] }
+
quinn = "*"
+rustls = { version = "*", features = ["dangerous_configuration", "quic"] }
 

Then, allow the client to skip the certificate validation by implementing ServerCertVerifier and letting it assert verification for any server.

#![allow(unused)]
@@ -235,7 +235,7 @@ This example uses rcgen to generate
 fn main() {
 fn generate_self_signed_cert() -> Result<(rustls::Certificate, rustls::PrivateKey), Box<dyn Error>>
 {
-    let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
+    let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_string()])?;
     let key = rustls::PrivateKey(cert.serialize_private_key_der());
     Ok((rustls::Certificate(cert.serialize_der()?), key))
 }
@@ -258,16 +258,16 @@ These files can then be referenced in code.

pub fn read_certs_from_file( ) -> Result<(Vec<rustls::Certificate>, rustls::PrivateKey), Box<dyn Error>> { - let mut cert_chain_reader = BufReader::new(File::open("./fullchain.pem")?); + let mut cert_chain_reader = BufReader::new(File::open("./fullchain.pem")?); let certs = rustls_pemfile::certs(&mut cert_chain_reader)? .into_iter() .map(rustls::Certificate) .collect(); - let mut key_reader = BufReader::new(File::open("./privkey.pem")?); - // if the file starts with "BEGIN RSA PRIVATE KEY" + let mut key_reader = BufReader::new(File::open("./privkey.pem")?); + // if the file starts with "BEGIN RSA PRIVATE KEY" // let mut keys = rustls_pemfile::rsa_private_keys(&mut key_reader)?; - // if the file starts with "BEGIN PRIVATE KEY" + // if the file starts with "BEGIN PRIVATE KEY" let mut keys = rustls_pemfile::pkcs8_private_keys(&mut key_reader)?; assert_eq!(keys.len(), 1); diff --git a/quinn/data-transfer.html b/quinn/data-transfer.html index 59ca152e8..1383a1f85 100644 --- a/quinn/data-transfer.html +++ b/quinn/data-transfer.html @@ -178,8 +178,8 @@ and then get access to a Connection. This chapter continues with the subject of sending data over this connection.

Multiplexing

-

Multiplexing is the act of combining data from multiple streams into a single stream. -This can have a significant positive effect on the performance of the application. +

Multiplexing is the act of combining data from multiple streams into a single stream. +This can have a significant positive effect on the performance of the application. With QUIC, the programmer is in full control over the stream allocation.

Stream Types

QUIC provides support for both stream and message-based communication. @@ -194,7 +194,7 @@ Streams and messages can be initiated both on the client and server.

New streams can be created with Connection's open_bi() and open_uni() methods.

Bidirectional Streams

-

With bidirectional streams, data can be sent in both directions. +

With bidirectional streams, data can be sent in both directions. For example, from the connection initiator to the peer and the other way around.

open bidirectional stream

#![allow(unused)]
@@ -204,7 +204,7 @@ For example, from the connection initiator to the peer and the other way around.
         .open_bi()
         .await?;
 
-    send.write_all(b"test").await?;
+    send.write_all(b"test").await?;
     send.finish().await?;
     
     let received = recv.read_to_end(10).await?;
@@ -218,9 +218,9 @@ For example, from the connection initiator to the peer and the other way around.
 async fn receive_bidirectional_stream(connection: Connection) -> anyhow::Result<()> {
     while let Ok((mut send, recv)) = connection.accept_bi().await {
         // Because it is a bidirectional stream, we can both send and receive.
-        println!("request: {:?}", recv.read_to_end(50).await?);
+        println!("request: {:?}", recv.read_to_end(50).await?);
 
-        send.write_all(b"response").await?;
+        send.write_all(b"response").await?;
         send.finish().await?;
     }
 
@@ -238,7 +238,7 @@ It is possible to get reliability without ordering (so no head-of-line blocking)
         .open_uni()
         .await?;
 
-    send.write_all(b"test").await?;
+    send.write_all(b"test").await?;
     send.finish().await?;
 
     Ok(())
@@ -250,21 +250,21 @@ It is possible to get reliability without ordering (so no head-of-line blocking)
 async fn receive_unidirectional_stream(connection: Connection) -> anyhow::Result<()> {
     while let Ok(recv) = connection.accept_uni().await {
         // Because it is a unidirectional stream, we can only receive not send back.
-        println!("{:?}", recv.read_to_end(50).await?);
+        println!("{:?}", recv.read_to_end(50).await?);
     }
 
     Ok(())
 }
 }

Unreliable Messaging

-

With unreliable messaging, you can transfer data without reliability. +

With unreliable messaging, you can transfer data without reliability. This could be useful if data arrival isn't essential or when high throughput is important.

send datagram

#![allow(unused)]
 fn main() {
 async fn send_unreliable(connection: Connection)-> anyhow::Result<()> {
     connection
-        .send_datagram(b"test".into())
+        .send_datagram(b"test".into())
         .await?;
 
     Ok(())
@@ -276,7 +276,7 @@ This could be useful if data arrival isn't essential or when high throughput is
 async fn receive_datagram(connection: Connection) -> anyhow::Result<()> {
     while let Ok(received_bytes) = connection.read_datagram().await {
         // Because it is a unidirectional stream, we can only receive not send back.
-        println!("request: {:?}", received);
+        println!("request: {:?}", received);
     }
 
     Ok(())
diff --git a/quinn/set-up-connection.html b/quinn/set-up-connection.html
index ff170306c..d120ce795 100644
--- a/quinn/set-up-connection.html
+++ b/quinn/set-up-connection.html
@@ -175,26 +175,26 @@
                     

Connection Setup

In the previous chapter we looked at how to configure a certificate. -This aspect is omitted in this chapter to prevent duplication. -But remember that this is required to get your Endpoint up and running. -This chapter explains how to set up a connection and prepare it for data transfer.

-

It all starts with the Endpoint struct, this is the entry point of the library.

+This aspect is omitted in this chapter to prevent duplication. +But remember that this is required to get your Endpoint up and running. +This chapter explains how to set up a connection and prepare it for data transfer.

+

It all starts with the Endpoint struct, this is the entry point of the library.

Example

-

Let's start by defining some constants.

+

Let's start by defining some constants.

#![allow(unused)]
 fn main() {
-static SERVER_NAME: &str = "localhost";
+static SERVER_NAME: &str = "localhost";
 
 fn client_addr() -> SocketAddr {
-    "127.0.0.1:5000".parse::<SocketAddr>().unwrap()
+    "127.0.0.1:5000".parse::<SocketAddr>().unwrap()
 }
 
 fn server_addr() -> SocketAddr {
-    "127.0.0.1:5001".parse::<SocketAddr>().unwrap()
+    "127.0.0.1:5001".parse::<SocketAddr>().unwrap()
 }
 }

Server

-

First, the server endpoint should be bound to a socket. +

First, the server endpoint should be bound to a socket. The server() method, which can be used for this, returns the Endpoint type. Endpoint is used to start outgoing connections and accept incoming connections.

#![allow(unused)]
diff --git a/searcher.js b/searcher.js
index d2b0aeed3..dc03e0a02 100644
--- a/searcher.js
+++ b/searcher.js
@@ -316,7 +316,7 @@ window.search = window.search || {};
     
     // Eventhandler for keyevents on `document`
     function globalKeyHandler(e) {
-        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; }
+        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text' || !hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)) { return; }
 
         if (e.keyCode === ESCAPE_KEYCODE) {
             e.preventDefault();