form_urlencoded.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright 2013-2015 Simon Sapin.
  2. //
  3. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  5. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  6. // option. This file may not be copied, modified, or distributed
  7. // except according to those terms.
  8. //! Parser and serializer for the [`application/x-www-form-urlencoded` format](
  9. //! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
  10. //! as used by HTML forms.
  11. //!
  12. //! Converts between a string (such as an URL’s query string)
  13. //! and a sequence of (name, value) pairs.
  14. use std::borrow::Borrow;
  15. use std::ascii::AsciiExt;
  16. use encoding::EncodingOverride;
  17. use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};
  18. /// Convert a byte string in the `application/x-www-form-urlencoded` format
  19. /// into a vector of (name, value) pairs.
  20. ///
  21. /// Use `parse(input.as_bytes())` to parse a `&str` string.
  22. #[inline]
  23. pub fn parse(input: &[u8]) -> Vec<(String, String)> {
  24. parse_internal(input, EncodingOverride::utf8(), false).unwrap()
  25. }
  26. /// Convert a byte string in the `application/x-www-form-urlencoded` format
  27. /// into a vector of (name, value) pairs.
  28. ///
  29. /// Use `parse(input.as_bytes())` to parse a `&str` string.
  30. ///
  31. /// This function is only available if the `query_encoding` Cargo feature is enabled.
  32. ///
  33. /// Arguments:
  34. ///
  35. /// * `encoding_override`: The character encoding each name and values is decoded as
  36. /// after percent-decoding. Defaults to UTF-8.
  37. /// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
  38. #[cfg(feature = "query_encoding")]
  39. #[inline]
  40. pub fn parse_with_encoding(input: &[u8], encoding_override: Option<::encoding::EncodingRef>,
  41. use_charset: bool)
  42. -> Option<Vec<(String, String)>> {
  43. parse_internal(input, EncodingOverride::from_opt_encoding(encoding_override), use_charset)
  44. }
  45. fn parse_internal(input: &[u8], mut encoding_override: EncodingOverride, mut use_charset: bool)
  46. -> Option<Vec<(String, String)>> {
  47. let mut pairs = Vec::new();
  48. for piece in input.split(|&b| b == b'&') {
  49. if !piece.is_empty() {
  50. let (name, value) = match piece.iter().position(|b| *b == b'=') {
  51. Some(position) => (&piece[..position], &piece[position + 1..]),
  52. None => (piece, &[][..])
  53. };
  54. #[inline]
  55. fn replace_plus(input: &[u8]) -> Vec<u8> {
  56. input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
  57. }
  58. let name = replace_plus(name);
  59. let value = replace_plus(value);
  60. if use_charset && name == b"_charset_" {
  61. if let Some(encoding) = EncodingOverride::lookup(&value) {
  62. encoding_override = encoding;
  63. }
  64. use_charset = false;
  65. }
  66. pairs.push((name, value));
  67. }
  68. }
  69. if !(encoding_override.is_utf8() || input.is_ascii()) {
  70. return None
  71. }
  72. Some(pairs.into_iter().map(|(name, value)| (
  73. encoding_override.decode(&percent_decode(&name)),
  74. encoding_override.decode(&percent_decode(&value))
  75. )).collect())
  76. }
  77. /// Convert an iterator of (name, value) pairs
  78. /// into a string in the `application/x-www-form-urlencoded` format.
  79. #[inline]
  80. pub fn serialize<I, K, V>(pairs: I) -> String
  81. where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
  82. serialize_internal(pairs, EncodingOverride::utf8())
  83. }
  84. /// Convert an iterator of (name, value) pairs
  85. /// into a string in the `application/x-www-form-urlencoded` format.
  86. ///
  87. /// This function is only available if the `query_encoding` Cargo feature is enabled.
  88. ///
  89. /// Arguments:
  90. ///
  91. /// * `encoding_override`: The character encoding each name and values is encoded as
  92. /// before percent-encoding. Defaults to UTF-8.
  93. #[cfg(feature = "query_encoding")]
  94. #[inline]
  95. pub fn serialize_with_encoding<I, K, V>(pairs: I,
  96. encoding_override: Option<::encoding::EncodingRef>)
  97. -> String
  98. where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
  99. serialize_internal(pairs, EncodingOverride::from_opt_encoding(encoding_override))
  100. }
  101. fn serialize_internal<I, K, V>(pairs: I, encoding_override: EncodingOverride) -> String
  102. where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
  103. #[inline]
  104. fn byte_serialize(input: &str, output: &mut String,
  105. encoding_override: EncodingOverride) {
  106. for &byte in encoding_override.encode(input).iter() {
  107. if byte == b' ' {
  108. output.push_str("+")
  109. } else {
  110. percent_encode_to(&[byte], FORM_URLENCODED_ENCODE_SET, output)
  111. }
  112. }
  113. }
  114. let mut output = String::new();
  115. for pair in pairs {
  116. let &(ref name, ref value) = pair.borrow();
  117. if output.len() > 0 {
  118. output.push_str("&");
  119. }
  120. byte_serialize(name.as_ref(), &mut output, encoding_override);
  121. output.push_str("=");
  122. byte_serialize(value.as_ref(), &mut output, encoding_override);
  123. }
  124. output
  125. }
  126. #[cfg(test)]
  127. mod tests {
  128. use super::*;
  129. #[test]
  130. fn test_form_urlencoded() {
  131. let pairs = &[
  132. ("foo".to_string(), "é&".to_string()),
  133. ("bar".to_string(), "".to_string()),
  134. ("foo".to_string(), "#".to_string())
  135. ];
  136. let encoded = serialize(pairs);
  137. assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23");
  138. assert_eq!(parse(encoded.as_bytes()), pairs.to_vec());
  139. }
  140. #[test]
  141. fn test_form_serialize() {
  142. let pairs = [("foo", "é&"),
  143. ("bar", ""),
  144. ("foo", "#")];
  145. let want = "foo=%C3%A9%26&bar=&foo=%23";
  146. // Works with referenced tuples
  147. assert_eq!(serialize(pairs.iter()), want);
  148. // Works with owned tuples
  149. assert_eq!(serialize(pairs.iter().map(|p| (p.0, p.1))), want);
  150. }
  151. }