form_urlencoded.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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 `application/x-www-form-urlencoded`
  9. ///
  10. /// Converts between a string (such as an URL’s query string)
  11. /// and a list of name/value pairs.
  12. use std::str;
  13. use encoding;
  14. use encoding::EncodingRef;
  15. use encoding::all::UTF_8;
  16. use encoding::label::encoding_from_whatwg_label;
  17. use super::{percent_encode_byte, percent_decode};
  18. pub fn parse_str(input: &str) -> Vec<(String, String)> {
  19. parse_bytes(input.as_bytes(), None, false, false).unwrap()
  20. }
  21. pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
  22. mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
  23. let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
  24. let mut pairs = Vec::new();
  25. for piece in input.split(|&b| b == '&' as u8) {
  26. if piece.is_empty() {
  27. if isindex {
  28. pairs.push((Vec::new(), Vec::new()))
  29. }
  30. } else {
  31. let (name, value) = match piece.position_elem(&('=' as u8)) {
  32. Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
  33. None => if isindex { (&[], piece) } else { (piece, &[]) }
  34. };
  35. let name = replace_plus(name);
  36. let value = replace_plus(value);
  37. if use_charset && name.as_slice() == "_charset_".as_bytes() {
  38. // Non-UTF8 here is ok, encoding_from_whatwg_label only matches in the ASCII range.
  39. match encoding_from_whatwg_label(unsafe { str::raw::from_utf8(value.as_slice()) }) {
  40. Some(encoding) => encoding_override = encoding,
  41. None => (),
  42. }
  43. use_charset = false;
  44. }
  45. pairs.push((name, value));
  46. }
  47. isindex = false;
  48. }
  49. if encoding_override.name() != "utf-8" && !input.is_ascii() {
  50. return None
  51. }
  52. #[inline]
  53. fn replace_plus(input: &[u8]) -> Vec<u8> {
  54. input.iter().map(|&b| if b == '+' as u8 { ' ' as u8 } else { b }).collect()
  55. }
  56. #[inline]
  57. fn decode(input: Vec<u8>, encoding_override: EncodingRef) -> String {
  58. let bytes = percent_decode(input.as_slice());
  59. encoding_override.decode(bytes.as_slice(), encoding::DecodeReplace).unwrap()
  60. }
  61. Some(pairs.move_iter().map(
  62. |(name, value)| (decode(name, encoding_override), decode(value, encoding_override))
  63. ).collect())
  64. }
  65. pub fn serialize(pairs: Vec<(String, String)>, encoding_override: Option<EncodingRef>) -> String {
  66. #[inline]
  67. fn byte_serialize(input: &str, output: &mut String,
  68. encoding_override: Option<EncodingRef>) {
  69. let keep_alive;
  70. let input = match encoding_override {
  71. None => input.as_bytes(), // "Encode" to UTF-8
  72. Some(encoding) => {
  73. keep_alive = encoding.encode(input, encoding::EncodeNcrEscape).unwrap();
  74. keep_alive.as_slice()
  75. }
  76. };
  77. for &byte in input.iter() {
  78. match byte {
  79. 0x20 => output.push_str("+"),
  80. 0x2A | 0x2D | 0x2E | 0x30 .. 0x39 | 0x41 .. 0x5A | 0x5F | 0x61 .. 0x7A
  81. => unsafe { output.push_byte(byte) },
  82. _ => percent_encode_byte(byte, output),
  83. }
  84. }
  85. }
  86. let mut output = String::new();
  87. for &(ref name, ref value) in pairs.iter() {
  88. if output.len() > 0 {
  89. output.push_str("&");
  90. byte_serialize(name.as_slice(), &mut output, encoding_override);
  91. output.push_str("=");
  92. byte_serialize(value.as_slice(), &mut output, encoding_override);
  93. }
  94. }
  95. output
  96. }