package org.pasif.server.http;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URLDecoder;
import java.util.Locale;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.entity.FileEntity;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.XPP3Reader;
import org.dom4j.util.XMLErrorHandler;
import org.pas.utils.LoggerHandler;
import org.pas.utils.Utils;
public class PasHttpFileHandler implements HttpRequestHandler {
private String docRoot = null;
private LoggerHandler log = null;
private byte[] pwd = null;
private Document index = null;
private String xsdFile = null;
private SAXReader reader = null;
private XMLWriter writer = null;
public PasHttpFileHandler(String docRoot, final byte[] pwd, LoggerHandler log, String xsdFile) {
super();
this.docRoot = docRoot;
this.log = log;
this.pwd = pwd;
this.xsdFile = xsdFile;
}
public void handle(final HttpRequest request,
final HttpResponse response, final HttpContext context)
throws HttpException, IOException {
String method = request.getRequestLine().getMethod().toUpperCase(
Locale.ENGLISH);
String target = request.getRequestLine().getUri();
if (method.equals("POST") && request instanceof HttpEntityEnclosingRequest) {
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
if (target.equals("--end--")) {
log.info("文件传输完毕。", true);
} else {
log.info("接收文件" + target, true);
target = target.replaceAll("\\\\", "/");
if (target.startsWith("/") && docRoot.endsWith("/")) {
target = docRoot + target.substring(0, target.length() - 2);
} else if (!target.startsWith("/") && !docRoot.endsWith("/")) {
target = docRoot + "/" + target;
} else {
target = docRoot + target;
}
File source = new File(URLDecoder.decode(target, "UTF-8"));
File tmp = new File(URLDecoder.decode(source.getName(), "UTF-8") + ".tmp");
int len = 0;
byte[] con = new byte[1024];
FileOutputStream fos = new FileOutputStream(tmp);
InputStream is = entity.getContent();
while (-1 != (len = is.read(con))) {
fos.write(con, 0, len);
}
fos.flush();
is.close();
fos.close();
log.info("接收文件完毕。", true);
try {
log.info("开始解密文件" + source.getName(), true);
Utils.decryptFile(tmp, source, pwd);
log.info("文件" + source.getName() + "解密完毕。", true);
if (source.getName().contains("Index-")) {
parse(source);
tmp.delete();
} else {
if (index != null) {
Node node = index.getRootElement().selectSingleNode("//item[file=\"" + source.getName() + "\"]/hash");
log.info("开始使用MD5验证文件" + source.getName() + "完整性。", true);
if (Utils.getHashCode(source, "MD5").equals(node.getText())) {
log.info("文件" + source.getName() + "通过MD5验证", true);
log.info("开始使用Schema校验XML文件" + source.getName() + "正确性", true);
if (validXML(source, new File("schema/" + xsdFile))) {
log.info("校验文件" + source.getName() + "成功。", true);
tmp.delete();
} else {
log.error("文件" + source.getName() + "不能通过Schema验证。", true);
source.delete();
tmp.delete();
}
} else {
log.error("文件" + source.getName() + "不能通过MD5验证", true);
source.delete();
tmp.delete();
}
}
}
} catch (Exception e) {
log.error(e.toString(), true);
}
}
} else if (method.equals("GET")) {
final File file = new File(this.docRoot, URLDecoder.decode(
target, "UTF-8"));
if (!file.exists()) {
response.setStatusCode(HttpStatus.SC_NOT_FOUND);
EntityTemplate body = new EntityTemplate(
new ContentProducer() {
public void writeTo(final OutputStream outstream)
throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(
outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write("File ");
writer.write(file.getPath());
writer.write(" not found");
writer.write("</h1></body></html>");
writer.flush();
}
});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
log.error("找不到文件" + file.getPath(), true);
} else if (!file.canRead() || file.isDirectory()) {
response.setStatusCode(HttpStatus.SC_FORBIDDEN);
EntityTemplate body = new EntityTemplate(
new ContentProducer() {
public void writeTo(final OutputStream outstream)
throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(
outstream, "UTF-8");
writer.write("<html><body><h1>");
writer.write("Access denied");
writer.write("</h1></body></html>");
writer.flush();
}
});
body.setContentType("text/html; charset=UTF-8");
response.setEntity(body);
log.error("无法读取文件" + file.getPath(), true);
} else {
response.setStatusCode(HttpStatus.SC_OK);
FileEntity body = new FileEntity(file, "text/html");
response.setEntity(body);
log.info("发送文件" + file.getPath(), true);
}
}
}
private void parse(File tmp) {
XPP3Reader xreader = new XPP3Reader();
try {
index = xreader.read(tmp);
} catch (Exception e) {
log.error(e.toString(), true);
}
}
private boolean validXML(File xmlFile, File xsdFile) {
XMLErrorHandler errorHandler = new XMLErrorHandler();
try {
if (reader == null) {
reader = new SAXReader();
reader.setValidation(true);
reader.setFeature("http://xml.org/sax/features/validation", true);
reader.setFeature("http://apache.org/xml/features/validation/schema", true);
reader.setProperty("http://apache.org/xml/properties/input-buffer-size", 8 * 1024);
}
reader.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
xsdFile.getAbsolutePath());
reader.setErrorHandler(errorHandler);
reader.read(xmlFile);
if (writer == null) {
writer = new XMLWriter(OutputFormat.createPrettyPrint());
}
if (errorHandler.getErrors().hasContent()) {
writer.write(errorHandler.getErrors());
return false;
} else {
return true;
}
} catch (Exception e) {
log.error(e.toString(), true);
return false;
}
}
}