src-main.org.kawanfw.file.servlet.ServerFileUploadAction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of awake-file Show documentation
Show all versions of awake-file Show documentation
Awake FILE is a secure Open Source framework that allows to program very easily file uploads/downloads and RPC through http. File transfers include
powerful features like file chunking and automatic recovery mechanism.
Security has been taken into account from the design: server side allows
to specify strong security rules in order to protect the files and to secure the RPC calls.
The newest version!
/*
* This file is part of Awake FILE.
* Awake file: Easy file upload & download over HTTP with Java.
* Copyright (C) 2015, KawanSoft SAS
* (http://www.kawansoft.com). All rights reserved.
*
* Awake FILE is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Awake FILE 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Any modifications to this file must keep this entire header
* intact.
*/
package org.kawanfw.file.servlet;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.kawanfw.commons.api.server.CommonsConfigurator;
import org.kawanfw.commons.server.util.ServerLogger;
import org.kawanfw.commons.util.FrameworkDebug;
import org.kawanfw.commons.util.HtmlConverter;
import org.kawanfw.commons.util.Tag;
import org.kawanfw.commons.util.TransferStatus;
import org.kawanfw.file.api.server.FileConfigurator;
import org.kawanfw.file.servlet.convert.StreamsEncrypted;
import org.kawanfw.file.servlet.util.FileTransferManager;
import org.kawanfw.file.util.parms.Parameter;
import org.kawanfw.file.util.parms.ReturnCode;
/**
*
* @author Nicolas de Pomereu
*
* Upload file name See Word Documentation for help
*/
public class ServerFileUploadAction {
private static boolean DEBUG = FrameworkDebug
.isSet(ServerFileUploadAction.class);
// Max file size
@SuppressWarnings("unused")
private static final int MAX_FILE_SIZE = 1024 * 1024 * 20;
// A space
public static final String SPACE = " ";
/**
*
* Execute the dispatched request
*
* @param request
* the http request
* @param response
* the http response
* @param servletContextTempDir
* The temp dir used by Servlets
* @param commonsConfigurator
* the client login specific class
* @throws IOException
*/
public void executeAction(HttpServletRequest request,
HttpServletResponse response, File servletContextTempDir,
CommonsConfigurator commonsConfigurator,
FileConfigurator fileConfigurator) throws IOException {
PrintWriter out = response.getWriter();
try {
String username = null;
String token = null;
String filename = null;
long chunkLength = 0;
response.setContentType("text/html");
// Prepare the response
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
debug("isMultipart: " + isMultipart);
if (!isMultipart) {
return;
}
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(servletContextTempDir);
debug("servletContextTempDir: " + servletContextTempDir);
// Create a new file upload handler using the factory
// that define the secure temp dir
ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
// Parse the request
// List /* FileItem */ items = upload.parseRequest(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
debug("name: " + name);
// The input Stream for the File
InputStream stream = item.openStream();
if (item.isFormField()) {
if (name.equals(Parameter.USERNAME)) {
// username = Streams.asString(stream);
username = StreamsEncrypted.asString(stream,
commonsConfigurator);
// Not sure it's necessary:
username = HtmlConverter.fromHtml(username);
debug("username: " + username);
} else if (name.equals(Parameter.TOKEN)) {
// token = Streams.asString(stream);
token = StreamsEncrypted.asString(stream,
commonsConfigurator);
debug("token: " + token);
} else if (name.equals(Parameter.FILENAME)) {
// filename = Streams.asString(stream);
filename = StreamsEncrypted.asString(stream,
commonsConfigurator);
debug("filename: " + filename);
} else if (name.equals(Parameter.CHUNKLENGTH)) {
String chunklengthStr = StreamsEncrypted.asString(
stream, commonsConfigurator);
chunkLength = Long.parseLong(chunklengthStr);
debug("chunklengthStr: " + chunklengthStr);
}
} else {
if (!isTokenValid(out, username, token, commonsConfigurator)) // Security
// check
{
return;
}
// Not sure it's necessary:
filename = HtmlConverter.fromHtml(filename);
debug("");
debug("File field " + name + " with file name "
+ item.getName() + " detected.");
debug("filename: " + filename);
new FileTransferManager().upload(fileConfigurator, stream,
username, filename, chunkLength);
out.println(TransferStatus.SEND_OK);
out.println("OK");
return;
}
}
} catch (Throwable throwable) {
Throwable finalThrowable = ServerFileDispatch.getFinalThrowable(throwable);
out.println(TransferStatus.SEND_FAILED);
out.println(finalThrowable.getClass().getName());
out.println(ServerUserThrowable.getMessage(finalThrowable));
out.println(ExceptionUtils.getStackTrace(finalThrowable)); // stack trace
try {
ServerLogger.getLogger().log(
Level.WARNING,
Tag.PRODUCT_EXCEPTION_RAISED + " "
+ ServerUserThrowable.getMessage(finalThrowable));
ServerLogger.getLogger().log(
Level.WARNING,
Tag.PRODUCT_EXCEPTION_RAISED + " "
+ ExceptionUtils.getStackTrace(finalThrowable));
} catch (Exception e1) {
e1.printStackTrace();
e1.printStackTrace(System.out);
}
}
}
/**
* Check the validity of the (username, token) pair
*
* @param out
* the out stream
* @param username
* the username to check
* @param token
* the associated token with the login
* @param commonsConfigurator
* the client commons configurator
*
* @return true if the pair (login, token) is verified and ok.
* @throws Exception
*/
private boolean isTokenValid(PrintWriter out, String username,
String token, CommonsConfigurator commonsConfigurator)
throws Exception {
// OK! Now build a token with SHA-1(username + secretValue)
String tokenRecomputed = CommonsConfiguratorCall.computeAuthToken(
commonsConfigurator, username);
if (token == null || !token.equals(tokenRecomputed)) {
debug("username : " + username + ":");
debug("token : " + token + ":");
debug("tokenRecomputed: " + tokenRecomputed + ":");
out.println(TransferStatus.SEND_OK + SPACE
+ ReturnCode.INVALID_LOGIN_OR_PASSWORD);
return false;
}
return true;
}
/**
* return the filename without the trailing / or \\
*
* @param filename
* the filename to remove the trailing file separator
* @return
*/
public static String removeTrailingFileSep(String filename) {
if (filename == null) {
return null;
}
if (filename.startsWith("" + File.separatorChar)) {
filename = filename.substring(1);
}
return filename;
}
private void debug(String s) {
if (DEBUG) {
ServerLogger.getLogger().log(Level.WARNING, s);
}
}
}