/src/kilim/http/HttpSession.java

http://github.com/kilim/kilim · Java · 163 lines · 103 code · 12 blank · 48 comment · 8 complexity · df4b7bece1e1b5f5cedbebe82aba686b MD5 · raw file

  1. package kilim.http;
  2. /* Copyright (c) 2006, Sriram Srinivasan, nqzero 2016
  3. *
  4. * You may distribute this software under the terms of the license
  5. * specified in the file "License"
  6. */
  7. import java.io.EOFException;
  8. import java.io.File;
  9. import java.io.FileInputStream;
  10. import java.io.IOException;
  11. import java.io.OutputStream;
  12. import java.nio.channels.FileChannel;
  13. import kilim.Pausable;
  14. import kilim.nio.SessionTask;
  15. /**
  16. * Responsible for creating an HTTPRequest object out of raw bytes from a socket, and for sending an HTTPResponse object
  17. * in its entirety.
  18. */
  19. public class HttpSession extends SessionTask {
  20. /**
  21. * Reads the socket, parses the HTTP headers and the body (including chunks) into the req object.
  22. *
  23. * @param req
  24. * . The HttpRequest object is reset before filling it in.
  25. * @return the supplied request object. This is to encourage buffer reuse.
  26. * @throws IOException
  27. */
  28. public HttpRequest readRequest(HttpRequest req) throws IOException, Pausable {
  29. req.reuse();
  30. req.readFrom(endpoint);
  31. return req;
  32. }
  33. // public static void dumpBuf(String msg, ByteBuffer buffer) {
  34. // System.out.println(msg);
  35. // int pos = buffer.position();
  36. // for (int i = 0; i < pos; i++) {
  37. // System.out.print((char)buffer.get(i));
  38. // }
  39. // System.out.println("============================");
  40. // }
  41. /**
  42. * Send the response object in its entirety, and mark it for reuse. Often, the resp object may only contain the
  43. * header, and the body is sent separately. It is the caller's responsibility to make sure that the body matches the
  44. * header (in terms of encoding, length, chunking etc.)
  45. */
  46. public void sendResponse(HttpResponse resp) throws IOException, Pausable {
  47. resp.writeTo(endpoint);
  48. resp.reuse();
  49. }
  50. static byte[] pre = "<html><body><p>".getBytes();
  51. static byte[] post = "</body></html>".getBytes();
  52. /**
  53. * Send an error page to the client.
  54. *
  55. * @param resp The response object.
  56. * @param statusCode See HttpResponse.ST*
  57. * @param htmlMsg The body of the message that gives more detail.
  58. * @throws IOException
  59. * @throws Pausable
  60. */
  61. public void problem(HttpResponse resp, byte[] statusCode, String htmlMsg) throws IOException, Pausable {
  62. resp.status = statusCode;
  63. resp.setContentType("text/html");
  64. OutputStream os = resp.getOutputStream();
  65. os.write(pre);
  66. os.write(htmlMsg.getBytes());
  67. os.write(post);
  68. sendResponse(resp);
  69. }
  70. /**
  71. * send a file with content length to the client
  72. * @param req the request
  73. * @param resp the response
  74. * @param file the file to send
  75. * @param contentType if non-null, set the content type
  76. * @return 0 on success, 1 for not found, 2 for couldn't send
  77. */
  78. public int sendFile(HttpRequest req,HttpResponse resp,File file,String contentType)
  79. throws Pausable {
  80. FileInputStream fis = null;
  81. FileChannel fc;
  82. boolean headOnly = req.method.equals("HEAD");
  83. try {
  84. fis = new FileInputStream(file);
  85. fc = fis.getChannel();
  86. } catch (IOException ex) {
  87. try { fis.close(); } catch (Exception ex2) {}
  88. return 1;
  89. }
  90. try {
  91. if (contentType != null)
  92. resp.setContentType(contentType);
  93. resp.setContentLength(file.length());
  94. sendResponse(resp);
  95. if (!headOnly)
  96. endpoint.write(fc, 0, file.length());
  97. }
  98. catch (IOException ex) {
  99. return 2;
  100. }
  101. finally {
  102. try { fc.close(); } catch (Exception ex) {}
  103. try { fis.close(); } catch (Exception ex) {}
  104. }
  105. return 0;
  106. }
  107. public boolean check(HttpResponse resp,File file,String...bases) throws IOException, Pausable {
  108. try {
  109. String path = file.getCanonicalPath();
  110. for (String base : bases)
  111. if (path.startsWith(base))
  112. return true;
  113. }
  114. catch (Exception ex) {}
  115. return false;
  116. }
  117. public interface StringRouter {
  118. public String route(HttpRequest req) throws Pausable;
  119. }
  120. public static class StringSession extends HttpSession {
  121. StringRouter handler;
  122. public StringSession(StringRouter handler) { this.handler = handler; }
  123. public void execute() throws Pausable, Exception {
  124. try {
  125. // We will reuse the req and resp objects
  126. HttpRequest req = new HttpRequest();
  127. HttpResponse resp = new HttpResponse();
  128. while (true) {
  129. super.readRequest(req);
  130. if (req.keepAlive())
  131. resp.addField("Connection", "Keep-Alive");
  132. OutputStream out = resp.getOutputStream();
  133. String result = handler.route(req);
  134. out.write( result.getBytes() );
  135. sendResponse(resp);
  136. if (!req.keepAlive())
  137. break;
  138. }
  139. }
  140. catch (EOFException e) {}
  141. catch (IOException ioe) {
  142. System.out.println("[" + this.id + "] IO Exception:" + ioe.getMessage());
  143. }
  144. catch (Exception ex) {
  145. System.out.println("HttpSession.Simple:exception -- " + ex);
  146. ex.printStackTrace();
  147. }
  148. super.close();
  149. }
  150. }
  151. }