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