form_urlencoded.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright 2013-2014 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::str;
  15. use encoding;
  16. use encoding::EncodingRef;
  17. use encoding::all::UTF_8;
  18. use encoding::label::encoding_from_whatwg_label;
  19. use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};
  20. /// Convert a string in the `application/x-www-form-urlencoded` format
  21. /// into a vector of (name, value) pairs.
  22. #[inline]
  23. pub fn parse_str(input: &str) -> Vec<(String, String)> {
  24. parse_bytes(input.as_bytes(), None, false, 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. /// Arguments:
  30. ///
  31. /// * `encoding_override`: The character encoding each name and values is decoded as
  32. /// after percent-decoding. Defaults to UTF-8.
  33. /// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
  34. /// * `isindex`: The *isindex flag*. If in doubt, set to `false`.
  35. pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
  36. mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
  37. let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
  38. let mut pairs = Vec::new();
  39. for piece in input.split(|&b| b == b'&') {
  40. if piece.is_empty() {
  41. if isindex {
  42. pairs.push((Vec::new(), Vec::new()))
  43. }
  44. } else {
  45. let (name, value) = match piece.position_elem(&b'=') {
  46. Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
  47. None => {
  48. let tmp: (&[u8], &[u8]) = if isindex { (&[], piece) } else { (piece, &[]) };
  49. tmp
  50. }
  51. };
  52. let name = replace_plus(name);
  53. let value = replace_plus(value);
  54. if use_charset && name.as_slice() == b"_charset_" {
  55. // Non-UTF8 here is ok, encoding_from_whatwg_label only matches in the ASCII range.
  56. match encoding_from_whatwg_label(unsafe { str::raw::from_utf8(value.as_slice()) }) {
  57. Some(encoding) => encoding_override = encoding,
  58. None => (),
  59. }
  60. use_charset = false;
  61. }
  62. pairs.push((name, value));
  63. }
  64. isindex = false;
  65. }
  66. if encoding_override.name() != "utf-8" && !input.is_ascii() {
  67. return None
  68. }
  69. #[inline]
  70. fn replace_plus(input: &[u8]) -> Vec<u8> {
  71. input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
  72. }
  73. #[inline]
  74. fn decode(input: Vec<u8>, encoding_override: EncodingRef) -> String {
  75. encoding_override.decode(
  76. percent_decode(input.as_slice()).as_slice(),
  77. encoding::DecodeReplace).unwrap()
  78. }
  79. Some(pairs.move_iter().map(
  80. |(name, value)| (decode(name, encoding_override), decode(value, encoding_override))
  81. ).collect())
  82. }
  83. /// Convert a slice of owned (name, value) pairs
  84. /// into a string in the `application/x-www-form-urlencoded` format.
  85. #[inline]
  86. pub fn serialize_owned(pairs: &[(String, String)]) -> String {
  87. serialize(pairs.iter().map(|&(ref n, ref v)| (n.as_slice(), v.as_slice())), None)
  88. }
  89. /// Convert an iterator of (name, value) pairs
  90. /// into a string in the `application/x-www-form-urlencoded` format.
  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. pub fn serialize<'a, I: Iterator<(&'a str, &'a str)>>(
  97. mut pairs: I, encoding_override: Option<EncodingRef>)
  98. -> String {
  99. #[inline]
  100. fn byte_serialize(input: &str, output: &mut String,
  101. encoding_override: Option<EncodingRef>) {
  102. let keep_alive;
  103. let input = match encoding_override {
  104. None => input.as_bytes(), // "Encode" to UTF-8
  105. Some(encoding) => {
  106. keep_alive = encoding.encode(input, encoding::EncodeNcrEscape).unwrap();
  107. keep_alive.as_slice()
  108. }
  109. };
  110. for &byte in input.iter() {
  111. if byte == b' ' {
  112. output.push_str("+")
  113. } else {
  114. percent_encode_to([byte], FORM_URLENCODED_ENCODE_SET, output)
  115. }
  116. }
  117. }
  118. let mut output = String::new();
  119. for (name, value) in pairs {
  120. if output.len() > 0 {
  121. output.push_str("&");
  122. byte_serialize(name, &mut output, encoding_override);
  123. output.push_str("=");
  124. byte_serialize(value, &mut output, encoding_override);
  125. }
  126. }
  127. output
  128. }