summaryrefslogblamecommitdiffstats
path: root/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java
blob: 5f82bac1cc95149e380cb183ede0b39db6ec02e8 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                 
                                    
                           
                             


                               

                                                          
                               
                                                       
                                                
                                                        
                                         
                             
                                      


                                              



                                          

                                                                               





















                                                                                                                                                 


                                                            
                                                                                                 



                                                                                 

         
 
                                    
                                         
                                             

         





















                                                                                


                                                     
 



                                                       












                                                                   

                                                        
                                                                      
                 


                                                                    



                                                                                   





                                                                                

                                                                                   


                                  
 


                                                                                                              

         





                                                                            












                                                                                                        






                                                                         
                                                                                                      
                                                                       

         
                                                      



                                                                                                     










                                                                                                                    
 
package org.openslx.bwlp.sat.web;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.LinkedHashMap;
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.GenericDataCache;
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 int LIST_CACHE_MS = 15000;
	private static final int LIST_CACHE_MAX_ENTRIES = 16;

	private static final Map<String, XmlDataCache> lectureListCache = Collections.synchronizedMap(new LinkedHashMap<String, XmlDataCache>() {
		private static final long serialVersionUID = -8461839969909678055L;

		@Override
		protected boolean removeEldestEntry(Map.Entry<String, XmlDataCache> eldest) {
			return size() > LIST_CACHE_MAX_ENTRIES;
		}
	});

	private static final Serializer serializer = new Persister();

	private class XmlDataCache extends GenericDataCache<byte[]> {

		private final String locationId;

		public XmlDataCache(String locations) {
			super(LIST_CACHE_MS);
			this.locationId = locations;
		}

		@Override
		protected byte[] update() throws Exception {
			VmChooserListXml listXml = DbLecture.getUsableListXml(false, locationId);
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			serializer.write(listXml, baos);
			return baos.toByteArray();
		}

	}

	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")) {
			return serveVmChooserList(session.getParms());
		}
		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) {
		String locations = params.get("locations");
		XmlDataCache cache = lectureListCache.get(locations);
		if (cache == null) {
			cache = new XmlDataCache(locations);
			lectureListCache.put(locations, cache);
		}
		return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/xml; charset=utf-8",
				new ByteArrayInputStream(cache.get()));
	}

	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);
	}

}