package zeta.handler;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import zeta.ZetaServlet;
import zeta.util.Base64;
import zeta.util.DatabaseUtils;
import zeta.util.Parameter;
import zeta.util.StreamUtils;
import BlowfishJ.BlowfishECB;
public class DataHandler implements GetHandler, PostHandler {
public DataHandler(ZetaServlet servlet) {
this.servlet = servlet;
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream in = null;
Connection con = null;
Statement stmt = null;
try {
con = servlet.getConnection();
stmt = con.createStatement();
String hostnames = Parameter.getValue(stmt, "grant_data_hostnames", Parameter.GLOBAL_PARAMETER, "", 3600000);
if (hostnames.length() > 0) {
String host = req.getRemoteHost() + '(' + req.getRemoteAddr() + ')';
boolean hostHasAccess = false;
StringTokenizer st = new StringTokenizer(hostnames, ",");
while (st.hasMoreTokens()) {
if (host.startsWith(st.nextToken())) {
hostHasAccess = true;
break;
}
}
if (!hostHasAccess) {
throw new ServletException("Access is denied - " + host + '.');
}
}
int serverId = servlet.getServerId();
String list = req.getParameter("list");
String dir = req.getParameter("dir");
String get = req.getParameter("get");
String del = req.getParameter("del");
File pathData = new File(Parameter.getValue(stmt, "path_data", Parameter.GLOBAL_PARAMETER, "", 3600000));
if (!Parameter.getValue(stmt, "encryption", Parameter.GLOBAL_PARAMETER, "Y", 3600000).equals("N")) {
list = dir = get = del = null;
ResultSet rs = stmt.executeQuery("SELECT key FROM zeta.server WHERE server_id=" + serverId);
byte[] serverKey = (rs.next())? rs.getBytes(1) : null;
rs.close();
if (serverKey == null) {
throw new ServletException("Missing key for server " + serverId);
}
String params = null;
try {
int actionsLength = Integer.parseInt(req.getParameter("actions_length"));
BlowfishECB bfecb = new BlowfishECB(serverKey);
byte[] actions = Base64.decode(req.getParameter("actions"));
bfecb.decrypt(actions);
bfecb.cleanUp();
params = new String(actions, 0, actionsLength, "UTF-8");
} catch (Exception e) {
throw new ServletException("Access is denied.", e);
}
if (params == null) {
throw new ServletException("Access is denied.");
}
int i = params.indexOf("dir=");
if (i >= 0) {
dir = params.substring(i+4);
} else {
i = params.indexOf("list=");
if (i >= 0) {
list = params.substring(i+5);
} else {
i = params.indexOf("get=");
if (i >= 0) {
int j = params.indexOf('&', i+4);
get = (j < 0)? params.substring(i+4) : params.substring(i+4, j);
}
i = params.indexOf("del=");
if (i >= 0) {
int j = params.indexOf('&', i+4);
del = (j < 0)? params.substring(i+4) : params.substring(i+4, j);
}
}
}
}
if (dir != null && dir.length() > 0) {
if (!Parameter.getValue(stmt, "grant_data_dir", Parameter.GLOBAL_PARAMETER, "", 3600000).equals("Y") || dir.indexOf("..") >= 0) {
throw new ServletException("Access is denied.");
}
File[] files = new File(pathData.getPath() + '/' + dir).listFiles();
if (files != null && files.length > 0) {
long maxTime = files[0].lastModified();
for (int i = 1; i < files.length; ++i) {
long m = files[i].lastModified();
if (m > maxTime) {
maxTime = m;
}
}
ByteArrayOutputStream out = new ByteArrayOutputStream(50*files.length);
for (int i = 0; i < files.length; ++i) {
long m = files[i].lastModified();
if (m < maxTime) {
String s = files[i].getName() + '\n';
out.write(s.getBytes("UTF-8"));
}
}
out.close();
resp.setContentType("application/octet-stream");
resp.setContentLength(out.size());
out.writeTo(resp.getOutputStream());
}
} else if (list != null && list.length() > 0) {
if (!Parameter.getValue(stmt, "grant_data_list", Parameter.GLOBAL_PARAMETER, "", 3600000).equals("Y") || list.indexOf("..") >= 0) {
throw new ServletException("Access is denied.");
}
File[] files = new File(pathData.getPath() + '/' + list).listFiles();
if (files != null && files.length > 0) {
ByteArrayOutputStream out = new ByteArrayOutputStream(50*files.length);
for (int i = 0; i < files.length; ++i) {
String s = files[i].getName() + '\n';
out.write(s.getBytes("UTF-8"));
}
out.close();
resp.setContentType("application/octet-stream");
resp.setContentLength(out.size());
out.writeTo(resp.getOutputStream());
}
} else {
if (get != null && get.length() > 0) {
if (!Parameter.getValue(stmt, "grant_data_get", Parameter.GLOBAL_PARAMETER, "", 3600000).equals("Y") || get.indexOf("..") >= 0) {
throw new ServletException("Access is denied.");
}
File file = new File(pathData.getPath() + '/' + get);
if (file.exists()) {
resp.setContentType("application/octet-stream");
resp.setContentLength((int)file.length());
in = new FileInputStream(file);
StreamUtils.writeData(in, resp.getOutputStream(), true, true);
}
}
if (del != null && del.length() > 0) {
if (!Parameter.getValue(stmt, "grant_data_del", Parameter.GLOBAL_PARAMETER, "", 3600000).equals("Y") || del.indexOf("..") >= 0) {
throw new ServletException("Access is denied.");
}
File file = new File(pathData.getPath() + '/' + del);
if (!file.delete()) {
throw new IOException("file '" + del + "' is not successfully deleted!");
}
}
}
} catch (IOException e) {
throw new ServletException(e);
} catch (SQLException e) {
throw new ServletException(e);
} finally {
StreamUtils.close(in);
DatabaseUtils.close(stmt);
DatabaseUtils.close(con);
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (req.getContentType().equals("application/octet-stream")) {
String paramString = req.getHeader("Param-String"); Map parameter = HttpUtils.parseQueryString(paramString);
OutputStream out = null;
Connection con = null;
Statement stmt = null;
try {
con = servlet.getConnection();
stmt = con.createStatement();
String hostnames = Parameter.getValue(stmt, "grant_data_hostnames", Parameter.GLOBAL_PARAMETER, "", 3600000);
if (hostnames.length() > 0) {
String s = req.getRemoteHost() + '(' + req.getRemoteAddr() + ')';
int idx = hostnames.indexOf(s);
if (idx == -1 || idx > 0 && hostnames.charAt(idx-1) != ',' || idx+s.length() < hostnames.length() && hostnames.charAt(idx+s.length()) != ',') {
throw new ServletException("Access is denied - " + s + '.');
}
}
String put = getParameter(parameter, "put");
int serverId = servlet.getServerId();
File pathData = new File(Parameter.getValue(stmt, "path_data", Parameter.GLOBAL_PARAMETER, "", 3600000));
if (!Parameter.getValue(stmt, "encryption", Parameter.GLOBAL_PARAMETER, "Y", 3600000).equals("N")) {
put = null;
ResultSet rs = stmt.executeQuery("SELECT key FROM zeta.server WHERE server_id=" + serverId);
byte[] serverKey = (rs.next())? rs.getBytes(1) : null;
rs.close();
if (serverKey == null) {
throw new ServletException("Missing key for server " + serverId);
}
int actionsLength = Integer.parseInt(getParameter(parameter, "actions_length"));
BlowfishECB bfecb = new BlowfishECB(serverKey);
byte[] actions = Base64.decode(getParameter(parameter, "actions"));
bfecb.decrypt(actions);
bfecb.cleanUp();
String params = new String(actions, 0, actionsLength, "UTF-8");
int i = params.indexOf("put=");
if (i >= 0) {
put = params.substring(i+4);
}
}
if (put != null && put.length() > 0) {
if (!Parameter.getValue(stmt, "grant_data_put", Parameter.GLOBAL_PARAMETER, "", 3600000).equals("Y") || put.indexOf("..") >= 0) {
throw new ServletException("Access is denied.");
}
File file = new File(pathData.getPath() + '/' + put);
out = new FileOutputStream(file);
StreamUtils.writeData(req.getInputStream(), out, false, true);
}
} catch (IOException e) {
throw new ServletException(e);
} catch (SQLException e) {
throw new ServletException(e);
} finally {
StreamUtils.close(out);
DatabaseUtils.close(stmt);
DatabaseUtils.close(con);
}
resp.setStatus(HttpServletResponse.SC_OK);
resp.getOutputStream().print("ok");
} else {
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
}
}
private static String getParameter(Map parameter, String key) {
String[] values = (String[])parameter.get(key);
return (values == null || values.length == 0)? "" : values[0];
}
private ZetaServlet servlet;
}