form_urlencoded.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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::ascii::AsciiExt;
  15. use encoding::EncodingOverride;
  16. use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};
  17. /// Convert a byte string in the `application/x-www-form-urlencoded` format
  18. /// into a vector of (name, value) pairs.
  19. ///
  20. /// Use `parse(input.as_bytes())` to parse a `&str` string.
  21. #[inline]
  22. pub fn parse(input: &[u8]) -> Vec<(String, String)> {
  23. parse_internal(input, EncodingOverride::utf8(), false).unwrap()
  24. }
  25. /// Convert a byte string in the `application/x-www-form-urlencoded` format
  26. /// into a vector of (name, value) pairs.
  27. ///
  28. /// Use `parse(input.as_bytes())` to parse a `&str` string.
  29. ///
  30. /// This function is only available if the `query_encoding` Cargo feature is enabled.
  31. ///
  32. /// Arguments:
  33. ///
  34. /// * `encoding_override`: The character encoding each name and values is decoded as
  35. /// after percent-decoding. Defaults to UTF-8.
  36. /// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
  37. #[cfg(feature = "query_encoding")]
  38. #[inline]
  39. pub fn parse_with_encoding(input: &[u8], encoding_override: Option<::encoding::EncodingRef>,
  40. use_charset: bool)
  41. -> Option<Vec<(String, String)>> {
  42. parse_internal(input, EncodingOverride::from_opt_encoding(encoding_override), use_charset)
  43. }
  44. fn parse_internal(input: &[u8], mut encoding_override: EncodingOverride, mut use_charset: bool)
  45. -> Option<Vec<(String, String)>> {
  46. let mut pairs = Vec::new();
  47. for piece in input.split(|&b| b == b'&') {
  48. if !piece.is_empty() {
  49. let (name, value) = match piece.position_elem(&b'=') {
  50. Some(position) => (&piece[..position], &piece[position + 1..]),
  51. None => (piece, &[][..])
  52. };
  53. #[inline]
  54. fn replace_plus(input: &[u8]) -> Vec<u8> {
  55. input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
  56. }
  57. let name = replace_plus(name);
  58. let value = replace_plus(value);
  59. if use_charset && name == b"_charset_" {
  60. if let Some(encoding) = EncodingOverride::lookup(&value) {
  61. encoding_override = encoding;
  62. }
  63. use_charset = false;
  64. }
  65. pairs.push((name, value));
  66. }
  67. }
  68. if !(encoding_override.is_utf8() || input.is_ascii()) {
  69. return None
  70. }
  71. Some(pairs.into_iter().map(|(name, value)| (
  72. encoding_override.decode(&percent_decode(&name)),
  73. encoding_override.decode(&percent_decode(&value))
  74. )).collect())
  75. }
  76. /// Convert a slice of owned (name, value) pairs
  77. /// into a string in the `application/x-www-form-urlencoded` format.
  78. #[inline]
  79. pub fn serialize_owned(pairs: &[(String, String)]) -> String {
  80. serialize(pairs.iter().map(|&(ref n, ref v)| (&**n, &**v)))
  81. }
  82. /// Convert an iterator of (name, value) pairs
  83. /// into a string in the `application/x-www-form-urlencoded` format.
  84. #[inline]
  85. pub fn serialize<'a, I>(pairs: I) -> String where I: Iterator<Item = (&'a str, &'a str)> {
  86. serialize_internal(pairs, EncodingOverride::utf8())
  87. }
  88. /// Convert an iterator of (name, value) pairs
  89. /// into a string in the `application/x-www-form-urlencoded` format.
  90. ///
  91. /// This function is only available if the `query_encoding` Cargo feature is enabled.
  92. ///
  93. /// Arguments:
  94. ///
  95. /// * `encoding_override`: The character encoding each name and values is encoded as
  96. /// before percent-encoding. Defaults to UTF-8.
  97. #[cfg(feature = "query_encoding")]
  98. #[inline]
  99. pub fn serialize_with_encoding<'a, I>(pairs: I, encoding_override: Option<::encoding::EncodingRef>)
  100. -> String
  101. where I: Iterator<Item = (&'a str, &'a str)> {
  102. serialize_internal(pairs, EncodingOverride::from_opt_encoding(encoding_override))
  103. }
  104. fn serialize_internal<'a, I>(pairs: I, encoding_override: EncodingOverride) -> String
  105. where I: Iterator<Item = (&'a str, &'a str)> {
  106. #[inline]
  107. fn byte_serialize(input: &str, output: &mut String,
  108. encoding_override: EncodingOverride) {
  109. for &byte in encoding_override.encode(input).iter() {
  110. if byte == b' ' {
  111. output.push_str("+")
  112. } else {
  113. percent_encode_to(&[byte], FORM_URLENCODED_ENCODE_SET, output)
  114. }
  115. }
  116. }
  117. let mut output = String::new();
  118. for (name, value) in pairs {
  119. if output.len() > 0 {
  120. output.push_str("&");
  121. }
  122. byte_serialize(name, &mut output, encoding_override);
  123. output.push_str("=");
  124. byte_serialize(value, &mut output, encoding_override);
  125. }
  126. output
  127. }
  128. #[test]
  129. fn test_form_urlencoded() {
  130. let pairs = &[
  131. ("foo".to_string(), "é&".to_string()),
  132. ("bar".to_string(), "".to_string()),
  133. ("foo".to_string(), "#".to_string())
  134. ];
  135. let encoded = serialize_owned(pairs);
  136. assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23");
  137. assert_eq!(parse(encoded.as_bytes()), pairs.to_vec());
  138. }