@@ -4,14 +4,12 @@ use std::pin::Pin;
4
4
5
5
use async_std:: io;
6
6
use async_std:: io:: prelude:: * ;
7
- use async_std:: task:: { Context , Poll } ;
7
+ use async_std:: task:: { ready , Context , Poll } ;
8
8
use http_types:: Response ;
9
9
10
+ use crate :: chunked:: ChunkedEncoder ;
10
11
use crate :: date:: fmt_http_date;
11
12
12
- const CR : u8 = b'\r' ;
13
- const LF : u8 = b'\n' ;
14
-
15
13
/// A streaming HTTP encoder.
16
14
///
17
15
/// This is returned from [`encode`].
@@ -33,6 +31,8 @@ pub(crate) struct Encoder {
33
31
/// The amount of bytes read from the body.
34
32
/// This is only used in the known-length body encoder.
35
33
body_bytes_read : usize ,
34
+ /// An encoder for chunked encoding.
35
+ chunked : ChunkedEncoder ,
36
36
}
37
37
38
38
#[ derive( Debug ) ]
@@ -55,6 +55,7 @@ impl Encoder {
55
55
head_bytes_read : 0 ,
56
56
body_len : 0 ,
57
57
body_bytes_read : 0 ,
58
+ chunked : ChunkedEncoder :: new ( ) ,
58
59
}
59
60
}
60
61
}
@@ -190,93 +191,19 @@ impl Encoder {
190
191
191
192
/// Encode an AsyncBufRead using "chunked" framing. This is used for streams
192
193
/// whose length is not known up front.
193
- ///
194
- /// # Format
195
- ///
196
- /// Each "chunk" uses the following encoding:
197
- ///
198
- /// ```txt
199
- /// 1. {byte length of `data` as hex}\r\n
200
- /// 2. {data}\r\n
201
- /// ```
202
- ///
203
- /// A chunk stream is finalized by appending the following:
204
- ///
205
- /// ```txt
206
- /// 1. 0\r\n
207
- /// 2. {trailing header}\r\n (can be repeated)
208
- /// 3. \r\n
209
- /// ```
210
194
fn encode_chunked_body (
211
195
& mut self ,
212
196
cx : & mut Context < ' _ > ,
213
197
buf : & mut [ u8 ] ,
214
198
) -> Poll < io:: Result < usize > > {
215
- // Get bytes from the underlying stream. If the stream is not ready yet,
216
- // return the header bytes if we have any.
217
- let src = match Pin :: new ( & mut self . res ) . poll_fill_buf ( cx) {
218
- Poll :: Ready ( Ok ( n) ) => n,
219
- Poll :: Ready ( Err ( e) ) => return Poll :: Ready ( Err ( e) ) ,
220
- Poll :: Pending => match self . bytes_read {
221
- 0 => return Poll :: Pending ,
222
- n => return Poll :: Ready ( Ok ( n) ) ,
223
- } ,
224
- } ;
199
+ let buf = & mut buf[ self . bytes_read ..] ;
200
+ let read = ready ! ( self . chunked. encode( & mut self . res, cx, buf) ) ?;
225
201
226
- // If the stream doesn't have any more bytes left to read we're done.
227
- if src. len ( ) == 0 {
228
- // Write out the final empty chunk
229
- let idx = self . bytes_read ;
230
- buf[ idx] = b'0' ;
231
- buf[ idx + 1 ] = CR ;
232
- buf[ idx + 2 ] = LF ;
233
-
234
- // Write the final CRLF
235
- buf[ idx + 3 ] = CR ;
236
- buf[ idx + 4 ] = LF ;
237
- self . bytes_read += 5 ;
238
-
239
- log:: trace!( "done sending bytes" ) ;
240
- self . state = EncoderState :: Done ;
241
- return Poll :: Ready ( Ok ( self . bytes_read ) ) ;
202
+ self . bytes_read += read;
203
+ if self . bytes_read == 0 {
204
+ self . state = EncoderState :: Done
242
205
}
243
206
244
- // Each chunk is prefixed with the length of the data in hex, then a
245
- // CRLF, then the content, then another CRLF. Calculate how many bytes
246
- // each part should be.
247
- let buf_len = buf. len ( ) . checked_sub ( self . bytes_read ) . unwrap_or ( 0 ) ;
248
- let amt = src. len ( ) . min ( buf_len) ;
249
- // Calculate the max char count encoding the `len_prefix` statement
250
- // as hex would take. This is done by rounding up `log16(amt + 1)`.
251
- let hex_len = ( ( amt + 1 ) as f64 ) . log ( 16.0 ) . ceil ( ) as usize ;
252
- let crlf_len = 2 * 2 ;
253
- let buf_upper = buf_len. checked_sub ( hex_len + crlf_len) . unwrap_or ( 0 ) ;
254
- let amt = amt. min ( buf_upper) ;
255
- let len_prefix = format ! ( "{:X}" , amt) . into_bytes ( ) ;
256
-
257
- // Write our frame header to the buffer.
258
- let lower = self . bytes_read ;
259
- let upper = self . bytes_read + len_prefix. len ( ) ;
260
- buf[ lower..upper] . copy_from_slice ( & len_prefix) ;
261
- buf[ upper] = CR ;
262
- buf[ upper + 1 ] = LF ;
263
- self . bytes_read += len_prefix. len ( ) + 2 ;
264
-
265
- // Copy the bytes from our source into the output buffer.
266
- let lower = self . bytes_read ;
267
- let upper = self . bytes_read + amt;
268
- buf[ lower..upper] . copy_from_slice ( & src[ 0 ..amt] ) ;
269
- Pin :: new ( & mut self . res ) . consume ( amt) ;
270
- self . bytes_read += amt;
271
-
272
- // Finalize the chunk with a final CRLF.
273
- let idx = self . bytes_read ;
274
- buf[ idx] = CR ;
275
- buf[ idx + 1 ] = LF ;
276
- self . bytes_read += 2 ;
277
-
278
- // Finally return how many bytes we've written to the buffer.
279
- log:: trace!( "sending {} bytes" , self . bytes_read) ;
280
207
Poll :: Ready ( Ok ( self . bytes_read ) )
281
208
}
282
209
}
0 commit comments