HTTP.java 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package de.tudarmstadt.informatik.hostage.protocol;
  2. import java.io.BufferedReader;
  3. import java.io.InputStreamReader;
  4. import java.net.Socket;
  5. import java.security.SecureRandom;
  6. import java.text.SimpleDateFormat;
  7. import java.util.ArrayList;
  8. import java.util.Calendar;
  9. import java.util.List;
  10. import java.util.Locale;
  11. import java.util.TimeZone;
  12. import android.content.Context;
  13. import android.os.AsyncTask;
  14. import de.tudarmstadt.informatik.hostage.Hostage;
  15. import de.tudarmstadt.informatik.hostage.R;
  16. import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
  17. import de.tudarmstadt.informatik.hostage.wrapper.Packet;
  18. /**
  19. * HTTP protocol. Implementation of RFC document 1945. It can handle the
  20. * following requests: GET, HEAD, TRACE, POST, DELETE. For all other requests
  21. * '400 Bad Request' will be replied.
  22. *
  23. * @author Wulf Pfeiffer
  24. */
  25. public class HTTP implements Protocol {
  26. public HTTP() {
  27. htmlDocumentContent = HelperUtils.getRandomString(32, false);
  28. Context context = Hostage.getContext();
  29. String sharedPreferencePath = context.getString(R.string.shared_preference_path);
  30. boolean useQotd = context.getSharedPreferences(sharedPreferencePath,
  31. Hostage.MODE_PRIVATE).getBoolean("useQotd", true);
  32. if (useQotd) {
  33. new QotdTask().execute(new String[] {});
  34. }
  35. }
  36. /**
  37. * Task for accuiring a qotd from one of four possible servers.
  38. *
  39. * @author Wulf Pfeiffer
  40. */
  41. private class QotdTask extends AsyncTask<String, Void, String> {
  42. @Override
  43. protected String doInBackground(String... unused) {
  44. String[] sources = new String[] { "djxmmx.net", "ota.iambic.com",
  45. "alpha.mike-r.com", "electricbiscuit.org" };
  46. SecureRandom rndm = new SecureRandom();
  47. StringBuffer sb = new StringBuffer();
  48. try {
  49. Socket client = new Socket(sources[rndm.nextInt(4)], 17);
  50. BufferedReader in = new BufferedReader(new InputStreamReader(
  51. client.getInputStream()));
  52. while (!in.ready())
  53. ;
  54. while (in.ready()) {
  55. sb.append(in.readLine());
  56. }
  57. in.close();
  58. client.close();
  59. } catch (Exception e) {
  60. e.printStackTrace();
  61. }
  62. return sb.toString();
  63. }
  64. @Override
  65. protected void onPostExecute(String result) {
  66. if (result != null)
  67. HTTP.setHtmlDocumentContent(result);
  68. }
  69. }
  70. /**
  71. * Get the current time in html header format.
  72. *
  73. * @return the formatted server time.
  74. */
  75. private static String getServerTime() {
  76. Calendar calendar = Calendar.getInstance();
  77. SimpleDateFormat dateFormat = new SimpleDateFormat(
  78. "EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
  79. dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
  80. return dateFormat.format(calendar.getTime());
  81. }
  82. /** Whole request that was sent by the client */
  83. private String request = "";
  84. // version stuff
  85. private static String[][][] possibleHttpVersions = {
  86. {
  87. { "Apache/2.0." },
  88. { "28", "32", "35", "36", "39", "40", "42", "43", "44",
  89. "45", "46", "47", "48", "49", "50", "51", "52",
  90. "53", "54", "55", "58", "59", "61", "63", "64",
  91. "65" } },
  92. {
  93. { "Apache/2.2." },
  94. { "0", "2", "3", "4", "6", "8", "9", "10", "11", "12",
  95. "13", "14", "15", "16", "17", "18", "19", "20",
  96. "21", "22", "23", "24", "25" } },
  97. { { "Apache/2.3." },
  98. { "4", "5", "6", "8", "10", "11", "12", "14", "15", "16" } },
  99. { { "Apache/2.4." }, { "1", "2", "3", "4", "6" } } };
  100. private static String serverVersion = initServerVersion();
  101. private static String initServerVersion() {
  102. SecureRandom rndm = new SecureRandom();
  103. int majorVersion = rndm.nextInt(possibleHttpVersions.length);
  104. return possibleHttpVersions[majorVersion][0][0]
  105. + possibleHttpVersions[majorVersion][1][rndm
  106. .nextInt(possibleHttpVersions[majorVersion][1].length)];
  107. }
  108. private String httpVersion = "HTTP/1.1";
  109. private static String htmlDocumentContent;
  110. // request codes
  111. private static final String OPTIONS = "OPTIONS";
  112. private static final String GET = "GET";
  113. private static final String HEAD = "HEAD";
  114. private static final String POST = "POST";
  115. private static final String PUT = "PUT";
  116. private static final String DELETE = "DELETE";
  117. private static final String TRACE = "TRACE";
  118. private static final String CONNECT = "CONNECT";
  119. private static final String STATUS_CODE_200 = "200 OK\r\n";
  120. private static final String STATUS_CODE_400 = "400 Bad Request\r\n";
  121. private static final String STATUS_CODE_505 = "505 HTTP Version not supported\r\n";
  122. /**
  123. * Sets the html document content for HTTP and HTTPS.
  124. *
  125. * @param htmlDocumentContent
  126. */
  127. public static void setHtmlDocumentContent(String htmlDocumentContent) {
  128. HTTP.htmlDocumentContent = htmlDocumentContent;
  129. }
  130. // html header pre and suffix
  131. private String headerPrefix = "Date: " + getServerTime() + "\r\n"
  132. + "Server: " + serverVersion + " \r\n"
  133. + "Vary: Accept-Encoding\r\n" + "Content-Length: ";
  134. private String headerSuffix = "\r\n" + "Keep-Alive: timeout=5, max=100\r\n"
  135. + "Connection: Keep-Alive\r\n" + "Content-Type: text/html\r\n"
  136. + "\r\n";
  137. // html website
  138. private String htmlDocument = "<!doctype html>\n" + "<html lang=\"en\">\n"
  139. + "<head>\n" + "<meta charset=\"UTF-8\">\n" + "<title>"
  140. + htmlDocumentContent + "</title>\n" + "<body>"
  141. + htmlDocumentContent + "</body>\n" + "</head>\n" + "</html>";
  142. // html error pre and suffix
  143. private String errorHtmlPrefix = "<!doctype html>\n"
  144. + "<html lang=\"en\">\n" + "<head>\n"
  145. + "<meta charset=\"UTF-8\">\n" + "<title>";
  146. private String errorHtmlSuffix = "</title>\n" + "</head>\n" + "</html>";
  147. @Override
  148. public int getPort() {
  149. return 80;
  150. }
  151. @Override
  152. public boolean isClosed() {
  153. return true;
  154. }
  155. @Override
  156. public boolean isSecure() {
  157. return false;
  158. }
  159. @Override
  160. public List<Packet> processMessage(Packet requestPacket) {
  161. String request = null;
  162. if (requestPacket != null) {
  163. request = requestPacket.toString();
  164. }
  165. List<Packet> responsePackets = new ArrayList<Packet>();
  166. this.request = request;
  167. if (!request.contains(httpVersion)) {
  168. responsePackets.add(buildPacket(STATUS_CODE_505, ""));
  169. } else if (request.contains(GET)) {
  170. responsePackets.add(buildPacket(STATUS_CODE_200, GET));
  171. } else if (request.contains(HEAD)) {
  172. responsePackets.add(buildPacket(STATUS_CODE_200, HEAD));
  173. } else if (request.contains(TRACE)) {
  174. responsePackets.add(buildPacket(STATUS_CODE_200, TRACE));
  175. } else if (request.contains(OPTIONS)) {
  176. responsePackets.add(buildPacket(STATUS_CODE_400, OPTIONS));
  177. } else if (request.contains(POST)) {
  178. responsePackets.add(buildPacket(STATUS_CODE_200, POST));
  179. } else if (request.contains(PUT)) {
  180. responsePackets.add(buildPacket(STATUS_CODE_400, PUT));
  181. } else if (request.contains(DELETE)) {
  182. responsePackets.add(buildPacket(STATUS_CODE_200, DELETE));
  183. } else if (request.contains(CONNECT)) {
  184. responsePackets.add(buildPacket(STATUS_CODE_400, CONNECT));
  185. } else {
  186. responsePackets.add(buildPacket(STATUS_CODE_400, ""));
  187. }
  188. return responsePackets;
  189. }
  190. @Override
  191. public String toString() {
  192. return "HTTP";
  193. }
  194. @Override
  195. public TALK_FIRST whoTalksFirst() {
  196. return TALK_FIRST.CLIENT;
  197. }
  198. /**
  199. * Builds a html response that can be sent
  200. *
  201. * @param code
  202. * response code that was determined
  203. * @param type
  204. * request type that was sent by the client
  205. * @return the html response
  206. */
  207. private Packet buildPacket(String code, String type) {
  208. String document = "";
  209. if (type.equals(GET)) {
  210. document = htmlDocument;
  211. } else if (type.equals(HEAD) || type.equals(DELETE)) {
  212. document = "";
  213. } else if (type.equals(TRACE)) {
  214. document = request;
  215. } else {
  216. document = errorHtmlPrefix + " " + code + errorHtmlSuffix;
  217. }
  218. return new Packet(httpVersion + " " + code + headerPrefix
  219. + document.length() + headerSuffix + document);
  220. }
  221. }