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
32package sun.net.www.protocol.file;
33
34import java.net.URL;
35import java.net.FileNameMap;
36import java.io.*;
37import java.text.Collator;
38import java.security.Permission;
39import sun.net.*;
40import sun.net.www.*;
41import java.util.*;
42import java.text.SimpleDateFormat;
43
44public 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}
235