Skip to content

Commit c591a9a

Browse files
committed
server: split encode_start & encode_head
1 parent 96032e5 commit c591a9a

File tree

1 file changed

+58
-49
lines changed

1 file changed

+58
-49
lines changed

src/server/encode.rs

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ pub(crate) struct Encoder {
2323
state: EncoderState,
2424
/// Track bytes read in a call to poll_read.
2525
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,
2630
}
2731

2832
#[derive(Debug)]
2933
enum EncoderState {
3034
Start,
31-
Head {
32-
data: Vec<u8>,
33-
head_bytes_read: usize,
34-
},
35+
Head,
3536
Body {
3637
body_bytes_read: usize,
3738
body_len: usize,
@@ -51,39 +52,79 @@ impl Encoder {
5152
res,
5253
state: EncoderState::Start,
5354
bytes_read: 0,
55+
head: vec![],
56+
head_bytes_read: 0,
5457
}
5558
}
59+
}
5660

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;
5965

6066
let reason = self.res.status().canonical_reason();
6167
let status = self.res.status();
6268
std::io::Write::write_fmt(
63-
&mut head,
69+
&mut self.head,
6470
format_args!("HTTP/1.1 {} {}\r\n", status, reason),
6571
)?;
6672

6773
// If the body isn't streaming, we can set the content-length ahead of time. Else we need to
6874
// send all items in chunks.
6975
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))?;
7177
} 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+
)?;
7382
}
7483

7584
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))?;
7786

7887
for (header, values) in self.res.iter() {
7988
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+
)?
8193
}
8294
}
8395

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+
}
8599

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+
}
87128
}
88129
}
89130

@@ -93,46 +134,14 @@ impl Read for Encoder {
93134
cx: &mut Context<'_>,
94135
mut buf: &mut [u8],
95136
) -> 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
97138
// in this call of `poll_read`
98139
self.bytes_read = 0;
99140
loop {
100141
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) {
136145
break;
137146
}
138147
}

0 commit comments

Comments
 (0)