1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17package org.apache.harmony.archive.tests.java.util.jar; 18 19 20import dalvik.annotation.AndroidOnly; 21import dalvik.annotation.TestLevel; 22import dalvik.annotation.TestTargetClass; 23import dalvik.annotation.TestTargetNew; 24 25import junit.framework.TestCase; 26 27import tests.support.Support_PlatformFile; 28import tests.support.resource.Support_Resources; 29 30import java.io.ByteArrayOutputStream; 31import java.io.File; 32import java.io.FileOutputStream; 33import java.io.IOException; 34import java.io.InputStream; 35import java.net.URL; 36import java.security.Permission; 37import java.security.cert.Certificate; 38import java.util.Enumeration; 39import java.util.Vector; 40import java.util.jar.Attributes; 41import java.util.jar.JarEntry; 42import java.util.jar.JarFile; 43import java.util.jar.JarOutputStream; 44import java.util.jar.Manifest; 45import java.util.zip.ZipEntry; 46import java.util.zip.ZipException; 47import java.util.zip.ZipFile; 48 49 50@TestTargetClass(JarFile.class) 51public class JarFileTest extends TestCase { 52 53 // BEGIN android-added 54 public byte[] getAllBytesFromStream(InputStream is) throws IOException { 55 ByteArrayOutputStream bs = new ByteArrayOutputStream(); 56 byte[] buf = new byte[666]; 57 int iRead; 58 int off; 59 while (is.available() > 0) { 60 iRead = is.read(buf, 0, buf.length); 61 if (iRead > 0) bs.write(buf, 0, iRead); 62 } 63 return bs.toByteArray(); 64 } 65 66 // END android-added 67 68 private final String jarName = "hyts_patch.jar"; // a 'normal' jar file 69 70 private final String jarName2 = "hyts_patch2.jar"; 71 72 private final String jarName3 = "hyts_manifest1.jar"; 73 74 private final String jarName4 = "hyts_signed.jar"; 75 76 private final String jarName5 = "hyts_signed_inc.jar"; 77 78 private final String entryName = "foo/bar/A.class"; 79 80 private final String entryName3 = "coucou/FileAccess.class"; 81 82 private final String integrateJar = "Integrate.jar"; 83 84 private final String integrateJarEntry = "Test.class"; 85 86 private final String emptyEntryJar = "EmptyEntries_signed.jar"; 87 88 private final String emptyEntry1 = "subfolder/internalSubset01.js"; 89 90 private final String emptyEntry2 = "svgtest.js"; 91 92 private final String emptyEntry3 = "svgunit.js"; 93 94 private File resources; 95 96 // custom security manager 97 SecurityManager sm = new SecurityManager() { 98 final String forbidenPermissionName = "user.dir"; 99 100 public void checkPermission(Permission perm) { 101 if (perm.getName().equals(forbidenPermissionName)) { 102 throw new SecurityException(); 103 } 104 } 105 }; 106 107 @Override 108 protected void setUp() { 109 resources = Support_Resources.createTempFolder(); 110 } 111 112 /** 113 * @tests java.util.jar.JarFile#JarFile(java.io.File) 114 */ 115 @TestTargetNew( 116 level = TestLevel.PARTIAL_COMPLETE, 117 notes = "", 118 method = "JarFile", 119 args = {java.io.File.class} 120 ) 121 public void test_ConstructorLjava_io_File() { 122 try { 123 JarFile jarFile = new JarFile(new File("Wrong.file")); 124 fail("Should throw IOException"); 125 } catch (IOException e) { 126 // expected 127 } 128 SecurityManager oldSm = System.getSecurityManager(); 129 System.setSecurityManager(sm); 130 try { 131 JarFile jarFile = new JarFile(new File("tmp.jar")); 132 fail("Should throw SecurityException"); 133 } catch (IOException e) { 134 fail("Should throw SecurityException"); 135 } catch (SecurityException e) { 136 // expected 137 } finally { 138 System.setSecurityManager(oldSm); 139 } 140 141 try { 142 Support_Resources.copyFile(resources, null, jarName); 143 JarFile jarFile = new JarFile(new File(resources, jarName)); 144 } catch (IOException e) { 145 fail("Should not throw IOException"); 146 } 147 } 148 149 /** 150 * @tests java.util.jar.JarFile#JarFile(java.lang.String) 151 */ 152 @TestTargetNew( 153 level = TestLevel.COMPLETE, 154 notes = "", 155 method = "JarFile", 156 args = {java.lang.String.class} 157 ) 158 public void test_ConstructorLjava_lang_String() { 159 try { 160 JarFile jarFile = new JarFile("Wrong.file"); 161 fail("Should throw IOException"); 162 } catch (IOException e) { 163 // expected 164 } 165 SecurityManager oldSm = System.getSecurityManager(); 166 System.setSecurityManager(sm); 167 try { 168 JarFile jarFile = new JarFile("tmp.jar"); 169 fail("Should throw SecurityException"); 170 } catch (IOException e) { 171 fail("Should throw SecurityException"); 172 } catch (SecurityException e) { 173 // expected 174 } finally { 175 System.setSecurityManager(oldSm); 176 } 177 178 try { 179 Support_Resources.copyFile(resources, null, jarName); 180 String fileName = (new File(resources, jarName)).getCanonicalPath(); 181 JarFile jarFile = new JarFile(fileName); 182 } catch (IOException e) { 183 fail("Should not throw IOException"); 184 } 185 } 186 187 /** 188 * @tests java.util.jar.JarFile#JarFile(java.lang.String, boolean) 189 */ 190 @TestTargetNew( 191 level = TestLevel.COMPLETE, 192 notes = "", 193 method = "JarFile", 194 args = {java.lang.String.class, boolean.class} 195 ) 196 public void test_ConstructorLjava_lang_StringZ() { 197 try { 198 JarFile jarFile = new JarFile("Wrong.file", false); 199 fail("Should throw IOException"); 200 } catch (IOException e) { 201 // expected 202 } 203 SecurityManager oldSm = System.getSecurityManager(); 204 System.setSecurityManager(sm); 205 try { 206 JarFile jarFile = new JarFile("tmp.jar", true); 207 fail("Should throw SecurityException"); 208 } catch (IOException e) { 209 fail("Should throw SecurityException"); 210 } catch (SecurityException e) { 211 // expected 212 } finally { 213 System.setSecurityManager(oldSm); 214 } 215 216 try { 217 Support_Resources.copyFile(resources, null, jarName); 218 String fileName = (new File(resources, jarName)).getCanonicalPath(); 219 JarFile jarFile = new JarFile(fileName, true); 220 } catch (IOException e) { 221 fail("Should not throw IOException"); 222 } 223 } 224 225 /** 226 * @tests java.util.jar.JarFile#JarFile(java.io.File, boolean) 227 */ 228 @TestTargetNew( 229 level = TestLevel.COMPLETE, 230 notes = "", 231 method = "JarFile", 232 args = {java.io.File.class, boolean.class} 233 ) 234 public void test_ConstructorLjava_io_FileZ() { 235 try { 236 JarFile jarFile = new JarFile(new File("Wrong.file"), true); 237 fail("Should throw IOException"); 238 } catch (IOException e) { 239 // expected 240 } 241 SecurityManager oldSm = System.getSecurityManager(); 242 System.setSecurityManager(sm); 243 try { 244 JarFile jarFile = new JarFile(new File("tmp.jar"), false); 245 fail("Should throw SecurityException"); 246 } catch (IOException e) { 247 fail("Should throw SecurityException"); 248 } catch (SecurityException e) { 249 // expected 250 } finally { 251 System.setSecurityManager(oldSm); 252 } 253 254 try { 255 Support_Resources.copyFile(resources, null, jarName); 256 JarFile jarFile = new JarFile(new File(resources, jarName), false); 257 } catch (IOException e) { 258 fail("Should not throw IOException"); 259 } 260 } 261 262 /** 263 * @tests java.util.jar.JarFile#JarFile(java.io.File, boolean, int) 264 */ 265 @TestTargetNew( 266 level = TestLevel.COMPLETE, 267 notes = "", 268 method = "JarFile", 269 args = {java.io.File.class, boolean.class, int.class} 270 ) 271 public void test_ConstructorLjava_io_FileZI() { 272 try { 273 JarFile jarFile = new JarFile(new File("Wrong.file"), true, 274 ZipFile.OPEN_READ); 275 fail("Should throw IOException"); 276 } catch (IOException e) { 277 // expected 278 } 279 SecurityManager oldSm = System.getSecurityManager(); 280 System.setSecurityManager(sm); 281 try { 282 JarFile jarFile = new JarFile(new File("tmp.jar"), false, 283 ZipFile.OPEN_READ); 284 fail("Should throw SecurityException"); 285 } catch (IOException e) { 286 fail("Should throw SecurityException"); 287 } catch (SecurityException e) { 288 // expected 289 } finally { 290 System.setSecurityManager(oldSm); 291 } 292 293 try { 294 Support_Resources.copyFile(resources, null, jarName); 295 JarFile jarFile = new JarFile(new File(resources, jarName), false, 296 ZipFile.OPEN_READ); 297 } catch (IOException e) { 298 fail("Should not throw IOException"); 299 } 300 301 try { 302 Support_Resources.copyFile(resources, null, jarName); 303 JarFile jarFile = new JarFile(new File(resources, jarName), false, 304 ZipFile.OPEN_READ | ZipFile.OPEN_DELETE + 33); 305 fail("Should throw IllegalArgumentException"); 306 } catch (IOException e) { 307 fail("Should not throw IOException"); 308 } catch (IllegalArgumentException e) { 309 // expected 310 } 311 } 312 313 /** 314 * Constructs JarFile object. 315 * 316 * @tests java.util.jar.JarFile#JarFile(java.io.File) 317 * @tests java.util.jar.JarFile#JarFile(java.lang.String) 318 */ 319 @TestTargetNew( 320 level = TestLevel.PARTIAL_COMPLETE, 321 notes = "", 322 method = "JarFile", 323 args = {java.io.File.class} 324 ) 325 public void testConstructor_file() throws IOException { 326 File f = new File(resources, jarName); 327 Support_Resources.copyFile(resources, null, jarName); 328 assertTrue(new JarFile(f).getEntry(entryName).getName().equals( 329 entryName)); 330 assertTrue(new JarFile(f.getPath()).getEntry(entryName).getName() 331 .equals(entryName)); 332 } 333 334 /** 335 * @tests java.util.jar.JarFile#entries() 336 */ 337 @TestTargetNew( 338 level = TestLevel.COMPLETE, 339 notes = "", 340 method = "entries", 341 args = {} 342 ) 343 public void test_entries() throws Exception { 344 /* 345 * Note only (and all of) the following should be contained in the file 346 * META-INF/ META-INF/MANIFEST.MF foo/ foo/bar/ foo/bar/A.class Blah.txt 347 */ 348 Support_Resources.copyFile(resources, null, jarName); 349 JarFile jarFile = new JarFile(new File(resources, jarName)); 350 Enumeration<JarEntry> e = jarFile.entries(); 351 int i; 352 for (i = 0; e.hasMoreElements(); i++) { 353 e.nextElement(); 354 } 355 assertEquals(jarFile.size(), i); 356 jarFile.close(); 357 assertEquals(6, i); 358 } 359 360 @TestTargetNew( 361 level = TestLevel.COMPLETE, 362 notes = "", 363 method = "entries", 364 args = {} 365 ) 366 public void test_entries2() throws Exception { 367 Support_Resources.copyFile(resources, null, jarName); 368 JarFile jarFile = new JarFile(new File(resources, jarName)); 369 Enumeration<JarEntry> enumeration = jarFile.entries(); 370 jarFile.close(); 371 try { 372 enumeration.hasMoreElements(); 373 fail("hasMoreElements() did not detect a closed jar file"); 374 } catch (IllegalStateException e) { 375 } 376 Support_Resources.copyFile(resources, null, jarName); 377 jarFile = new JarFile(new File(resources, jarName)); 378 enumeration = jarFile.entries(); 379 jarFile.close(); 380 try { 381 enumeration.nextElement(); 382 fail("nextElement() did not detect closed jar file"); 383 } catch (IllegalStateException e) { 384 } 385 } 386 387 /** 388 * @throws IOException 389 * @tests java.util.jar.JarFile#getJarEntry(java.lang.String) 390 */ 391 @TestTargetNew( 392 level = TestLevel.PARTIAL_COMPLETE, 393 notes = "", 394 method = "getEntry", 395 args = {java.lang.String.class} 396 ) 397 public void test_getEntryLjava_lang_String() throws IOException { 398 try { 399 Support_Resources.copyFile(resources, null, jarName); 400 JarFile jarFile = new JarFile(new File(resources, jarName)); 401 assertEquals("Error in returned entry", 311, jarFile.getEntry( 402 entryName).getSize()); 403 jarFile.close(); 404 } catch (Exception e) { 405 fail("Exception during test: " + e.toString()); 406 } 407 408 Support_Resources.copyFile(resources, null, jarName); 409 JarFile jarFile = new JarFile(new File(resources, jarName)); 410 Enumeration<JarEntry> enumeration = jarFile.entries(); 411 assertTrue(enumeration.hasMoreElements()); 412 while (enumeration.hasMoreElements()) { 413 JarEntry je = enumeration.nextElement(); 414 jarFile.getEntry(je.getName()); 415 } 416 417 enumeration = jarFile.entries(); 418 assertTrue(enumeration.hasMoreElements()); 419 JarEntry je = enumeration.nextElement(); 420 try { 421 jarFile.close(); 422 jarFile.getEntry(je.getName()); 423 // fail("IllegalStateException expected."); 424 } catch (IllegalStateException ee) { // Per documentation exception 425 // may be thrown. 426 // expected 427 } 428 } 429 430 /** 431 * @throws IOException 432 * @tests java.util.jar.JarFile#getJarEntry(java.lang.String) 433 */ 434 @TestTargetNew( 435 level = TestLevel.COMPLETE, 436 notes = "", 437 method = "getJarEntry", 438 args = {java.lang.String.class} 439 ) 440 public void test_getJarEntryLjava_lang_String() throws IOException { 441 try { 442 Support_Resources.copyFile(resources, null, jarName); 443 JarFile jarFile = new JarFile(new File(resources, jarName)); 444 assertEquals("Error in returned entry", 311, jarFile.getJarEntry( 445 entryName).getSize()); 446 jarFile.close(); 447 } catch (Exception e) { 448 fail("Exception during test: " + e.toString()); 449 } 450 451 Support_Resources.copyFile(resources, null, jarName); 452 JarFile jarFile = new JarFile(new File(resources, jarName)); 453 Enumeration<JarEntry> enumeration = jarFile.entries(); 454 assertTrue(enumeration.hasMoreElements()); 455 while (enumeration.hasMoreElements()) { 456 JarEntry je = enumeration.nextElement(); 457 jarFile.getJarEntry(je.getName()); 458 } 459 460 enumeration = jarFile.entries(); 461 assertTrue(enumeration.hasMoreElements()); 462 JarEntry je = enumeration.nextElement(); 463 try { 464 jarFile.close(); 465 jarFile.getJarEntry(je.getName()); 466 // fail("IllegalStateException expected."); 467 } catch (IllegalStateException ee) { // Per documentation exception 468 // may be thrown. 469 // expected 470 } 471 } 472 473 474 /** 475 * @tests java.util.jar.JarFile#getJarEntry(java.lang.String) 476 */ 477 @TestTargetNew( 478 level = TestLevel.PARTIAL_COMPLETE, 479 notes = "", 480 method = "getEntry", 481 args = {java.lang.String.class} 482 ) 483 public void testGetJarEntry() throws Exception { 484 Support_Resources.copyFile(resources, null, jarName); 485 JarFile jarFile = new JarFile(new File(resources, jarName)); 486 assertEquals("Error in returned entry", 311, jarFile.getEntry( 487 entryName).getSize()); 488 jarFile.close(); 489 490 // tests for signed jars 491 // test all signed jars in the /Testres/Internal/SignedJars directory 492 String jarDirUrl = Support_Resources 493 .getResourceURL("/../internalres/signedjars"); 494 Vector<String> signedJars = new Vector<String>(); 495 try { 496 InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream(); 497 while (is.available() > 0) { 498 StringBuilder linebuff = new StringBuilder(80); // Typical line 499 // length 500 done: while (true) { 501 int nextByte = is.read(); 502 switch (nextByte) { 503 case -1: 504 break done; 505 case (byte) '\r': 506 if (linebuff.length() == 0) { 507 // ignore 508 } 509 break done; 510 case (byte) '\n': 511 if (linebuff.length() == 0) { 512 // ignore 513 } 514 break done; 515 default: 516 linebuff.append((char) nextByte); 517 } 518 } 519 if (linebuff.length() == 0) { 520 break; 521 } 522 String line = linebuff.toString(); 523 signedJars.add(line); 524 } 525 is.close(); 526 } catch (IOException e) { 527 // no list of jars found 528 } 529 530 for (int i = 0; i < signedJars.size(); i++) { 531 String jarName = signedJars.get(i); 532 try { 533 File file = Support_Resources.getExternalLocalFile(jarDirUrl 534 + "/" + jarName); 535 jarFile = new JarFile(file, true); 536 boolean foundCerts = false; 537 Enumeration<JarEntry> e = jarFile.entries(); 538 while (e.hasMoreElements()) { 539 JarEntry entry = e.nextElement(); 540 InputStream is = jarFile.getInputStream(entry); 541 is.skip(100000); 542 is.close(); 543 Certificate[] certs = entry.getCertificates(); 544 if (certs != null && certs.length > 0) { 545 foundCerts = true; 546 break; 547 } 548 } 549 assertTrue( 550 "No certificates found during signed jar test for jar \"" 551 + jarName + "\"", foundCerts); 552 } catch (IOException e) { 553 fail("Exception during signed jar test for jar \"" + jarName 554 + "\": " + e.toString()); 555 } 556 } 557 } 558 559 /** 560 * @tests java.util.jar.JarFile#getManifest() 561 */ 562 @TestTargetNew( 563 level = TestLevel.COMPLETE, 564 notes = "", 565 method = "getManifest", 566 args = {} 567 ) 568 public void test_getManifest() { 569 // Test for method java.util.jar.Manifest 570 // java.util.jar.JarFile.getManifest() 571 try { 572 Support_Resources.copyFile(resources, null, jarName); 573 JarFile jarFile = new JarFile(new File(resources, jarName)); 574 assertNotNull("Error--Manifest not returned", jarFile.getManifest()); 575 jarFile.close(); 576 } catch (Exception e) { 577 fail("Exception during 1st test: " + e.toString()); 578 } 579 try { 580 Support_Resources.copyFile(resources, null, jarName2); 581 JarFile jarFile = new JarFile(new File(resources, jarName2)); 582 assertNull("Error--should have returned null", jarFile 583 .getManifest()); 584 jarFile.close(); 585 } catch (Exception e) { 586 fail("Exception during 2nd test: " + e.toString()); 587 } 588 589 try { 590 // jarName3 was created using the following test 591 Support_Resources.copyFile(resources, null, jarName3); 592 JarFile jarFile = new JarFile(new File(resources, jarName3)); 593 assertNotNull("Should find manifest without verifying", jarFile 594 .getManifest()); 595 jarFile.close(); 596 } catch (Exception e) { 597 fail("Exception during 3rd test: " + e.toString()); 598 } 599 600 try { 601 // this is used to create jarName3 used in the previous test 602 Manifest manifest = new Manifest(); 603 Attributes attributes = manifest.getMainAttributes(); 604 attributes.put(new Attributes.Name("Manifest-Version"), "1.0"); 605 ByteArrayOutputStream manOut = new ByteArrayOutputStream(); 606 manifest.write(manOut); 607 byte[] manBytes = manOut.toByteArray(); 608 File file = File.createTempFile( 609 Support_PlatformFile.getNewPlatformFile("hyts_manifest1", 610 ""), ".jar"); 611 JarOutputStream jarOut = new JarOutputStream(new FileOutputStream( 612 file.getAbsolutePath())); 613 ZipEntry entry = new ZipEntry("META-INF/"); 614 entry.setSize(0); 615 jarOut.putNextEntry(entry); 616 entry = new ZipEntry(JarFile.MANIFEST_NAME); 617 entry.setSize(manBytes.length); 618 jarOut.putNextEntry(entry); 619 jarOut.write(manBytes); 620 entry = new ZipEntry("myfile"); 621 entry.setSize(1); 622 jarOut.putNextEntry(entry); 623 jarOut.write(65); 624 jarOut.close(); 625 JarFile jar = new JarFile(file.getAbsolutePath(), false); 626 assertNotNull("Should find manifest without verifying", jar 627 .getManifest()); 628 jar.close(); 629 file.delete(); 630 } catch (IOException e) { 631 fail("IOException 3"); 632 } 633 try { 634 Support_Resources.copyFile(resources, null, jarName2); 635 JarFile jF = new JarFile(new File(resources, jarName2)); 636 jF.close(); 637 jF.getManifest(); 638 fail("FAILED: expected IllegalStateException"); 639 } catch (IllegalStateException ise) { 640 // expected; 641 } catch (Exception e) { 642 fail("Exception during 4th test: " + e.toString()); 643 } 644 645 Support_Resources.copyFile(resources, null, "Broken_manifest.jar"); 646 JarFile jf; 647 try { 648 jf = new JarFile(new File(resources, "Broken_manifest.jar")); 649 jf.getManifest(); 650 fail("IOException expected."); 651 } catch (IOException e) { 652 // expected. 653 } 654 } 655 656 /** 657 * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) 658 */ 659 @TestTargetNew( 660 level = TestLevel.PARTIAL_COMPLETE, 661 notes = "SecurityException and functionality checked.", 662 method = "getInputStream", 663 args = {java.util.zip.ZipEntry.class} 664 ) 665 @AndroidOnly("This test doesn't pass on RI. If entry size is set up " + 666 "incorrectly, SecurityException is thrown. " + 667 "But SecurityException is thrown on RI only " + 668 "if jar file is signed incorreclty.") 669 public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() { 670 File signedFile = null; 671 try { 672 Support_Resources.copyFile(resources, null, jarName4); 673 signedFile = new File(resources, jarName4); 674 } catch (Exception e) { 675 fail("Failed to create local file 2: " + e); 676 } 677 678 try { 679 JarFile jar = new JarFile(signedFile); 680 JarEntry entry = new JarEntry(entryName3); 681 InputStream in = jar.getInputStream(entry); 682 in.read(); 683 } catch (Exception e) { 684 fail("Exception during test 3: " + e); 685 } 686 687 try { 688 JarFile jar = new JarFile(signedFile); 689 JarEntry entry = new JarEntry(entryName3); 690 InputStream in = jar.getInputStream(entry); 691 // BEGIN android-added 692 byte[] dummy = getAllBytesFromStream(in); 693 // END android-added 694 assertNull("found certificates", entry.getCertificates()); 695 } catch (Exception e) { 696 fail("Exception during test 4: " + e); 697 } 698 699 try { 700 JarFile jar = new JarFile(signedFile); 701 JarEntry entry = new JarEntry(entryName3); 702 entry.setSize(1076); 703 InputStream in = jar.getInputStream(entry); 704 // BEGIN android-added 705 byte[] dummy = getAllBytesFromStream(in); 706 // END android-added 707 fail("SecurityException should be thrown."); 708 } catch (SecurityException e) { 709 // expected 710 } catch (Exception e) { 711 fail("Exception during test 5: " + e); 712 } 713 714 try { 715 Support_Resources.copyFile(resources, null, jarName5); 716 signedFile = new File(resources, jarName5); 717 } catch (Exception e) { 718 fail("Failed to create local file 5: " + e); 719 } 720 721 try { 722 JarFile jar = new JarFile(signedFile); 723 JarEntry entry = new JarEntry(entryName3); 724 InputStream in = jar.getInputStream(entry); 725 fail("SecurityException should be thrown."); 726 } catch (SecurityException e) { 727 // expected 728 } catch (Exception e) { 729 fail("Exception during test 5: " + e); 730 } 731 } 732 733 /* 734 * The jar created by 1.4 which does not provide a 735 * algorithm-Digest-Manifest-Main-Attributes entry in .SF file. 736 */ 737 @TestTargetNew( 738 level = TestLevel.COMPLETE, 739 notes = "", 740 method = "entries", 741 args = {} 742 ) 743 public void test_Jar_created_before_java_5() throws IOException { 744 String modifiedJarName = "Created_by_1_4.jar"; 745 Support_Resources.copyFile(resources, null, modifiedJarName); 746 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 747 true); 748 Enumeration<JarEntry> entries = jarFile.entries(); 749 while (entries.hasMoreElements()) { 750 ZipEntry zipEntry = entries.nextElement(); 751 jarFile.getInputStream(zipEntry); 752 } 753 } 754 755 /* The jar is intact, then everything is all right. */ 756 @TestTargetNew( 757 level = TestLevel.COMPLETE, 758 notes = "", 759 method = "entries", 760 args = {} 761 ) 762 public void test_JarFile_Integrate_Jar() throws IOException { 763 String modifiedJarName = "Integrate.jar"; 764 Support_Resources.copyFile(resources, null, modifiedJarName); 765 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 766 true); 767 Enumeration<JarEntry> entries = jarFile.entries(); 768 while (entries.hasMoreElements()) { 769 ZipEntry zipEntry = entries.nextElement(); 770 jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 771 } 772 } 773 774 /** 775 * The jar is intact, but the entry object is modified. 776 */ 777 @TestTargetNew( 778 level = TestLevel.PARTIAL_COMPLETE, 779 notes = "", 780 method = "getInputStream", 781 args = {ZipEntry.class} 782 ) 783 public void testJarVerificationModifiedEntry() throws IOException { 784 Support_Resources.copyFile(resources, null, integrateJar); 785 File f = new File(resources, integrateJar); 786 787 JarFile jarFile = new JarFile(f); 788 ZipEntry zipEntry = jarFile.getJarEntry(integrateJarEntry); 789 zipEntry.setSize(zipEntry.getSize() + 1); 790 jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 791 792 jarFile = new JarFile(f); 793 zipEntry = jarFile.getJarEntry(integrateJarEntry); 794 zipEntry.setSize(zipEntry.getSize() - 1); 795 try { 796 //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 797 jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000); 798 fail("SecurityException expected"); 799 } catch (SecurityException e) { 800 // desired 801 } 802 } 803 804 /* 805 * If another entry is inserted into Manifest, no security exception will be 806 * thrown out. 807 */ 808 @TestTargetNew( 809 level = TestLevel.COMPLETE, 810 notes = "", 811 method = "entries", 812 args = {} 813 ) 814 public void test_JarFile_InsertEntry_in_Manifest_Jar() throws IOException { 815 String modifiedJarName = "Inserted_Entry_Manifest.jar"; 816 Support_Resources.copyFile(resources, null, modifiedJarName); 817 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 818 true); 819 Enumeration<JarEntry> entries = jarFile.entries(); 820 int count = 0; 821 while (entries.hasMoreElements()) { 822 823 ZipEntry zipEntry = entries.nextElement(); 824 jarFile.getInputStream(zipEntry); 825 count++; 826 } 827 assertEquals(5, count); 828 } 829 830 /* 831 * If another entry is inserted into Manifest, no security exception will be 832 * thrown out. 833 */ 834 @TestTargetNew( 835 level = TestLevel.COMPLETE, 836 notes = "", 837 method = "entries", 838 args = {} 839 ) 840 public void test_Inserted_Entry_Manifest_with_DigestCode() 841 throws IOException { 842 String modifiedJarName = "Inserted_Entry_Manifest_with_DigestCode.jar"; 843 Support_Resources.copyFile(resources, null, modifiedJarName); 844 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 845 true); 846 Enumeration<JarEntry> entries = jarFile.entries(); 847 int count = 0; 848 while (entries.hasMoreElements()) { 849 ZipEntry zipEntry = entries.nextElement(); 850 jarFile.getInputStream(zipEntry); 851 count++; 852 } 853 assertEquals(5, count); 854 } 855 856 /* 857 * The content of Test.class is modified, jarFile.getInputStream will not 858 * throw security Exception, but it will anytime before the inputStream got 859 * from getInputStream method has been read to end. 860 */ 861 @TestTargetNew( 862 level = TestLevel.PARTIAL_COMPLETE, 863 notes = "SecurityException and functionality checked.", 864 method = "getInputStream", 865 args = {java.util.zip.ZipEntry.class} 866 ) 867 public void test_JarFile_Modified_Class() throws IOException { 868 String modifiedJarName = "Modified_Class.jar"; 869 Support_Resources.copyFile(resources, null, modifiedJarName); 870 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 871 true); 872 Enumeration<JarEntry> entries = jarFile.entries(); 873 while (entries.hasMoreElements()) { 874 ZipEntry zipEntry = entries.nextElement(); 875 jarFile.getInputStream(zipEntry); 876 } 877 /* The content of Test.class has been tampered. */ 878 ZipEntry zipEntry = jarFile.getEntry("Test.class"); 879 InputStream in = jarFile.getInputStream(zipEntry); 880 byte[] buffer = new byte[1024]; 881 try { 882 while (in.available() > 0) { 883 in.read(buffer); 884 } 885 fail("SecurityException expected"); 886 } catch (SecurityException e) { 887 // desired 888 } 889 } 890 891 /* 892 * In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is 893 * tampered manually. Hence the RI 5.0 JarFile.getInputStream of any 894 * JarEntry will throw security exception. 895 */ 896 @TestTargetNew( 897 level = TestLevel.PARTIAL_COMPLETE, 898 notes = "SecurityException and functionality checked.", 899 method = "getInputStream", 900 args = {java.util.zip.ZipEntry.class} 901 ) 902 public void test_JarFile_Modified_Manifest_MainAttributes() 903 throws IOException { 904 String modifiedJarName = "Modified_Manifest_MainAttributes.jar"; 905 Support_Resources.copyFile(resources, null, modifiedJarName); 906 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 907 true); 908 Enumeration<JarEntry> entries = jarFile.entries(); 909 while (entries.hasMoreElements()) { 910 ZipEntry zipEntry = entries.nextElement(); 911 try { 912 jarFile.getInputStream(zipEntry); 913 fail("SecurityException expected"); 914 } catch (SecurityException e) { 915 // desired 916 } 917 } 918 } 919 920 /* 921 * It is all right in our original JarFile. If the Entry Attributes, for 922 * example Test.class in our jar, the jarFile.getInputStream will throw 923 * Security Exception. 924 */ 925 @TestTargetNew( 926 level = TestLevel.PARTIAL_COMPLETE, 927 notes = "SecurityException and functionality checked.", 928 method = "getInputStream", 929 args = {java.util.zip.ZipEntry.class} 930 ) 931 public void test_JarFile_Modified_Manifest_EntryAttributes() 932 throws IOException { 933 String modifiedJarName = "Modified_Manifest_EntryAttributes.jar"; 934 Support_Resources.copyFile(resources, null, modifiedJarName); 935 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 936 true); 937 Enumeration<JarEntry> entries = jarFile.entries(); 938 while (entries.hasMoreElements()) { 939 ZipEntry zipEntry = entries.nextElement(); 940 try { 941 jarFile.getInputStream(zipEntry); 942 fail("should throw Security Exception"); 943 } catch (SecurityException e) { 944 // desired 945 } 946 } 947 } 948 949 /* 950 * If the content of the .SA file is modified, no matter what it resides, 951 * JarFile.getInputStream of any JarEntry will throw Security Exception. 952 */ 953 @TestTargetNew( 954 level = TestLevel.PARTIAL_COMPLETE, 955 notes = "SecurityException and functionality checked.", 956 method = "getInputStream", 957 args = {java.util.zip.ZipEntry.class} 958 ) 959 public void test_JarFile_Modified_SF_EntryAttributes() throws IOException { 960 String modifiedJarName = "Modified_SF_EntryAttributes.jar"; 961 Support_Resources.copyFile(resources, null, modifiedJarName); 962 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 963 true); 964 Enumeration<JarEntry> entries = jarFile.entries(); 965 while (entries.hasMoreElements()) { 966 ZipEntry zipEntry = entries.nextElement(); 967 try { 968 jarFile.getInputStream(zipEntry); 969 fail("should throw Security Exception"); 970 } catch (SecurityException e) { 971 // desired 972 } 973 } 974 } 975 976 @TestTargetNew( 977 level = TestLevel.COMPLETE, 978 notes = "", 979 method = "close", 980 args = {} 981 ) 982 public void test_close() throws IOException { 983 String modifiedJarName = "Modified_SF_EntryAttributes.jar"; 984 Support_Resources.copyFile(resources, null, modifiedJarName); 985 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 986 true); 987 Enumeration<JarEntry> entries = jarFile.entries(); 988 989 jarFile.close(); 990 jarFile.close(); 991 992 // Can not check IOException 993 } 994 995 /** 996 * @throws IOException 997 * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) 998 */ 999 @TestTargetNew( 1000 level = TestLevel.COMPLETE, 1001 notes = "", 1002 method = "getInputStream", 1003 args = {java.util.zip.ZipEntry.class} 1004 ) 1005 public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException { 1006 File localFile = null; 1007 try { 1008 Support_Resources.copyFile(resources, null, jarName); 1009 localFile = new File(resources, jarName); 1010 } catch (Exception e) { 1011 fail("Failed to create local file: " + e); 1012 } 1013 1014 byte[] b = new byte[1024]; 1015 try { 1016 JarFile jf = new JarFile(localFile); 1017 java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName)); 1018 // BEGIN android-removed 1019 // jf.close(); 1020 // END android-removed 1021 assertTrue("Returned invalid stream", is.available() > 0); 1022 int r = is.read(b, 0, 1024); 1023 is.close(); 1024 StringBuffer sb = new StringBuffer(r); 1025 for (int i = 0; i < r; i++) { 1026 sb.append((char) (b[i] & 0xff)); 1027 } 1028 String contents = sb.toString(); 1029 assertTrue("Incorrect stream read", contents.indexOf("bar") > 0); 1030 // BEGIN android-added 1031 jf.close(); 1032 // END android-added 1033 } catch (Exception e) { 1034 fail("Exception during test: " + e.toString()); 1035 } 1036 1037 try { 1038 JarFile jf = new JarFile(localFile); 1039 InputStream in = jf.getInputStream(new JarEntry("invalid")); 1040 assertNull("Got stream for non-existent entry", in); 1041 } catch (Exception e) { 1042 fail("Exception during test 2: " + e); 1043 } 1044 1045 try { 1046 Support_Resources.copyFile(resources, null, jarName); 1047 File signedFile = new File(resources, jarName); 1048 JarFile jf = new JarFile(signedFile); 1049 JarEntry jre = new JarEntry("foo/bar/A.class"); 1050 jf.getInputStream(jre); 1051 // InputStream returned in any way, exception can be thrown in case 1052 // of reading from this stream only. 1053 // fail("Should throw ZipException"); 1054 } catch (ZipException ee) { 1055 // expected 1056 } 1057 1058 try { 1059 Support_Resources.copyFile(resources, null, jarName); 1060 File signedFile = new File(resources, jarName); 1061 JarFile jf = new JarFile(signedFile); 1062 JarEntry jre = new JarEntry("foo/bar/A.class"); 1063 jf.close(); 1064 jf.getInputStream(jre); 1065 // InputStream returned in any way, exception can be thrown in case 1066 // of reading from this stream only. 1067 // The same for IOException 1068 fail("Should throw IllegalStateException"); 1069 } catch (IllegalStateException ee) { 1070 // expected 1071 } 1072 } 1073 1074 /** 1075 * The jar is intact, but the entry object is modified. 1076 */ 1077 @TestTargetNew( 1078 level = TestLevel.PARTIAL_COMPLETE, 1079 notes = "Regression test for issue introduced by HAROMNY-4569. " 1080 + "signed archives containing files with size 0 could not get verified", 1081 method = "getInputStream", 1082 args = {ZipEntry.class} 1083 ) 1084 public void testJarVerificationEmptyEntry() throws IOException { 1085 Support_Resources.copyFile(resources, null, emptyEntryJar); 1086 File f = new File(resources, emptyEntryJar); 1087 1088 JarFile jarFile = new JarFile(f); 1089 1090 ZipEntry zipEntry = jarFile.getJarEntry(emptyEntry1); 1091 int res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); 1092 assertEquals("Wrong length of empty jar entry", -1, res); 1093 1094 zipEntry = jarFile.getJarEntry(emptyEntry2); 1095 res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); 1096 assertEquals("Wrong length of empty jar entry", -1, res); 1097 1098 zipEntry = jarFile.getJarEntry(emptyEntry3); 1099 res = jarFile.getInputStream(zipEntry).read(); 1100 assertEquals("Wrong length of empty jar entry", -1, res); 1101 } 1102} 1103