@@ -196,6 +196,25 @@ impl Encoder {
196
196
}
197
197
}
198
198
199
+ /// Encode an AsyncBufRead using "chunked" framing. This is used for streams
200
+ /// whose length is not known up front.
201
+ ///
202
+ /// # Format
203
+ ///
204
+ /// Each "chunk" uses the following encoding:
205
+ ///
206
+ /// ```txt
207
+ /// 1. {byte length of `data` as hex}\r\n
208
+ /// 2. {data}\r\n
209
+ /// ```
210
+ ///
211
+ /// A chunk stream is finalized by appending the following:
212
+ ///
213
+ /// ```txt
214
+ /// 1. 0\r\n
215
+ /// 2. {trailing header}\r\n (can be repeated)
216
+ /// 3. \r\n
217
+ /// ```
199
218
fn encode_chunked_body (
200
219
& mut self ,
201
220
cx : & mut Context < ' _ > ,
@@ -230,13 +249,15 @@ impl Encoder {
230
249
return Poll :: Ready ( Ok ( self . bytes_read ) ) ;
231
250
}
232
251
233
- // Each chunk is prefixed with the length, then a CRLF , then the
234
- // content, then another CRLF. Ensure we leave enough space in the
235
- // buffer to read all that .
252
+ // Each chunk is prefixed with the length of the data in hex , then a
253
+ // CRLF, then the content, then another CRLF. Calculate how many bytes
254
+ // each part should be .
236
255
let buf_len = buf. len ( ) . checked_sub ( self . bytes_read ) . unwrap_or ( 0 ) ;
237
256
let amt = src. len ( ) . min ( buf_len) ;
238
- let len_prefix = format ! ( "{:X}" , amt) . into_bytes ( ) ;
239
- let buf_upper = buf_len. checked_sub ( len_prefix. len ( ) + 4 ) . unwrap_or ( 0 ) ;
257
+ // Calculate the max char count encoding the `len_prefix` statement
258
+ // as hex would take. This is done by rounding up `log16(amt)`.
259
+ let hex_len = ( amt as f64 ) . log ( 16.0 ) . ceil ( ) as usize ;
260
+ let buf_upper = buf_len. checked_sub ( hex_len + 4 ) . unwrap_or ( 0 ) ;
240
261
let amt = amt. min ( buf_upper) ;
241
262
let len_prefix = format ! ( "{:X}" , amt) . into_bytes ( ) ;
242
263
0 commit comments