form_urlencoded.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. ///
  23. /// The names and values are URL-decoded. For instance, `%23first=%25try%25` will be
  24. /// converted to `[("#first", "%try%")]`.
  25. #[inline]
  26. pub fn parse(input: &[u8]) -> Vec<(String, String)> {
  27. parse_internal(input, EncodingOverride::utf8(), false).unwrap()
  28. }
  29. /// Convert a byte string in the `application/x-www-form-urlencoded` format
  30. /// into a vector of (name, value) pairs.
  31. ///
  32. /// Use `parse(input.as_bytes())` to parse a `&str` string.
  33. ///
  34. /// This function is only available if the `query_encoding` Cargo feature is enabled.
  35. ///
  36. /// Arguments:
  37. ///
  38. /// * `encoding_override`: The character encoding each name and values is decoded as
  39. /// after percent-decoding. Defaults to UTF-8.
  40. /// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
  41. #[cfg(feature = "query_encoding")]
  42. #[inline]
  43. pub fn parse_with_encoding(input: &[u8], encoding_override: Option<::encoding::EncodingRef>,
  44. use_charset: bool)
  45. -> Option<Vec<(String, String)>> {
  46. parse_internal(input, EncodingOverride::from_opt_encoding(encoding_override), use_charset)
  47. }
  48. fn parse_internal(input: &[u8], mut encoding_override: EncodingOverride, mut use_charset: bool)
  49. -> Option<Vec<(String, String)>> {
  50. let mut pairs = Vec::new();
  51. for piece in input.split(|&b| b == b'&') {
  52. if !piece.is_empty() {
  53. let (name, value) = match piece.iter().position(|b| *b == b'=') {
  54. Some(position) => (&piece[..position], &piece[position + 1..]),
  55. None => (piece, &[][..])
  56. };
  57. #[inline]
  58. fn replace_plus(input: &[u8]) -> Vec<u8> {
  59. input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
  60. }
  61. let name = replace_plus(name);
  62. let value = replace_plus(value);
  63. if use_charset && name == b"_charset_" {
  64. if let Some(encoding) = EncodingOverride::lookup(&value) {
  65. encoding_override = encoding;
  66. }
  67. use_charset = false;
  68. }
  69. pairs.push((name, value));
  70. }
  71. }
  72. if !(encoding_override.is_utf8() || input.is_ascii()) {
  73. return None
  74. }
  75. Some(pairs.into_iter().map(|(name, value)| (
  76. encoding_override.decode(&percent_decode(&name)),
  77. encoding_override.decode(&percent_decode(&value))
  78. )).collect())
  79. }
  80. /// Convert an iterator of (name, value) pairs
  81. /// into a string in the `application/x-www-form-urlencoded` format.
  82. #[inline]
  83. pub fn serialize<I, K, V>(pairs: I) -> String
  84. where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
  85. serialize_internal(pairs, EncodingOverride::utf8())
  86. }
  87. /// Convert an iterator of (name, value) pairs
  88. /// into a string in the `application/x-www-form-urlencoded` format.
  89. ///
  90. /// This function is only available if the `query_encoding` Cargo feature is enabled.
  91. ///
  92. /// Arguments:
  93. ///
  94. /// * `encoding_override`: The character encoding each name and values is encoded as
  95. /// before percent-encoding. Defaults to UTF-8.
  96. #[cfg(feature = "query_encoding")]
  97. #[inline]
  98. pub fn serialize_with_encoding<I, K, V>(pairs: I,
  99. encoding_override: Option<::encoding::EncodingRef>)
  100. -> String
  101. where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
  102. serialize_internal(pairs, EncodingOverride::from_opt_encoding(encoding_override))
  103. }
  104. fn serialize_internal<I, K, V>(pairs: I, encoding_override: EncodingOverride) -> String
  105. where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<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 pair in pairs {
  119. let &(ref name, ref value) = pair.borrow();
  120. if output.len() > 0 {
  121. output.push_str("&");
  122. }
  123. byte_serialize(name.as_ref(), &mut output, encoding_override);
  124. output.push_str("=");
  125. byte_serialize(value.as_ref(), &mut output, encoding_override);
  126. }
  127. output
  128. }