package org.fnppl.opensdx.http; /* * Copyright (C) 2010-2015 * fine people e.V. <opensdx@fnppl.org> * Henning Thieß <ht@fnppl.org> * * http://fnppl.org */ /* * Software license * * As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied. * * This file is part of openSDX * openSDX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * openSDX is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * and GNU General Public License along with openSDX. * If not, see <http://www.gnu.org/licenses/>. * */ /* * Documentation license * * As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied. * * This file is part of openSDX. * Permission is granted to copy, distribute and/or modify this document * under the terms of the GNU Free Documentation License, Version 1.3 * or any later version published by the Free Software Foundation; * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. * A copy of the license is included in the section entitled "GNU * Free Documentation License" resp. in the file called "FDL.txt". * */ import java.io.*; import java.net.*; import java.util.*; import java.util.Map.Entry; import org.fnppl.opensdx.gui.DefaultMessageHandler; import org.fnppl.opensdx.gui.MessageHandler; import org.fnppl.opensdx.http.HTTPServerRequest; import org.fnppl.opensdx.http.HTTPServerResponse; import org.fnppl.opensdx.keyserver.KeyServerResponse; import org.fnppl.opensdx.security.*; import org.fnppl.opensdx.xml.Document; import org.fnppl.opensdx.xml.Element; public abstract class HTTPServer { // protected String host = "localhost"; protected int port = -1; protected String prepath = ""; private int maxRequestsPerMinute = 100; private int maxThreadCount = 30; protected InetAddress address = null; private HashMap<String, int[]> ipRequests = new HashMap<String, int[]>(); private HashMap<String, Thread> currentWorkingThreads = new HashMap<String, Thread>(); protected OSDXKey signingKey = null; private String serverid = "serverid"; public abstract String getServerID(); public abstract void readConfig(); public abstract HTTPServerResponse prepareResponse(HTTPServerRequest request) throws Exception; public HTTPServer() { } public void exit() { System.exit(0); } public void handleSocket(final Socket s) throws Exception { Thread t = new Thread() { public void run() { String threadID = null; try { InetAddress addr = s.getInetAddress(); String remoteIP = addr.getHostAddress(); int remotePort = s.getPort(); // check on *too* many requests from one ip int[] rc = ipRequests.get(remoteIP); if (rc == null) { ipRequests.put(remoteIP, new int[]{1}); } else { rc[0]++; //System.out.println("anz req: "+rc[0]); if (rc[0]>maxRequestsPerMinute) { if (rc[0]<=100) { System.out.println("WARNING: too many requests ("+rc[0]+") from ip: "+remoteIP); } return; } } threadID = remoteIP+remotePort; currentWorkingThreads.put(threadID,this); try { InputStream _in = s.getInputStream(); BufferedInputStream in = new BufferedInputStream(_in); HTTPServerRequest request = HTTPServerRequest.fromInputStream( in, addr.getHostAddress() ); HTTPServerResponse response = prepareResponse(request); System.out.println("ServerSocket | ::response ready"); if (response == null) { //send error response = new HTTPServerResponse(serverid); response.setRetCode(400, "BAD REQUEST"); } if (response != null) { System.out.println("SENDING THIS::");response.toOutput(System.out);System.out.println("::/SENDING_THIS"); OutputStream out = s.getOutputStream(); BufferedOutputStream bout = new BufferedOutputStream(out); response.toOutput(bout); bout.flush(); bout.close(); } else { Exception ex = new Exception("RESPONSE COULD NOT BE CREATED"); throw ex; } } catch(Exception ex2) { ex2.printStackTrace(); } currentWorkingThreads.remove(threadID); } catch(Exception ex) { ex.printStackTrace(); } } }; t.start(); } public void startService() throws Exception { System.out.println("Starting Server "+getServerID()+" on port " + port +" at "+SecurityHelper.getFormattedDate(System.currentTimeMillis())); ServerSocket so = new ServerSocket(port); Thread requestMonitor = new Thread() { public void run() { while (true) { updateIPRequestCounter(); try { Thread.sleep(60000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; requestMonitor.start(); while (true) { try { while (currentWorkingThreads.size()>maxThreadCount) { Thread.sleep(100); } final Socket me = so.accept(); handleSocket(me); } catch (Exception ex) { ex.printStackTrace(); Thread.sleep(250);// cooldown... } } //System.out.println("Service closed at "+SecurityHelper.getFormattedDate(System.currentTimeMillis())); } private void updateIPRequestCounter() { try { Vector<String> remove = new Vector<String>(); for (Entry<String, int[]> e : ipRequests.entrySet()) { int[] v = e.getValue(); v[0] -= maxRequestsPerMinute; //System.out.println(e.getKey()+ " v[0] = "+v[0]); if (v[0] < 0) { remove.add(e.getKey()); } } for (String r : remove) { ipRequests.remove(r); } } catch (Exception ex) { ex.printStackTrace(); } } }