|
1 | | -//! Frame a stream of bytes based on a length prefix |
2 | | -//! |
3 | | -//! Many protocols delimit their frames by prefacing frame data with a |
4 | | -//! frame head that specifies the length of the frame. The |
5 | | -//! `length_delimited` module provides utilities for handling the length |
6 | | -//! based framing. This allows the consumer to work with entire frames |
7 | | -//! without having to worry about buffering or other framing logic. |
8 | | -//! |
9 | | -//! # Getting started |
10 | | -//! |
11 | | -//! If implementing a protocol from scratch, using length delimited framing |
12 | | -//! is an easy way to get started. [`Framed::new()`] will adapt a |
13 | | -//! full-duplex byte stream with a length delimited framer using default |
14 | | -//! configuration values. |
15 | | -//! |
16 | | -//! ``` |
17 | | -//! use tokio_io::{AsyncRead, AsyncWrite}; |
18 | | -//! use tokio_io::codec::length_delimited; |
19 | | -//! |
20 | | -//! fn bind_transport<T: AsyncRead + AsyncWrite>(io: T) |
21 | | -//! -> length_delimited::Framed<T> |
22 | | -//! { |
23 | | -//! length_delimited::Framed::new(io) |
24 | | -//! } |
25 | | -//! ``` |
26 | | -//! |
27 | | -//! The returned transport implements `Sink + Stream` for `BytesMut`. It |
28 | | -//! encodes the frame with a big-endian `u32` header denoting the frame |
29 | | -//! payload length: |
30 | | -//! |
31 | | -//! ```text |
32 | | -//! +----------+--------------------------------+ |
33 | | -//! | len: u32 | frame payload | |
34 | | -//! +----------+--------------------------------+ |
35 | | -//! ``` |
36 | | -//! |
37 | | -//! Specifically, given the following: |
38 | | -//! |
39 | | -//! ``` |
40 | | -//! # extern crate tokio_io; |
41 | | -//! # extern crate bytes; |
42 | | -//! # extern crate futures; |
43 | | -//! # |
44 | | -//! use tokio_io::{AsyncRead, AsyncWrite}; |
45 | | -//! use tokio_io::codec::length_delimited; |
46 | | -//! use bytes::BytesMut; |
47 | | -//! use futures::{Sink, Future}; |
48 | | -//! |
49 | | -//! fn write_frame<T: AsyncRead + AsyncWrite>(io: T) { |
50 | | -//! let mut transport = length_delimited::Framed::new(io); |
51 | | -//! let frame = BytesMut::from("hello world"); |
52 | | -//! |
53 | | -//! transport.send(frame).wait().unwrap(); |
54 | | -//! } |
55 | | -//! # |
56 | | -//! # pub fn main() {} |
57 | | -//! ``` |
58 | | -//! |
59 | | -//! The encoded frame will look like this: |
60 | | -//! |
61 | | -//! ```text |
62 | | -//! +---- len: u32 ----+---- data ----+ |
63 | | -//! | \x00\x00\x00\x0b | hello world | |
64 | | -//! +------------------+--------------+ |
65 | | -//! ``` |
66 | | -//! |
67 | | -//! # Decoding |
68 | | -//! |
69 | | -//! [`FramedRead`] adapts an [`AsyncRead`] into a `Stream` of [`BytesMut`], |
70 | | -//! such that each yielded [`BytesMut`] value contains the contents of an |
71 | | -//! entire frame. There are many configuration parameters enabling |
72 | | -//! [`FramedRead`] to handle a wide range of protocols. Here are some |
73 | | -//! examples that will cover the various options at a high level. |
74 | | -//! |
75 | | -//! ## Example 1 |
76 | | -//! |
77 | | -//! The following will parse a `u16` length field at offset 0, including the |
78 | | -//! frame head in the yielded `BytesMut`. |
79 | | -//! |
80 | | -//! ``` |
81 | | -//! # use tokio_io::AsyncRead; |
82 | | -//! # use tokio_io::codec::length_delimited; |
83 | | -//! # fn bind_read<T: AsyncRead>(io: T) { |
84 | | -//! length_delimited::Builder::new() |
85 | | -//! .length_field_offset(0) // default value |
86 | | -//! .length_field_length(2) |
87 | | -//! .length_adjustment(0) // default value |
88 | | -//! .num_skip(0) // Do not strip frame header |
89 | | -//! .new_read(io); |
90 | | -//! # } |
91 | | -//! ``` |
92 | | -//! |
93 | | -//! The following frame will be decoded as such: |
94 | | -//! |
95 | | -//! ```text |
96 | | -//! INPUT DECODED |
97 | | -//! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ |
98 | | -//! | \x00\x0B | Hello world | --> | \x00\x0B | Hello world | |
99 | | -//! +----------+---------------+ +----------+---------------+ |
100 | | -//! ``` |
101 | | -//! |
102 | | -//! The value of the length field is 11 (`\x0B`) which represents the length |
103 | | -//! of the payload, `hello world`. By default, [`FramedRead`] assumes that |
104 | | -//! the length field represents the number of bytes that **follows** the |
105 | | -//! length field. Thus, the entire frame has a length of 13: 2 bytes for the |
106 | | -//! frame head + 11 bytes for the payload. |
107 | | -//! |
108 | | -//! ## Example 2 |
109 | | -//! |
110 | | -//! The following will parse a `u16` length field at offset 0, omitting the |
111 | | -//! frame head in the yielded `BytesMut`. |
112 | | -//! |
113 | | -//! ``` |
114 | | -//! # use tokio_io::AsyncRead; |
115 | | -//! # use tokio_io::codec::length_delimited; |
116 | | -//! # fn bind_read<T: AsyncRead>(io: T) { |
117 | | -//! length_delimited::Builder::new() |
118 | | -//! .length_field_offset(0) // default value |
119 | | -//! .length_field_length(2) |
120 | | -//! .length_adjustment(0) // default value |
121 | | -//! // `num_skip` is not needed, the default is to skip |
122 | | -//! .new_read(io); |
123 | | -//! # } |
124 | | -//! ``` |
125 | | -//! |
126 | | -//! The following frame will be decoded as such: |
127 | | -//! |
128 | | -//! ```text |
129 | | -//! INPUT DECODED |
130 | | -//! +-- len ---+--- Payload ---+ +--- Payload ---+ |
131 | | -//! | \x00\x0B | Hello world | --> | Hello world | |
132 | | -//! +----------+---------------+ +---------------+ |
133 | | -//! ``` |
134 | | -//! |
135 | | -//! This is similar to the first example, the only difference is that the |
136 | | -//! frame head is **not** included in the yielded `BytesMut` value. |
137 | | -//! |
138 | | -//! ## Example 3 |
139 | | -//! |
140 | | -//! The following will parse a `u16` length field at offset 0, including the |
141 | | -//! frame head in the yielded `BytesMut`. In this case, the length field |
142 | | -//! **includes** the frame head length. |
143 | | -//! |
144 | | -//! ``` |
145 | | -//! # use tokio_io::AsyncRead; |
146 | | -//! # use tokio_io::codec::length_delimited; |
147 | | -//! # fn bind_read<T: AsyncRead>(io: T) { |
148 | | -//! length_delimited::Builder::new() |
149 | | -//! .length_field_offset(0) // default value |
150 | | -//! .length_field_length(2) |
151 | | -//! .length_adjustment(-2) // size of head |
152 | | -//! .num_skip(0) |
153 | | -//! .new_read(io); |
154 | | -//! # } |
155 | | -//! ``` |
156 | | -//! |
157 | | -//! The following frame will be decoded as such: |
158 | | -//! |
159 | | -//! ```text |
160 | | -//! INPUT DECODED |
161 | | -//! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ |
162 | | -//! | \x00\x0D | Hello world | --> | \x00\x0D | Hello world | |
163 | | -//! +----------+---------------+ +----------+---------------+ |
164 | | -//! ``` |
165 | | -//! |
166 | | -//! In most cases, the length field represents the length of the payload |
167 | | -//! only, as shown in the previous examples. However, in some protocols the |
168 | | -//! length field represents the length of the whole frame, including the |
169 | | -//! head. In such cases, we specify a negative `length_adjustment` to adjust |
170 | | -//! the value provided in the frame head to represent the payload length. |
171 | | -//! |
172 | | -//! ## Example 4 |
173 | | -//! |
174 | | -//! The following will parse a 3 byte length field at offset 0 in a 5 byte |
175 | | -//! frame head, including the frame head in the yielded `BytesMut`. |
176 | | -//! |
177 | | -//! ``` |
178 | | -//! # use tokio_io::AsyncRead; |
179 | | -//! # use tokio_io::codec::length_delimited; |
180 | | -//! # fn bind_read<T: AsyncRead>(io: T) { |
181 | | -//! length_delimited::Builder::new() |
182 | | -//! .length_field_offset(0) // default value |
183 | | -//! .length_field_length(3) |
184 | | -//! .length_adjustment(2) // remaining head |
185 | | -//! .num_skip(0) |
186 | | -//! .new_read(io); |
187 | | -//! # } |
188 | | -//! ``` |
189 | | -//! |
190 | | -//! The following frame will be decoded as such: |
191 | | -//! |
192 | | -//! ```text |
193 | | -//! INPUT |
194 | | -//! +---- len -----+- head -+--- Payload ---+ |
195 | | -//! | \x00\x00\x0B | \xCAFE | Hello world | |
196 | | -//! +--------------+--------+---------------+ |
197 | | -//! |
198 | | -//! DECODED |
199 | | -//! +---- len -----+- head -+--- Payload ---+ |
200 | | -//! | \x00\x00\x0B | \xCAFE | Hello world | |
201 | | -//! +--------------+--------+---------------+ |
202 | | -//! ``` |
203 | | -//! |
204 | | -//! A more advanced example that shows a case where there is extra frame |
205 | | -//! head data between the length field and the payload. In such cases, it is |
206 | | -//! usually desirable to include the frame head as part of the yielded |
207 | | -//! `BytesMut`. This lets consumers of the length delimited framer to |
208 | | -//! process the frame head as needed. |
209 | | -//! |
210 | | -//! The positive `length_adjustment` value lets `FramedRead` factor in the |
211 | | -//! additional head into the frame length calculation. |
212 | | -//! |
213 | | -//! ## Example 5 |
214 | | -//! |
215 | | -//! The following will parse a `u16` length field at offset 1 of a 4 byte |
216 | | -//! frame head. The first byte and the length field will be omitted from the |
217 | | -//! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be |
218 | | -//! included. |
219 | | -//! |
220 | | -//! ``` |
221 | | -//! # use tokio_io::AsyncRead; |
222 | | -//! # use tokio_io::codec::length_delimited; |
223 | | -//! # fn bind_read<T: AsyncRead>(io: T) { |
224 | | -//! length_delimited::Builder::new() |
225 | | -//! .length_field_offset(1) // length of hdr1 |
226 | | -//! .length_field_length(2) |
227 | | -//! .length_adjustment(1) // length of hdr2 |
228 | | -//! .num_skip(3) // length of hdr1 + LEN |
229 | | -//! .new_read(io); |
230 | | -//! # } |
231 | | -//! ``` |
232 | | -//! |
233 | | -//! The following frame will be decoded as such: |
234 | | -//! |
235 | | -//! ```text |
236 | | -//! INPUT |
237 | | -//! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+ |
238 | | -//! | \xCA | \x00\x0B | \xFE | Hello world | |
239 | | -//! +--------+----------+--------+---------------+ |
240 | | -//! |
241 | | -//! DECODED |
242 | | -//! +- hdr2 -+--- Payload ---+ |
243 | | -//! | \xFE | Hello world | |
244 | | -//! +--------+---------------+ |
245 | | -//! ``` |
246 | | -//! |
247 | | -//! The length field is situated in the middle of the frame head. In this |
248 | | -//! case, the first byte in the frame head could be a version or some other |
249 | | -//! identifier that is not needed for processing. On the other hand, the |
250 | | -//! second half of the head is needed. |
251 | | -//! |
252 | | -//! `length_field_offset` indicates how many bytes to skip before starting |
253 | | -//! to read the length field. `length_adjustment` is the number of bytes to |
254 | | -//! skip starting at the end of the length field. In this case, it is the |
255 | | -//! second half of the head. |
256 | | -//! |
257 | | -//! ## Example 6 |
258 | | -//! |
259 | | -//! The following will parse a `u16` length field at offset 1 of a 4 byte |
260 | | -//! frame head. The first byte and the length field will be omitted from the |
261 | | -//! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be |
262 | | -//! included. In this case, the length field **includes** the frame head |
263 | | -//! length. |
264 | | -//! |
265 | | -//! ``` |
266 | | -//! # use tokio_io::AsyncRead; |
267 | | -//! # use tokio_io::codec::length_delimited; |
268 | | -//! # fn bind_read<T: AsyncRead>(io: T) { |
269 | | -//! length_delimited::Builder::new() |
270 | | -//! .length_field_offset(1) // length of hdr1 |
271 | | -//! .length_field_length(2) |
272 | | -//! .length_adjustment(-3) // length of hdr1 + LEN, negative |
273 | | -//! .num_skip(3) |
274 | | -//! .new_read(io); |
275 | | -//! # } |
276 | | -//! ``` |
277 | | -//! |
278 | | -//! The following frame will be decoded as such: |
279 | | -//! |
280 | | -//! ```text |
281 | | -//! INPUT |
282 | | -//! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+ |
283 | | -//! | \xCA | \x00\x0F | \xFE | Hello world | |
284 | | -//! +--------+----------+--------+---------------+ |
285 | | -//! |
286 | | -//! DECODED |
287 | | -//! +- hdr2 -+--- Payload ---+ |
288 | | -//! | \xFE | Hello world | |
289 | | -//! +--------+---------------+ |
290 | | -//! ``` |
291 | | -//! |
292 | | -//! Similar to the example above, the difference is that the length field |
293 | | -//! represents the length of the entire frame instead of just the payload. |
294 | | -//! The length of `hdr1` and `len` must be counted in `length_adjustment`. |
295 | | -//! Note that the length of `hdr2` does **not** need to be explicitly set |
296 | | -//! anywhere because it already is factored into the total frame length that |
297 | | -//! is read from the byte stream. |
298 | | -//! |
299 | | -//! # Encoding |
300 | | -//! |
301 | | -//! [`FramedWrite`] adapts an [`AsyncWrite`] into a `Sink` of [`BytesMut`], |
302 | | -//! such that each submitted [`BytesMut`] is prefaced by a length field. |
303 | | -//! There are fewer configuration options than [`FramedRead`]. Given |
304 | | -//! protocols that have more complex frame heads, an encoder should probably |
305 | | -//! be written by hand using [`Encoder`]. |
306 | | -//! |
307 | | -//! Here is a simple example, given a `FramedWrite` with the following |
308 | | -//! configuration: |
309 | | -//! |
310 | | -//! ``` |
311 | | -//! # extern crate tokio_io; |
312 | | -//! # extern crate bytes; |
313 | | -//! # use tokio_io::AsyncWrite; |
314 | | -//! # use tokio_io::codec::length_delimited; |
315 | | -//! # use bytes::BytesMut; |
316 | | -//! # fn write_frame<T: AsyncWrite>(io: T) { |
317 | | -//! # let _: length_delimited::FramedWrite<T, BytesMut> = |
318 | | -//! length_delimited::Builder::new() |
319 | | -//! .length_field_length(2) |
320 | | -//! .new_write(io); |
321 | | -//! # } |
322 | | -//! # pub fn main() {} |
323 | | -//! ``` |
324 | | -//! |
325 | | -//! A payload of `hello world` will be encoded as: |
326 | | -//! |
327 | | -//! ```text |
328 | | -//! +- len: u16 -+---- data ----+ |
329 | | -//! | \x00\x0b | hello world | |
330 | | -//! +------------+--------------+ |
331 | | -//! ``` |
332 | | -//! |
333 | | -//! [`FramedRead`]: struct.FramedRead.html |
334 | | -//! [`FramedWrite`]: struct.FramedWrite.html |
335 | | -//! [`AsyncRead`]: ../../trait.AsyncRead.html |
336 | | -//! [`AsyncWrite`]: ../../trait.AsyncWrite.html |
337 | | -//! [`Encoder`]: ../trait.Encoder.html |
338 | | -//! [`BytesMut`]: https://docs.rs/bytes/0.4/bytes/struct.BytesMut.html |
339 | 1 | #![allow(deprecated)] |
340 | 2 |
|
341 | 3 | use tokio_io::{codec, AsyncRead, AsyncWrite}; |
|
0 commit comments