HttpWorker.java
上传用户:songled
上传日期:2022-07-14
资源大小:94k
文件大小:7k
源码类别:

进程与线程

开发平台:

Java

  1. import java.io.*;
  2. import java.net.*;
  3. import java.util.*;
  4. // uses class ObjectFIFO from chapter 18
  5. public class HttpWorker extends Object {
  6. private static int nextWorkerID = 0;
  7. private File docRoot;
  8. private ObjectFIFO idleWorkers;
  9. private int workerID;
  10. private ObjectFIFO handoffBox;
  11. private Thread internalThread;
  12. private volatile boolean noStopRequested;
  13. public HttpWorker(
  14. File docRoot, 
  15. int workerPriority, 
  16. ObjectFIFO idleWorkers
  17. ) {
  18. this.docRoot = docRoot;
  19. this.idleWorkers = idleWorkers;
  20. workerID = getNextWorkerID();
  21. handoffBox = new ObjectFIFO(1); // only one slot
  22. // Just before returning, the thread should be 
  23. // created and started.
  24. noStopRequested = true;
  25. Runnable r = new Runnable() {
  26. public void run() {
  27. try {
  28. runWork();
  29. } catch ( Exception x ) {
  30. // in case ANY exception slips through
  31. x.printStackTrace(); 
  32. }
  33. }
  34. };
  35. internalThread = new Thread(r);
  36. internalThread.setPriority(workerPriority);
  37. internalThread.start();
  38. }
  39. public static synchronized int getNextWorkerID() { 
  40. // synchronized at the class level to ensure uniqueness
  41. int id = nextWorkerID;
  42. nextWorkerID++;
  43. return id;
  44. }
  45. public void processRequest(Socket s) 
  46. throws InterruptedException {
  47. handoffBox.add(s);
  48. }
  49. private void runWork() {
  50. Socket s = null;
  51. InputStream in = null;
  52. OutputStream out = null;
  53. while ( noStopRequested ) {
  54. try {
  55. // Worker is ready to receive new service 
  56. // requests, so it adds itself to the idle 
  57. // worker queue.
  58. idleWorkers.add(this);
  59. // Wait here until the server puts a request 
  60. // into the handoff box.
  61. s = (Socket) handoffBox.remove();
  62. in = s.getInputStream();
  63. out = s.getOutputStream();
  64. generateResponse(in, out);
  65. out.flush();
  66. } catch ( IOException iox ) {
  67. System.err.println(
  68. "I/O error while processing request, " +
  69. "ignoring and adding back to idle " +
  70. "queue - workerID=" + workerID);
  71. } catch ( InterruptedException x ) {
  72. // re-assert the interrupt
  73. Thread.currentThread().interrupt(); 
  74. } finally {
  75. // Try to close everything, ignoring 
  76. // any IOExceptions that might occur.
  77. if ( in != null ) {
  78. try { 
  79. in.close(); 
  80. } catch ( IOException iox ) {
  81. // ignore
  82. } finally {
  83. in = null;
  84. }
  85. }
  86. if ( out != null ) {
  87. try { 
  88. out.close(); 
  89. } catch ( IOException iox ) {
  90. // ignore
  91. } finally {
  92. out = null;
  93. }
  94. }
  95. if ( s != null ) {
  96. try { 
  97. s.close(); 
  98. } catch ( IOException iox ) {
  99. // ignore
  100. } finally {
  101. s = null;
  102. }
  103. }
  104. }
  105. }
  106. }
  107. private void generateResponse(
  108. InputStream in, 
  109. OutputStream out
  110. ) throws IOException {
  111. BufferedReader reader = 
  112. new BufferedReader(new InputStreamReader(in));
  113. String requestLine = reader.readLine();
  114. if ( ( requestLine == null ) || 
  115.  ( requestLine.length() < 1 ) 
  116.    ) {
  117. throw new IOException("could not read request");
  118. }
  119. System.out.println("workerID=" + workerID + 
  120. ", requestLine=" + requestLine);
  121. StringTokenizer st = new StringTokenizer(requestLine);
  122. String filename = null;
  123. try {
  124. // request method, typically 'GET', but ignored
  125. st.nextToken(); 
  126. // the second token should be the filename
  127. filename = st.nextToken();
  128. } catch ( NoSuchElementException x ) {
  129. throw new IOException(
  130. "could not parse request line");
  131. }
  132. File requestedFile = generateFile(filename);
  133. BufferedOutputStream buffOut = 
  134. new BufferedOutputStream(out);
  135. if ( requestedFile.exists() ) {
  136. System.out.println("workerID=" + workerID + 
  137. ", 200 OK: " + filename);
  138. int fileLen = (int) requestedFile.length();
  139. BufferedInputStream fileIn = 
  140. new BufferedInputStream(
  141. new FileInputStream(requestedFile));
  142. // Use this utility to make a guess obout the
  143. // content type based on the first few bytes 
  144. // in the stream.
  145. String contentType = 
  146. URLConnection.guessContentTypeFromStream(
  147. fileIn);
  148. byte[] headerBytes = createHeaderBytes(
  149. "HTTP/1.0 200 OK", 
  150. fileLen,
  151. contentType
  152. );
  153. buffOut.write(headerBytes);
  154. byte[] buf = new byte[2048];
  155. int blockLen = 0;
  156. while ( ( blockLen = fileIn.read(buf) ) != -1 ) {
  157. buffOut.write(buf, 0, blockLen);
  158. }
  159. fileIn.close();
  160. } else {
  161. System.out.println("workerID=" + workerID + 
  162. ", 404 Not Found: " + filename );
  163. byte[] headerBytes = createHeaderBytes(
  164. "HTTP/1.0 404 Not Found", 
  165. -1,
  166. null
  167. );
  168. buffOut.write(headerBytes);
  169. }
  170. buffOut.flush();
  171. }
  172. private File generateFile(String filename) {
  173. File requestedFile = docRoot; // start at the base
  174. // Build up the path to the requested file in a 
  175. // platform independent way. URL's use '/' in their
  176. // path, but this platform may not.
  177. StringTokenizer st = new StringTokenizer(filename, "/");
  178. while ( st.hasMoreTokens() ) {
  179. String tok = st.nextToken();
  180. if ( tok.equals("..") ) {
  181. // Silently ignore parts of path that might
  182. // lead out of the document root area.
  183. continue;
  184. }
  185. requestedFile = 
  186. new File(requestedFile, tok);
  187. }
  188. if ( requestedFile.exists() && 
  189.  requestedFile.isDirectory() 
  190.    ) {
  191. // If a directory was requested, modify the request
  192. // to look for the "index.html" file in that
  193. // directory.
  194. requestedFile = 
  195. new File(requestedFile, "index.html");
  196. }
  197. return requestedFile;
  198. }
  199. private byte[] createHeaderBytes(
  200. String resp, 
  201. int contentLen,
  202. String contentType
  203. ) throws IOException {
  204. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  205. BufferedWriter writer = new BufferedWriter(
  206. new OutputStreamWriter(baos));
  207. // Write the first line of the response, followed by
  208. // the RFC-specified line termination sequence.
  209. writer.write(resp + "rn");
  210. // If a length was specified, add it to the header
  211. if ( contentLen != -1 ) {
  212. writer.write(
  213. "Content-Length: " + contentLen + "rn");
  214. }
  215. // If a type was specified, add it to the header
  216. if ( contentType != null ) {
  217. writer.write(
  218. "Content-Type: " + contentType + "rn");
  219. }
  220. // A blank line is required after the header.
  221. writer.write("rn");
  222. writer.flush();
  223. byte[] data = baos.toByteArray();
  224. writer.close();
  225. return data;
  226. }
  227. public void stopRequest() {
  228. noStopRequested = false;
  229. internalThread.interrupt();
  230. }
  231. public boolean isAlive() {
  232. return internalThread.isAlive();
  233. }
  234. }