فهرست منبع

Separate base64 error from IO error

Simon Sapin 8 سال پیش
والد
کامیت
dd3e072232
1فایلهای تغییر یافته به همراه23 افزوده شده و 18 حذف شده
  1. 23 18
      src/lib.rs

+ 23 - 18
src/lib.rs

@@ -14,6 +14,8 @@ pub struct DataUrl<'a> {
     encoded_body_plus_fragment: &'a str,
 }
 
+pub struct Base64Error(());
+
 impl<'a> DataUrl<'a> {
     /// <https://fetch.spec.whatwg.org/#data-url-processor>
     /// but starting from a string rather than a Url, to avoid extra string copies.
@@ -43,29 +45,21 @@ impl<'a> DataUrl<'a> {
     /// The fragment identifier is represented as in the origin input.
     /// It needs to be either percent-encoded to obtain the same string as in a parsed URL,
     /// or percent-decoded to interpret it as text.
-    pub fn decode_body<W>(&self, sink: W) -> io::Result<Option<&'a str>>
+    pub fn decode_body<W>(&self, sink: W) -> io::Result<Result<Option<&'a str>, Base64Error>>
         where W: io::Write
     {
         if self.base64 {
             decode_with_base64(self.encoded_body_plus_fragment, sink)
         } else {
-            decode_without_base64(self.encoded_body_plus_fragment, sink)
+            decode_without_base64(self.encoded_body_plus_fragment, sink).map(Ok)
         }
     }
 
-    pub fn decode_body_to_vec(&self) -> Result<(Vec<u8>, Option<&str>), ()> {
+    pub fn decode_body_to_vec(&self) -> Result<(Vec<u8>, Option<&str>), Base64Error> {
         let mut sink = Vec::new();
-        match self.decode_body(&mut sink) {
-            Ok(url_fragment) => {
-                Ok((sink, url_fragment))
-            }
-            Err(e) => {
-                // Vec::write_all never returns an error
-                debug_assert!(e.kind() == io::ErrorKind::InvalidData && self.base64);
-
-                Err(())
-            }
-        }
+        let base64_result = self.decode_body(&mut sink).unwrap();
+        let url_fragment = base64_result?;
+        Ok((sink, url_fragment))
     }
 }
 
@@ -134,6 +128,8 @@ fn parse_header(from_colon_to_comma: &str) -> (mime::Mime, bool) {
         None => (input, false),
     };
 
+    // FIXME: percent-encode
+
     if input.starts_with(';') {
         string = String::from("text/plain");
         string.push_str(input);
@@ -226,7 +222,8 @@ fn decode_without_base64<W>(encoded_body_plus_fragment: &str, mut sink: W)
 /// `decode_without_base64()` composed with
 /// <https://infra.spec.whatwg.org/#isomorphic-decode> composed with
 /// <https://infra.spec.whatwg.org/#forgiving-base64-decode>.
-fn decode_with_base64<W>(encoded_body_plus_fragment: &str, sink: W) -> io::Result<Option<&str>>
+fn decode_with_base64<W>(encoded_body_plus_fragment: &str, sink: W)
+                          -> io::Result<Result<Option<&str>, Base64Error>>
     where W: io::Write
 {
     let mut decoder = Base64Decoder {
@@ -234,8 +231,13 @@ fn decode_with_base64<W>(encoded_body_plus_fragment: &str, sink: W) -> io::Resul
         bit_buffer: 0,
         buffer_bit_length: 0,
         padding_symbols: 0,
+        base64_error: false,
     };
-    let fragment = decode_without_base64(encoded_body_plus_fragment, &mut decoder)?;
+    let result = decode_without_base64(encoded_body_plus_fragment, &mut decoder);
+    if decoder.base64_error {
+        return Ok(Err(Base64Error(())))
+    }
+    let fragment = result?;
     match (decoder.buffer_bit_length, decoder.padding_symbols) {
         (0, 0) => {
             // A multiple of four of alphabet symbols, and nothing else.
@@ -259,10 +261,10 @@ fn decode_with_base64<W>(encoded_body_plus_fragment: &str, sink: W) -> io::Resul
         }
         _ => {
             // No other combination is acceptable
-            Err(io::ErrorKind::InvalidData)?
+            return Ok(Err(Base64Error(())))
         }
     }
-    Ok(fragment)
+    Ok(Ok(fragment))
 }
 
 struct Base64Decoder<W> {
@@ -270,6 +272,7 @@ struct Base64Decoder<W> {
     bit_buffer: u32,
     buffer_bit_length: u8,
     padding_symbols: u8,
+    base64_error: bool,
 }
 
 impl<W> io::Write for Base64Decoder<W> where W: io::Write {
@@ -293,10 +296,12 @@ impl<W> io::Write for Base64Decoder<W> where W: io::Write {
                     continue
                 }
 
+                self.base64_error = true;
                 Err(io::ErrorKind::InvalidData)?
             }
             if self.padding_symbols > 0 {
                 // Alphabet symbols after padding
+                self.base64_error = true;
                 Err(io::ErrorKind::InvalidData)?
             }
             self.bit_buffer <<= 6;