@@ -18,7 +18,7 @@ pub(crate) struct Encoder {
18
18
/// HTTP headers to be sent.
19
19
res : Response ,
20
20
/// The state of the encoding process
21
- state : EncoderState ,
21
+ state : State ,
22
22
/// Track bytes read in a call to poll_read.
23
23
bytes_read : usize ,
24
24
/// The data we're writing as part of the head section.
@@ -36,20 +36,21 @@ pub(crate) struct Encoder {
36
36
}
37
37
38
38
#[ derive( Debug ) ]
39
- enum EncoderState {
40
- Start ,
41
- Head ,
39
+ enum State {
40
+ Init ,
41
+ ComputeHead ,
42
+ EncodeHead ,
42
43
FixedBody ,
43
44
ChunkedBody ,
44
- Done ,
45
+ End ,
45
46
}
46
47
47
48
impl Encoder {
48
- /// Create a new instance.
49
- pub ( crate ) fn encode ( res : Response ) -> Self {
49
+ /// Create a new instance of Encoder .
50
+ pub ( crate ) fn new ( res : Response ) -> Self {
50
51
Self {
51
52
res,
52
- state : EncoderState :: Start ,
53
+ state : State :: Init ,
53
54
bytes_read : 0 ,
54
55
head : vec ! [ ] ,
55
56
head_bytes_read : 0 ,
@@ -58,14 +59,51 @@ impl Encoder {
58
59
chunked : ChunkedEncoder :: new ( ) ,
59
60
}
60
61
}
61
- }
62
62
63
- impl Encoder {
64
- // Encode the headers to a buffer, the first time we poll.
65
- fn encode_start ( & mut self , cx : & mut Context < ' _ > , buf : & mut [ u8 ] ) -> Poll < io:: Result < usize > > {
66
- log:: trace!( "Server response encoding: start" ) ;
67
- self . state = EncoderState :: Head ;
63
+ pub ( crate ) fn encode (
64
+ & mut self ,
65
+ cx : & mut Context < ' _ > ,
66
+ buf : & mut [ u8 ] ,
67
+ ) -> Poll < io:: Result < usize > > {
68
+ self . bytes_read = 0 ;
69
+ let res = match self . state {
70
+ State :: Init => self . init ( cx, buf) ,
71
+ State :: ComputeHead => self . compute_head ( cx, buf) ,
72
+ State :: EncodeHead => self . encode_head ( cx, buf) ,
73
+ State :: FixedBody => self . encode_fixed_body ( cx, buf) ,
74
+ State :: ChunkedBody => self . encode_chunked_body ( cx, buf) ,
75
+ State :: End => Poll :: Ready ( Ok ( self . bytes_read ) ) ,
76
+ } ;
77
+ log:: trace!( "ServerEncoder {} bytes written" , self . bytes_read) ;
78
+ res
79
+ }
80
+
81
+ /// Switch the internal state to a new state.
82
+ fn set_state ( & mut self , state : State ) {
83
+ use State :: * ;
84
+ log:: trace!( "Server Encoder state: {:?} -> {:?}" , self . state, state) ;
68
85
86
+ #[ cfg( debug_assertions) ]
87
+ match self . state {
88
+ Init => assert ! ( matches!( state, ComputeHead ) ) ,
89
+ ComputeHead => assert ! ( matches!( state, EncodeHead ) ) ,
90
+ EncodeHead => assert ! ( matches!( state, ChunkedBody | FixedBody ) ) ,
91
+ FixedBody => assert ! ( matches!( state, End ) ) ,
92
+ ChunkedBody => assert ! ( matches!( state, End ) ) ,
93
+ End => panic ! ( "No state transitions allowed after the stream has ended" ) ,
94
+ }
95
+
96
+ self . state = state;
97
+ }
98
+
99
+ /// Initialize to the first state.
100
+ fn init ( & mut self , cx : & mut Context < ' _ > , buf : & mut [ u8 ] ) -> Poll < io:: Result < usize > > {
101
+ self . set_state ( State :: ComputeHead ) ;
102
+ self . compute_head ( cx, buf)
103
+ }
104
+
105
+ /// Encode the headers to a buffer, the first time we poll.
106
+ fn compute_head ( & mut self , cx : & mut Context < ' _ > , buf : & mut [ u8 ] ) -> Poll < io:: Result < usize > > {
69
107
let reason = self . res . status ( ) . canonical_reason ( ) ;
70
108
let status = self . res . status ( ) ;
71
109
std:: io:: Write :: write_fmt (
@@ -97,6 +135,8 @@ impl Encoder {
97
135
}
98
136
99
137
std:: io:: Write :: write_fmt ( & mut self . head , format_args ! ( "\r \n " ) ) ?;
138
+
139
+ self . set_state ( State :: EncodeHead ) ;
100
140
self . encode_head ( cx, buf)
101
141
}
102
142
@@ -118,12 +158,12 @@ impl Encoder {
118
158
match self . res . len ( ) {
119
159
Some ( body_len) => {
120
160
self . body_len = body_len;
121
- self . state = EncoderState :: FixedBody ;
161
+ self . state = State :: FixedBody ;
122
162
log:: trace!( "Server response encoding: fixed length body" ) ;
123
163
return self . encode_fixed_body ( cx, buf) ;
124
164
}
125
165
None => {
126
- self . state = EncoderState :: ChunkedBody ;
166
+ self . state = State :: ChunkedBody ;
127
167
log:: trace!( "Server response encoding: chunked body" ) ;
128
168
return self . encode_chunked_body ( cx, buf) ;
129
169
}
@@ -177,12 +217,12 @@ impl Encoder {
177
217
178
218
if self . body_len == self . body_bytes_read {
179
219
// If we've read the `len` number of bytes, end
180
- self . state = EncoderState :: Done ;
220
+ self . set_state ( State :: End ) ;
181
221
return Poll :: Ready ( Ok ( self . bytes_read ) ) ;
182
222
} else if new_body_bytes_read == 0 {
183
223
// If we've reached unexpected EOF, end anyway
184
224
// TODO: do something?
185
- self . state = EncoderState :: Done ;
225
+ self . set_state ( State :: End ) ;
186
226
return Poll :: Ready ( Ok ( self . bytes_read ) ) ;
187
227
} else {
188
228
self . encode_fixed_body ( cx, buf)
@@ -201,7 +241,7 @@ impl Encoder {
201
241
Poll :: Ready ( Ok ( read) ) => {
202
242
self . bytes_read += read;
203
243
if self . bytes_read == 0 {
204
- self . state = EncoderState :: Done
244
+ self . set_state ( State :: End ) ;
205
245
}
206
246
Poll :: Ready ( Ok ( self . bytes_read ) )
207
247
}
@@ -222,17 +262,6 @@ impl Read for Encoder {
222
262
cx : & mut Context < ' _ > ,
223
263
buf : & mut [ u8 ] ,
224
264
) -> Poll < io:: Result < usize > > {
225
- // we keep track how many bytes of the head and body we've read
226
- // in this call of `poll_read`
227
- self . bytes_read = 0 ;
228
- let res = match self . state {
229
- EncoderState :: Start => self . encode_start ( cx, buf) ,
230
- EncoderState :: Head => self . encode_head ( cx, buf) ,
231
- EncoderState :: FixedBody => self . encode_fixed_body ( cx, buf) ,
232
- EncoderState :: ChunkedBody => self . encode_chunked_body ( cx, buf) ,
233
- EncoderState :: Done => Poll :: Ready ( Ok ( 0 ) ) ,
234
- } ;
235
- // dbg!(String::from_utf8(buf[..self.bytes_read].to_vec()).unwrap());
236
- res
265
+ self . encode ( cx, buf)
237
266
}
238
267
}
0 commit comments