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 }