##// END OF EJS Templates
rust-chg: add helper to pack environment variables...
Yuya Nishihara -
r45164:8a7beeea default
parent child Browse files
Show More
@@ -5,7 +5,7 b''
5 5
6 6 //! Utility for parsing and building command-server messages.
7 7
8 use bytes::Bytes;
8 use bytes::{BufMut, Bytes, BytesMut};
9 9 use std::error;
10 10 use std::ffi::{OsStr, OsString};
11 11 use std::io;
@@ -67,6 +67,45 b' fn parse_command_type(value: &[u8]) -> i'
67 67 }
68 68 }
69 69
70 // allocate large buffer as environment variables can be quite long
71 const INITIAL_PACKED_ENV_VARS_CAPACITY: usize = 4096;
72
73 /// Packs environment variables of platform encoding into bytes.
74 ///
75 /// # Panics
76 ///
77 /// Panics if key or value contains `\0` character, or key contains '='
78 /// character.
79 pub fn pack_env_vars_os<I, P>(vars: I) -> Bytes
80 where
81 I: IntoIterator<Item = (P, P)>,
82 P: AsRef<OsStr>,
83 {
84 let mut vars_iter = vars.into_iter();
85 if let Some((k, v)) = vars_iter.next() {
86 let mut dst = BytesMut::with_capacity(INITIAL_PACKED_ENV_VARS_CAPACITY);
87 pack_env_into(&mut dst, k.as_ref(), v.as_ref());
88 for (k, v) in vars_iter {
89 dst.reserve(1);
90 dst.put_u8(b'\0');
91 pack_env_into(&mut dst, k.as_ref(), v.as_ref());
92 }
93 dst.freeze()
94 } else {
95 Bytes::new()
96 }
97 }
98
99 fn pack_env_into(dst: &mut BytesMut, k: &OsStr, v: &OsStr) {
100 assert!(!k.as_bytes().contains(&0), "key shouldn't contain NUL");
101 assert!(!k.as_bytes().contains(&b'='), "key shouldn't contain '='");
102 assert!(!v.as_bytes().contains(&0), "value shouldn't contain NUL");
103 dst.reserve(k.as_bytes().len() + 1 + v.as_bytes().len());
104 dst.put_slice(k.as_bytes());
105 dst.put_u8(b'=');
106 dst.put_slice(v.as_bytes());
107 }
108
70 109 fn decode_latin1<S>(s: S) -> String
71 110 where
72 111 S: AsRef<[u8]>,
@@ -85,6 +124,7 b' where'
85 124 mod tests {
86 125 use super::*;
87 126 use std::os::unix::ffi::OsStringExt;
127 use std::panic;
88 128
89 129 #[test]
90 130 fn parse_command_spec_good() {
@@ -127,7 +167,66 b' mod tests {'
127 167 assert!(parse_command_spec(Bytes::from_static(b"paper\0less")).is_err());
128 168 }
129 169
170 #[test]
171 fn pack_env_vars_os_good() {
172 assert_eq!(
173 pack_env_vars_os(vec![] as Vec<(OsString, OsString)>),
174 Bytes::new()
175 );
176 assert_eq!(
177 pack_env_vars_os(vec![os_string_pair_from(b"FOO", b"bar")]),
178 Bytes::from_static(b"FOO=bar")
179 );
180 assert_eq!(
181 pack_env_vars_os(vec![
182 os_string_pair_from(b"FOO", b""),
183 os_string_pair_from(b"BAR", b"baz")
184 ]),
185 Bytes::from_static(b"FOO=\0BAR=baz")
186 );
187 }
188
189 #[test]
190 fn pack_env_vars_os_large_key() {
191 let mut buf = vec![b'A'; INITIAL_PACKED_ENV_VARS_CAPACITY];
192 let envs = vec![os_string_pair_from(&buf, b"")];
193 buf.push(b'=');
194 assert_eq!(pack_env_vars_os(envs), Bytes::from(buf));
195 }
196
197 #[test]
198 fn pack_env_vars_os_large_value() {
199 let mut buf = vec![b'A', b'='];
200 buf.resize(INITIAL_PACKED_ENV_VARS_CAPACITY + 1, b'a');
201 let envs = vec![os_string_pair_from(&buf[..1], &buf[2..])];
202 assert_eq!(pack_env_vars_os(envs), Bytes::from(buf));
203 }
204
205 #[test]
206 fn pack_env_vars_os_nul_eq() {
207 assert!(panic::catch_unwind(|| {
208 pack_env_vars_os(vec![os_string_pair_from(b"\0", b"")])
209 })
210 .is_err());
211 assert!(panic::catch_unwind(|| {
212 pack_env_vars_os(vec![os_string_pair_from(b"FOO", b"\0bar")])
213 })
214 .is_err());
215 assert!(panic::catch_unwind(|| {
216 pack_env_vars_os(vec![os_string_pair_from(b"FO=", b"bar")])
217 })
218 .is_err());
219 assert_eq!(
220 pack_env_vars_os(vec![os_string_pair_from(b"FOO", b"=ba")]),
221 Bytes::from_static(b"FOO==ba")
222 );
223 }
224
130 225 fn os_string_from(s: &[u8]) -> OsString {
131 226 OsString::from_vec(s.to_vec())
132 227 }
228
229 fn os_string_pair_from(k: &[u8], v: &[u8]) -> (OsString, OsString) {
230 (os_string_from(k), os_string_from(v))
231 }
133 232 }
General Comments 0
You need to be logged in to leave comments. Login now