url.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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(macro_rules)];
  11. extern mod encoding;
  12. #[cfg(test)]
  13. extern mod extra;
  14. use std::ascii::Ascii;
  15. use encoding::Encoding;
  16. use encoding::all::UTF_8;
  17. use encoding::label::encoding_from_whatwg_label;
  18. pub mod punycode;
  19. #[cfg(test)]
  20. mod tests;
  21. pub struct URL {
  22. scheme: ~[Ascii],
  23. scheme_data: SchemeData,
  24. query: Option<~[Ascii]>, // parse_form_urlencoded() parses this into ~[(~str, ~str)]
  25. fragment: Option<~[Ascii]>,
  26. }
  27. pub enum SchemeData {
  28. RelativeSchemeData(SchemeRelativeURL),
  29. OtherSchemeData(~[Ascii])
  30. }
  31. pub struct SchemeRelativeURL {
  32. userinfo: Option<UserInfo>,
  33. host: Host,
  34. port: ~[Ascii],
  35. path: ~[~[Ascii]],
  36. }
  37. pub struct UserInfo {
  38. username: ~[Ascii],
  39. password: Option<~[Ascii]>,
  40. }
  41. pub enum Host {
  42. Domain(~[~[Ascii]]),
  43. IPv6(IPv6Address)
  44. }
  45. pub struct IPv6Address {
  46. pieces: [u16, ..8]
  47. }
  48. pub type ParseResult<T> = Result<T, &'static str>;
  49. impl URL {
  50. pub fn parse(input: &str, base_url: Option<URL>) -> Option<URL> {
  51. let _ = input;
  52. let _ = base_url;
  53. // TODO
  54. None
  55. }
  56. pub fn serialize(&self) -> ~[Ascii] {
  57. let mut result = self.serialize_no_fragment();
  58. match self.fragment {
  59. None => (),
  60. Some(ref fragment) => {
  61. result.push('#'.to_ascii());
  62. result.push_all(fragment.as_slice());
  63. }
  64. }
  65. result
  66. }
  67. pub fn serialize_no_fragment(&self) -> ~[Ascii] {
  68. let mut result = self.scheme.to_owned();
  69. result.push(':'.to_ascii());
  70. match self.scheme_data {
  71. RelativeSchemeData(SchemeRelativeURL {
  72. userinfo: ref userinfo, host: ref host, port: ref port, path: ref path
  73. }) => {
  74. result.push_all("//".to_ascii());
  75. match userinfo {
  76. &None => (),
  77. &Some(UserInfo { username: ref username, password: ref password })
  78. => if username.len() > 0 || password.is_some() {
  79. result.push_all(username.as_slice());
  80. match password {
  81. &None => (),
  82. &Some(ref password) => {
  83. result.push(':'.to_ascii());
  84. result.push_all(password.as_slice());
  85. }
  86. }
  87. result.push('@'.to_ascii());
  88. }
  89. }
  90. result.push_all(host.serialize());
  91. if port.len() > 0 {
  92. result.push(':'.to_ascii());
  93. result.push_all(port.as_slice());
  94. }
  95. if path.len() > 0 {
  96. for path_part in path.iter() {
  97. result.push('/'.to_ascii());
  98. result.push_all(path_part.as_slice());
  99. }
  100. } else {
  101. result.push('/'.to_ascii());
  102. }
  103. },
  104. OtherSchemeData(ref data) => result.push_all(data.as_slice()),
  105. }
  106. match self.query {
  107. None => (),
  108. Some(ref query) => {
  109. result.push('?'.to_ascii());
  110. result.push_all(query.as_slice());
  111. }
  112. }
  113. result
  114. }
  115. }
  116. impl Host {
  117. pub fn parse(input: &str) -> ParseResult<Host> {
  118. if input.len() == 0 {
  119. Err("Empty host")
  120. } else if input[0] == '[' as u8 {
  121. if input[input.len()] == ']' as u8 {
  122. match IPv6Address::parse(input.slice(1, input.len() - 1)) {
  123. Some(address) => Ok(IPv6(address)),
  124. None => Err("Invalid IPv6 address"),
  125. }
  126. } else {
  127. Err("Invalid IPv6 address")
  128. }
  129. } else {
  130. let mut percent_encoded = ~[];
  131. utf8_percent_encode(input, SimpleEncodeSet, &mut percent_encoded);
  132. let bytes = percent_decode(percent_encoded);
  133. let decoded = UTF_8.decode(bytes, encoding::DecodeReplace).unwrap();
  134. let mut labels = ~[];
  135. for label in decoded.split_iter(&['.', '\u3002', '\uFF0E', '\uFF61']) {
  136. // TODO: Remove this check and use IDNA "domain to ASCII"
  137. // TODO: switch to .map(domain_label_to_ascii).collect() then.
  138. if label.is_ascii() {
  139. labels.push(unsafe { label.to_ascii_nocheck() }.to_owned())
  140. } else {
  141. return Err("Non-ASCII domains (IDNA) are not supported yet.")
  142. }
  143. }
  144. Ok(Domain(labels))
  145. }
  146. }
  147. pub fn serialize(&self) -> ~[Ascii] {
  148. match *self {
  149. Domain(ref labels) => labels.connect_vec(&'.'.to_ascii()),
  150. IPv6(ref address) => {
  151. let mut result = ~['['.to_ascii()];
  152. result.push_all(address.serialize());
  153. result.push(']'.to_ascii());
  154. result
  155. }
  156. }
  157. }
  158. }
  159. macro_rules! matches(
  160. ($value: expr, ($pattern: pat)|+) => {
  161. match $value {
  162. $($pattern)|+ => true,
  163. _ => false,
  164. }
  165. };
  166. )
  167. impl IPv6Address {
  168. pub fn parse(input: &str) -> Option<IPv6Address> {
  169. let len = input.len();
  170. let mut is_ip_v4 = false;
  171. let mut pieces = [0, 0, 0, 0, 0, 0, 0, 0];
  172. let mut piece_pointer = 0u;
  173. let mut compress_pointer = None;
  174. let mut i = 0u;
  175. if input[0] == ':' as u8 {
  176. if input[1] != ':' as u8 {
  177. return None
  178. }
  179. i = 2;
  180. piece_pointer = 1;
  181. compress_pointer = Some(1u);
  182. }
  183. while i < len {
  184. if piece_pointer == 8 {
  185. return None
  186. }
  187. if input[i] == ':' as u8 {
  188. if compress_pointer.is_some() {
  189. return None
  190. }
  191. piece_pointer += 1;
  192. compress_pointer = Some(piece_pointer);
  193. continue
  194. }
  195. let start = i;
  196. let end = len.min(&(start + 4));
  197. let mut value = 0u16;
  198. while i < end {
  199. match from_hex(input[i]) {
  200. Some(digit) => {
  201. value = value * 0x10 + digit as u16;
  202. i += 1;
  203. },
  204. None => {
  205. if input[i] == 0x2E { // .
  206. if i == start {
  207. return None
  208. }
  209. i = start;
  210. is_ip_v4 = true;
  211. break
  212. }
  213. if input[i] == 0x3A { // :
  214. i += 1;
  215. if i == len {
  216. return None
  217. }
  218. break
  219. }
  220. return None
  221. }
  222. }
  223. }
  224. if is_ip_v4 {
  225. break
  226. }
  227. pieces[piece_pointer] = value;
  228. piece_pointer += 1;
  229. }
  230. if is_ip_v4 {
  231. if piece_pointer > 6 {
  232. return None
  233. }
  234. let mut dots_seen = 0u;
  235. while i < len {
  236. let mut value = 0u16;
  237. while i < len {
  238. let digit = match input[i] {
  239. c @ 0x30 .. 0x39 => c - 0x30, // 0..9
  240. _ => break
  241. };
  242. value = value * 10 + digit as u16;
  243. if value > 255 {
  244. return None
  245. }
  246. }
  247. if dots_seen < 3 && !(i < len && input[i] == '.' as u8) {
  248. return None
  249. }
  250. pieces[piece_pointer] = pieces[piece_pointer] * 0x100 + value;
  251. if dots_seen == 0 || dots_seen == 2 {
  252. piece_pointer += 1;
  253. }
  254. i += 1;
  255. if dots_seen == 3 && i < len {
  256. return None
  257. }
  258. dots_seen += 1;
  259. }
  260. }
  261. match compress_pointer {
  262. Some(compress_pointer) => {
  263. let mut swaps = piece_pointer - compress_pointer;
  264. piece_pointer = 7;
  265. while swaps > 0 {
  266. pieces[piece_pointer] = pieces[compress_pointer + swaps - 1];
  267. pieces[compress_pointer + swaps - 1] = 0;
  268. swaps -= 1;
  269. piece_pointer -= 1;
  270. }
  271. }
  272. _ => if piece_pointer != 8 {
  273. return None
  274. }
  275. }
  276. Some(IPv6Address { pieces: pieces })
  277. }
  278. pub fn serialize(&self) -> ~[Ascii] {
  279. let mut output = ~[];
  280. let (compress_start, compress_end) = longest_zero_sequence(&self.pieces);
  281. let mut i = 0;
  282. while i < 8 {
  283. if i == compress_start {
  284. output.push(':'.to_ascii());
  285. if i == 0 {
  286. output.push(':'.to_ascii());
  287. }
  288. if compress_end < 8 {
  289. i = compress_end;
  290. } else {
  291. break;
  292. }
  293. }
  294. let hex = self.pieces[i].to_str_radix(16);
  295. // No need to check that hex digits are ASCII
  296. output.push_all(unsafe { hex.to_ascii_nocheck() });
  297. if i < 7 {
  298. output.push(':'.to_ascii());
  299. }
  300. }
  301. output
  302. }
  303. }
  304. fn longest_zero_sequence(pieces: &[u16, ..8]) -> (int, int) {
  305. let mut longest = -1;
  306. let mut longest_length = -1;
  307. let mut start = -1;
  308. macro_rules! finish_sequence(
  309. ($end: expr) => {
  310. if start >= 0 {
  311. let length = $end - start;
  312. if length > longest_length {
  313. longest = start;
  314. longest_length = length;
  315. }
  316. }
  317. };
  318. );
  319. for i in range(0, 8) {
  320. if pieces[i] == 0 {
  321. if start < 0 {
  322. start = i;
  323. }
  324. } else {
  325. finish_sequence!(i);
  326. start = -1;
  327. }
  328. }
  329. finish_sequence!(8);
  330. (longest, longest + longest_length)
  331. }
  332. #[inline]
  333. fn from_hex(byte: u8) -> Option<u8> {
  334. match byte {
  335. 0x30 .. 0x39 => Some(byte - 0x30), // 0..9
  336. 0x41 .. 0x46 => Some(byte + 10 - 0x41), // A..F
  337. 0x61 .. 0x66 => Some(byte + 10 - 0x61), // a..f
  338. _ => None
  339. }
  340. }
  341. #[inline]
  342. fn to_hex_upper(value: u8) -> Ascii {
  343. let digit = match value {
  344. 0 .. 9 => value + 0x30,
  345. 10 .. 15 => value - 10 + 0x41,
  346. _ => fail!()
  347. };
  348. unsafe { digit.to_ascii_nocheck() }
  349. }
  350. enum EncodeSet {
  351. SimpleEncodeSet,
  352. DefaultEncodeSet,
  353. PasswordEncodeSet,
  354. UsernameEncodeSet
  355. }
  356. #[inline]
  357. fn utf8_percent_encode(input: &str, encode_set: EncodeSet, output: &mut ~[Ascii]) {
  358. use Default = self::DefaultEncodeSet;
  359. use Password = self::PasswordEncodeSet;
  360. use Username = self::UsernameEncodeSet;
  361. for &byte in input.as_bytes().iter() {
  362. if byte < 0x20 || byte > 0x7E || match byte as char {
  363. ' ' | '"' | '#' | '<' | '>' | '?' | '`'
  364. => match encode_set { Default | Password | Username => true, _ => false },
  365. '/' | '@' | '\\'
  366. => match encode_set { Password | Username => true, _ => false },
  367. ':'
  368. => match encode_set { Username => true, _ => false },
  369. _ => false,
  370. } {
  371. percent_encode_byte(byte, output)
  372. } else {
  373. output.push(unsafe { byte.to_ascii_nocheck() }) // Already checked
  374. }
  375. }
  376. }
  377. #[inline]
  378. fn percent_encode_byte(byte: u8, output: &mut ~[Ascii]) {
  379. output.push_all(['%'.to_ascii(), to_hex_upper(byte >> 4), to_hex_upper(byte & 0x0F)])
  380. }
  381. #[inline]
  382. fn percent_decode(input: &[Ascii]) -> ~[u8] {
  383. let mut output = ~[];
  384. let mut i = 0u;
  385. while i < input.len() {
  386. let c = input[i];
  387. if c == '%'.to_ascii() && i + 2 < input.len() {
  388. match (from_hex(input[i + 1].to_byte()),
  389. from_hex(input[i + 2].to_byte())) {
  390. (Some(h), Some(l)) => {
  391. output.push(h * 0x10 + l);
  392. i += 3;
  393. continue
  394. },
  395. _ => (),
  396. }
  397. }
  398. output.push(c.to_byte());
  399. i += 1;
  400. }
  401. output
  402. }
  403. pub fn parse_form_urlencoded(input: &[Ascii],
  404. encoding_override: Option<&'static Encoding>,
  405. use_charset: bool,
  406. mut isindex: bool)
  407. -> ~[(~str, ~str)] {
  408. let mut encoding_override = encoding_override.unwrap_or(UTF_8 as &'static Encoding);
  409. let mut pairs = ~[];
  410. for string in input.split_iter(|&c| c == '&'.to_ascii()) {
  411. if string.len() > 0 {
  412. let (name, value) = match string.position_elem(&'='.to_ascii()) {
  413. Some(position) => (string.slice_to(position), string.slice_from(position + 1)),
  414. None => if isindex { (&[], string) } else { (string, &[]) }
  415. };
  416. let name = name.to_str_ascii().replace("+", " ");
  417. let value = value.to_str_ascii().replace("+", " ");
  418. if use_charset && name.as_slice() == "_charset_" {
  419. match encoding_from_whatwg_label(value) {
  420. Some(encoding) => encoding_override = encoding,
  421. None => (),
  422. }
  423. }
  424. pairs.push((name, value));
  425. }
  426. isindex = false;
  427. }
  428. #[inline]
  429. fn decode(input: &~str, encoding_override: &'static Encoding) -> ~str {
  430. // No need to check as input comes from &[Ascii].to_str_ascii().replace("+", " ")
  431. let bytes = percent_decode(unsafe { input.as_slice().to_ascii_nocheck() });
  432. encoding_override.decode(bytes, encoding::DecodeReplace).unwrap()
  433. }
  434. for pair in pairs.mut_iter() {
  435. let new_pair = {
  436. let &(ref name, ref value) = pair;
  437. (decode(name, encoding_override), decode(value, encoding_override))
  438. };
  439. *pair = new_pair;
  440. }
  441. pairs
  442. }
  443. pub fn serialize_form_urlencoded(pairs: ~[(~str, ~str)],
  444. encoding_override: Option<&'static Encoding>)
  445. -> ~[Ascii] {
  446. #[inline]
  447. fn byte_serialize(input: &str, output: &mut ~[Ascii],
  448. encoding_override: Option<&'static Encoding>) {
  449. let keep_alive;
  450. let input = match encoding_override {
  451. None => input.as_bytes(), // "Encode" to UTF-8
  452. Some(encoding) => {
  453. keep_alive = encoding.encode(input, encoding::EncodeNcrEscape).unwrap();
  454. keep_alive.as_slice()
  455. }
  456. };
  457. for byte in input.iter() {
  458. match *byte {
  459. 0x20 => output.push('+'.to_ascii()),
  460. 0x2A | 0x2D | 0x2E | 0x30 .. 0x39 | 0x41 .. 0x5A | 0x5F | 0x61 .. 0x7A
  461. => output.push(unsafe { byte.to_ascii_nocheck() }),
  462. _ => percent_encode_byte(*byte, output),
  463. }
  464. }
  465. }
  466. let mut output = ~[];
  467. for &(ref name, ref value) in pairs.iter() {
  468. if output.len() > 0 {
  469. output.push('&'.to_ascii());
  470. byte_serialize(name.as_slice(), &mut output, encoding_override);
  471. output.push('='.to_ascii());
  472. byte_serialize(value.as_slice(), &mut output, encoding_override);
  473. }
  474. }
  475. output
  476. }