package de.tudarmstadt.informatik.hostage.protocol; import java.security.SecureRandom; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Locale; import java.util.TimeZone; import de.tudarmstadt.informatik.hostage.commons.HelperUtils; import de.tudarmstadt.informatik.hostage.wrapper.Packet; /** * HTTP protocol. * Implementation of RFC document 1945. * It can handle the following requests: GET, HEAD, TRACE, POST, DELETE. * For all other requests '400 Bad Request' will be replied. * @author Wulf Pfeiffer */ public class HTTP implements Protocol { @Override public int getDefaultPort() { return 80; } @Override public TALK_FIRST whoTalksFirst() { return TALK_FIRST.CLIENT; } @Override public List processMessage(Packet requestPacket) { String request = null; if (requestPacket != null) { request = requestPacket.toString(); } List responsePackets = new ArrayList(); this.request = request; if(!request.contains(httpVersion)){ responsePackets.add(buildPacket(STATUS_CODE_505, "")); } else if(request.contains(GET)) { responsePackets.add(buildPacket(STATUS_CODE_200, GET)); } else if(request.contains(HEAD)) { responsePackets.add(buildPacket(STATUS_CODE_200, HEAD)); } else if(request.contains(TRACE)){ responsePackets.add(buildPacket(STATUS_CODE_200, TRACE)); } else if(request.contains(OPTIONS)){ responsePackets.add(buildPacket(STATUS_CODE_400, OPTIONS)); } else if(request.contains(POST)){ responsePackets.add(buildPacket(STATUS_CODE_200, POST)); } else if(request.contains(PUT)){ responsePackets.add(buildPacket(STATUS_CODE_400, PUT)); } else if(request.contains(DELETE)){ responsePackets.add(buildPacket(STATUS_CODE_200, DELETE)); } else if(request.contains(CONNECT)){ responsePackets.add(buildPacket(STATUS_CODE_400, CONNECT)); } else { responsePackets.add(buildPacket(STATUS_CODE_400, "")); } return responsePackets; } @Override public boolean isClosed() { return true; } @Override public boolean isSecure() { return false; } @Override public Class getType() { return String.class; } @Override public String toString() { return "HTTP"; } /** * Builds a html response that can be sent * @param code response code that was determined * @param type request type that was sent by the client * @return the html response */ private Packet buildPacket(String code, String type) { String document = ""; if (type.equals(GET)) { document = htmlDocument; } else if (type.equals(HEAD) || type.equals(DELETE)) { document = ""; } else if (type.equals(TRACE)) { document = request; } else { document = errorHtmlPrefix + " " + code + errorHtmlSuffix; } return new Packet(httpVersion + " " + code + headerPrefix + document.length() + headerSuffix + document); } /** * Get the current time in html header format. * @return the formatted server time. */ private static String getServerTime() { Calendar calendar = Calendar.getInstance(); SimpleDateFormat dateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", Locale.US); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); return dateFormat.format(calendar.getTime()); } /** Whole request that was sent by the client */ private String request = ""; //version stuff private static String[][][] possibleHttpVersions = { {{"Apache/2.0."},{"28","32","35","36","39","40","42","43","44","45","46","47","48","49","50","51","52","53","54","55","58","59","61","63","64","65"}}, {{"Apache/2.2."},{"0","2","3","4","6","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25"}}, {{"Apache/2.3."},{"4","5","6","8","10","11","12","14","15","16"}}, {{"Apache/2.4."},{"1","2","3","4","6"}} }; private static String initServerVersion() { SecureRandom rndm = new SecureRandom(); int majorVersion = rndm.nextInt(possibleHttpVersions.length); return possibleHttpVersions[majorVersion][0][0] + possibleHttpVersions[majorVersion][1][rndm.nextInt(possibleHttpVersions[majorVersion][1].length)]; } private String httpVersion = "HTTP/1.1"; private static String serverVersion = initServerVersion(); private static String htmlDocumentContent = HelperUtils.getRandomString(32, false); //request codes private static final String OPTIONS = "OPTIONS"; private static final String GET = "GET"; private static final String HEAD = "HEAD"; private static final String POST = "POST"; private static final String PUT = "PUT"; private static final String DELETE = "DELETE"; private static final String TRACE = "TRACE"; private static final String CONNECT = "CONNECT"; private static final String STATUS_CODE_200 = "200 OK\r\n"; private static final String STATUS_CODE_400 = "400 Bad Request\r\n"; private static final String STATUS_CODE_505 = "505 HTTP Version not supported\r\n"; //html header pre and suffix private String headerPrefix = "Date: " + getServerTime() + "\r\n" + "Server: " + serverVersion + " \r\n" + "Vary: Accept-Encoding\r\n" + "Content-Length: "; private String headerSuffix = "\r\n" + "Keep-Alive: timeout=5, max=100\r\n" + "Connection: Keep-Alive\r\n" + "Content-Type: text/html\r\n" + "\r\n"; //html website private String htmlDocument = "\n" + "\n" + "\n" + "\n" + "" + htmlDocumentContent + "\n" + "" + htmlDocumentContent + "\n" + "\n" + ""; //html error pre and suffix private String errorHtmlPrefix = "\n" + "\n" + "\n" + "\n" + ""; private String errorHtmlSuffix = "\n" + "\n" + ""; /** * Sets the html document content for HTTP and HTTPS. * * @param htmlDocumentContent */ public static void setHtmlDocumentContent(String htmlDocumentContent) { HTTP.htmlDocumentContent = htmlDocumentContent; } }