percent_encoding.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. #[path = "encode_sets.rs"]
  9. mod encode_sets;
  10. /// Represents a set of characters / bytes that should be percent-encoded.
  11. ///
  12. /// See [encode sets specification](http://url.spec.whatwg.org/#simple-encode-set).
  13. ///
  14. /// Different characters need to be encoded in different parts of an URL.
  15. /// For example, a literal `?` question mark in an URL’s path would indicate
  16. /// the start of the query string.
  17. /// A question mark meant to be part of the path therefore needs to be percent-encoded.
  18. /// In the query string however, a question mark does not have any special meaning
  19. /// and does not need to be percent-encoded.
  20. ///
  21. /// Since the implementation details of `EncodeSet` are private,
  22. /// the set of available encode sets is not extensible beyond the ones
  23. /// provided here.
  24. /// If you need a different encode set,
  25. /// please [file a bug](https://github.com/servo/rust-url/issues)
  26. /// explaining the use case.
  27. pub struct EncodeSet {
  28. map: &'static [&'static str, ..256],
  29. }
  30. /// This encode set is used for fragment identifier and non-relative scheme data.
  31. pub static SIMPLE_ENCODE_SET: EncodeSet = EncodeSet { map: &encode_sets::SIMPLE };
  32. /// This encode set is used in the URL parser for query strings.
  33. pub static QUERY_ENCODE_SET: EncodeSet = EncodeSet { map: &encode_sets::QUERY };
  34. /// This encode set is used for path components.
  35. pub static DEFAULT_ENCODE_SET: EncodeSet = EncodeSet { map: &encode_sets::DEFAULT };
  36. /// This encode set is used in the URL parser for usernames and passwords.
  37. pub static USERINFO_ENCODE_SET: EncodeSet = EncodeSet { map: &encode_sets::USERINFO };
  38. /// This encode set should be used when setting the password field of a parsed URL.
  39. pub static PASSWORD_ENCODE_SET: EncodeSet = EncodeSet { map: &encode_sets::PASSWORD };
  40. /// This encode set should be used when setting the username field of a parsed URL.
  41. pub static USERNAME_ENCODE_SET: EncodeSet = EncodeSet { map: &encode_sets::USERNAME };
  42. /// This encode set is used in `application/x-www-form-urlencoded` serialization.
  43. pub static FORM_URLENCODED_ENCODE_SET: EncodeSet = EncodeSet {
  44. map: &encode_sets::FORM_URLENCODED,
  45. };
  46. /// Percent-encode the given bytes, and push the result to `output`.
  47. ///
  48. /// The pushed strings are within the ASCII range.
  49. #[inline]
  50. pub fn percent_encode_to(input: &[u8], encode_set: EncodeSet, output: &mut String) {
  51. for &byte in input.iter() {
  52. output.push_str(encode_set.map[byte as uint])
  53. }
  54. }
  55. /// Percent-encode the given bytes.
  56. ///
  57. /// The returned string is within the ASCII range.
  58. #[inline]
  59. pub fn percent_encode(input: &[u8], encode_set: EncodeSet) -> String {
  60. let mut output = String::new();
  61. percent_encode_to(input, encode_set, &mut output);
  62. output
  63. }
  64. /// Percent-encode the UTF-8 encoding of the given string, and push the result to `output`.
  65. ///
  66. /// The pushed strings are within the ASCII range.
  67. #[inline]
  68. pub fn utf8_percent_encode_to(input: &str, encode_set: EncodeSet, output: &mut String) {
  69. percent_encode_to(input.as_bytes(), encode_set, output)
  70. }
  71. /// Percent-encode the UTF-8 encoding of the given string.
  72. ///
  73. /// The returned string is within the ASCII range.
  74. #[inline]
  75. pub fn utf8_percent_encode(input: &str, encode_set: EncodeSet) -> String {
  76. let mut output = String::new();
  77. utf8_percent_encode_to(input, encode_set, &mut output);
  78. output
  79. }
  80. /// Percent-decode the given bytes, and push the result to `output`.
  81. pub fn percent_decode_to(input: &[u8], output: &mut Vec<u8>) {
  82. let mut i = 0u;
  83. while i < input.len() {
  84. let c = input[i];
  85. if c == b'%' && i + 2 < input.len() {
  86. match (from_hex(input[i + 1]), from_hex(input[i + 2])) {
  87. (Some(h), Some(l)) => {
  88. output.push(h * 0x10 + l);
  89. i += 3;
  90. continue
  91. },
  92. _ => (),
  93. }
  94. }
  95. output.push(c);
  96. i += 1;
  97. }
  98. }
  99. /// Percent-decode the given bytes.
  100. #[inline]
  101. pub fn percent_decode(input: &[u8]) -> Vec<u8> {
  102. let mut output = Vec::new();
  103. percent_decode_to(input, &mut output);
  104. output
  105. }
  106. /// Percent-decode the given bytes, and decode the result as UTF-8.
  107. ///
  108. /// This is “lossy”: invalid UTF-8 percent-encoded byte sequences
  109. /// will be replaced � U+FFFD, the replacement character.
  110. #[inline]
  111. pub fn lossy_utf8_percent_decode(input: &[u8]) -> String {
  112. String::from_utf8_lossy(percent_decode(input).as_slice()).into_string()
  113. }
  114. #[inline]
  115. pub fn from_hex(byte: u8) -> Option<u8> {
  116. match byte {
  117. b'0' .. b'9' => Some(byte - b'0'), // 0..9
  118. b'A' .. b'F' => Some(byte + 10 - b'A'), // A..F
  119. b'a' .. b'f' => Some(byte + 10 - b'a'), // a..f
  120. _ => None
  121. }
  122. }