package center.app.common;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.w3c.dom.Element;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters;
import com.sun.net.httpserver.HttpsServer;
import ru.vassaev.core.TimeoutInputStream;
import ru.vassaev.core.base.Null;
import ru.vassaev.core.container.ApplicationManager;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.exception.SysRuntimeException;
import ru.vassaev.core.io.OutputByteBuffer;
import ru.vassaev.core.thread.PoolThread;
import ru.vassaev.core.thread.Process;
import ru.vassaev.core.util.Strings;
import ru.vassaev.core.xml.XMLFileWaiter;
import center.task.AProcessor;
import center.task.CalculateException;
import center.task.Context;
import center.task.NewTaskInfo;
import center.task.State;
import center.task.TaskException;
import center.task.TypeOfState;
import center.task.prm.IDependentParam;
/**
* Процессор обработки http запросов
*
* @author Vassaev A.V.
* @version 1.1 13/03/2009
*/
public class HTTPResponseProcessor extends AProcessor {
// private static final int THREADS_AMOUNT = 20;
// private static final int MAX_THREADS_AMOUNT = 2 * THREADS_AMOUNT;
// private static final int QUEUE_CAPACITY = 1024;
private SSLParameters sslp = null;
private boolean https = false;
private HttpServer server = null;
private Integer port;
private String story_file = null;
private char[] story_pwd = null;
private char[] key_pwd = null;
private String path = null;
private PoolThread executor = null;
public void paramsValidateAndPrepare(Context cntx) throws SysException {
port = Strings.parseInteger(cntx.getPrmString("port"));
if (port == null)
throw new SysException("Parameter port isn't set");
https = Strings.parseBooleanNvl(cntx.getPrmString("https"), false);
if (https) {
story_file = cntx.getPrmString("story_file");
if (story_file == null)
throw new SysException("Parameter story_file isn't set");
if (File.separatorChar != '\\')
story_file = story_file.replace('\\', File.separatorChar);
if (File.separatorChar != '/')
story_file = story_file.replace('/', File.separatorChar);
File sf = new File(story_file);
try {
story_file = sf.getCanonicalPath();
} catch (IOException e) {
throw new SysException(e);
}
String story_pwd = cntx.getPrmString("story_pwd");
if (story_pwd == null)
throw new SysException("Parameter story_pwd isn't set");
this.story_pwd = story_pwd.toCharArray();
String key_pwd = cntx.getPrmString("key_pwd");
if (key_pwd == null)
throw new SysException("Parameter key_pwd isn't set");
this.key_pwd = key_pwd.toCharArray();
}
path = cntx.getPrmString("path");
if (path == null)
path = "/";
String poolProcessName = cntx.getPrmString("process_pool");
if (Null.equ(poolProcessName))
throw new SysException("Parameter process_pool isn't set");
executor = (PoolThread) ApplicationManager.getPoolByName(
poolProcessName, Process.class);
}
private Thread main_thread;
public State process(Context cntx) throws TaskException, SysException,
InterruptedException {
paramsValidateAndPrepare(cntx);
main_thread = Process.currentProcess();
try {
// *
if (https)
try {
server = HttpsServer.create(new InetSocketAddress(port), 0);
HttpsServer ss = (HttpsServer) server;
// Получить экземпляр хранилища ключей.
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(story_file);
keyStore.load(fis, story_pwd);
// Получить диспетчеры ключей базовой реализации для
// заданного хранилища ключей.
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance("SunX509");
keyManagerFactory.init(keyStore, key_pwd);
KeyManager[] keyManagers = keyManagerFactory
.getKeyManagers();
// Получить доверенные диспетчеры базовой реализации.
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance("SunX509");
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory
.getTrustManagers();
// Получить защищенное случайное число.
SecureRandom secureRandom = SecureRandom.getInstance(
"SHA1PRNG", "SUN");
// Создание SSL контекста
SSLContext sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(keyManagers, trustManagers, secureRandom);
sslp = sslContext.getSupportedSSLParameters();
boolean needClientAuth = Strings.parseBoolean(cntx
.getPrmNvl("needClientAuth", "false"));
sslp.setNeedClientAuth(needClientAuth);
boolean wantClientAuth = Strings.parseBoolean(cntx
.getPrmNvl("wantClientAuth", "false"));
sslp.setWantClientAuth(wantClientAuth);
HttpsConfigurator conf = new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
params.setSSLParameters(sslp);
}
};
ss.setHttpsConfigurator(conf);
System.setProperty("javax.net.ssl.trustStore", story_file);
System.setProperty("javax.net.ssl.keyStore", story_file);
String trustStore = System
.getProperty("javax.net.ssl.trustStore");
if (trustStore == null)
System.out
.println("javax.net.ssl.trustStore is not defined");
else
System.out.println("javax.net.ssl.trustStore = "
+ trustStore);
String keyStore1 = System
.getProperty("javax.net.ssl.keyStore");
if (keyStore1 == null)
System.out
.println("javax.net.ssl.keyStore is not defined");
else
System.out.println("javax.net.ssl.keyStore = "
+ keyStore1);
} catch (NoSuchProviderException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (NoSuchAlgorithmException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (KeyManagementException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (CertificateException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (UnrecoverableKeyException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (KeyStoreException e) {
throw new TaskException(State.DONE_ERR, e);
}
else
server = HttpServer.create(new InetSocketAddress(port), 0);
server.createContext(path, new XMLHttpHandler(cntx));
server.setExecutor(executor);
server.start();
Process prc = Process.currentProcess();
while (true) {
try {
if (prc.isWillBreak())
return State.BROKEN;
State st = cntx.ta.getState(cntx.id_task);
if (st.getType().equals(TypeOfState.LAST))
return st;
if (st.equals(State.BREAKING))
return State.BROKEN;
} catch (SysException ex) {
ex.printStackTrace();
}
Thread.sleep(2000);// !!!
}
} catch (IOException e) {
throw new TaskException(State.DONE_ERR, e);
} catch (InterruptedException e) {
throw new TaskException(State.DONE_ERR, e);
} finally {
if (server != null)
server.stop(0);
}
}
public final class XMLHttpHandler implements HttpHandler {
private void setPrms(Process cp, Map<String, Object> prms, String key,
Object value) {
cp.regResourceName(value, "msg." + key);
prms.put(key, value);
System.out.println("msg." + key + " = " + value);
}
private Context cntx;
public XMLHttpHandler(Context cntx) {
this.cntx = cntx;
}
public void handle(HttpExchange httpExchange) throws IOException {
Process.currentProcess().setParent(main_thread);
try {
InetSocketAddress ra = httpExchange.getRemoteAddress();
Process cp = Process.currentProcess();
Map<String, Object> prms = new HashMap<String, Object>();
setPrms(cp, prms, "protocol", httpExchange.getProtocol());
setPrms(cp, prms, "method", httpExchange.getRequestMethod());
// setPrms(cp, prms, "remote.hostName", ra.getHostName()); !!!
// TODO
setPrms(cp, prms, "remote.port", ra.getPort());
setPrms(cp, prms, "remote.ip", ra.getAddress().getHostAddress());
setPrms(cp, prms, "query.path", httpExchange.getRequestURI()
.getPath());
String query = httpExchange.getRequestURI().getQuery();
if (query != null) {
String[] eqs = Strings.parseXVSLine(query, '/', '&');
for (int i = 0; i < eqs.length; i++) {
String eq = eqs[i];
int j = eq.indexOf('=');
if (j >= 0)
setPrms(cp, prms, "get." + eq.substring(0, j),
eq.substring(j + 1));
}
setPrms(cp, prms, "query", query);
}
String ct = null;
int cl = 0;
for (Map.Entry<String, List<String>> e : httpExchange
.getRequestHeaders().entrySet()) {
List<String> v = e.getValue();
String k = e.getKey();
if ("Content-type".equals(k))
ct = v.toString();
else if ("Content-length".equals(k))
cl = Strings.parseInteger(v.get(0));
setPrms(cp, prms, "hdrs." + k, v.toString());
}
InputStream is = httpExchange.getRequestBody();
Process tprc = executor.occupyOrNew();
OutputByteBuffer obb = null;
try {
long read_wait = Strings.parseIntegerNvl(
cntx.getPrmByFullName("read_wait"), 10000);// !!!
TimeoutInputStream tis = new TimeoutInputStream(tprc);
tis.setTimeout(read_wait);
tis.setLimitRead(cl);
tis.setCircleBufferSize(50);
tis.startReadSource(is);
obb = (cl <= 0) ? Process.getByteBuffer(8000, tis)
: Process.getByteBuffer(8000, tis, cl);
} catch (SysException e) {
e.printStackTrace();
tprc.interrupt();
throw new SysRuntimeException(e);
} finally {
executor.free(tprc);
}
try {
setPrms(cp, prms, "body", obb);
if ("POST".equals(httpExchange.getRequestMethod())
&& ct != null
&& ct.indexOf("application/x-www-form-urlencoded") >= 0) {
String enc;
try {
enc = cntx.getPrmNvl("request.encoding", "UTF-8");
if (enc == null || enc.trim().length() == 0)
enc = "UTF-8";
} catch (SysException e2) {
enc = "UTF-8";
}
StringBuffer sb = Strings.getStringBuffer(obb.getIS(),
enc);
setPrms(cp, prms, "postquery", sb);
try {
boolean parse_postquery = cntx.getPrmNvl(
"parse_postquery", false);
if (parse_postquery) {
String[] eqs = Strings.parseXVSLine(
sb.toString(), '/', '&');
for (String eq : eqs) {
int j = eq.indexOf('=');
if (j >= 0)
setPrms(cp, prms,
"post." + eq.substring(0, j),
eq.substring(j + 1));
}
}
} catch (SysException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
throw new SysRuntimeException(e);
}
String enc;
try {
enc = cntx.getPrmNvl("response.encoding", "UTF-8");
if (enc == null || enc.trim().length() == 0)
enc = "UTF-8";
} catch (SysException e2) {
enc = "UTF-8";
}
// if (https) {
// HttpsServer srv = (HttpsServer)
// httpExchange.getHttpContext().getServer();
// SSLContext ssl = srv.getHttpsConfigurator().getSSLContext();
// }
NewTaskInfo nti = getChild();
Context cntx_child = null;
try {
String grp_in = cntx.getPrmString("grp_in");
if (grp_in == null)
grp_in = "in";
String grp_out = cntx.getPrmString("grp_out");
if (grp_out == null)
grp_out = "out";
if (!Strings.parseBooleanNvl(
cntx.getPrmString("save-in-body"), true)) {
prms.remove("body");
}
cntx_child = nti.createAndReadyTask(cntx.ta, cntx,
cntx.id_subject, grp_in, prms);
Object res = null;
if ((cntx_child == null) || (cntx_child.id_task <= 0)) {
res = cntx_child
.getPrmByFullName(((grp_out == null) || (grp_out
.length() == 0)) ? "body" : grp_out
+ "/body");
if (res == null) {
Headers hd = httpExchange.getResponseHeaders();
hd.put("Content-Type",
Arrays.asList("text/plain; charset=" + enc));
httpExchange.sendResponseHeaders(503, 0);
OutputStream w = httpExchange.getResponseBody();
w.write("Обработчик не выбран".getBytes(enc));
w.close();
return;
}
} else {
Process.currentProcess().regResourceName(
cntx_child.id_task, "child.id");
long wait = Strings.parseIntegerNvl(
cntx.getPrmByFullName("wait"), 30000);// !!!
cntx.log(false, "Start waiting (", wait, ")");
cntx_child.ta.waitFinished(cntx_child.id_subject,
cntx_child.id_task, wait);
cntx.log(false, "End waiting");
res = cntx_child
.getPrmByFullName(((grp_out == null) || (grp_out
.length() == 0)) ? "body" : grp_out
+ "/body");
}
if (res != null) {
Map<String, Object> result = cntx_child
.getGroupParams(grp_out);
long l = 0;
if (res instanceof FileInputStream) {
is = (FileInputStream) res;
l = ((FileInputStream) is).getChannel().size();
} else if (res instanceof Element) {
Element el = (Element) res;
obb = new OutputByteBuffer(8000);
XMLFileWaiter.putStream(el, obb, "utf-8");
try {
obb.close();
l = obb.getLength();
} catch (IOException e1) {
e1.printStackTrace();
}
is = obb.getIS();
} else if (res instanceof OutputByteBuffer) {
is = ((OutputByteBuffer) res).getIS();
l = ((OutputByteBuffer) res).getLength();
} else if (res instanceof File) {
File f = (File) res;
cntx.log(false, "source file name = ",
f.getCanonicalPath());
is = new FileInputStream(f.getCanonicalPath());
l = f.length();
} else if (res instanceof InputStreamReader) {
InputStreamReader f = (InputStreamReader) res;
File x = File.createTempFile("dbms", "clob");
FileWriter w = new FileWriter(x);
char[] buf = new char[8 * 1024];
int len;
while ((len = f.read(buf)) > 0) {
w.write(buf, 0, len);
}
w.flush();
w.close();
is = new FileInputStream(x);
l = ((FileInputStream) is).getChannel().size();
} else {
byte[] buf = res.toString().getBytes(enc);
is = new ByteArrayInputStream(buf);
l = buf.length;
}
Headers hd = httpExchange.getResponseHeaders();
hd.put("Content-Type",
Arrays.asList("text/plain; charset=" + enc));
hd.put("Content-Length",
Arrays.asList(Long.toString(l)));
String h = cntx.getFullName(grp_out, "hdrs.");
for (Map.Entry<String, Object> e : result.entrySet()) {
String k = e.getKey();
if (k.indexOf(h) == 0) {
k = k.substring(h.length());
Object o = e.getValue();
String v;
if (o != null && o instanceof IDependentParam) {
IDependentParam idp = (IDependentParam) o;
try {
o = idp.getValue(cntx_child);
} catch (CalculateException e1) {
e1.printStackTrace();
}
}
if (o == null)
continue;
v = Strings.getString(o);
hd.put(k, Arrays.asList(v));
}
}
httpExchange.sendResponseHeaders(200, l);
OutputStream w = httpExchange.getResponseBody();
byte[] buf = new byte[8 * 1024];
int len;
while ((len = is.read(buf)) > 0) {
w.write(buf, 0, len);
}
is.close();
w.close();
} else {
httpExchange.sendResponseHeaders(503, 0);
}
} catch (SysException e) {
e.printStackTrace();
if (cntx_child != null)
try {
cntx_child.ta.setState(cntx_child.id_subject,
cntx_child.id_task, State.DONE_ERR);
} catch (SysException e1) {
e1.printStackTrace(); // To change body of catch
// statement use File |
// Settings | File
// Templates.
}
return;
} finally {
try {
cntx.getPrmByFullName("finish", 1000);
} catch (SysException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}// !!!
}
} finally {
httpExchange.close();
}
}
}
@Override
public Set<String> dependentOn() {
// TODO Auto-generated method stub
return null;
}
@Override
public Set<String> loopDependentOn() {
// TODO Auto-generated method stub
return null;
}
}