com.sun.webkit.network.DirectoryURLConnection Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.webkit.network;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PushbackInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.sun.webkit.network.URLs.newURL;
/*
* Interposing class that will transform the raw stream from a FtpURLConnection
* or FileURLConnection into an HTML page listing the content of the directory
*/
final class DirectoryURLConnection extends URLConnection {
// Patterns used to parse the output from a FTP directory list.
private static final String[] patStrings = {
// drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
// drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
"([\\-ld](?:[r\\-][w\\-][x\\-]){3})\\s*\\d+ (\\w+)\\s*(\\w+)\\s*(\\d+)\\s*([A-Z][a-z][a-z]\\s*\\d+)\\s*((?:\\d\\d:\\d\\d)|(?:\\d{4}))\\s*(\\p{Print}*)",
// 04/28/2006 09:12a 3,563 genBuffer.sh
"(\\d{2}/\\d{2}/\\d{4})\\s*(\\d{2}:\\d{2}[ap])\\s*((?:[0-9,]+)|(?:))\\s*(\\p{Graph}*)",
// 01-29-97 11:32PM prog
"(\\d{2}-\\d{2}-\\d{2})\\s*(\\d{2}:\\d{2}[AP]M)\\s*((?:[0-9,]+)|(?:))\\s*(\\p{Graph}*)"
};
private static final int[][] patternGroups = {
// file, size, date1, date2, permissions
{7, 4, 5, 6, 1},
{4, 3, 1, 2, 0},
{4, 3, 1, 2, 0}
};
private static final Pattern[] patterns;
private static final Pattern linkp = Pattern.compile("(\\p{Print}+) \\-\\> (\\p{Print}+)$");
// Style sheet to make the TABLE better looking
private static final String styleSheet =
"";
static {
patterns = new Pattern[patStrings.length];
for (int i = 0; i < patStrings.length; i++) {
patterns[i] = Pattern.compile(patStrings[i]);
}
}
private final URLConnection inner;
private final boolean sure;
private String dirUrl = null;
// Set toHTML to false when it is not a directory and we don't want to
// change the stream.
private boolean toHTML = true;
private final boolean ftp;
private InputStream ins = null;
/*
* We need an interposing InputStream as well. We subclass PushbackInputStream
* so that we can do some safe read-ahead if we have to guess whether the
* URL points to a directory or not (the read-ahead is for FTP only).
*/
private final class DirectoryInputStream extends PushbackInputStream {
private final byte[] buffer;
private boolean endOfStream = false;
private ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
private PrintStream out = new PrintStream(bytesOut);
private ByteArrayInputStream bytesIn = null;
private final StringBuffer tmpString = new StringBuffer();
private int lineCount = 0;
private DirectoryInputStream(InputStream ins, boolean guess) {
super(ins, 512);
buffer = new byte[512];
/*
* If 'guess' is true, it means it's an FTP link and we're not sure
* this is a directory
*/
if (guess) {
StringBuffer line = new StringBuffer();
int l = 0;
int c;
try {
l = super.read(buffer, 0, buffer.length);
} catch (IOException e) {
}
if (l <= 0) {
toHTML = false;
} else {
for (int i = 0; i < l; i++) {
line.append((char) buffer[i]);
}
String line2 = line.toString();
toHTML = false;
for (Pattern p : patterns) {
Matcher m = p.matcher(line2);
if (m.find()) {
// One of the patterns matched
// Means it's a directory listing
toHTML = true;
break;
}
}
try {
super.unread(buffer, 0, l);
} catch (IOException ioe) {
// Shouldn't happen
}
}
}
if (toHTML) {
/*
* We're good to go. Let's generate the header for the table
*/
String parent = null;
String path;
URL prevUrl = null;
if (!dirUrl.endsWith("/")) {
dirUrl = dirUrl + "/";
}
try {
prevUrl = newURL(dirUrl);
} catch (Exception e) {
// can't happen
}
path = prevUrl.getPath();
if (path != null && !path.isEmpty()) {
int index = path.lastIndexOf("/", path.length() - 2);
if (index >= 0) {
int removed = path.length() - index - 1;
index = dirUrl.indexOf(path);
parent = dirUrl.substring(0, index + path.length() - removed) + dirUrl.substring(index + path.length());
}
}
out.print("index of ");
out.print(dirUrl);
out.print(" ");
out.print(styleSheet);
out.print("Index of ");
out.print(dirUrl);
out.print("
");
out.print("");
out.print("File Size Last Modified ");
if (parent != null) {
lineCount++;
out.print("Up to parent directory ");
}
out.close();
bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
out = null;
bytesOut = null;
}
}
private void parseFile(String s)
{
tmpString.append(s);
int i;
while ((i = tmpString.indexOf("\n")) >= 0) {
String sb = tmpString.substring(0, i);
tmpString.delete(0, i + 1);
String filename = sb;
String size = null;
String date = null;
boolean dir = false;
boolean noaccess = false;
URL furl = null;
if (filename != null) {
lineCount++;
try {
furl = newURL(dirUrl + URLEncoder.encode(filename, "UTF-8"));
URLConnection fconn = furl.openConnection();
fconn.connect();
date = fconn.getHeaderField("last-modified");
size = fconn.getHeaderField("content-length");
if (size == null) {
dir = true;
}
fconn.getInputStream().close();
} catch (IOException e) {
// No access right
noaccess = true;
}
if (bytesOut == null) {
bytesOut = new ByteArrayOutputStream();
out = new PrintStream(bytesOut);
}
out.print("");
if (noaccess) {
out.print(filename);
} else {
out.print("");
out.print(filename);
out.print("");
}
if (dir) {
out.print(" <Directory> ");
} else {
out.print("" + (size == null ? " " : size) + " ");
}
out.print("" + (date == null ? " " : date) + " ");
}
}
if (bytesOut != null) {
out.close();
bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
out = null;
bytesOut = null;
}
}
private void parseFTP(String s)
{
tmpString.append(s);
int i;
while ((i = tmpString.indexOf("\n")) >= 0) {
String sb = tmpString.substring(0, i);
tmpString.delete(0, i + 1);
String filename = null;
String link = null;
String size = null;
String date = null;
boolean dir = false;
Matcher m = null;
for (int j = 0; j < patterns.length; j++) {
m = patterns[j].matcher(sb);
if (m.find()) {
filename = m.group(patternGroups[j][0]);
size = m.group(patternGroups[j][1]);
date = m.group(patternGroups[j][2]);
if (patternGroups[j][3] > 0) {
date += (" " + m.group(patternGroups[j][3]));
}
if (patternGroups[j][4] > 0) {
String perms = m.group(patternGroups[j][4]);
dir = perms.startsWith("d");
}
if ("".equals(size)) {
dir = true;
size = null;
}
}
}
if (filename != null) {
m = linkp.matcher(filename);
if (m.find()) {
// There is a symbolic link
filename = m.group(1);
link = m.group(2);
}
if (bytesOut == null) {
bytesOut = new ByteArrayOutputStream();
out = new PrintStream(bytesOut);
}
lineCount++;
out.print("");
out.print(filename);
out.print("");
if (link != null) {
out.print(" → " + link + " <Link> ");
} else if (dir) {
out.print("<Directory> ");
} else {
out.print("" + size + " ");
}
out.print("" + date + " ");
}
}
if (bytesOut != null) {
out.close();
bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
out = null;
bytesOut = null;
}
}
private void endOfList()
{
// Let's make sure we don't miss the last line because a new-line
// is missing
if (ftp) {
parseFTP("\n");
} else {
parseFile("\n");
}
if (bytesOut == null) {
bytesOut = new ByteArrayOutputStream();
out = new PrintStream(bytesOut);
}
out.print("
");
out.close();
bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
out = null;
bytesOut = null;
}
@Override
public int read(byte[] buf) throws IOException
{
return read(buf, 0, buf.length);
}
@Override
public int read(byte[] buf, int offset, int length) throws IOException
{
int l = 0;
if (!toHTML) {
return super.read(buf, offset, length);
}
if (bytesIn != null) {
l = bytesIn.read(buf, offset, length);
if (l == -1) {
bytesIn.close();
bytesIn = null;
if (endOfStream) {
return -1;
}
} else {
return l;
}
}
if (!endOfStream) {
l = super.read(buffer, 0, buffer.length);
if (l == -1) {
endOfStream = true;
endOfList();
return read(buf, offset, length);
} else {
if (ftp) {
parseFTP(new String(buffer, 0, l));
} else {
parseFile(new String(buffer, 0, l));
}
if (bytesIn != null) {
return read(buf, offset, length);
}
}
}
return 0;
}
}
/*
* Constructor to use for an FTP (or FTPS) URLConnection.
* Set 'notsure' to true if it is necessary to look ahead to make sure
* it is, indeed, a directory.
*/
DirectoryURLConnection(URLConnection con, boolean notsure) {
super(con.getURL());
dirUrl = con.getURL().toExternalForm();
inner = con;
sure = !notsure;
ftp = true;
}
/*
* Constructor to use for a File URLConnection.
*/
DirectoryURLConnection(URLConnection con) {
super(con.getURL());
dirUrl = con.getURL().toExternalForm();
ftp = false;
sure = true;
inner = con;
}
@Override
public void connect() throws IOException
{
inner.connect();
}
@Override
public InputStream getInputStream() throws IOException
{
if (ins == null) {
if (ftp) {
ins = new DirectoryInputStream(inner.getInputStream(), !sure);
} else {
ins = new DirectoryInputStream(inner.getInputStream(), false);
}
}
return ins;
}
@Override
public String getContentType()
{
try {
if (!sure) {
getInputStream();
}
} catch (IOException e) {
}
if (toHTML) {
return "text/html";
}
return inner.getContentType();
}
@Override
public String getContentEncoding()
{
return inner.getContentEncoding();
}
@Override
public int getContentLength()
{
return inner.getContentLength();
}
@Override
public Map> getHeaderFields()
{
return inner.getHeaderFields();
}
@Override
public String getHeaderField(String key)
{
return inner.getHeaderField(key);
}
}