1
+ use std:: collections:: HashMap ;
1
2
use std:: fmt;
2
3
use std:: io:: IoSlice ;
3
4
4
5
use bytes:: buf:: { Chain , Take } ;
5
- use bytes:: Buf ;
6
+ use bytes:: { Buf , Bytes } ;
7
+ use http:: {
8
+ header:: {
9
+ AUTHORIZATION , CACHE_CONTROL , CONTENT_ENCODING , CONTENT_LENGTH , CONTENT_RANGE ,
10
+ CONTENT_TYPE , HOST , MAX_FORWARDS , SET_COOKIE , TRAILER , TRANSFER_ENCODING ,
11
+ } ,
12
+ HeaderMap , HeaderName , HeaderValue ,
13
+ } ;
6
14
7
15
use super :: io:: WriteBuf ;
16
+ use super :: role:: { write_headers, write_headers_title_case} ;
8
17
9
18
type StaticBuf = & ' static [ u8 ] ;
10
19
@@ -26,7 +35,7 @@ pub(crate) struct NotEof(u64);
26
35
#[ derive( Debug , PartialEq , Clone ) ]
27
36
enum Kind {
28
37
/// An Encoder for when Transfer-Encoding includes `chunked`.
29
- Chunked ,
38
+ Chunked ( Option < Vec < HeaderValue > > ) ,
30
39
/// An Encoder for when Content-Length is set.
31
40
///
32
41
/// Enforces that the body is not longer than the Content-Length header.
@@ -45,6 +54,7 @@ enum BufKind<B> {
45
54
Limited ( Take < B > ) ,
46
55
Chunked ( Chain < Chain < ChunkSize , B > , StaticBuf > ) ,
47
56
ChunkedEnd ( StaticBuf ) ,
57
+ Trailers ( Chain < Chain < StaticBuf , Bytes > , StaticBuf > ) ,
48
58
}
49
59
50
60
impl Encoder {
@@ -55,7 +65,7 @@ impl Encoder {
55
65
}
56
66
}
57
67
pub ( crate ) fn chunked ( ) -> Encoder {
58
- Encoder :: new ( Kind :: Chunked )
68
+ Encoder :: new ( Kind :: Chunked ( None ) )
59
69
}
60
70
61
71
pub ( crate ) fn length ( len : u64 ) -> Encoder {
@@ -67,6 +77,16 @@ impl Encoder {
67
77
Encoder :: new ( Kind :: CloseDelimited )
68
78
}
69
79
80
+ pub ( crate ) fn into_chunked_with_trailing_fields ( self , trailers : Vec < HeaderValue > ) -> Encoder {
81
+ match self . kind {
82
+ Kind :: Chunked ( _) => Encoder {
83
+ kind : Kind :: Chunked ( Some ( trailers) ) ,
84
+ is_last : self . is_last ,
85
+ } ,
86
+ _ => self ,
87
+ }
88
+ }
89
+
70
90
pub ( crate ) fn is_eof ( & self ) -> bool {
71
91
matches ! ( self . kind, Kind :: Length ( 0 ) )
72
92
}
@@ -89,10 +109,17 @@ impl Encoder {
89
109
}
90
110
}
91
111
112
+ pub ( crate ) fn is_chunked ( & self ) -> bool {
113
+ match self . kind {
114
+ Kind :: Chunked ( _) => true ,
115
+ _ => false ,
116
+ }
117
+ }
118
+
92
119
pub ( crate ) fn end < B > ( & self ) -> Result < Option < EncodedBuf < B > > , NotEof > {
93
120
match self . kind {
94
121
Kind :: Length ( 0 ) => Ok ( None ) ,
95
- Kind :: Chunked => Ok ( Some ( EncodedBuf {
122
+ Kind :: Chunked ( _ ) => Ok ( Some ( EncodedBuf {
96
123
kind : BufKind :: ChunkedEnd ( b"0\r \n \r \n " ) ,
97
124
} ) ) ,
98
125
#[ cfg( feature = "server" ) ]
@@ -109,7 +136,7 @@ impl Encoder {
109
136
debug_assert ! ( len > 0 , "encode() called with empty buf" ) ;
110
137
111
138
let kind = match self . kind {
112
- Kind :: Chunked => {
139
+ Kind :: Chunked ( _ ) => {
113
140
trace ! ( "encoding chunked {}B" , len) ;
114
141
let buf = ChunkSize :: new ( len)
115
142
. chain ( msg)
@@ -136,6 +163,54 @@ impl Encoder {
136
163
EncodedBuf { kind }
137
164
}
138
165
166
+ pub ( crate ) fn encode_trailers < B > (
167
+ & self ,
168
+ mut trailers : HeaderMap ,
169
+ title_case_headers : bool ,
170
+ ) -> Option < EncodedBuf < B > > {
171
+ match & self . kind {
172
+ Kind :: Chunked ( allowed_trailer_fields) => {
173
+ let allowed_trailer_fields_map = match allowed_trailer_fields {
174
+ Some ( ref allowed_trailer_fields) => {
175
+ allowed_trailer_field_map ( & allowed_trailer_fields)
176
+ }
177
+ None => return None ,
178
+ } ;
179
+
180
+ let mut cur_name = None ;
181
+ let mut allowed_trailers = HeaderMap :: new ( ) ;
182
+
183
+ for ( opt_name, value) in trailers. drain ( ) {
184
+ if let Some ( n) = opt_name {
185
+ cur_name = Some ( n) ;
186
+ }
187
+ let name = cur_name. as_ref ( ) . expect ( "current header name" ) ;
188
+
189
+ if allowed_trailer_fields_map. contains_key ( name. as_str ( ) )
190
+ && !invalid_trailer_field ( name)
191
+ {
192
+ allowed_trailers. insert ( name, value) ;
193
+ }
194
+ }
195
+
196
+ let mut buf = Vec :: new ( ) ;
197
+ if title_case_headers {
198
+ write_headers_title_case ( & allowed_trailers, & mut buf) ;
199
+ } else {
200
+ write_headers ( & allowed_trailers, & mut buf) ;
201
+ }
202
+
203
+ Some ( EncodedBuf {
204
+ kind : BufKind :: Trailers ( b"0\r \n " . chain ( Bytes :: from ( buf) ) . chain ( b"\r \n " ) ) ,
205
+ } )
206
+ }
207
+ _ => {
208
+ debug ! ( "attempted to encode trailers for non-chunked response" ) ;
209
+ None
210
+ }
211
+ }
212
+ }
213
+
139
214
pub ( super ) fn encode_and_end < B > ( & self , msg : B , dst : & mut WriteBuf < EncodedBuf < B > > ) -> bool
140
215
where
141
216
B : Buf ,
@@ -144,7 +219,7 @@ impl Encoder {
144
219
debug_assert ! ( len > 0 , "encode() called with empty buf" ) ;
145
220
146
221
match self . kind {
147
- Kind :: Chunked => {
222
+ Kind :: Chunked ( _ ) => {
148
223
trace ! ( "encoding chunked {}B" , len) ;
149
224
let buf = ChunkSize :: new ( len)
150
225
. chain ( msg)
@@ -181,6 +256,39 @@ impl Encoder {
181
256
}
182
257
}
183
258
259
+ fn invalid_trailer_field ( name : & HeaderName ) -> bool {
260
+ match name {
261
+ & AUTHORIZATION => true ,
262
+ & CACHE_CONTROL => true ,
263
+ & CONTENT_ENCODING => true ,
264
+ & CONTENT_LENGTH => true ,
265
+ & CONTENT_RANGE => true ,
266
+ & CONTENT_TYPE => true ,
267
+ & HOST => true ,
268
+ & MAX_FORWARDS => true ,
269
+ & SET_COOKIE => true ,
270
+ & TRAILER => true ,
271
+ & TRANSFER_ENCODING => true ,
272
+ _ => false ,
273
+ }
274
+ }
275
+
276
+ fn allowed_trailer_field_map ( allowed_trailer_fields : & Vec < HeaderValue > ) -> HashMap < String , ( ) > {
277
+ let mut trailer_map = HashMap :: new ( ) ;
278
+
279
+ for header_value in allowed_trailer_fields {
280
+ if let Ok ( header_str) = header_value. to_str ( ) {
281
+ let items: Vec < & str > = header_str. split ( ',' ) . map ( |item| item. trim ( ) ) . collect ( ) ;
282
+
283
+ for item in items {
284
+ trailer_map. entry ( item. to_string ( ) ) . or_insert ( ( ) ) ;
285
+ }
286
+ }
287
+ }
288
+
289
+ trailer_map
290
+ }
291
+
184
292
impl < B > Buf for EncodedBuf < B >
185
293
where
186
294
B : Buf ,
@@ -192,6 +300,7 @@ where
192
300
BufKind :: Limited ( ref b) => b. remaining ( ) ,
193
301
BufKind :: Chunked ( ref b) => b. remaining ( ) ,
194
302
BufKind :: ChunkedEnd ( ref b) => b. remaining ( ) ,
303
+ BufKind :: Trailers ( ref b) => b. remaining ( ) ,
195
304
}
196
305
}
197
306
@@ -202,6 +311,7 @@ where
202
311
BufKind :: Limited ( ref b) => b. chunk ( ) ,
203
312
BufKind :: Chunked ( ref b) => b. chunk ( ) ,
204
313
BufKind :: ChunkedEnd ( ref b) => b. chunk ( ) ,
314
+ BufKind :: Trailers ( ref b) => b. chunk ( ) ,
205
315
}
206
316
}
207
317
@@ -212,6 +322,7 @@ where
212
322
BufKind :: Limited ( ref mut b) => b. advance ( cnt) ,
213
323
BufKind :: Chunked ( ref mut b) => b. advance ( cnt) ,
214
324
BufKind :: ChunkedEnd ( ref mut b) => b. advance ( cnt) ,
325
+ BufKind :: Trailers ( ref mut b) => b. advance ( cnt) ,
215
326
}
216
327
}
217
328
@@ -222,6 +333,7 @@ where
222
333
BufKind :: Limited ( ref b) => b. chunks_vectored ( dst) ,
223
334
BufKind :: Chunked ( ref b) => b. chunks_vectored ( dst) ,
224
335
BufKind :: ChunkedEnd ( ref b) => b. chunks_vectored ( dst) ,
336
+ BufKind :: Trailers ( ref b) => b. chunks_vectored ( dst) ,
225
337
}
226
338
}
227
339
}
0 commit comments