Это ошибка в классе Java GZipInputStream?

Я заметил, что некоторые из моих кодов декодирования gzip, похоже, не могут обнаружить поврежденные данные. Я думаю, что я проследил проблему до класса Java GZipInputStream. В частности, кажется, что когда вы читаете весь поток с помощью одного вызова read, поврежденные данные не вызывают IOException. Если вы читаете поток в двух или более вызовах с одними и теми же поврежденными данными, это вызывает исключение.

Я хотел узнать, что думает здесь сообщество, прежде чем подавать отчет об ошибке.

РЕДАКТИРОВАТЬ: Я изменил свой пример, потому что последний не так четко проиллюстрировал то, что я считаю проблемой. В этом новом примере 10-байтовый буфер сжат с помощью gzip, один байт буфера с gzip-сжатием модифицируется, а затем разархивируется. Вызов GZipInputStream.read возвращает 10 в качестве количества прочитанных байтов, что можно ожидать от 10-байтового буфера. Тем не менее, распакованный буфер отличается от оригинала (из-за повреждения). Исключение не создается. Я заметил, что вызов «доступно» после чтения возвращает «1» вместо «0», что было бы, если бы EOF был достигнут.

Вот источник:

  @Test public void gzip() {
    try {
      int length = 10;
      byte[] bytes = new byte[]{12, 19, 111, 14, -76, 34, 60, -43, -91, 101};
      System.out.println(Arrays.toString(bytes));

      //Gzip the byte array
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      GZIPOutputStream gos = new GZIPOutputStream(baos);
      gos.write(bytes);
      gos.finish();
      byte[] zipped = baos.toByteArray();

      //Alter one byte of the gzipped array.  
      //This should be detected by gzip crc-32 checksum
      zipped[15] = (byte)(0);

      //Unzip the modified array
      ByteArrayInputStream bais = new ByteArrayInputStream(zipped);
      GZIPInputStream gis = new GZIPInputStream(bais);
      byte[] unzipped = new byte[length];
      int numRead = gis.read(unzipped);
      System.out.println("NumRead: " + numRead);
      System.out.println("Available: " + gis.available());

      //The unzipped array is now [12, 19, 111, 14, -80, 0, 0, 0, 10, -118].
      //No IOException was thrown.
      System.out.println(Arrays.toString(unzipped));

      //Assert that the input and unzipped arrays are equal (they aren't)
      org.junit.Assert.assertArrayEquals(unzipped, bytes);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

person Jacob    schedule 11.03.2011    source источник
comment
+1 хороший вопрос; хорошо написано, с самодостаточным, кратким, РАБОЧИМ примером. Вот почему вы получили такой быстрый ответ :-)   -  person Jim Garrison    schedule 11.03.2011


Ответы (1)


Решил запустить тест:

Что вы упустили. gis.read(unzipped) возвращает 1, поэтому он прочитал только один байт. Вы не можете жаловаться, это еще не конец потока.

Следующий read() выдает «Поврежденный трейлер GZIP».

Так что все хорошо! (и ошибок нет, по крайней мере, в GZIPInputStream)

person Community    schedule 11.03.2011
comment
+1 Обыграй меня :-) По крайней мере, мне было весело ковыряться в JDK :-) - person Jim Garrison; 11.03.2011
comment
на самом деле я был более чем на 99% уверен, что происходит, когда я увидел код. byte [] {0,0, -1, -1} - это метка для Z_SYNC_FLUSH, поэтому подумал, что он мог попасть в нее. - person bestsss; 11.03.2011
comment
Я никогда не использовал GZIPInputStream, поэтому мне пришлось отследить его. Я думаю, дело в том, что повреждение было в трейлере, а не в данных? - person Jim Garrison; 11.03.2011
comment
Почему он перестает читать вместо того, чтобы продолжить до конца и в первый раз выбросить исключение? - person Jacob; 11.03.2011
comment
@Jacob, я оставлю тест для вас, но вот подсказка, что Z_SYNC_FLUSH используется для очистки потока. Я не уверен, что это правильно, я могу войти и отладить его по точной причине (но мне это не интересно), но если вы хотите перейти в режим отладки, найдите jzlib и просто используйте его вместо этого, вы можете поиграть в полном режиме java. - person bestsss; 11.03.2011
comment
Мне кажется, что GZipInputStream не подчиняется контракту метода «чтения»: этот метод блокируется до тех пор, пока не станут доступны входные данные, не будет обнаружен конец файла или возникнет исключение. Из download.oracle. com / javase / 6 / docs / api / java / io / - person Jacob; 11.03.2011
comment
Этот метод блокируется до тех пор, пока не станут доступны входные данные, поэтому, если есть НЕКОТОРЫЕ данные, метод не требуется для возврата всех данных. Так что все в порядке, imo: см. Документ самого gzip: метод будет заблокирован до тех пор, пока какой-либо ввод не будет распакован - person bestsss; 11.03.2011
comment
Я изменил свой пример на тот, где read возвращает то же количество байтов, что и ожидалось. - person Jacob; 11.03.2011