@@ -23,15 +23,16 @@ pub(crate) struct Encoder {
23
23
state : EncoderState ,
24
24
/// Track bytes read in a call to poll_read.
25
25
bytes_read : usize ,
26
+ /// The data we're writing as part of the head section.
27
+ head : Vec < u8 > ,
28
+ /// The amount of bytes read from the head section.
29
+ head_bytes_read : usize ,
26
30
}
27
31
28
32
#[ derive( Debug ) ]
29
33
enum EncoderState {
30
34
Start ,
31
- Head {
32
- data : Vec < u8 > ,
33
- head_bytes_read : usize ,
34
- } ,
35
+ Head ,
35
36
Body {
36
37
body_bytes_read : usize ,
37
38
body_len : usize ,
@@ -51,39 +52,79 @@ impl Encoder {
51
52
res,
52
53
state : EncoderState :: Start ,
53
54
bytes_read : 0 ,
55
+ head : vec ! [ ] ,
56
+ head_bytes_read : 0 ,
54
57
}
55
58
}
59
+ }
56
60
57
- fn encode_head ( & self ) -> io:: Result < Vec < u8 > > {
58
- let mut head: Vec < u8 > = vec ! [ ] ;
61
+ impl Encoder {
62
+ // Encode the headers to a buffer, the first time we poll.
63
+ fn encode_start ( & mut self ) -> io:: Result < ( ) > {
64
+ self . state = EncoderState :: Head ;
59
65
60
66
let reason = self . res . status ( ) . canonical_reason ( ) ;
61
67
let status = self . res . status ( ) ;
62
68
std:: io:: Write :: write_fmt (
63
- & mut head,
69
+ & mut self . head ,
64
70
format_args ! ( "HTTP/1.1 {} {}\r \n " , status, reason) ,
65
71
) ?;
66
72
67
73
// If the body isn't streaming, we can set the content-length ahead of time. Else we need to
68
74
// send all items in chunks.
69
75
if let Some ( len) = self . res . len ( ) {
70
- std:: io:: Write :: write_fmt ( & mut head, format_args ! ( "content-length: {}\r \n " , len) ) ?;
76
+ std:: io:: Write :: write_fmt ( & mut self . head , format_args ! ( "content-length: {}\r \n " , len) ) ?;
71
77
} else {
72
- std:: io:: Write :: write_fmt ( & mut head, format_args ! ( "transfer-encoding: chunked\r \n " ) ) ?;
78
+ std:: io:: Write :: write_fmt (
79
+ & mut self . head ,
80
+ format_args ! ( "transfer-encoding: chunked\r \n " ) ,
81
+ ) ?;
73
82
}
74
83
75
84
let date = fmt_http_date ( std:: time:: SystemTime :: now ( ) ) ;
76
- std:: io:: Write :: write_fmt ( & mut head, format_args ! ( "date: {}\r \n " , date) ) ?;
85
+ std:: io:: Write :: write_fmt ( & mut self . head , format_args ! ( "date: {}\r \n " , date) ) ?;
77
86
78
87
for ( header, values) in self . res . iter ( ) {
79
88
for value in values. iter ( ) {
80
- std:: io:: Write :: write_fmt ( & mut head, format_args ! ( "{}: {}\r \n " , header, value) ) ?
89
+ std:: io:: Write :: write_fmt (
90
+ & mut self . head ,
91
+ format_args ! ( "{}: {}\r \n " , header, value) ,
92
+ ) ?
81
93
}
82
94
}
83
95
84
- std:: io:: Write :: write_fmt ( & mut head, format_args ! ( "\r \n " ) ) ?;
96
+ std:: io:: Write :: write_fmt ( & mut self . head , format_args ! ( "\r \n " ) ) ?;
97
+ Ok ( ( ) )
98
+ }
85
99
86
- Ok ( head)
100
+ /// Encode the status code + headers of the response.
101
+ fn encode_head ( & mut self , buf : & mut [ u8 ] ) -> bool {
102
+ // Read from the serialized headers, url and methods.
103
+ let head_len = self . head . len ( ) ;
104
+ let len = std:: cmp:: min ( head_len - self . head_bytes_read , buf. len ( ) ) ;
105
+ let range = self . head_bytes_read ..self . head_bytes_read + len;
106
+ buf[ 0 ..len] . copy_from_slice ( & self . head [ range] ) ;
107
+ self . bytes_read += len;
108
+ self . head_bytes_read += len;
109
+
110
+ // If we've read the total length of the head we're done
111
+ // reading the head and can transition to reading the body
112
+ if self . head_bytes_read == head_len {
113
+ // The response length lets us know if we are encoding
114
+ // our body in chunks or not
115
+ self . state = match self . res . len ( ) {
116
+ Some ( body_len) => EncoderState :: Body {
117
+ body_bytes_read : 0 ,
118
+ body_len,
119
+ } ,
120
+ None => EncoderState :: UncomputedChunked ,
121
+ } ;
122
+ true
123
+ } else {
124
+ // If we haven't read the entire header it means `buf` isn't
125
+ // big enough. Break out of loop and return from `poll_read`
126
+ false
127
+ }
87
128
}
88
129
}
89
130
@@ -93,46 +134,14 @@ impl Read for Encoder {
93
134
cx : & mut Context < ' _ > ,
94
135
mut buf : & mut [ u8 ] ,
95
136
) -> Poll < io:: Result < usize > > {
96
- // we must keep track how many bytes of the head and body we've read
137
+ // we keep track how many bytes of the head and body we've read
97
138
// in this call of `poll_read`
98
139
self . bytes_read = 0 ;
99
140
loop {
100
141
match self . state {
101
- EncoderState :: Start => {
102
- // Encode the headers to a buffer, the first time we poll
103
- let head = self . encode_head ( ) ?;
104
- self . state = EncoderState :: Head {
105
- data : head,
106
- head_bytes_read : 0 ,
107
- } ;
108
- }
109
- EncoderState :: Head {
110
- ref data,
111
- mut head_bytes_read,
112
- } => {
113
- // Read from the serialized headers, url and methods.
114
- let head_len = data. len ( ) ;
115
- let len = std:: cmp:: min ( head_len - head_bytes_read, buf. len ( ) ) ;
116
- let range = head_bytes_read..head_bytes_read + len;
117
- buf[ 0 ..len] . copy_from_slice ( & data[ range] ) ;
118
- self . bytes_read += len;
119
- head_bytes_read += len;
120
-
121
- // If we've read the total length of the head we're done
122
- // reading the head and can transition to reading the body
123
- if head_bytes_read == head_len {
124
- // The response length lets us know if we are encoding
125
- // our body in chunks or not
126
- self . state = match self . res . len ( ) {
127
- Some ( body_len) => EncoderState :: Body {
128
- body_bytes_read : 0 ,
129
- body_len,
130
- } ,
131
- None => EncoderState :: UncomputedChunked ,
132
- } ;
133
- } else {
134
- // If we haven't read the entire header it means `buf` isn't
135
- // big enough. Break out of loop and return from `poll_read`
142
+ EncoderState :: Start => self . encode_start ( ) ?,
143
+ EncoderState :: Head { .. } => {
144
+ if !self . encode_head ( buf) {
136
145
break ;
137
146
}
138
147
}
0 commit comments