1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  this work for additional information regarding copyright ownership.
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  the License.  You may obtain a copy of the License at
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  See the License for the specific language governing permissions and
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  limitations under the License.
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.apache.harmony.luni.internal.net.www.protocol.file;
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.BufferedInputStream;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayInputStream;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayOutputStream;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FileInputStream;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FilePermission;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.InputStream;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.PrintStream;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.URL;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.URLConnection;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.luni.internal.net.www.MimeTable;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.luni.util.Util;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This subclass extends <code>URLConnection</code>.
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p>
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This class is responsible for connecting, getting content and input stream of
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the file.
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class FileURLConnection extends URLConnection {
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    String fileName;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private InputStream is;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int length = -1;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isDir;
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private FilePermission permission;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates an instance of <code>FileURLConnection</code> for establishing
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * a connection to the file pointed by this <code>URL<code>
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param url The URL this connection is connected to
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public FileURLConnection(URL url) {
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(url);
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fileName = url.getFile();
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (fileName == null) {
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fileName = ""; //$NON-NLS-1$
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fileName = Util.decode(fileName, false);
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This methods will attempt to obtain the input stream of the file pointed
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * by this <code>URL</code>. If the file is a directory, it will return
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * that directory listing as an input stream.
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO error occurs while connecting
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void connect() throws IOException {
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        File f = new File(fileName);
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (f.isDirectory()) {
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            isDir = true;
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            is = getDirectoryListing(f);
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // use -1 for the contentLength
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // BEGIN android-modified
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            is = new BufferedInputStream(new FileInputStream(f), 8192);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // END android-modified
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            length = is.available();
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        connected = true;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the length of the file in bytes.
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the length of the file
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see #getContentType()
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getContentLength() {
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!connected) {
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                connect();
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IOException e) {
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // default is -1
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return length;
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the content type of the resource. Just takes a guess based on the
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * name.
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the content type
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String getContentType() {
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!connected) {
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                connect();
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IOException e) {
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return MimeTable.UNKNOWN;
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isDir) {
1273819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            return "text/plain"; //$NON-NLS-1$
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String result = guessContentTypeFromName(url.getFile());
1303819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (result != null) {
1313819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            return result;
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1333819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
1343819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        try {
1353819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            result = guessContentTypeFromStream(is);
1363819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        } catch (IOException e) {
1373819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            // Ignore
1383819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        }
1393819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (result != null) {
1403819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            return result;
1413819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        }
1423819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
1433819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        return MimeTable.UNKNOWN;
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the directory listing of the file component as an input stream.
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the input stream of the directory listing
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private InputStream getDirectoryListing(File f) {
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String fileList[] = f.list();
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteArrayOutputStream bytes = new java.io.ByteArrayOutputStream();
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        PrintStream out = new PrintStream(bytes);
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.print("<title>Directory Listing</title>\n"); //$NON-NLS-1$
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.print("<base href=\"file:"); //$NON-NLS-1$
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.print(f.getPath().replace('\\', '/') + "/\"><h1>" + f.getPath() //$NON-NLS-1$
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                + "</h1>\n<hr>\n"); //$NON-NLS-1$
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int i;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (i = 0; i < fileList.length; i++) {
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.print(fileList[i] + "<br>\n"); //$NON-NLS-1$
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.close();
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new ByteArrayInputStream(bytes.toByteArray());
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the input stream of the object referred to by this
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <code>URLConnection</code>
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * File Sample : "/ZIP211/+/harmony/tools/javac/resources/javac.properties"
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Invalid File Sample:
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * "/ZIP/+/harmony/tools/javac/resources/javac.properties"
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * "ZIP211/+/harmony/tools/javac/resources/javac.properties"
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return input stream of the object
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO error occurs
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public InputStream getInputStream() throws IOException {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!connected) {
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            connect();
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return is;
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the permission, in this case the subclass, FilePermission object
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * which represents the permission necessary for this URLConnection to
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * establish the connection.
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the permission required for this URLConnection.
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO exception occurs while creating the permission.
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public java.security.Permission getPermission() throws IOException {
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (permission == null) {
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String path = fileName;
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (File.separatorChar != '/') {
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                path = path.replace('/', File.separatorChar);
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            permission = new FilePermission(path, "read"); //$NON-NLS-1$
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return permission;
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
211