1 /*
   2  * Copyright (c) 1995, 2010, 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 /**
  27  * Open an file input stream given a URL.
  28  * @author      James Gosling
  29  * @author      Steven B. Byrne
  30  */
  31 
  32 package sun.net.www.protocol.file;
  33 
  34 import java.net.URL;
  35 import java.net.FileNameMap;
  36 import java.io.*;
  37 import java.text.Collator;
  38 import java.security.Permission;
  39 import sun.net.*;
  40 import sun.net.www.*;
  41 import java.util.*;
  42 import java.text.SimpleDateFormat;
  43 
  44 import sun.security.action.GetPropertyAction;
  45 import sun.security.action.GetIntegerAction;
  46 import sun.security.action.GetBooleanAction;
  47 
  48 public class FileURLConnection extends URLConnection {
  49 
  50     static String CONTENT_LENGTH = "content-length";
  51     static String CONTENT_TYPE = "content-type";
  52     static String TEXT_PLAIN = "text/plain";
  53     static String LAST_MODIFIED = "last-modified";
  54 
  55     String contentType;
  56     InputStream is;
  57 
  58     File file;
  59     String filename;
  60     boolean isDirectory = false;
  61     boolean exists = false;
  62     List<String> files;
  63 
  64     long length = -1;
  65     long lastModified = 0;
  66 
  67     protected FileURLConnection(URL u, File file) {
  68         super(u);
  69         this.file = file;
  70     }
  71 
  72     /*
  73      * Note: the semantics of FileURLConnection object is that the
  74      * results of the various URLConnection calls, such as
  75      * getContentType, getInputStream or getContentLength reflect
  76      * whatever was true when connect was called.
  77      */
  78     public void connect() throws IOException {
  79         if (!connected) {
  80             try {
  81                 filename = file.toString();
  82                 isDirectory = file.isDirectory();
  83                 if (isDirectory) {
  84                     String[] fileList = file.list();
  85                     if (fileList == null)
  86                         throw new FileNotFoundException(filename + " exists, but is not accessible");
  87                     files = Arrays.<String>asList(fileList);
  88                 } else {
  89 
  90                     is = new BufferedInputStream(new FileInputStream(filename));
  91 
  92                     // Check if URL should be metered
  93                     boolean meteredInput = ProgressMonitor.getDefault().shouldMeterInput(url, "GET");
  94                     if (meteredInput)   {
  95                         ProgressSource pi = new ProgressSource(url, "GET", file.length());
  96                         is = new MeteredStream(is, pi, file.length());
  97                     }
  98                 }
  99             } catch (IOException e) {
 100                 throw e;
 101             }
 102             connected = true;
 103         }
 104     }
 105 
 106     private boolean initializedHeaders = false;
 107 
 108     private void initializeHeaders() {
 109         try {
 110             connect();
 111             exists = file.exists();
 112         } catch (IOException e) {
 113         }
 114         if (!initializedHeaders || !exists) {
 115             length = file.length();
 116             lastModified = file.lastModified();
 117 
 118             if (!isDirectory) {
 119                 FileNameMap map = java.net.URLConnection.getFileNameMap();
 120                 contentType = map.getContentTypeFor(filename);
 121                 if (contentType != null) {
 122                     properties.add(CONTENT_TYPE, contentType);
 123                 }
 124                 properties.add(CONTENT_LENGTH, String.valueOf(length));
 125 
 126                 /*
 127                  * Format the last-modified field into the preferred
 128                  * Internet standard - ie: fixed-length subset of that
 129                  * defined by RFC 1123
 130                  */
 131                 if (lastModified != 0) {
 132                     Date date = new Date(lastModified);
 133                     SimpleDateFormat fo =
 134                         new SimpleDateFormat ("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
 135                     fo.setTimeZone(TimeZone.getTimeZone("GMT"));
 136                     properties.add(LAST_MODIFIED, fo.format(date));
 137                 }
 138             } else {
 139                 properties.add(CONTENT_TYPE, TEXT_PLAIN);
 140             }
 141             initializedHeaders = true;
 142         }
 143     }
 144 
 145     public String getHeaderField(String name) {
 146         initializeHeaders();
 147         return super.getHeaderField(name);
 148     }
 149 
 150     public String getHeaderField(int n) {
 151         initializeHeaders();
 152         return super.getHeaderField(n);
 153     }
 154 
 155     public int getContentLength() {
 156         initializeHeaders();
 157         if (length > Integer.MAX_VALUE)
 158             return -1;
 159         return (int) length;
 160     }
 161 
 162     public long getContentLengthLong() {
 163         initializeHeaders();
 164         return length;
 165     }
 166 
 167     public String getHeaderFieldKey(int n) {
 168         initializeHeaders();
 169         return super.getHeaderFieldKey(n);
 170     }
 171 
 172     public MessageHeader getProperties() {
 173         initializeHeaders();
 174         return super.getProperties();
 175     }
 176 
 177     public long getLastModified() {
 178         initializeHeaders();
 179         return lastModified;
 180     }
 181 
 182     public synchronized InputStream getInputStream()
 183         throws IOException {
 184 
 185         int iconHeight;
 186         int iconWidth;
 187 
 188         connect();
 189 
 190         if (is == null) {
 191             if (isDirectory) {
 192                 FileNameMap map = java.net.URLConnection.getFileNameMap();
 193 
 194                 StringBuffer buf = new StringBuffer();
 195 
 196                 if (files == null) {
 197                     throw new FileNotFoundException(filename);
 198                 }
 199 
 200                 Collections.sort(files, Collator.getInstance());
 201 
 202                 for (int i = 0 ; i < files.size() ; i++) {
 203                     String fileName = files.get(i);
 204                     buf.append(fileName);
 205                     buf.append("\n");
 206                 }
 207                 // Put it into a (default) locale-specific byte-stream.
 208                 is = new ByteArrayInputStream(buf.toString().getBytes());
 209             } else {
 210                 throw new FileNotFoundException(filename);
 211             }
 212         }
 213         return is;
 214     }
 215 
 216     Permission permission;
 217 
 218     /* since getOutputStream isn't supported, only read permission is
 219      * relevant
 220      */
 221     public Permission getPermission() throws IOException {
 222         if (permission == null) {
 223             String decodedPath = ParseUtil.decode(url.getPath());
 224             if (File.separatorChar == '/') {
 225                 permission = new FilePermission(decodedPath, "read");
 226             } else {
 227                 permission = new FilePermission(
 228                         decodedPath.replace('/',File.separatorChar), "read");
 229             }
 230         }
 231         return permission;
 232     }
 233 }