The client
This page shows the HTTP/3 client in Rust, the scion-http3 crate,
as the terminal client of the chat uses it. The SCION code of the Rust client is in one file,
transport/scion.rs.
The mobile clients shows the Android and iOS clients of the chat.
Build the client and send a request
A Config names the endhost
API and the credential.
Client::new
builds the client from it. The client sends a
Request and returns the
response. The SDK example
http3_get_post.rs
shows these steps in one short program.
The chat builds one Client in ScionTransport::new, each time the user connects to a server. The
credential is an API key or a SNAP token. An API key goes into an AnapayaAaTokenSource.
A SNAP token expires. A fixed token is enough for a test, but a running app needs new tokens.
AnapayaAaTokenSource sends the API key to the Anapaya AA (Authentication and Authorization
service) and gets a new token before the current token expires.
Access and authentication
explains token sources.
To send a request, the transport converts an http::Request into a scion_http3::Request and
sends it with Client::request. It collects the body of the response up to a limit.
Trust the server
The client verifies the certificate of the server. The chat offers three choices, and the transport
turns each choice into a QuicConfig:
let mut quic = QuicConfig::builder();
match &config.trust {
Trust::SystemRoots => {}
Trust::Pinned(path) => {
let path = path.to_str().ok_or_else(|| {
ChatError::Config(format!("the certificate path is not utf-8: {path:?}"))
})?;
quic = quic.ca_certs_file(path);
}
Trust::Insecure => {
tracing::warn!(
"certificate verification is off: any server on the path can answer as this \
one"
);
quic = quic.verify_peer(false);
}
}
settings = settings.with_quic_config(quic.build());
SystemRootskeeps the default: the root certificates of the system.Pinnedtrusts one certificate file, for example the self-signed certificate of the chat server.Insecureaccepts any certificate. Use it for tests only, because anyone on the path can then answer as the server.
Reach a server without a TSAR record
The client resolves the host of a URL to a SCION address. It reads a DNS TXT record in the TSAR
format (TXT-based SCION address resolution). A server in a local SCION network has no such record.
The chat gives the address of such a server as target, and the resolver answers for the host of
the server from the configuration:
/// A resolver that answers for the server's host from configuration, and every other host normally.
fn resolver(server_url: &Url, target: &str) -> Result<ScionTxtDnsResolver, ChatError> {
let host = server_url
.host_str()
.ok_or_else(|| ChatError::Config(format!("the server url has no host: {server_url}")))?;
let address = ScionIpAddr::from_str(target).map_err(|error| {
ChatError::Config(format!("the target is not a scion address: {error}"))
})?;
ScionTxtDnsResolver::new()
.map(|resolver| resolver.with_override(host, vec![address]))
.map_err(|error| ChatError::Config(format!("building a resolver failed: {error}")))
}
with_override maps one host to fixed SCION addresses. The resolver looks up every other host in
DNS. The address has no port: the port and the name that the certificate must match come from the
URL.
Map the errors
Every failure of the client is a
scion_http3::Error. The chat
sorts the variants into its own error kinds:
/// Sorts an HTTP/3 failure into the taxonomy every transport reports.
fn failure(error: Error) -> TransportError {
let detail = describe(&error);
match error {
Error::Resolution { .. } => TransportError::Resolution(detail),
Error::Connect { .. } | Error::StackBuild { .. } => TransportError::Connect(detail),
Error::Tls { .. } => TransportError::Tls(detail),
Error::StreamReset { .. } | Error::ConnectionLimit => TransportError::StreamReset(detail),
Error::BodyTooLarge { limit, .. } => TransportError::BodyTooLarge { limit },
Error::Timeout { .. } => TransportError::Timeout,
_ => TransportError::Protocol(detail),
}
}
The TCP transport of the chat reports the same error kinds. Thus the rest of the client handles one set of errors for all transports.
Where to go next
- The server: the other end of the connection.
- The mobile clients: the same transport on Android and iOS.
- From a local SCION network to a real network: the credential, the address and the trust of a real deployment.
scion-http3API reference: the complete client API.