📄 httpworker.java
字号:
import java.io.*;
import java.net.*;
import java.util.*;
// uses class ObjectFIFO from chapter 18
public class HttpWorker extends Object {
private static int nextWorkerID = 0;
private File docRoot;
private ObjectFIFO idleWorkers;
private int workerID;
private ObjectFIFO handoffBox;
private Thread internalThread;
private volatile boolean noStopRequested;
public HttpWorker(
File docRoot,
int workerPriority,
ObjectFIFO idleWorkers
) {
this.docRoot = docRoot;
this.idleWorkers = idleWorkers;
workerID = getNextWorkerID();
handoffBox = new ObjectFIFO(1); // only one slot
// Just before returning, the thread should be
// created and started.
noStopRequested = true;
Runnable r = new Runnable() {
public void run() {
try {
runWork();
} catch ( Exception x ) {
// in case ANY exception slips through
x.printStackTrace();
}
}
};
internalThread = new Thread(r);
internalThread.setPriority(workerPriority);
internalThread.start();
}
public static synchronized int getNextWorkerID() {
// synchronized at the class level to ensure uniqueness
int id = nextWorkerID;
nextWorkerID++;
return id;
}
public void processRequest(Socket s)
throws InterruptedException {
handoffBox.add(s);
}
private void runWork() {
Socket s = null;
InputStream in = null;
OutputStream out = null;
while ( noStopRequested ) {
try {
// Worker is ready to receive new service
// requests, so it adds itself to the idle
// worker queue.
idleWorkers.add(this);
// Wait here until the server puts a request
// into the handoff box.
s = (Socket) handoffBox.remove();
in = s.getInputStream();
out = s.getOutputStream();
generateResponse(in, out);
out.flush();
} catch ( IOException iox ) {
System.err.println(
"I/O error while processing request, " +
"ignoring and adding back to idle " +
"queue - workerID=" + workerID);
} catch ( InterruptedException x ) {
// re-assert the interrupt
Thread.currentThread().interrupt();
} finally {
// Try to close everything, ignoring
// any IOExceptions that might occur.
if ( in != null ) {
try {
in.close();
} catch ( IOException iox ) {
// ignore
} finally {
in = null;
}
}
if ( out != null ) {
try {
out.close();
} catch ( IOException iox ) {
// ignore
} finally {
out = null;
}
}
if ( s != null ) {
try {
s.close();
} catch ( IOException iox ) {
// ignore
} finally {
s = null;
}
}
}
}
}
private void generateResponse(
InputStream in,
OutputStream out
) throws IOException {
BufferedReader reader =
new BufferedReader(new InputStreamReader(in));
String requestLine = reader.readLine();
if ( ( requestLine == null ) ||
( requestLine.length() < 1 )
) {
throw new IOException("could not read request");
}
System.out.println("workerID=" + workerID +
", requestLine=" + requestLine);
StringTokenizer st = new StringTokenizer(requestLine);
String filename = null;
try {
// request method, typically 'GET', but ignored
st.nextToken();
// the second token should be the filename
filename = st.nextToken();
} catch ( NoSuchElementException x ) {
throw new IOException(
"could not parse request line");
}
File requestedFile = generateFile(filename);
BufferedOutputStream buffOut =
new BufferedOutputStream(out);
if ( requestedFile.exists() ) {
System.out.println("workerID=" + workerID +
", 200 OK: " + filename);
int fileLen = (int) requestedFile.length();
BufferedInputStream fileIn =
new BufferedInputStream(
new FileInputStream(requestedFile));
// Use this utility to make a guess obout the
// content type based on the first few bytes
// in the stream.
String contentType =
URLConnection.guessContentTypeFromStream(
fileIn);
byte[] headerBytes = createHeaderBytes(
"HTTP/1.0 200 OK",
fileLen,
contentType
);
buffOut.write(headerBytes);
byte[] buf = new byte[2048];
int blockLen = 0;
while ( ( blockLen = fileIn.read(buf) ) != -1 ) {
buffOut.write(buf, 0, blockLen);
}
fileIn.close();
} else {
System.out.println("workerID=" + workerID +
", 404 Not Found: " + filename );
byte[] headerBytes = createHeaderBytes(
"HTTP/1.0 404 Not Found",
-1,
null
);
buffOut.write(headerBytes);
}
buffOut.flush();
}
private File generateFile(String filename) {
File requestedFile = docRoot; // start at the base
// Build up the path to the requested file in a
// platform independent way. URL's use '/' in their
// path, but this platform may not.
StringTokenizer st = new StringTokenizer(filename, "/");
while ( st.hasMoreTokens() ) {
String tok = st.nextToken();
if ( tok.equals("..") ) {
// Silently ignore parts of path that might
// lead out of the document root area.
continue;
}
requestedFile =
new File(requestedFile, tok);
}
if ( requestedFile.exists() &&
requestedFile.isDirectory()
) {
// If a directory was requested, modify the request
// to look for the "index.html" file in that
// directory.
requestedFile =
new File(requestedFile, "index.html");
}
return requestedFile;
}
private byte[] createHeaderBytes(
String resp,
int contentLen,
String contentType
) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(baos));
// Write the first line of the response, followed by
// the RFC-specified line termination sequence.
writer.write(resp + "\r\n");
// If a length was specified, add it to the header
if ( contentLen != -1 ) {
writer.write(
"Content-Length: " + contentLen + "\r\n");
}
// If a type was specified, add it to the header
if ( contentType != null ) {
writer.write(
"Content-Type: " + contentType + "\r\n");
}
// A blank line is required after the header.
writer.write("\r\n");
writer.flush();
byte[] data = baos.toByteArray();
writer.close();
return data;
}
public void stopRequest() {
noStopRequested = false;
internalThread.interrupt();
}
public boolean isAlive() {
return internalThread.isAlive();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -