urlutils.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. //! These methods are not meant for use in Rust code,
  9. //! only to help implement the JavaScript URLUtils API: http://url.spec.whatwg.org/#urlutils
  10. use super::{Url, UrlParser, SchemeType, SchemeData, RelativeSchemeData};
  11. use parser::{ParseError, ParseResult, Context};
  12. use percent_encoding::{utf8_percent_encode_to, USERNAME_ENCODE_SET, PASSWORD_ENCODE_SET};
  13. #[allow(dead_code)]
  14. struct UrlUtilsWrapper<'a> {
  15. url: &'a mut Url,
  16. parser: &'a UrlParser<'a>,
  17. }
  18. #[doc(hidden)]
  19. trait UrlUtils {
  20. fn set_scheme(&mut self, input: &str) -> ParseResult<()>;
  21. fn set_username(&mut self, input: &str) -> ParseResult<()>;
  22. fn set_password(&mut self, input: &str) -> ParseResult<()>;
  23. fn set_host_and_port(&mut self, input: &str) -> ParseResult<()>;
  24. fn set_host(&mut self, input: &str) -> ParseResult<()>;
  25. fn set_port(&mut self, input: &str) -> ParseResult<()>;
  26. fn set_path(&mut self, input: &str) -> ParseResult<()>;
  27. fn set_query(&mut self, input: &str) -> ParseResult<()>;
  28. fn set_fragment(&mut self, input: &str) -> ParseResult<()>;
  29. }
  30. impl<'a> UrlUtils for UrlUtilsWrapper<'a> {
  31. /// `URLUtils.protocol` setter
  32. fn set_scheme(&mut self, input: &str) -> ParseResult<()> {
  33. match ::parser::parse_scheme(input.as_slice(), Context::Setter) {
  34. Some((scheme, _)) => {
  35. self.url.scheme = scheme;
  36. Ok(())
  37. },
  38. None => Err(ParseError::InvalidScheme),
  39. }
  40. }
  41. /// `URLUtils.username` setter
  42. fn set_username(&mut self, input: &str) -> ParseResult<()> {
  43. match self.url.scheme_data {
  44. SchemeData::Relative(RelativeSchemeData { ref mut username, .. }) => {
  45. username.truncate(0);
  46. utf8_percent_encode_to(input, USERNAME_ENCODE_SET, username);
  47. Ok(())
  48. },
  49. SchemeData::NonRelative(_) => Err(ParseError::CannotSetUsernameWithNonRelativeScheme)
  50. }
  51. }
  52. /// `URLUtils.password` setter
  53. fn set_password(&mut self, input: &str) -> ParseResult<()> {
  54. match self.url.scheme_data {
  55. SchemeData::Relative(RelativeSchemeData { ref mut password, .. }) => {
  56. let mut new_password = String::new();
  57. utf8_percent_encode_to(input, PASSWORD_ENCODE_SET, &mut new_password);
  58. *password = Some(new_password);
  59. Ok(())
  60. },
  61. SchemeData::NonRelative(_) => Err(ParseError::CannotSetPasswordWithNonRelativeScheme)
  62. }
  63. }
  64. /// `URLUtils.host` setter
  65. fn set_host_and_port(&mut self, input: &str) -> ParseResult<()> {
  66. match self.url.scheme_data {
  67. SchemeData::Relative(RelativeSchemeData {
  68. ref mut host, ref mut port, ref mut default_port, ..
  69. }) => {
  70. let scheme_type = self.parser.get_scheme_type(self.url.scheme.as_slice());
  71. let (new_host, new_port, new_default_port, _) = try!(::parser::parse_host(
  72. input, scheme_type, self.parser));
  73. *host = new_host;
  74. *port = new_port;
  75. *default_port = new_default_port;
  76. Ok(())
  77. },
  78. SchemeData::NonRelative(_) => Err(ParseError::CannotSetHostPortWithNonRelativeScheme)
  79. }
  80. }
  81. /// `URLUtils.hostname` setter
  82. fn set_host(&mut self, input: &str) -> ParseResult<()> {
  83. match self.url.scheme_data {
  84. SchemeData::Relative(RelativeSchemeData { ref mut host, .. }) => {
  85. let (new_host, _) = try!(::parser::parse_hostname(input, self.parser));
  86. *host = new_host;
  87. Ok(())
  88. },
  89. SchemeData::NonRelative(_) => Err(ParseError::CannotSetHostWithNonRelativeScheme)
  90. }
  91. }
  92. /// `URLUtils.port` setter
  93. fn set_port(&mut self, input: &str) -> ParseResult<()> {
  94. match self.url.scheme_data {
  95. SchemeData::Relative(RelativeSchemeData { ref mut port, ref mut default_port, .. }) => {
  96. let scheme_type = self.parser.get_scheme_type(self.url.scheme.as_slice());
  97. if scheme_type == SchemeType::FileLike {
  98. return Err(ParseError::CannotSetPortWithFileLikeScheme);
  99. }
  100. let (new_port, new_default_port, _) = try!(::parser::parse_port(
  101. input, scheme_type, self.parser));
  102. *port = new_port;
  103. *default_port = new_default_port;
  104. Ok(())
  105. },
  106. SchemeData::NonRelative(_) => Err(ParseError::CannotSetPortWithNonRelativeScheme)
  107. }
  108. }
  109. /// `URLUtils.pathname` setter
  110. fn set_path(&mut self, input: &str) -> ParseResult<()> {
  111. match self.url.scheme_data {
  112. SchemeData::Relative(RelativeSchemeData { ref mut path, .. }) => {
  113. let scheme_type = self.parser.get_scheme_type(self.url.scheme.as_slice());
  114. let (new_path, _) = try!(::parser::parse_path_start(
  115. input, Context::Setter, scheme_type, self.parser));
  116. *path = new_path;
  117. Ok(())
  118. },
  119. SchemeData::NonRelative(_) => Err(ParseError::CannotSetPathWithNonRelativeScheme)
  120. }
  121. }
  122. /// `URLUtils.search` setter
  123. fn set_query(&mut self, input: &str) -> ParseResult<()> {
  124. self.url.query = if input.is_empty() {
  125. None
  126. } else {
  127. let input = if input.starts_with("?") { &input[1..] } else { input };
  128. let (new_query, _) = try!(::parser::parse_query(
  129. input, Context::Setter, self.parser));
  130. Some(new_query)
  131. };
  132. Ok(())
  133. }
  134. /// `URLUtils.hash` setter
  135. fn set_fragment(&mut self, input: &str) -> ParseResult<()> {
  136. if self.url.scheme.as_slice() == "javascript" {
  137. return Err(ParseError::CannotSetJavascriptFragment)
  138. }
  139. self.url.fragment = if input.is_empty() {
  140. None
  141. } else {
  142. let input = if input.starts_with("#") { &input[1..] } else { input };
  143. Some(try!(::parser::parse_fragment(input, self.parser)))
  144. };
  145. Ok(())
  146. }
  147. }