Просмотр исходного кода

Auto merge of #404 - valenting:ipv6_parser, r=SimonSapin

Update IPv6 parser

The IPv6 parser is updated to match the latest version of the spec.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-url/404)
<!-- Reviewable:end -->
bors-servo 9 лет назад
Родитель
Сommit
67367e98da
2 измененных файлов с 49 добавлено и 14 удалено
  1. 29 14
      src/host.rs
  2. 20 0
      tests/urltestdata.json

+ 29 - 14
src/host.rs

@@ -423,6 +423,9 @@ fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> {
                         return Err(ParseError::InvalidIpv6Address)
                     }
                     i = start;
+                    if piece_pointer > 6 {
+                        return Err(ParseError::InvalidIpv6Address)
+                    }
                     is_ip_v4 = true;
                 },
                 b':' => {
@@ -445,16 +448,24 @@ fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> {
         if piece_pointer > 6 {
             return Err(ParseError::InvalidIpv6Address)
         }
-        let mut dots_seen = 0;
+        let mut numbers_seen = 0;
         while i < len {
-            let mut value = None;
+            if numbers_seen > 0 {
+                if numbers_seen < 4 && (i < len && input[i] == b'.') {
+                    i += 1
+                } else {
+                    return Err(ParseError::InvalidIpv6Address)
+                }
+            }
+
+            let mut ipv4_piece = None;
             while i < len {
                 let digit = match input[i] {
                     c @ b'0' ... b'9' => c - b'0',
                     _ => break
                 };
-                match value {
-                    None => value = Some(digit as u16),
+                match ipv4_piece {
+                    None => ipv4_piece = Some(digit as u16),
                     Some(0) => return Err(ParseError::InvalidIpv6Address),  // No leading zero
                     Some(ref mut v) => {
                         *v = *v * 10 + digit as u16;
@@ -465,24 +476,28 @@ fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> {
                 }
                 i += 1;
             }
-            if dots_seen < 3 && !(i < len && input[i] == b'.') {
-                return Err(ParseError::InvalidIpv6Address)
-            }
-            pieces[piece_pointer] = if let Some(v) = value {
+
+            pieces[piece_pointer] = if let Some(v) = ipv4_piece {
                 pieces[piece_pointer] * 0x100 + v
             } else {
                 return Err(ParseError::InvalidIpv6Address)
             };
-            if dots_seen == 1 || dots_seen == 3 {
+            numbers_seen += 1;
+
+            if numbers_seen == 2 || numbers_seen == 4 {
                 piece_pointer += 1;
             }
-            i += 1;
-            if dots_seen == 3 && i < len {
-                return Err(ParseError::InvalidIpv6Address)
-            }
-            dots_seen += 1;
+        }
+
+        if numbers_seen != 4 {
+            return Err(ParseError::InvalidIpv6Address)
         }
     }
+
+    if i < len {
+        return Err(ParseError::InvalidIpv6Address)
+    }
+
     match compress_pointer {
         Some(compress_pointer) => {
             let mut swaps = piece_pointer - compress_pointer;

+ 20 - 0
tests/urltestdata.json

@@ -3634,6 +3634,26 @@
     "base": "http://other.com/",
     "failure": true
   },
+  {
+    "input": "http://[::1.2.3.4x]",
+    "base": "http://other.com/",
+    "failure": true
+  },
+  {
+    "input": "http://[::1.2.3.]",
+    "base": "http://other.com/",
+    "failure": true
+  },
+  {
+    "input": "http://[::1.2.]",
+    "base": "http://other.com/",
+    "failure": true
+  },
+  {
+    "input": "http://[::1.]",
+    "base": "http://other.com/",
+    "failure": true
+  },
   "Misc Unicode",
   {
     "input": "http://foo:💩@example.com/bar",