ureq_proto/server/
sendres.rs1use std::io::Write;
2
3use http::{HeaderName, HeaderValue};
4
5use crate::util::Writer;
6use crate::Error;
7
8use super::state::SendResponse;
9use super::{do_write_send_line, Reply, ResponsePhase, SendResponseResult};
10
11impl Reply<SendResponse> {
12 pub fn write(&mut self, output: &mut [u8]) -> Result<usize, Error> {
19 let response = self.inner.response.as_ref().unwrap();
21
22 let mut w = Writer::new(output);
23 try_write_prelude(response, &mut self.inner.phase, &mut w)?;
24
25 let output_used = w.len();
26
27 Ok(output_used)
28 }
29
30 pub fn is_finished(&self) -> bool {
35 !self.inner.phase.is_prelude()
36 }
37
38 pub fn proceed(self) -> SendResponseResult {
48 assert!(self.is_finished());
49
50 if let Some(writer) = self.inner.state.writer {
51 if writer.is_chunked() || writer.left_to_send().is_some() {
56 return SendResponseResult::SendBody(Reply::wrap(self.inner));
57 }
58 }
59
60 SendResponseResult::Cleanup(Reply::wrap(self.inner))
61 }
62}
63
64fn try_write_prelude(
65 response: &super::amended::AmendedResponse,
66 phase: &mut ResponsePhase,
67 w: &mut Writer,
68) -> Result<(), Error> {
69 let at_start = w.len();
70
71 loop {
72 if try_write_prelude_part(response, phase, w) {
73 continue;
74 }
75
76 let written = w.len() - at_start;
77
78 if written > 0 || phase.is_body() {
79 return Ok(());
80 } else {
81 return Err(Error::OutputOverflow);
82 }
83 }
84}
85
86fn try_write_prelude_part(
87 response: &super::amended::AmendedResponse,
88 phase: &mut ResponsePhase,
89 w: &mut Writer,
90) -> bool {
91 match phase {
92 ResponsePhase::Status => {
93 let success = do_write_send_line(response.prelude(), w, false);
94 if success {
95 *phase = ResponsePhase::Headers(0);
96 }
97 success
98 }
99
100 ResponsePhase::Headers(index) => {
101 let header_count = response.headers_len();
102 let all = response.headers();
103 let skipped = all.skip(*index);
104
105 do_write_headers(skipped, index, w);
106 if *index == header_count && w.try_write(|w| write!(w, "\r\n")) {
107 *phase = ResponsePhase::Body;
108 }
109 false
110 }
111
112 _ => false,
114 }
115}
116
117fn do_write_headers<'a, I>(headers: I, index: &mut usize, w: &mut Writer)
118where
119 I: Iterator<Item = (&'a HeaderName, &'a HeaderValue)>,
120{
121 for h in headers {
122 let success = w.try_write(|w| {
123 write!(w, "{}: ", h.0)?;
124 w.write_all(h.1.as_bytes())?;
125 write!(w, "\r\n")?;
126
127 Ok(())
128 });
129
130 if success {
131 *index += 1;
132 } else {
133 break;
134 }
135 }
136}