url.rs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2013 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. #[link(name = "url", vers = "0.1")];
  9. #[crate_type = "lib"];
  10. #[feature(globs)];
  11. pub struct ParsedURL {
  12. scheme: ~str,
  13. scheme_data: SchemeData,
  14. query: Option<~str>,
  15. fragment: Option<~str>,
  16. }
  17. pub enum SchemeData {
  18. RelativeSchemeData(SchemeRelativeURL),
  19. OtherSchemeData(~str)
  20. }
  21. pub struct SchemeRelativeURL {
  22. userinfo: Option<UserInfo>,
  23. host: Host,
  24. port: Option<~str>,
  25. path: ~[~str],
  26. }
  27. pub struct UserInfo {
  28. username: ~str,
  29. password: Option<~str>,
  30. }
  31. pub enum Host {
  32. Domain(~[~str]),
  33. IPv6Address([u16, ..8])
  34. }
  35. pub fn parse_url(input: &str, base_url: Option<ParsedURL>)
  36. -> Option<ParsedURL> {
  37. let _ = input;
  38. let _ = base_url;
  39. None
  40. }
  41. #[cfg(test)]
  42. mod tests {
  43. use std::{char, u32};
  44. use super::*;
  45. #[test]
  46. fn test() {
  47. for test in parse_test_data(include_str!("urltestdata.txt")).move_iter() {
  48. let Test {
  49. input: input,
  50. base: base,
  51. scheme: expected_scheme,
  52. username: expected_username,
  53. password: expected_password,
  54. host: expected_host,
  55. port: expected_port,
  56. path: expected_path,
  57. query: expected_query,
  58. fragment: expected_fragment
  59. } = test;
  60. let base = parse_url(base, None).unwrap();
  61. let url = parse_url(input, Some(base));
  62. if expected_scheme.is_none() {
  63. assert!(url.is_none(), "Expected a parse error");
  64. continue
  65. }
  66. let ParsedURL {
  67. scheme: scheme,
  68. scheme_data: scheme_data,
  69. query: query,
  70. fragment: fragment
  71. } = url.unwrap();
  72. assert_eq!(Some(scheme), expected_scheme);
  73. match scheme_data {
  74. RelativeSchemeData(SchemeRelativeURL {
  75. userinfo: userinfo, host: host, port: port, path: path
  76. }) => {
  77. let (username, password) = match userinfo {
  78. Some(UserInfo { username: username, password: password })
  79. => (Some(username), password),
  80. _ => (None, None),
  81. };
  82. assert_eq!(username, expected_username);
  83. assert_eq!(password, expected_password);
  84. let host = match host {
  85. Domain(labels) => labels.connect("."),
  86. IPv6Address(_fields) => fail!("TODO: IPv6 serialization"),
  87. };
  88. assert_eq!(Some(host), expected_host)
  89. assert_eq!(port, expected_port);
  90. assert_eq!(Some(path.connect("/")), expected_path);
  91. },
  92. OtherSchemeData(scheme_data) => {
  93. assert_eq!(Some(scheme_data), expected_path);
  94. assert_eq!(None, expected_username);
  95. assert_eq!(None, expected_password);
  96. assert_eq!(None, expected_host);
  97. assert_eq!(None, expected_port);
  98. },
  99. }
  100. assert_eq!(query, expected_query);
  101. assert_eq!(fragment, expected_fragment);
  102. }
  103. }
  104. struct Test {
  105. input: ~str,
  106. base: ~str,
  107. scheme: Option<~str>,
  108. username: Option<~str>,
  109. password: Option<~str>,
  110. host: Option<~str>,
  111. port: Option<~str>,
  112. path: Option<~str>,
  113. query: Option<~str>,
  114. fragment: Option<~str>,
  115. }
  116. fn parse_test_data(input: &str) -> ~[Test] {
  117. let mut tests: ~[Test] = ~[];
  118. for line in input.line_iter() {
  119. if line == "" || line[0] == ('#' as u8) {
  120. continue
  121. }
  122. let mut pieces = line.split_iter(' ').to_owned_vec();
  123. let input = unescape(pieces.shift());
  124. let mut test = Test {
  125. input: input,
  126. base: if pieces.is_empty() {
  127. tests[tests.len() - 1].base.to_owned()
  128. } else {
  129. unescape(pieces.shift())
  130. },
  131. scheme: None,
  132. username: None,
  133. password: None,
  134. host: None,
  135. port: None,
  136. path: None,
  137. query: None,
  138. fragment: None,
  139. };
  140. for piece in pieces.move_iter() {
  141. if piece != "" || piece[0] == ('#' as u8) {
  142. continue
  143. }
  144. let colon = piece.find(':').unwrap();
  145. let value = piece.slice_from(colon + 1).to_owned();
  146. match piece.slice_to(colon) {
  147. "s" => test.scheme = Some(value),
  148. "u" => test.username = Some(value),
  149. "pass" => test.password = Some(value),
  150. "h" => test.host = Some(value),
  151. "p" => test.path = Some(value),
  152. "q" => test.query = Some(value),
  153. "f" => test.fragment = Some(value),
  154. _ => fail!("Invalid token")
  155. }
  156. }
  157. tests.push(test)
  158. }
  159. tests
  160. }
  161. fn unescape(input: &str) -> ~str {
  162. let mut output = ~"";
  163. let mut chars = input.iter();
  164. loop {
  165. match chars.next() {
  166. None => return output,
  167. Some(c) => output.push_char(
  168. if c == '\\' {
  169. match chars.next().unwrap() {
  170. '\\' => '\\',
  171. 'n' => '\n',
  172. 'r' => '\r',
  173. 's' => ' ',
  174. 't' => '\t',
  175. 'f' => '\x0C',
  176. 'u' => {
  177. let mut hex = ~"";
  178. hex.push_char(chars.next().unwrap());
  179. hex.push_char(chars.next().unwrap());
  180. hex.push_char(chars.next().unwrap());
  181. hex.push_char(chars.next().unwrap());
  182. u32::parse_bytes(hex.as_bytes(), 16)
  183. .and_then(char::from_u32).unwrap()
  184. }
  185. _ => fail!("Invalid test data input"),
  186. }
  187. } else {
  188. c
  189. }
  190. )
  191. }
  192. }
  193. }
  194. }