webidl.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright 2016 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. use {Url, ParseError};
  9. use host::Host;
  10. use idna::domain_to_unicode;
  11. use parser::{Parser, SchemeType, default_port};
  12. /// https://url.spec.whatwg.org/#api
  13. pub struct WebIdl;
  14. impl WebIdl {
  15. /// https://url.spec.whatwg.org/#dom-url-domaintoascii
  16. pub fn domain_to_ascii(domain: &str) -> String {
  17. match Host::parse(domain) {
  18. Ok(Host::Domain(domain)) => domain,
  19. _ => String::new(),
  20. }
  21. }
  22. /// https://url.spec.whatwg.org/#dom-url-domaintounicode
  23. pub fn domain_to_unicode(domain: &str) -> String {
  24. match Host::parse(domain) {
  25. Ok(Host::Domain(ref domain)) => {
  26. let (unicode, _errors) = domain_to_unicode(domain);
  27. unicode
  28. }
  29. _ => String::new(),
  30. }
  31. }
  32. pub fn href(url: &Url) -> &str {
  33. &url.serialization
  34. }
  35. pub fn set_href(url: &mut Url, value: &str) -> Result<(), ParseError> {
  36. *url = try!(Url::parse(value));
  37. Ok(())
  38. }
  39. /// Getter for https://url.spec.whatwg.org/#dom-url-origin
  40. pub fn origin(url: &Url) -> String {
  41. url.origin().unicode_serialization()
  42. }
  43. /// Getter for https://url.spec.whatwg.org/#dom-url-protocol
  44. #[inline]
  45. pub fn protocol(url: &Url) -> &str {
  46. debug_assert!(url.byte_at(url.scheme_end) == b':');
  47. url.slice(..url.scheme_end + 1)
  48. }
  49. /// Setter for https://url.spec.whatwg.org/#dom-url-protocol
  50. pub fn set_protocol(url: &mut Url, new_protocol: &str) {
  51. let _ = url.set_scheme_internal(new_protocol, true);
  52. }
  53. /// Getter for https://url.spec.whatwg.org/#dom-url-username
  54. #[inline]
  55. pub fn username(url: &Url) -> &str {
  56. url.username()
  57. }
  58. /// Setter for https://url.spec.whatwg.org/#dom-url-username
  59. pub fn set_username(url: &mut Url, new_username: &str) {
  60. let _ = url.set_username(new_username);
  61. }
  62. /// Getter for https://url.spec.whatwg.org/#dom-url-password
  63. #[inline]
  64. pub fn password(url: &Url) -> &str {
  65. url.password().unwrap_or("")
  66. }
  67. /// Setter for https://url.spec.whatwg.org/#dom-url-password
  68. pub fn set_password(url: &mut Url, new_password: &str) {
  69. let _ = url.set_password(if new_password.is_empty() { None } else { Some(new_password) });
  70. }
  71. /// Getter for https://url.spec.whatwg.org/#dom-url-host
  72. #[inline]
  73. pub fn host(url: &Url) -> &str {
  74. let host = url.slice(url.host_start..url.path_start);
  75. host
  76. }
  77. /// Setter for https://url.spec.whatwg.org/#dom-url-host
  78. pub fn set_host(url: &mut Url, new_host: &str) {
  79. if url.cannot_be_a_base() {
  80. return
  81. }
  82. let host;
  83. let opt_port;
  84. {
  85. let scheme = url.scheme();
  86. let result = Parser::parse_host(new_host, SchemeType::from(scheme), |_| ());
  87. match result {
  88. Ok((h, remaining)) => {
  89. host = h;
  90. opt_port = if remaining.starts_with(':') {
  91. Parser::parse_port(remaining, |_| (), || default_port(scheme))
  92. .ok().map(|(port, _remaining)| port)
  93. } else {
  94. None
  95. };
  96. }
  97. Err(_) => return
  98. }
  99. }
  100. url.set_host_internal(host, opt_port)
  101. }
  102. /// Getter for https://url.spec.whatwg.org/#dom-url-hostname
  103. #[inline]
  104. pub fn hostname(url: &Url) -> &str {
  105. url.host_str().unwrap_or("")
  106. }
  107. /// Setter for https://url.spec.whatwg.org/#dom-url-hostname
  108. pub fn set_hostname(url: &mut Url, new_hostname: &str) {
  109. if url.cannot_be_a_base() {
  110. return
  111. }
  112. let result = Parser::parse_host(new_hostname, SchemeType::from(url.scheme()), |_| ());
  113. if let Ok((host, _remaining)) = result {
  114. url.set_host_internal(host, None)
  115. }
  116. }
  117. /// Getter for https://url.spec.whatwg.org/#dom-url-port
  118. #[inline]
  119. pub fn port(url: &Url) -> &str {
  120. if url.port.is_some() {
  121. debug_assert!(url.byte_at(url.host_end) == b':');
  122. url.slice(url.host_end + 1..url.path_start)
  123. } else {
  124. ""
  125. }
  126. }
  127. /// Setter for https://url.spec.whatwg.org/#dom-url-port
  128. pub fn set_port(url: &mut Url, new_port: &str) {
  129. let result;
  130. {
  131. // has_host implies !cannot_be_a_base
  132. let scheme = url.scheme();
  133. if !url.has_host() || scheme == "file" {
  134. return
  135. }
  136. result = Parser::parse_port(new_port, |_| (), || default_port(scheme))
  137. }
  138. if let Ok((new_port, _remaining)) = result {
  139. url.set_port_internal(new_port)
  140. }
  141. }
  142. /// Getter for https://url.spec.whatwg.org/#dom-url-pathname
  143. #[inline]
  144. pub fn pathname(url: &Url) -> &str {
  145. url.path()
  146. }
  147. /// Setter for https://url.spec.whatwg.org/#dom-url-pathname
  148. pub fn set_pathname(url: &mut Url, new_pathname: &str) {
  149. if !url.cannot_be_a_base() {
  150. url.set_path(new_pathname)
  151. }
  152. }
  153. /// Getter for https://url.spec.whatwg.org/#dom-url-search
  154. pub fn search(url: &Url) -> &str {
  155. match (url.query_start, url.fragment_start) {
  156. (Some(query_start), None) if {
  157. debug_assert!(url.byte_at(query_start) == b'?');
  158. // If the query (after ?) is not empty
  159. (query_start as usize) < url.serialization.len() - 1
  160. } => url.slice(query_start..),
  161. (Some(query_start), Some(fragment_start)) if {
  162. debug_assert!(url.byte_at(query_start) == b'?');
  163. // If the fragment (after ?) is not empty
  164. query_start < fragment_start
  165. } => url.slice(query_start..fragment_start),
  166. _ => "",
  167. }
  168. }
  169. /// Setter for https://url.spec.whatwg.org/#dom-url-search
  170. pub fn set_search(url: &mut Url, new_search: &str) {
  171. url.set_query(match new_search {
  172. "" => None,
  173. _ if new_search.starts_with('?') => Some(&new_search[1..]),
  174. _ => Some(new_search),
  175. })
  176. }
  177. /// Getter for https://url.spec.whatwg.org/#dom-url-searchparams
  178. pub fn search_params(url: &Url) -> Vec<(String, String)> {
  179. url.query_pairs().unwrap_or_else(Vec::new)
  180. }
  181. /// Getter for https://url.spec.whatwg.org/#dom-url-hash
  182. pub fn hash(url: &Url) -> &str {
  183. match url.fragment_start {
  184. Some(start) if {
  185. debug_assert!(url.byte_at(start) == b'#');
  186. // If the fragment (after #) is not empty
  187. (start as usize) < url.serialization.len() - 1
  188. } => url.slice(start..),
  189. _ => "",
  190. }
  191. }
  192. /// Setter for https://url.spec.whatwg.org/#dom-url-hash
  193. pub fn set_hash(url: &mut Url, new_hash: &str) {
  194. if url.scheme() != "javascript" {
  195. url.set_fragment(match new_hash {
  196. "" => None,
  197. _ if new_hash.starts_with('#') => Some(&new_hash[1..]),
  198. _ => Some(new_hash),
  199. })
  200. }
  201. }
  202. }