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