package org.openslx.bwlp.sat.web;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Map;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.log4j.Logger;
import org.openslx.bwlp.sat.database.mappers.DbLecture;
import org.openslx.bwlp.sat.fileserv.FileServer;
import org.openslx.bwlp.thrift.iface.TNotFoundException;
import org.openslx.util.Json;
import org.openslx.util.vm.VmMetaData;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import fi.iki.elonen.NanoHTTPD;
public class WebServer extends NanoHTTPD {
private static final Logger LOGGER = Logger.getLogger(WebServer.class);
private static final Serializer serializer = new Persister();
public WebServer(int port) {
super("127.0.0.1", port);
super.maxRequestSize = 65535;
}
/**
* Extract request source ip address. Honors the x-forwarded-for header.
*
* @param headers
* map of headers as supplied by nanohttpd
* @return IP address, or empty string if unknown
*/
private String extractIp(Map<String, String> headers) {
String ip;
ip = headers.get("remote-addr");
if (ip != null && !ip.equals("127.0.0.1"))
return ip;
if (headers == null || headers.isEmpty())
return "";
ip = headers.get("x-forwarded-for");
if (ip == null || ip.isEmpty())
return "";
final int i = ip.lastIndexOf(',');
if (i == -1)
return ip.trim();
return ip.substring(i + 1).trim();
}
@Override
public Response serve(IHTTPSession session) {
String uri = session.getUri();
if (uri == null || uri.length() == 0) {
return internalServerError();
}
// Sanitize
if (uri.contains("//")) {
uri = uri.replaceAll("//+", "/");
}
try {
return handle(session, uri);
} catch (Throwable t) {
return internalServerError();
}
}
private Response handle(IHTTPSession session, String uri) {
// Our special stuff
if (uri.startsWith("/vmchooser/list")) {
try {
return serveVmChooserList(session.getParms());
} catch (Exception e) {
LOGGER.debug("problem while retrieving the vmChooserList", e);
return internalServerError();
}
}
if (uri.startsWith("/vmchooser/lecture/")) {
return serveLectureStart(uri.substring(19));
}
if (uri.startsWith("/status/fileserver")) {
return serveStatus();
}
if (session.getMethod() == Method.POST && uri.startsWith("/do/")) {
try {
session.parseBody(null);
} catch (IOException | ResponseException e) {
LOGGER.debug("could not parse request body", e);
return internalServerError();
}
return WebRpc.handle(uri.substring(4), session.getParms());
}
return notFound();
}
private Response serveStatus() {
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "application/json; charset=utf-8",
Json.serialize(FileServer.instance().getStatus()));
}
/**
* Return meta data (eg. *.vmx) required to start the given lecture.
*
* @param lectureId
* @return
*/
private Response serveLectureStart(String lectureId) {
VmMetaData meta;
try {
meta = DbLecture.getClientLaunchData(lectureId);
} catch (TNotFoundException e) {
return notFound();
} catch (SQLException e) {
return internalServerError();
}
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/plain; charset=utf-8",
new ByteArrayInputStream(meta.getFilteredDefinitionArray()));
}
private Response serveVmChooserList(Map<String, String> params) throws Exception {
String locations = params.get("locations");
boolean exams = params.containsKey("exams");
VmChooserListXml listXml = DbLecture.getUsableListXml(exams, locations);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.write(listXml, baos);
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/xml; charset=utf-8",
new ByteArrayInputStream(baos.toByteArray()));
}
public static Response internalServerError() {
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.INTERNAL_ERROR, "text/plain", "Internal Server Error");
}
public static Response notFound() {
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.NOT_FOUND, "text/plain", "Nicht gefunden!");
}
public static Response badRequest(String message) {
if (message == null) {
message = "Schlechte Anfrage!";
}
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.BAD_REQUEST, "text/plain", message);
}
}