src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java
changeset 47216 71c04702a3d5
parent 39646 2bf99fe5023b
child 52902 e3398b2e1ab0
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.net.www.protocol.jar;
       
    27 
       
    28 import java.io.*;
       
    29 import java.net.*;
       
    30 import java.nio.file.Files;
       
    31 import java.nio.file.Path;
       
    32 import java.nio.file.StandardCopyOption;
       
    33 import java.util.*;
       
    34 import java.util.jar.*;
       
    35 import java.util.zip.ZipFile;
       
    36 import java.util.zip.ZipEntry;
       
    37 import java.security.CodeSigner;
       
    38 import java.security.cert.Certificate;
       
    39 import java.security.AccessController;
       
    40 import java.security.PrivilegedAction;
       
    41 import java.security.PrivilegedExceptionAction;
       
    42 import java.security.PrivilegedActionException;
       
    43 import sun.net.www.ParseUtil;
       
    44 
       
    45 /* URL jar file is a common JarFile subtype used for JarURLConnection */
       
    46 public class URLJarFile extends JarFile {
       
    47 
       
    48     /*
       
    49      * Interface to be able to call retrieve() in plugin if
       
    50      * this variable is set.
       
    51      */
       
    52     private static URLJarFileCallBack callback = null;
       
    53 
       
    54     /* Controller of the Jar File's closing */
       
    55     private URLJarFileCloseController closeController = null;
       
    56 
       
    57     private static int BUF_SIZE = 2048;
       
    58 
       
    59     private Manifest superMan;
       
    60     private Attributes superAttr;
       
    61     private Map<String, Attributes> superEntries;
       
    62 
       
    63     static JarFile getJarFile(URL url) throws IOException {
       
    64         return getJarFile(url, null);
       
    65     }
       
    66 
       
    67     static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
       
    68         if (isFileURL(url)) {
       
    69             Runtime.Version version = "runtime".equals(url.getRef())
       
    70                     ? JarFile.runtimeVersion()
       
    71                     : JarFile.baseVersion();
       
    72             return new URLJarFile(url, closeController, version);
       
    73         } else {
       
    74             return retrieve(url, closeController);
       
    75         }
       
    76     }
       
    77 
       
    78     /*
       
    79      * Changed modifier from private to public in order to be able
       
    80      * to instantiate URLJarFile from sun.plugin package.
       
    81      */
       
    82     public URLJarFile(File file) throws IOException {
       
    83         this(file, null);
       
    84     }
       
    85 
       
    86     /*
       
    87      * Changed modifier from private to public in order to be able
       
    88      * to instantiate URLJarFile from sun.plugin package.
       
    89      */
       
    90     public URLJarFile(File file, URLJarFileCloseController closeController) throws IOException {
       
    91         super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
       
    92         this.closeController = closeController;
       
    93     }
       
    94 
       
    95     private URLJarFile(File file, URLJarFileCloseController closeController, Runtime.Version version)
       
    96             throws IOException {
       
    97         super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE, version);
       
    98         this.closeController = closeController;
       
    99     }
       
   100 
       
   101     private URLJarFile(URL url, URLJarFileCloseController closeController, Runtime.Version version)
       
   102             throws IOException {
       
   103         super(new File(ParseUtil.decode(url.getFile())), true, ZipFile.OPEN_READ, version);
       
   104         this.closeController = closeController;
       
   105     }
       
   106 
       
   107     private static boolean isFileURL(URL url) {
       
   108         if (url.getProtocol().equalsIgnoreCase("file")) {
       
   109             /*
       
   110              * Consider this a 'file' only if it's a LOCAL file, because
       
   111              * 'file:' URLs can be accessible through ftp.
       
   112              */
       
   113             String host = url.getHost();
       
   114             if (host == null || host.equals("") || host.equals("~") ||
       
   115                 host.equalsIgnoreCase("localhost"))
       
   116                 return true;
       
   117         }
       
   118         return false;
       
   119     }
       
   120 
       
   121     /**
       
   122      * Returns the <code>ZipEntry</code> for the given entry name or
       
   123      * <code>null</code> if not found.
       
   124      *
       
   125      * @param name the JAR file entry name
       
   126      * @return the <code>ZipEntry</code> for the given entry name or
       
   127      *         <code>null</code> if not found
       
   128      * @see java.util.zip.ZipEntry
       
   129      */
       
   130     public ZipEntry getEntry(String name) {
       
   131         ZipEntry ze = super.getEntry(name);
       
   132         if (ze != null) {
       
   133             if (ze instanceof JarEntry)
       
   134                 return new URLJarFileEntry((JarEntry)ze);
       
   135             else
       
   136                 throw new InternalError(super.getClass() +
       
   137                                         " returned unexpected entry type " +
       
   138                                         ze.getClass());
       
   139         }
       
   140         return null;
       
   141     }
       
   142 
       
   143     public Manifest getManifest() throws IOException {
       
   144 
       
   145         if (!isSuperMan()) {
       
   146             return null;
       
   147         }
       
   148 
       
   149         Manifest man = new Manifest();
       
   150         Attributes attr = man.getMainAttributes();
       
   151         attr.putAll((Map)superAttr.clone());
       
   152 
       
   153         // now deep copy the manifest entries
       
   154         if (superEntries != null) {
       
   155             Map<String, Attributes> entries = man.getEntries();
       
   156             for (String key : superEntries.keySet()) {
       
   157                 Attributes at = superEntries.get(key);
       
   158                 entries.put(key, (Attributes) at.clone());
       
   159             }
       
   160         }
       
   161 
       
   162         return man;
       
   163     }
       
   164 
       
   165     /* If close controller is set the notify the controller about the pending close */
       
   166     public void close() throws IOException {
       
   167         if (closeController != null) {
       
   168                 closeController.close(this);
       
   169         }
       
   170         super.close();
       
   171     }
       
   172 
       
   173     // optimal side-effects
       
   174     private synchronized boolean isSuperMan() throws IOException {
       
   175 
       
   176         if (superMan == null) {
       
   177             superMan = super.getManifest();
       
   178         }
       
   179 
       
   180         if (superMan != null) {
       
   181             superAttr = superMan.getMainAttributes();
       
   182             superEntries = superMan.getEntries();
       
   183             return true;
       
   184         } else
       
   185             return false;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Given a URL, retrieves a JAR file, caches it to disk, and creates a
       
   190      * cached JAR file object.
       
   191      */
       
   192      private static JarFile retrieve(final URL url, final URLJarFileCloseController closeController) throws IOException {
       
   193         /*
       
   194          * See if interface is set, then call retrieve function of the class
       
   195          * that implements URLJarFileCallBack interface (sun.plugin - to
       
   196          * handle the cache failure for JARJAR file.)
       
   197          */
       
   198         if (callback != null)
       
   199         {
       
   200             return callback.retrieve(url);
       
   201         }
       
   202 
       
   203         else
       
   204         {
       
   205 
       
   206             JarFile result = null;
       
   207             Runtime.Version version = "runtime".equals(url.getRef())
       
   208                     ? JarFile.runtimeVersion()
       
   209                     : JarFile.baseVersion();
       
   210 
       
   211             /* get the stream before asserting privileges */
       
   212             try (final InputStream in = url.openConnection().getInputStream()) {
       
   213                 result = AccessController.doPrivileged(
       
   214                     new PrivilegedExceptionAction<>() {
       
   215                         public JarFile run() throws IOException {
       
   216                             Path tmpFile = Files.createTempFile("jar_cache", null);
       
   217                             try {
       
   218                                 Files.copy(in, tmpFile, StandardCopyOption.REPLACE_EXISTING);
       
   219                                 JarFile jarFile = new URLJarFile(tmpFile.toFile(), closeController, version);
       
   220                                 tmpFile.toFile().deleteOnExit();
       
   221                                 return jarFile;
       
   222                             } catch (Throwable thr) {
       
   223                                 try {
       
   224                                     Files.delete(tmpFile);
       
   225                                 } catch (IOException ioe) {
       
   226                                     thr.addSuppressed(ioe);
       
   227                                 }
       
   228                                 throw thr;
       
   229                             }
       
   230                         }
       
   231                     });
       
   232             } catch (PrivilegedActionException pae) {
       
   233                 throw (IOException) pae.getException();
       
   234             }
       
   235 
       
   236             return result;
       
   237         }
       
   238     }
       
   239 
       
   240     /*
       
   241      * Set the call back interface to call retrive function in sun.plugin
       
   242      * package if plugin is running.
       
   243      */
       
   244     public static void setCallBack(URLJarFileCallBack cb)
       
   245     {
       
   246         callback = cb;
       
   247     }
       
   248 
       
   249 
       
   250     private class URLJarFileEntry extends JarEntry {
       
   251         private JarEntry je;
       
   252 
       
   253         URLJarFileEntry(JarEntry je) {
       
   254             super(je);
       
   255             this.je=je;
       
   256         }
       
   257 
       
   258         public Attributes getAttributes() throws IOException {
       
   259             if (URLJarFile.this.isSuperMan()) {
       
   260                 Map<String, Attributes> e = URLJarFile.this.superEntries;
       
   261                 if (e != null) {
       
   262                     Attributes a = e.get(getName());
       
   263                     if (a != null)
       
   264                         return  (Attributes)a.clone();
       
   265                 }
       
   266             }
       
   267             return null;
       
   268         }
       
   269 
       
   270         public java.security.cert.Certificate[] getCertificates() {
       
   271             Certificate[] certs = je.getCertificates();
       
   272             return certs == null? null: certs.clone();
       
   273         }
       
   274 
       
   275         public CodeSigner[] getCodeSigners() {
       
   276             CodeSigner[] csg = je.getCodeSigners();
       
   277             return csg == null? null: csg.clone();
       
   278         }
       
   279     }
       
   280 
       
   281     public interface URLJarFileCloseController {
       
   282         public void close(JarFile jarFile);
       
   283     }
       
   284 }