Mercurial > crates > nonstick
comparison src/libpam/response.rs @ 77:351bdc13005e
Update the libpam module to work with the new structure.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 08 Jun 2025 01:03:46 -0400 |
parents | c30811b4afae |
children |
comparison
equal
deleted
inserted
replaced
76:e58d24849e82 | 77:351bdc13005e |
---|---|
1 //! Types used when dealing with PAM conversations. | 1 //! Types used to communicate data from the application to the module. |
2 | 2 |
3 use crate::conv::BinaryData; | 3 use crate::conv::BorrowedBinaryData; |
4 use crate::libpam::conversation::OwnedMessage; | |
4 use crate::libpam::memory; | 5 use crate::libpam::memory; |
5 use crate::libpam::memory::{CBinaryData, Immovable, NulError, TooBigError}; | 6 use crate::libpam::memory::{CBinaryData, Immovable}; |
6 use crate::Response; | 7 use crate::{ErrorCode, Result}; |
7 use std::ffi::{c_int, c_void, CStr}; | 8 use std::ffi::{c_int, c_void, CStr}; |
8 use std::ops::{Deref, DerefMut}; | 9 use std::ops::{Deref, DerefMut}; |
9 use std::result::Result as StdResult; | |
10 use std::str::Utf8Error; | |
11 use std::{iter, mem, ptr, slice}; | 10 use std::{iter, mem, ptr, slice}; |
12 | 11 |
13 #[repr(transparent)] | 12 #[repr(transparent)] |
14 #[derive(Debug)] | 13 #[derive(Debug)] |
15 pub struct RawTextResponse(RawResponse); | 14 pub struct TextAnswer(Answer); |
16 | 15 |
17 impl RawTextResponse { | 16 impl TextAnswer { |
18 /// Interprets the provided `RawResponse` as a text response. | 17 /// Interprets the provided `Answer` as a text answer. |
19 /// | 18 /// |
20 /// # Safety | 19 /// # Safety |
21 /// | 20 /// |
22 /// It's up to you to provide a response that is a `RawTextResponse`. | 21 /// It's up to you to provide an answer that is a `TextAnswer`. |
23 pub unsafe fn upcast(from: &mut RawResponse) -> &mut Self { | 22 pub unsafe fn upcast(from: &mut Answer) -> &mut Self { |
24 // SAFETY: We're provided a valid reference. | 23 // SAFETY: We're provided a valid reference. |
25 &mut *(from as *mut RawResponse).cast::<Self>() | 24 &mut *(from as *mut Answer).cast::<Self>() |
26 } | 25 } |
27 | 26 |
28 /// Fills in the provided `RawResponse` with the given text. | 27 /// Converts the `Answer` to a `TextAnswer` with the given text. |
29 /// | 28 fn fill(dest: &mut Answer, text: &str) -> Result<()> { |
30 /// You are responsible for calling [`free`](Self::free_contents) | 29 let allocated = memory::malloc_str(text)?; |
31 /// on the pointer you get back when you're done with it. | 30 dest.free_contents(); |
32 pub fn fill(dest: &mut RawResponse, text: impl AsRef<str>) -> StdResult<&mut Self, NulError> { | 31 dest.data = allocated.cast(); |
33 dest.data = memory::malloc_str(text)?.cast(); | 32 Ok(()) |
34 // SAFETY: We just filled this in so we know it's a text response. | 33 } |
35 Ok(unsafe { Self::upcast(dest) }) | 34 |
36 } | 35 /// Gets the string stored in this answer. |
37 | 36 pub fn contents(&self) -> Result<&str> { |
38 /// Gets the string stored in this response. | |
39 pub fn contents(&self) -> StdResult<&str, Utf8Error> { | |
40 if self.0.data.is_null() { | 37 if self.0.data.is_null() { |
41 Ok("") | 38 Ok("") |
42 } else { | 39 } else { |
43 // SAFETY: This data is either passed from PAM (so we are forced to | 40 // SAFETY: This data is either passed from PAM (so we are forced |
44 // trust it) or was created by us in TextResponseInner::alloc. | 41 // to trust it) or was created by us in TextAnswerInner::alloc. |
45 // In either case, it's going to be a valid null-terminated string. | 42 // In either case, it's going to be a valid null-terminated string. |
46 unsafe { CStr::from_ptr(self.0.data.cast()) }.to_str() | 43 unsafe { CStr::from_ptr(self.0.data.cast()) } |
47 } | 44 .to_str() |
48 } | 45 .map_err(|_| ErrorCode::ConversationError) |
49 | 46 } |
50 /// Releases memory owned by this response. | 47 } |
48 | |
49 /// Zeroes out the answer data, frees it, and points our data to `null`. | |
50 /// | |
51 /// When this `TextAnswer` is part of an [`Answers`], | |
52 /// this is optional (since that will perform the `free`), | |
53 /// but it will clear potentially sensitive data. | |
51 pub fn free_contents(&mut self) { | 54 pub fn free_contents(&mut self) { |
52 // SAFETY: We know we own this data. | 55 // SAFETY: We own this data and know it's valid. |
56 // If it's null, this is a no-op. | |
53 // After we're done, it will be null. | 57 // After we're done, it will be null. |
54 unsafe { | 58 unsafe { |
55 memory::zero_c_string(self.0.data); | 59 memory::zero_c_string(self.0.data); |
56 libc::free(self.0.data); | 60 libc::free(self.0.data); |
57 self.0.data = ptr::null_mut() | 61 self.0.data = ptr::null_mut() |
58 } | 62 } |
59 } | 63 } |
60 } | 64 } |
61 | 65 |
62 /// A [`RawResponse`] with [`CBinaryData`] in it. | 66 /// A [`Answer`] with [`CBinaryData`] in it. |
63 #[repr(transparent)] | 67 #[repr(transparent)] |
64 #[derive(Debug)] | 68 #[derive(Debug)] |
65 pub struct RawBinaryResponse(RawResponse); | 69 pub struct BinaryAnswer(Answer); |
66 | 70 |
67 impl RawBinaryResponse { | 71 impl BinaryAnswer { |
68 /// Interprets the provided `RawResponse` as a binary response. | 72 /// Interprets the provided [`Answer`] as a binary answer. |
69 /// | 73 /// |
70 /// # Safety | 74 /// # Safety |
71 /// | 75 /// |
72 /// It's up to you to provide a response that is a `RawBinaryResponse`. | 76 /// It's up to you to provide an answer that is a `BinaryAnswer`. |
73 pub unsafe fn upcast(from: &mut RawResponse) -> &mut Self { | 77 pub unsafe fn upcast(from: &mut Answer) -> &mut Self { |
74 // SAFETY: We're provided a valid reference. | 78 // SAFETY: We're provided a valid reference. |
75 &mut *(from as *mut RawResponse).cast::<Self>() | 79 &mut *(from as *mut Answer).cast::<Self>() |
76 } | 80 } |
77 | 81 |
78 /// Fills in a `RawResponse` with the provided binary data. | 82 /// Fills in a [`Answer`] with the provided binary data. |
79 /// | 83 /// |
80 /// The `data_type` is a tag you can use for whatever. | 84 /// The `data_type` is a tag you can use for whatever. |
81 /// It is passed through PAM unchanged. | 85 /// It is passed through PAM unchanged. |
82 /// | 86 /// |
83 /// The referenced data is copied to the C heap. We do not take ownership. | 87 /// The referenced data is copied to the C heap. |
84 /// You are responsible for calling [`free`](Self::free_contents) | 88 /// We do not take ownership of the original data. |
85 /// on the pointer you get back when you're done with it. | 89 pub fn fill(dest: &mut Answer, data: BorrowedBinaryData) -> Result<()> { |
86 pub fn fill<'a>( | 90 let allocated = CBinaryData::alloc(data.data(), data.data_type())?; |
87 dest: &'a mut RawResponse, | 91 dest.free_contents(); |
88 data: &[u8], | 92 dest.data = allocated.cast(); |
89 data_type: u8, | 93 Ok(()) |
90 ) -> StdResult<&'a mut Self, TooBigError> { | 94 } |
91 dest.data = CBinaryData::alloc(data, data_type)?.cast(); | 95 |
92 // SAFETY: We just filled this in, so we know it's binary. | 96 /// Gets the binary data in this answer. |
93 Ok(unsafe { Self::upcast(dest) }) | 97 pub fn data(&self) -> Option<&CBinaryData> { |
94 } | 98 // SAFETY: We either got this data from PAM or allocated it ourselves. |
95 | 99 // Either way, we trust that it is either valid data or null. |
96 /// Gets the binary data in this response. | |
97 pub fn data(&self) -> &[u8] { | |
98 self.contents().map(CBinaryData::contents).unwrap_or(&[]) | |
99 } | |
100 | |
101 /// Gets the `data_type` tag that was embedded with the message. | |
102 pub fn data_type(&self) -> u8 { | |
103 self.contents().map(CBinaryData::data_type).unwrap_or(0) | |
104 } | |
105 | |
106 fn contents(&self) -> Option<&CBinaryData> { | |
107 // SAFETY: This was either something we got from PAM (in which case | |
108 // we trust it), or something that was created with | |
109 // BinaryResponseInner::alloc. In both cases, it points to valid data. | |
110 unsafe { self.0.data.cast::<CBinaryData>().as_ref() } | 100 unsafe { self.0.data.cast::<CBinaryData>().as_ref() } |
111 } | 101 } |
112 | 102 |
113 pub fn to_owned(&self) -> BinaryData { | 103 /// Zeroes out the answer data, frees it, and points our data to `null`. |
114 BinaryData::new(self.data().into(), self.data_type()) | 104 /// |
115 } | 105 /// When this `TextAnswer` is part of an [`Answers`], |
116 | 106 /// this is optional (since that will perform the `free`), |
117 /// Releases memory owned by this response. | 107 /// but it will clear potentially sensitive data. |
118 pub fn free_contents(&mut self) { | 108 pub fn zero_contents(&mut self) { |
119 // SAFETY: We know that our data pointer is either valid or null. | 109 // SAFETY: We know that our data pointer is either valid or null. |
120 // Once we're done, it's null and the response is safe. | 110 // Once we're done, it's null and the answer is safe. |
121 unsafe { | 111 unsafe { |
122 let data_ref = self.0.data.cast::<CBinaryData>().as_mut(); | 112 let data_ref = self.0.data.cast::<CBinaryData>().as_mut(); |
123 if let Some(d) = data_ref { | 113 if let Some(d) = data_ref { |
124 d.zero_contents() | 114 d.zero_contents() |
125 } | 115 } |
127 self.0.data = ptr::null_mut() | 117 self.0.data = ptr::null_mut() |
128 } | 118 } |
129 } | 119 } |
130 } | 120 } |
131 | 121 |
132 /// Generic version of response data. | 122 /// Generic version of answer data. |
133 /// | 123 /// |
134 /// This has the same structure as [`RawBinaryResponse`] | 124 /// This has the same structure as [`BinaryAnswer`] |
135 /// and [`RawTextResponse`]. | 125 /// and [`TextAnswer`]. |
136 #[repr(C)] | 126 #[repr(C)] |
137 #[derive(Debug)] | 127 #[derive(Debug)] |
138 pub struct RawResponse { | 128 pub struct Answer { |
139 /// Pointer to the data returned in a response. | 129 /// Pointer to the data returned in an answer. |
140 /// For most responses, this will be a [`CStr`], but for responses to | 130 /// For most answers, this will be a [`CStr`], but for answers to |
141 /// [`MessageStyle::BinaryPrompt`]s, this will be [`CBinaryData`] | 131 /// [`MessageStyle::BinaryPrompt`]s, this will be [`CBinaryData`] |
142 /// (a Linux-PAM extension). | 132 /// (a Linux-PAM extension). |
143 data: *mut c_void, | 133 data: *mut c_void, |
144 /// Unused. | 134 /// Unused. |
145 return_code: c_int, | 135 return_code: c_int, |
146 _marker: Immovable, | 136 _marker: Immovable, |
147 } | 137 } |
148 | 138 |
149 /// A contiguous block of responses. | 139 impl Answer { |
140 /// Frees the contents of this answer. | |
141 /// | |
142 /// After this is done, this answer's `data` will be `null`, | |
143 /// which is a valid (empty) state. | |
144 fn free_contents(&mut self) { | |
145 // SAFETY: We have either an owned valid pointer, or null. | |
146 // We can free our owned pointer, and `free(null)` is a no-op. | |
147 unsafe { | |
148 libc::free(self.data); | |
149 self.data = ptr::null_mut(); | |
150 } | |
151 } | |
152 } | |
153 | |
154 /// An owned, contiguous block of [`Answer`]s. | |
150 #[derive(Debug)] | 155 #[derive(Debug)] |
151 pub struct OwnedResponses { | 156 pub struct Answers { |
152 base: *mut RawResponse, | 157 base: *mut Answer, |
153 count: usize, | 158 count: usize, |
154 } | 159 } |
155 | 160 |
156 impl OwnedResponses { | 161 impl Answers { |
157 /// Allocates an owned list of responses on the C heap. | 162 /// Allocates an owned list of answers on the C heap. |
158 fn alloc(count: usize) -> Self { | 163 fn alloc(count: usize) -> Self { |
159 OwnedResponses { | 164 Answers { |
160 // SAFETY: We are doing allocation here. | 165 // SAFETY: We are doing allocation here. |
161 base: unsafe { libc::calloc(count, size_of::<RawResponse>()) }.cast(), | 166 base: unsafe { libc::calloc(count, size_of::<Answer>()) }.cast(), |
162 count, | 167 count, |
163 } | 168 } |
164 } | 169 } |
165 | 170 |
166 pub fn build(value: &[Response]) -> StdResult<Self, FillError> { | 171 pub fn build(value: Vec<OwnedMessage>) -> Result<Self> { |
167 let mut outputs = OwnedResponses::alloc(value.len()); | 172 let mut outputs = Answers::alloc(value.len()); |
168 // If we fail in here after allocating OwnedResponses, | 173 // Even if we fail during this process, we still end up freeing |
169 // we still free all memory, even though we don't zero it first. | 174 // all allocated answer memory. |
170 // This is an acceptable level of risk. | 175 for (input, output) in iter::zip(value, outputs.iter_mut()) { |
171 for (input, output) in iter::zip(value.iter(), outputs.iter_mut()) { | |
172 match input { | 176 match input { |
173 Response::NoResponse => { | 177 OwnedMessage::MaskedPrompt(p) => TextAnswer::fill(output, p.answer()?.unsecure())?, |
174 RawTextResponse::fill(output, "")?; | 178 OwnedMessage::Prompt(p) => TextAnswer::fill(output, &(p.answer()?))?, |
175 } | 179 OwnedMessage::BinaryPrompt(p) => BinaryAnswer::fill(output, (&p.answer()?).into())?, |
176 Response::Text(data) => { | 180 OwnedMessage::Error(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?, |
177 RawTextResponse::fill(output, data)?; | 181 OwnedMessage::Info(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?, |
178 } | 182 OwnedMessage::RadioPrompt(p) => TextAnswer::fill(output, &(p.answer()?))?, |
179 Response::MaskedText(data) => { | |
180 RawTextResponse::fill(output, data.unsecure())?; | |
181 } | |
182 Response::Binary(data) => { | |
183 RawBinaryResponse::fill(output, data.data(), data.data_type())?; | |
184 } | |
185 } | 183 } |
186 } | 184 } |
187 Ok(outputs) | 185 Ok(outputs) |
188 } | 186 } |
189 | 187 |
190 /// Converts this into a `*RawResponse` for passing to PAM. | 188 /// Converts this into a `*Answer` for passing to PAM. |
191 /// | 189 /// |
192 /// The pointer "owns" its own data (i.e., this will not be dropped). | 190 /// The pointer "owns" its own data (i.e., this will not be dropped). |
193 pub fn into_ptr(self) -> *mut RawResponse { | 191 pub fn into_ptr(self) -> *mut Answer { |
194 let ret = self.base; | 192 let ret = self.base; |
195 mem::forget(self); | 193 mem::forget(self); |
196 ret | 194 ret |
197 } | 195 } |
198 | 196 |
199 /// Takes ownership of a list of responses allocated on the C heap. | 197 /// Takes ownership of a list of answers allocated on the C heap. |
200 /// | 198 /// |
201 /// # Safety | 199 /// # Safety |
202 /// | 200 /// |
203 /// It's up to you to make sure you pass a valid pointer. | 201 /// It's up to you to make sure you pass a valid pointer. |
204 pub unsafe fn from_c_heap(base: *mut RawResponse, count: usize) -> Self { | 202 pub unsafe fn from_c_heap(base: *mut Answer, count: usize) -> Self { |
205 OwnedResponses { base, count } | 203 Answers { base, count } |
206 } | 204 } |
207 } | 205 } |
208 | 206 |
209 #[derive(Debug, thiserror::Error)] | 207 impl Deref for Answers { |
210 #[error("error converting responses: {0}")] | 208 type Target = [Answer]; |
211 pub enum FillError { | |
212 NulError(#[from] NulError), | |
213 TooBigError(#[from] TooBigError), | |
214 } | |
215 | |
216 impl Deref for OwnedResponses { | |
217 type Target = [RawResponse]; | |
218 fn deref(&self) -> &Self::Target { | 209 fn deref(&self) -> &Self::Target { |
219 // SAFETY: This is the memory we manage ourselves. | 210 // SAFETY: This is the memory we manage ourselves. |
220 unsafe { slice::from_raw_parts(self.base, self.count) } | 211 unsafe { slice::from_raw_parts(self.base, self.count) } |
221 } | 212 } |
222 } | 213 } |
223 | 214 |
224 impl DerefMut for OwnedResponses { | 215 impl DerefMut for Answers { |
225 fn deref_mut(&mut self) -> &mut Self::Target { | 216 fn deref_mut(&mut self) -> &mut Self::Target { |
226 // SAFETY: This is the memory we manage ourselves. | 217 // SAFETY: This is the memory we manage ourselves. |
227 unsafe { slice::from_raw_parts_mut(self.base, self.count) } | 218 unsafe { slice::from_raw_parts_mut(self.base, self.count) } |
228 } | 219 } |
229 } | 220 } |
230 | 221 |
231 impl Drop for OwnedResponses { | 222 impl Drop for Answers { |
232 fn drop(&mut self) { | 223 fn drop(&mut self) { |
233 // SAFETY: We allocated this ourselves, or it was provided to us by PAM. | 224 // SAFETY: We allocated this ourselves, or it was provided to us by PAM. |
234 unsafe { | 225 unsafe { |
235 for resp in self.iter_mut() { | 226 for answer in self.iter_mut() { |
236 libc::free(resp.data) | 227 answer.free_contents() |
237 } | 228 } |
238 libc::free(self.base.cast()) | 229 libc::free(self.base.cast()) |
239 } | 230 } |
240 } | 231 } |
241 } | 232 } |
242 | 233 |
243 #[cfg(test)] | 234 #[cfg(test)] |
244 mod tests { | 235 mod tests { |
245 use super::{BinaryData, OwnedResponses, RawBinaryResponse, RawTextResponse, Response}; | 236 use super::{Answers, BinaryAnswer, TextAnswer, BorrowedBinaryData}; |
237 use crate::BinaryData; | |
238 use crate::conv::{BinaryQAndA, ErrorMsg, InfoMsg, MaskedQAndA, QAndA, RadioQAndA}; | |
239 use crate::libpam::conversation::OwnedMessage; | |
246 | 240 |
247 #[test] | 241 #[test] |
248 fn test_round_trip() { | 242 fn test_round_trip() { |
249 let responses = [ | 243 let binary_msg = { |
250 Response::Binary(BinaryData::new(vec![1, 2, 3], 99)), | 244 let qa = BinaryQAndA::new(&[], 0); |
251 Response::Text("whats going on".to_owned()), | 245 qa.set_answer(Ok(BinaryData::new(vec![1, 2, 3], 99))); |
252 Response::MaskedText("well then".into()), | 246 OwnedMessage::BinaryPrompt(qa) |
253 Response::NoResponse, | 247 }; |
254 Response::Text("bogus".to_owned()), | 248 |
249 macro_rules! answered { | |
250 ($typ:ty, $msg:path, $data:expr) => { | |
251 {let qa = <$typ>::new(""); | |
252 qa.set_answer(Ok($data)); $msg(qa)} | |
253 } | |
254 } | |
255 | |
256 | |
257 let answers = vec![ | |
258 binary_msg, | |
259 answered!(QAndA, OwnedMessage::Prompt, "whats going on".to_owned()), | |
260 answered!(MaskedQAndA, OwnedMessage::MaskedPrompt, "well then".into()), | |
261 answered!(ErrorMsg, OwnedMessage::Error, ()), | |
262 answered!(InfoMsg, OwnedMessage::Info, ()), | |
263 answered!(RadioQAndA, OwnedMessage::RadioPrompt, "beep boop".to_owned()), | |
255 ]; | 264 ]; |
256 let sent = OwnedResponses::build(&responses).unwrap(); | 265 let n = answers.len(); |
257 let heap_resps = sent.into_ptr(); | 266 let sent = Answers::build(answers).unwrap(); |
258 let mut received = unsafe { OwnedResponses::from_c_heap(heap_resps, 5) }; | 267 let heap_answers = sent.into_ptr(); |
268 let mut received = unsafe { Answers::from_c_heap(heap_answers, n) }; | |
259 | 269 |
260 let assert_text = |want, raw| { | 270 let assert_text = |want, raw| { |
261 let up = unsafe { RawTextResponse::upcast(raw) }; | 271 let up = unsafe { TextAnswer::upcast(raw) }; |
262 assert_eq!(want, up.contents().unwrap()); | 272 assert_eq!(want, up.contents().unwrap()); |
263 up.free_contents(); | 273 up.free_contents(); |
264 assert_eq!("", up.contents().unwrap()); | 274 assert_eq!("", up.contents().unwrap()); |
265 }; | 275 }; |
266 let assert_bin = |want_data: &[u8], want_type, raw| { | 276 let assert_bin = |want_data: &[u8], want_type, raw| { |
267 let up = unsafe { RawBinaryResponse::upcast(raw) }; | 277 let up = unsafe { BinaryAnswer::upcast(raw) }; |
268 assert_eq!(want_data, up.data()); | 278 assert_eq!(BinaryData::new(want_data.into(), want_type), up.data().into()); |
269 assert_eq!(want_type, up.data_type()); | 279 up.zero_contents(); |
270 up.free_contents(); | 280 assert_eq!(BinaryData::default(), up.data().into()); |
271 let empty: [u8; 0] = []; | |
272 assert_eq!(&empty, up.data()); | |
273 assert_eq!(0, up.data_type()); | |
274 }; | 281 }; |
275 if let [zero, one, two, three, four] = &mut received[..] { | 282 if let [zero, one, two, three, four, five] = &mut received[..] { |
276 assert_bin(&[1, 2, 3], 99, zero); | 283 assert_bin(&[1, 2, 3], 99, zero); |
277 assert_text("whats going on", one); | 284 assert_text("whats going on", one); |
278 assert_text("well then", two); | 285 assert_text("well then", two); |
279 assert_text("", three); | 286 assert_text("", three); |
280 assert_text("bogus", four); | 287 assert_text("", four); |
288 assert_text("beep boop", five); | |
281 } else { | 289 } else { |
282 panic!("wrong size!") | 290 panic!("received wrong size {len}!", len = received.len()) |
283 } | 291 } |
284 } | 292 } |
285 | 293 |
286 #[test] | 294 #[test] |
287 fn test_text_response() { | 295 fn test_text_answer() { |
288 let mut responses = OwnedResponses::alloc(2); | 296 let mut answers = Answers::alloc(2); |
289 let text = RawTextResponse::fill(&mut responses[0], "hello").unwrap(); | 297 let zeroth = &mut answers[0]; |
290 let data = text.contents().expect("valid"); | 298 TextAnswer::fill(zeroth, "hello").unwrap(); |
299 let zeroth_text = unsafe { TextAnswer::upcast(zeroth) }; | |
300 let data = zeroth_text.contents().expect("valid"); | |
291 assert_eq!("hello", data); | 301 assert_eq!("hello", data); |
292 text.free_contents(); | 302 zeroth_text.free_contents(); |
293 text.free_contents(); | 303 zeroth_text.free_contents(); |
294 RawTextResponse::fill(&mut responses[1], "hell\0").expect_err("should error; contains nul"); | 304 TextAnswer::fill(&mut answers[1], "hell\0").expect_err("should error; contains nul"); |
295 } | 305 } |
296 | 306 |
297 #[test] | 307 #[test] |
298 fn test_binary_response() { | 308 fn test_binary_answer() { |
299 let mut responses = OwnedResponses::alloc(1); | 309 let mut answers = Answers::alloc(1); |
300 let real_data = [1, 2, 3, 4, 5, 6, 7, 8]; | 310 let real_data = BinaryData::new(vec![1, 2, 3, 4, 5, 6, 7, 8], 9); |
301 let resp = RawBinaryResponse::fill(&mut responses[0], &real_data, 7) | 311 let answer = &mut answers[0]; |
302 .expect("alloc should succeed"); | 312 BinaryAnswer::fill(answer, (&real_data).into()).expect("alloc should succeed"); |
303 let data = resp.data(); | 313 let bin_answer = unsafe { BinaryAnswer::upcast(answer) }; |
304 assert_eq!(&real_data, data); | 314 assert_eq!(real_data, bin_answer.data().into()); |
305 assert_eq!(7, resp.data_type()); | 315 answer.free_contents(); |
306 resp.free_contents(); | 316 answer.free_contents(); |
307 resp.free_contents(); | |
308 } | 317 } |
309 | 318 |
310 #[test] | 319 #[test] |
311 #[ignore] | 320 #[ignore] |
312 fn test_binary_response_too_big() { | 321 fn test_binary_answer_too_big() { |
313 let big_data: Vec<u8> = vec![0xFFu8; 10_000_000_000]; | 322 let big_data: Vec<u8> = vec![0xFFu8; 10_000_000_000]; |
314 let mut responses = OwnedResponses::alloc(1); | 323 let mut answers = Answers::alloc(1); |
315 RawBinaryResponse::fill(&mut responses[0], &big_data, 0).expect_err("this is too big!"); | 324 BinaryAnswer::fill(&mut answers[0], BorrowedBinaryData::new(&big_data, 100)) |
316 } | 325 .expect_err("this is too big!"); |
317 } | 326 } |
327 } |