rust/chg/src/message.rs
changeset 45620 426294d06ddc
parent 44693 61fda2dbc522
equal deleted inserted replaced
45619:e8078af6af30 45620:426294d06ddc
    30     pub current_dir: OsString,
    30     pub current_dir: OsString,
    31     pub envs: Vec<(OsString, OsString)>,
    31     pub envs: Vec<(OsString, OsString)>,
    32 }
    32 }
    33 
    33 
    34 /// Parses "S" channel request into command type and spec.
    34 /// Parses "S" channel request into command type and spec.
    35 pub fn parse_command_spec(data: Bytes) -> io::Result<(CommandType, CommandSpec)> {
    35 pub fn parse_command_spec(
       
    36     data: Bytes,
       
    37 ) -> io::Result<(CommandType, CommandSpec)> {
    36     let mut split = data.split(|&c| c == b'\0');
    38     let mut split = data.split(|&c| c == b'\0');
    37     let ctype = parse_command_type(split.next().ok_or(new_parse_error("missing type"))?)?;
    39     let ctype = parse_command_type(
       
    40         split.next().ok_or(new_parse_error("missing type"))?,
       
    41     )?;
    38     let command = split.next().ok_or(new_parse_error("missing command"))?;
    42     let command = split.next().ok_or(new_parse_error("missing command"))?;
    39     let current_dir = split.next().ok_or(new_parse_error("missing current dir"))?;
    43     let current_dir =
       
    44         split.next().ok_or(new_parse_error("missing current dir"))?;
    40 
    45 
    41     let mut envs = Vec::new();
    46     let mut envs = Vec::new();
    42     for l in split {
    47     for l in split {
    43         let mut s = l.splitn(2, |&c| c == b'=');
    48         let mut s = l.splitn(2, |&c| c == b'=');
    44         let k = s.next().unwrap();
    49         let k = s.next().unwrap();
    87         let mut s = l.splitn(2, |&c| c == b' ');
    92         let mut s = l.splitn(2, |&c| c == b' ');
    88         let inst = match (s.next().unwrap(), s.next()) {
    93         let inst = match (s.next().unwrap(), s.next()) {
    89             (b"exit", Some(arg)) => decode_latin1(arg)
    94             (b"exit", Some(arg)) => decode_latin1(arg)
    90                 .parse()
    95                 .parse()
    91                 .map(Instruction::Exit)
    96                 .map(Instruction::Exit)
    92                 .map_err(|_| new_parse_error(format!("invalid exit code: {:?}", arg)))?,
    97                 .map_err(|_| {
       
    98                     new_parse_error(format!("invalid exit code: {:?}", arg))
       
    99                 })?,
    93             (b"reconnect", None) => Instruction::Reconnect,
   100             (b"reconnect", None) => Instruction::Reconnect,
    94             (b"redirect", Some(arg)) => {
   101             (b"redirect", Some(arg)) => {
    95                 Instruction::Redirect(OsStr::from_bytes(arg).to_owned().into())
   102                 Instruction::Redirect(OsStr::from_bytes(arg).to_owned().into())
    96             }
   103             }
    97             (b"unlink", Some(arg)) => Instruction::Unlink(OsStr::from_bytes(arg).to_owned().into()),
   104             (b"unlink", Some(arg)) => {
       
   105                 Instruction::Unlink(OsStr::from_bytes(arg).to_owned().into())
       
   106             }
    98             _ => {
   107             _ => {
    99                 return Err(new_parse_error(format!("unknown command: {:?}", l)));
   108                 return Err(new_parse_error(format!(
       
   109                     "unknown command: {:?}",
       
   110                     l
       
   111                 )));
   100             }
   112             }
   101         };
   113         };
   102         instructions.push(inst);
   114         instructions.push(inst);
   103     }
   115     }
   104     Ok(instructions)
   116     Ok(instructions)
   116 pub fn pack_env_vars_os(
   128 pub fn pack_env_vars_os(
   117     vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
   129     vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
   118 ) -> Bytes {
   130 ) -> Bytes {
   119     let mut vars_iter = vars.into_iter();
   131     let mut vars_iter = vars.into_iter();
   120     if let Some((k, v)) = vars_iter.next() {
   132     if let Some((k, v)) = vars_iter.next() {
   121         let mut dst = BytesMut::with_capacity(INITIAL_PACKED_ENV_VARS_CAPACITY);
   133         let mut dst =
       
   134             BytesMut::with_capacity(INITIAL_PACKED_ENV_VARS_CAPACITY);
   122         pack_env_into(&mut dst, k.as_ref(), v.as_ref());
   135         pack_env_into(&mut dst, k.as_ref(), v.as_ref());
   123         for (k, v) in vars_iter {
   136         for (k, v) in vars_iter {
   124             dst.reserve(1);
   137             dst.reserve(1);
   125             dst.put_u8(b'\0');
   138             dst.put_u8(b'\0');
   126             pack_env_into(&mut dst, k.as_ref(), v.as_ref());
   139             pack_env_into(&mut dst, k.as_ref(), v.as_ref());
   143 
   156 
   144 fn decode_latin1(s: impl AsRef<[u8]>) -> String {
   157 fn decode_latin1(s: impl AsRef<[u8]>) -> String {
   145     s.as_ref().iter().map(|&c| c as char).collect()
   158     s.as_ref().iter().map(|&c| c as char).collect()
   146 }
   159 }
   147 
   160 
   148 fn new_parse_error(error: impl Into<Box<dyn error::Error + Send + Sync>>) -> io::Error {
   161 fn new_parse_error(
       
   162     error: impl Into<Box<dyn error::Error + Send + Sync>>,
       
   163 ) -> io::Error {
   149     io::Error::new(io::ErrorKind::InvalidData, error)
   164     io::Error::new(io::ErrorKind::InvalidData, error)
   150 }
   165 }
   151 
   166 
   152 #[cfg(test)]
   167 #[cfg(test)]
   153 mod tests {
   168 mod tests {
   181 
   196 
   182     #[test]
   197     #[test]
   183     fn parse_command_spec_too_short() {
   198     fn parse_command_spec_too_short() {
   184         assert!(parse_command_spec(Bytes::from_static(b"")).is_err());
   199         assert!(parse_command_spec(Bytes::from_static(b"")).is_err());
   185         assert!(parse_command_spec(Bytes::from_static(b"pager")).is_err());
   200         assert!(parse_command_spec(Bytes::from_static(b"pager")).is_err());
   186         assert!(parse_command_spec(Bytes::from_static(b"pager\0less")).is_err());
   201         assert!(
       
   202             parse_command_spec(Bytes::from_static(b"pager\0less")).is_err()
       
   203         );
   187     }
   204     }
   188 
   205 
   189     #[test]
   206     #[test]
   190     fn parse_command_spec_malformed_env() {
   207     fn parse_command_spec_malformed_env() {
   191         assert!(parse_command_spec(Bytes::from_static(b"pager\0less\0/tmp\0HOME")).is_err());
   208         assert!(parse_command_spec(Bytes::from_static(
       
   209             b"pager\0less\0/tmp\0HOME"
       
   210         ))
       
   211         .is_err());
   192     }
   212     }
   193 
   213 
   194     #[test]
   214     #[test]
   195     fn parse_command_spec_unknown_type() {
   215     fn parse_command_spec_unknown_type() {
   196         assert!(parse_command_spec(Bytes::from_static(b"paper\0less")).is_err());
   216         assert!(
       
   217             parse_command_spec(Bytes::from_static(b"paper\0less")).is_err()
       
   218         );
   197     }
   219     }
   198 
   220 
   199     #[test]
   221     #[test]
   200     fn parse_instructions_good() {
   222     fn parse_instructions_good() {
   201         let src = [
   223         let src = [