From f2c3f45a6fd30386737bcfba21432d07c833d84b Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 24 Feb 2019 19:25:14 +0100 Subject: [PATCH] data_forms: Stop duplicating FORM_TYPE in memory. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FORM_TYPE is now only present once, as the form_type member of the DataForm struct, it isn’t duplicated in fields anymore. This removes the need to ignore this special field in every single protocol built on XEP-0128. --- src/caps.rs | 4 +--- src/data_forms.rs | 16 +++++++++++++--- src/ecaps2.rs | 31 ++++++++++++++++++++----------- src/ibr.rs | 12 ------------ 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/caps.rs b/src/caps.rs index a7948d19..1a0d5769 100644 --- a/src/caps.rs +++ b/src/caps.rs @@ -329,9 +329,7 @@ mod tests { "# .parse() .unwrap(); - let data = b"client/pc/el/\xce\xa8 0.11 for DataForm { form.instructions = Some(child.text()); } else if child.is("field", ns::DATA_FORMS) { let field = Field::try_from(child.clone())?; - if field.var == "FORM_TYPE" && field.type_ == FieldType::Hidden { + if field.var == "FORM_TYPE" { + let mut field = field; if form.form_type.is_some() { return Err(Error::ParseError("More than one FORM_TYPE in a data form.")); } + if field.type_ != FieldType::Hidden { + return Err(Error::ParseError("Invalid field type for FORM_TYPE.")); + } if field.values.len() != 1 { return Err(Error::ParseError("Wrong number of values in FORM_TYPE.")); } - form.form_type = Some(field.values[0].clone()); + form.form_type = field.values.pop(); + } else { + form.fields.push(field); } - form.fields.push(field); } else { return Err(Error::ParseError("Unknown child in data form element.")); } @@ -279,6 +284,11 @@ impl From for Element { .ns(ns::DATA_FORMS) .append(text) })) + .append(if let Some(form_type) = form.form_type { + vec![Element::builder("field").ns(ns::DATA_FORMS).attr("var", "FORM_TYPE").attr("type", "hidden").append(Element::builder("value").ns(ns::DATA_FORMS).append(form_type).build()).build()] + } else { + vec![] + }) .append(form.fields) .build() } diff --git a/src/ecaps2.rs b/src/ecaps2.rs index ef3a5932..352881f1 100644 --- a/src/ecaps2.rs +++ b/src/ecaps2.rs @@ -69,31 +69,40 @@ fn compute_identities(identities: &[Identity]) -> Vec { }) } -fn compute_extensions(extensions: &[DataForm]) -> Vec { - compute_items(extensions, 0x1c, |extension| { - compute_items(&extension.fields, 0x1d, |field| { +fn compute_extensions(extensions: &[DataForm]) -> Result, ()> { + for extension in extensions { + if extension.form_type.is_none() { + return Err(()); + } + } + Ok(compute_items(extensions, 0x1c, |extension| { + let mut bytes = compute_item("FORM_TYPE"); + bytes.append(&mut compute_item(if let Some(ref form_type) = extension.form_type { form_type } else { unreachable!() })); + bytes.push(0x1e); + bytes.append(&mut compute_items(&extension.fields, 0x1d, |field| { let mut bytes = compute_item(&field.var); bytes.append(&mut compute_items(&field.values, 0x1e, |value| { compute_item(value) })); bytes - }) - }) + })); + bytes + })) } /// Applies the [algorithm from /// XEP-0390](https://xmpp.org/extensions/xep-0390.html#algorithm-input) on a /// [disco#info query element](../disco/struct.DiscoInfoResult.html). -pub fn compute_disco(disco: &DiscoInfoResult) -> Vec { +pub fn compute_disco(disco: &DiscoInfoResult) -> Result, ()> { let features_string = compute_features(&disco.features); let identities_string = compute_identities(&disco.identities); - let extensions_string = compute_extensions(&disco.extensions); + let extensions_string = compute_extensions(&disco.extensions)?; let mut final_string = vec![]; final_string.extend(features_string); final_string.extend(identities_string); final_string.extend(extensions_string); - final_string + Ok(final_string) } fn get_hash_vec(hash: &[u8]) -> Vec { @@ -204,7 +213,7 @@ mod tests { fn test_simple() { let elem: Element = "".parse().unwrap(); let disco = DiscoInfoResult::try_from(elem).unwrap(); - let ecaps2 = compute_disco(&disco); + let ecaps2 = compute_disco(&disco).unwrap(); assert_eq!(ecaps2.len(), 54); } @@ -263,7 +272,7 @@ mod tests { 117, 115, 77, 111, 100, 31, 30, 28, 28, ]; let disco = DiscoInfoResult::try_from(elem).unwrap(); - let ecaps2 = compute_disco(&disco); + let ecaps2 = compute_disco(&disco).unwrap(); assert_eq!(ecaps2.len(), 0x1d9); assert_eq!(ecaps2, expected); @@ -424,7 +433,7 @@ mod tests { 98, 50, 41, 31, 30, 29, 28, ]; let disco = DiscoInfoResult::try_from(elem).unwrap(); - let ecaps2 = compute_disco(&disco); + let ecaps2 = compute_disco(&disco).unwrap(); assert_eq!(ecaps2.len(), 0x543); assert_eq!(ecaps2, expected); diff --git a/src/ibr.rs b/src/ibr.rs index f19c47c1..c98c9093 100644 --- a/src/ibr.rs +++ b/src/ibr.rs @@ -207,18 +207,6 @@ mod tests { assert!(!query.fields["instructions"].is_empty()); let form = query.form.clone().unwrap(); assert!(!form.instructions.unwrap().is_empty()); - assert!(form - .fields - .binary_search_by(|field| field.var.cmp(&String::from("first"))) - .is_ok()); - assert!(form - .fields - .binary_search_by(|field| field.var.cmp(&String::from("x-gender"))) - .is_ok()); - assert!(form - .fields - .binary_search_by(|field| field.var.cmp(&String::from("coucou"))) - .is_err()); let elem2 = query.into(); assert!(elem1.compare_to(&elem2)); }