/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.qpid.restapi; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import static java.net.HttpURLConnection.HTTP_OK; import static java.net.HttpURLConnection.HTTP_BAD_METHOD; import static java.net.HttpURLConnection.HTTP_PARTIAL; import static java.net.HttpURLConnection.HTTP_MOVED_PERM; import static java.net.HttpURLConnection.HTTP_FORBIDDEN; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; /** * FileServer is a fairly simple HTTP File Server that can be used to serve files from the root directory specified * during construction. *
* Although this is a relatively simple File Server it is still able to serve large files as it uses streaming, in
* addition it uses the HTTP Range/Content-Range/Content-Length Headers to allow resuming of partial downloads
* from clients that support it.
*
* @author Fraser Adams
*/
public class FileServer implements Server
{
/**
* HashMap mapping file extension to MIME type for common types.
* TODO make this set of mappings configurable via properties or similar mechanism.
*/
private static MapDirectory " + path + "
");
if (path.length() > 1)
{
String u = path.substring(0, path.length() - 1);
int slash = u.lastIndexOf('/');
if (slash >= 0 && slash < u.length())
{
response.append("..
");
}
}
String[] files = directory.list();
for (String name : files)
{
File current = new File(directory, name);
boolean isDir = current.isDirectory();
boolean isFile = current.isFile();
if (isDir)
{
response.append("");
name += "/";
}
response.append("" + name + "");
if (isFile)
{ // If it's a file show the file size
response.append(" (" + renderNumber(current.length()) + ")");
}
response.append("
");
if (isDir)
{
response.append("");
}
}
tx.sendResponse(HTTP_OK, "text/html", response.toString());
return;
}
else
{
tx.sendResponse(HTTP_FORBIDDEN, "text/plain", "403 Forbidden: No directory listing.");
return;
}
}
try
{
// Get MIME type from file name extension, if possible
String fileName = file.getCanonicalPath();
String mime = null;
int dot = fileName.lastIndexOf('.');
if (dot >= 0)
{
String fileExtension = fileName.substring(dot + 1).toLowerCase();
mime = _mimeTypes.get(fileExtension);
}
if (mime == null)
{
mime = "application/octet-stream";
}
// Use Range header allow download resuming.
long startFrom = 0;
long length = file.length();
String range = tx.getHeader("Range");
if (range != null)
{
if (range.startsWith("bytes="))
{
range = range.substring("bytes=".length());
int minus = range.indexOf('-');
if (minus > 0)
{
range = range.substring(0, minus);
}
try
{
startFrom = Long.parseLong(range);
}
catch (NumberFormatException nfe)
{
}
}
}
FileInputStream is = new FileInputStream(file);
is.skip(startFrom);
int status = (startFrom == 0) ? HTTP_OK : HTTP_PARTIAL;
tx.setHeader("Content-Length", "" + (length - startFrom));
tx.setHeader("Content-Range", "" + startFrom + "-" + (length - 1) + "/" + length);
tx.sendResponse(status, mime, is);
}
catch (IOException ioe)
{
tx.sendResponse(HTTP_FORBIDDEN, "text/plain", "403 Forbidden: Reading file failed.");
}
}
/**
* Called by the Web Server to allow a Server to handle a POST request.
*
* @param tx the HttpTransaction containing the request from the client and used to send the response.
*/
public void doPost(final HttpTransaction tx) throws IOException
{
tx.sendResponse(HTTP_BAD_METHOD, "text/plain", "405 Bad Method.");
}
/**
* Called by the Web Server to allow a Server to handle a PUT request.
*
* @param tx the HttpTransaction containing the request from the client and used to send the response.
*/
public void doPut(final HttpTransaction tx) throws IOException
{
tx.sendResponse(HTTP_BAD_METHOD, "text/plain", "405 Bad Method.");
}
/**
* Called by the Web Server to allow a Server to handle a DELETE request.
*
* @param tx the HttpTransaction containing the request from the client and used to send the response.
*/
public void doDelete(final HttpTransaction tx) throws IOException
{
tx.sendResponse(HTTP_BAD_METHOD, "text/plain", "405 Bad Method.");
}
}