1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! An HTTP/1, HTTP/2 and HTTP/3 library.
//!
//! Soyokaze speaks all three versions of HTTP through one set of types. A
//! [`Message`] carries a request or a response regardless of the version that
//! framed it, and every connection implements [`protocol::base::Connection`],
//! so code written against the trait works unchanged over HTTP/1.1, HTTP/2 and
//! HTTP/3.
//!
//! # Layers
//!
//! The crate is arranged in layers, each usable on its own, and each module
//! standing alone as a library for exactly its own concern:
//!
//! - [`helpers`] holds the codecs the versions share — [`helpers::huffman`],
//! [`helpers::hpack`] for HTTP/2 and [`helpers::qpack`] for HTTP/3, over
//! the shared vocabulary in [`helpers::fields`] — plus the small pieces
//! ([`helpers::base64`], [`helpers::sha1`], [`helpers::text`],
//! [`helpers::scan`], [`helpers::sync`]) everything else leans on. Nothing
//! here knows about connections or transports.
//! - [`models`] is the vocabulary: [`Message`], [`Headers`], [`Version`],
//! [`Port`], [`Limits`]. [`tls`] holds the TLS side of it — [`Security`]
//! and the BoringSSL contexts — and [`cookies`], [`hsts`], [`responses`]
//! and [`finalizer`] each hold one message-level concern.
//! - [`protocol`] holds one connection type per version — [`protocol::h1`],
//! [`protocol::h2`] and [`protocol::h3`] — implementing the traits in
//! [`protocol::base`] over the shared vocabulary in [`protocol::common`].
//! Each binary version keeps its wire format in a module of its own
//! ([`protocol::h2::frames`], [`protocol::h3::frames`]), which encodes and
//! decodes frames and knows nothing of connections, exactly as
//! [`helpers::hpack`] and [`helpers::qpack`] do for field compression.
//! [`protocol::quic`] is the seam QUIC is consumed through, the transport
//! counterpart of [`protocol::base::Transport`], and [`protocol::handler`]
//! bridges each transport into a connection the same way. A higher layer
//! drives a lower one exactly the way an outside caller would.
//! - [`api`] holds the entry points: [`Client`] dials an origin, [`Server`]
//! binds ports and accepts connections, [`api::gate`] admits them, and
//! [`api::cluster`] runs the server across worker threads.
//!
//! # Symmetry
//!
//! Corresponding pieces are kept interchangeable on purpose. Client and server,
//! request and response, encoder and decoder, HTTP/1 and HTTP/2 and HTTP/3 —
//! each pair shares the shape of its counterpart, and version-specific
//! connections are drop-in replacements for one another wherever the protocol
//! itself does not force a difference. Prefer naming the base type
//! ([`protocol::base::Connection`], [`AnyConnection`]) over a concrete
//! version wherever a choice exists. Nothing keys on a version where the
//! transport is the real question: a port carries whichever versions run over
//! its transport, per [`Port::carries`], so a new version slots in without
//! touching the routing.
//!
//! # Getting started
//!
//! Fetch a resource:
//!
//! ```no_run
//! # async fn example() -> Result<(), soyokaze::Error> {
//! let client = soyokaze::Client::default();
//! let response = client.get("https://example.com/").await?;
//!
//! println!("{:?}", response.status_code);
//! # Ok(())
//! # }
//! ```
//!
//! Serve one:
//!
//! ```no_run
//! # async fn example() -> Result<(), soyokaze::Error> {
//! use soyokaze::{Port, Server};
//!
//! struct Echo;
//! impl soyokaze::Handler for Echo {}
//!
//! let server = Server::default();
//! let handle = server.serve(Echo, &[Port::TCP(8080)]).await?;
//!
//! handle.close(None).await;
//! # Ok(())
//! # }
//! ```
//!
//! [`AnyConnection`]: protocol::base::AnyConnection
pub use Error;
pub use ;
pub use ;
pub use ;
pub use VERSIONS;
pub use ;
pub use ;
pub use ;
pub use Cluster;
pub use ;
pub use ;
pub use Compression;
pub use Text;
pub use ;