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 FileURLConnection(URL u, File file)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 */ connect()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 initializeHeaders()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 getHeaderField(String name)145 public String getHeaderField(String name) { 146 initializeHeaders(); 147 return super.getHeaderField(name); 148 } 149 getHeaderField(int n)150 public String getHeaderField(int n) { 151 initializeHeaders(); 152 return super.getHeaderField(n); 153 } 154 getContentLength()155 public int getContentLength() { 156 initializeHeaders(); 157 if (length > Integer.MAX_VALUE) 158 return -1; 159 return (int) length; 160 } 161 getContentLengthLong()162 public long getContentLengthLong() { 163 initializeHeaders(); 164 return length; 165 } 166 getHeaderFieldKey(int n)167 public String getHeaderFieldKey(int n) { 168 initializeHeaders(); 169 return super.getHeaderFieldKey(n); 170 } 171 getProperties()172 public MessageHeader getProperties() { 173 initializeHeaders(); 174 return super.getProperties(); 175 } 176 getLastModified()177 public long getLastModified() { 178 initializeHeaders(); 179 return lastModified; 180 } 181 getInputStream()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 */ getPermission()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 } 234