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