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
44import sun.security.action.GetPropertyAction;
45import sun.security.action.GetIntegerAction;
46import sun.security.action.GetBooleanAction;
47
48public 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
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     */
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
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
145    public String getHeaderField(String name) {
146        initializeHeaders();
147        return super.getHeaderField(name);
148    }
149
150    public String getHeaderField(int n) {
151        initializeHeaders();
152        return super.getHeaderField(n);
153    }
154
155    public int getContentLength() {
156        initializeHeaders();
157        if (length > Integer.MAX_VALUE)
158            return -1;
159        return (int) length;
160    }
161
162    public long getContentLengthLong() {
163        initializeHeaders();
164        return length;
165    }
166
167    public String getHeaderFieldKey(int n) {
168        initializeHeaders();
169        return super.getHeaderFieldKey(n);
170    }
171
172    public MessageHeader getProperties() {
173        initializeHeaders();
174        return super.getProperties();
175    }
176
177    public long getLastModified() {
178        initializeHeaders();
179        return lastModified;
180    }
181
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     */
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