]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/resource/JarFileResource.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / util / resource / JarFileResource.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.util.resource;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.JarURLConnection;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.List;
29 import java.util.jar.JarEntry;
30 import java.util.jar.JarFile;
31
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.util.log.Logger;
34
35 /* ------------------------------------------------------------ */
36 class JarFileResource extends JarResource
37 {
38     private static final Logger LOG = Log.getLogger(JarFileResource.class);
39     private JarFile _jarFile;
40     private File _file;
41     private String[] _list;
42     private JarEntry _entry;
43     private boolean _directory;
44     private String _jarUrl;
45     private String _path;
46     private boolean _exists;
47     
48     /* -------------------------------------------------------- */
49     protected JarFileResource(URL url)
50     {
51         super(url);
52     }
53     
54     /* ------------------------------------------------------------ */
55     protected JarFileResource(URL url, boolean useCaches)
56     {
57         super(url, useCaches);
58     }
59    
60
61     /* ------------------------------------------------------------ */
62     @Override
63     public synchronized void close()
64     {
65         _list=null;
66         _entry=null;
67         _file=null;
68         //if the jvm is not doing url caching, then the JarFiles will not be cached either,
69         //and so they are safe to close
70         if (!getUseCaches())
71         {
72             if ( _jarFile != null )
73             {
74                 try
75                 {
76                     if (LOG.isDebugEnabled())
77                         LOG.debug("Closing JarFile "+_jarFile.getName());
78                     _jarFile.close();
79                 }
80                 catch ( IOException ioe )
81                 {
82                     LOG.ignore(ioe);
83                 }
84             }
85         }
86         _jarFile=null;
87         super.close();
88     }
89     
90     /* ------------------------------------------------------------ */
91     @Override
92     protected synchronized boolean checkConnection()
93     {
94         try
95         {
96             super.checkConnection();
97         }
98         finally
99         {
100             if (_jarConnection==null)
101             {
102                 _entry=null;
103                 _file=null;
104                 _jarFile=null;
105                 _list=null;
106             }
107         }
108         return _jarFile!=null;
109     }
110
111
112     /* ------------------------------------------------------------ */
113     @Override
114     protected synchronized void newConnection()
115         throws IOException
116     {
117         super.newConnection();
118         
119         _entry=null;
120         _file=null;
121         _jarFile=null;
122         _list=null;
123         
124         int sep = _urlString.indexOf("!/");
125         _jarUrl=_urlString.substring(0,sep+2);
126         _path=_urlString.substring(sep+2);
127         if (_path.length()==0)
128             _path=null;   
129         _jarFile=_jarConnection.getJarFile();
130         _file=new File(_jarFile.getName());
131     }
132     
133     
134     /* ------------------------------------------------------------ */
135     /**
136      * Returns true if the represented resource exists.
137      */
138     @Override
139
140     public boolean exists()
141     {
142         if (_exists)
143             return true;
144
145         if (_urlString.endsWith("!/"))
146         {
147             
148             String file_url=_urlString.substring(4,_urlString.length()-2);
149             try{return newResource(file_url).exists();}
150             catch(Exception e) {LOG.ignore(e); return false;}
151         }
152         
153         boolean check=checkConnection();
154         
155         // Is this a root URL?
156         if (_jarUrl!=null && _path==null)
157         {
158             // Then if it exists it is a directory
159             _directory=check;
160             return true;
161         }
162         else 
163         {
164             // Can we find a file for it?
165             boolean close_jar_file= false;
166             JarFile jar_file=null;
167             if (check)
168                 // Yes
169                 jar_file=_jarFile;
170             else
171             {
172                 // No - so lets look if the root entry exists.
173                 try
174                 {
175                     JarURLConnection c=(JarURLConnection)((new URL(_jarUrl)).openConnection());
176                     c.setUseCaches(getUseCaches());
177                     jar_file=c.getJarFile();
178                     close_jar_file = !getUseCaches();
179                 }
180                 catch(Exception e)
181                 {
182                        LOG.ignore(e);
183                 }
184             }
185
186             // Do we need to look more closely?
187             if (jar_file!=null && _entry==null && !_directory)
188             {
189                 // OK - we have a JarFile, lets look at the entries for our path
190                 Enumeration<JarEntry> e=jar_file.entries();
191                 while(e.hasMoreElements())
192                 {
193                     JarEntry entry = e.nextElement();
194                     String name=entry.getName().replace('\\','/');
195                     
196                     // Do we have a match
197                     if (name.equals(_path))
198                     {
199                         _entry=entry;
200                         // Is the match a directory
201                         _directory=_path.endsWith("/");
202                         break;
203                     }
204                     else if (_path.endsWith("/"))
205                     {
206                         if (name.startsWith(_path))
207                         {
208                             _directory=true;
209                             break;
210                         }
211                     }
212                     else if (name.startsWith(_path) && name.length()>_path.length() && name.charAt(_path.length())=='/')
213                     {
214                         _directory=true;
215                         break;
216                     }
217                 }
218             }
219
220             if(close_jar_file && jar_file!=null) 
221             {
222                 try 
223                 {
224                     jar_file.close();
225                 } 
226                 catch (IOException ioe) 
227                 {
228                     LOG.ignore(ioe);
229                 }
230             }
231         }    
232         
233         _exists= ( _directory || _entry!=null);
234         return _exists;
235     }
236
237     
238     /* ------------------------------------------------------------ */
239     /**
240      * Returns true if the represented resource is a container/directory.
241      * If the resource is not a file, resources ending with "/" are
242      * considered directories.
243      */
244     @Override
245     public boolean isDirectory()
246     {
247         return _urlString.endsWith("/") || exists() && _directory;
248     }
249     
250     /* ------------------------------------------------------------ */
251     /**
252      * Returns the last modified time
253      */
254     @Override
255     public long lastModified()
256     {
257         if (checkConnection() && _file!=null)
258         {
259             if (exists() && _entry!=null)
260                 return _entry.getTime();
261             return _file.lastModified();
262         }
263         return -1;
264     }
265
266     /* ------------------------------------------------------------ */
267     @Override
268     public synchronized String[] list()
269     {
270         if (isDirectory() && _list==null)
271         {
272             List<String> list = null;
273             try
274             {
275                 list = listEntries();
276             }
277             catch (Exception e)
278             {
279                 //Sun's JarURLConnection impl for jar: protocol will close a JarFile in its connect() method if
280                 //useCaches == false (eg someone called URLConnection with defaultUseCaches==true).
281                 //As their sun.net.www.protocol.jar package caches JarFiles and/or connections, we can wind up in 
282                 //the situation where the JarFile we have remembered in our _jarFile member has actually been closed
283                 //by other code.
284                 //So, do one retry to drop a connection and get a fresh JarFile
285                 LOG.warn("Retrying list:"+e);
286                 LOG.debug(e);
287                 release();
288                 list = listEntries();
289             }
290
291             if (list != null)
292             {
293                 _list=new String[list.size()];
294                 list.toArray(_list);
295             }  
296         }
297         return _list;
298     }
299     
300     
301     /* ------------------------------------------------------------ */
302     private List<String> listEntries ()
303     {
304         checkConnection();
305         
306         ArrayList<String> list = new ArrayList<String>(32);
307         JarFile jarFile=_jarFile;
308         if(jarFile==null)
309         {
310             try
311             {
312                 JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
313                 jc.setUseCaches(getUseCaches());
314                 jarFile=jc.getJarFile();
315             }
316             catch(Exception e)
317             {
318
319                 e.printStackTrace();
320                  LOG.ignore(e);
321             }
322                 if(jarFile==null)
323                     throw new IllegalStateException();
324         }
325         
326         Enumeration<JarEntry> e=jarFile.entries();
327         String dir=_urlString.substring(_urlString.indexOf("!/")+2);
328         while(e.hasMoreElements())
329         {
330             JarEntry entry = e.nextElement();               
331             String name=entry.getName().replace('\\','/');               
332             if(!name.startsWith(dir) || name.length()==dir.length())
333             {
334                 continue;
335             }
336             String listName=name.substring(dir.length());               
337             int dash=listName.indexOf('/');
338             if (dash>=0)
339             {
340                 //when listing jar:file urls, you get back one
341                 //entry for the dir itself, which we ignore
342                 if (dash==0 && listName.length()==1)
343                     continue;
344                 //when listing jar:file urls, all files and
345                 //subdirs have a leading /, which we remove
346                 if (dash==0)
347                     listName=listName.substring(dash+1, listName.length());
348                 else
349                     listName=listName.substring(0,dash+1);
350                 
351                 if (list.contains(listName))
352                     continue;
353             }
354             
355             list.add(listName);
356         }
357         
358         return list;
359     }
360     
361     
362     
363     
364     
365     /* ------------------------------------------------------------ */
366     /**
367      * Return the length of the resource
368      */
369     @Override
370     public long length()
371     {
372         if (isDirectory())
373             return -1;
374
375         if (_entry!=null)
376             return _entry.getSize();
377         
378         return -1;
379     }
380
381     
382     /**
383      * Take a Resource that possibly might use URLConnection caching
384      * and turn it into one that doesn't.
385      * @param resource
386      * @return the non-caching resource
387      */
388     public static Resource getNonCachingResource (Resource resource)
389     {
390         if (!(resource instanceof JarFileResource))
391             return resource;
392         
393         JarFileResource oldResource = (JarFileResource)resource;
394         
395         JarFileResource newResource = new JarFileResource(oldResource.getURL(), false);
396         return newResource;
397         
398     }
399     
400     /**
401      * Check if this jar:file: resource is contained in the
402      * named resource. Eg <code>jar:file:///a/b/c/foo.jar!/x.html</code> isContainedIn <code>file:///a/b/c/foo.jar</code>
403      * @param resource
404      * @return true if resource is contained in the named resource
405      * @throws MalformedURLException
406      */
407     @Override
408     public boolean isContainedIn (Resource resource) 
409     throws MalformedURLException
410     {
411         String string = _urlString;
412         int index = string.indexOf("!/");
413         if (index > 0)
414             string = string.substring(0,index);
415         if (string.startsWith("jar:"))
416             string = string.substring(4);
417         URL url = new URL(string);
418         return url.sameFile(resource.getURL());     
419     }
420 }
421
422
423
424
425
426
427
428