📄 serverthread.java
字号:
// $Id: ServerThread.java,v 1.42 2001/01/23 03:08:28 nconway Exp $
package tornado;
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
public class ServerThread extends Thread {
private final static int READ_BLOCK = 8192;
// per-client resources: these are recreated for every connection
private Request request;
private Response response;
/** The file asked for by the client, if appropriate.*/
private File requestFile;
/** The message in the access log for this request.*/
private CommonLogMessage accessLog;
// per-server resources: these are created once per ServerThread
private final ArrayList taskPool;
private final ServerPool serverPool;
/** Constructs a new ServerThread using the specified values. This should
* only rarely be called directly: for most purposes, you should spawn
* new threads using {@link tornado.ServerPool#addThread()}.
*/
ServerThread(ThreadGroup group, ArrayList tPool, ServerPool sPool) {
super(group, "");
taskPool = tPool;
serverPool = sPool;
}
/** Begins an infinite loop waiting for connections and serving them.*/
public void run() {
Socket socket;
while (true) {
synchronized (taskPool) {
/* Wait until we find an incoming connection. If
* pool is non-empty, there is already a connection
* waiting to be processed, so we can skip the wait().*/
while (taskPool.isEmpty()) {
try {
taskPool.wait();
} catch (InterruptedException e) {
/* We were interrupted by another thread. In the
* current design, this means the ServerPool wants
* us to die.*/
return;
}
}
// finally, we have an incoming connection
socket = (Socket)taskPool.remove(0);
}
// start the HTTP transaction with the client
try {
request = new Request(socket);
response = new Response(request);
accessLog = new CommonLogMessage(request);
handOffRequest();
} catch (HTTPException e) {
// we got a protocol error of some kind - expected
sendErrorPage(e);
} catch (Exception e) {
// we got a more serious error - these should not occur
e.printStackTrace();
} finally {
Tornado.log.logAccess(accessLog);
finishConnection();
}
}
}
/** Decides what to do with a connection. This looks at the HTTP
* headers sent by the client, sends error pages as necessary, and
* then decides which method to use to actually handle this request.
*/
private void handOffRequest() throws HTTPException {
String method = request.getType();
if (method == null) {
return;
} else if (method.equals("GET")) {
handleGetRequest();
} else if (method.equals("HEAD")) {
handleHeadRequest();
} else if (method.equals("POST")) {
handlePostRequest();
} else if (method.equals("PUT")) {
handlePutRequest();
} else if (method.equals("OPTIONS")) {
handleOptionsRequest();
} else if (method.equals("DELETE")) {
handleDeleteRequest();
} else if (method.equals("TRACE")) {
handleTraceRequest();
} else if (method.equals("CONNECT")) {
handleConnectRequest();
} else {
throw new HTTPException(HTTP.NOT_IMPLEMENTED);
}
}
/** Handles an HTTP GET request from the client.*/
private void handleGetRequest() throws HTTPException {
describeFile();
try {
response.finishHeaders();
FileInputStream file = new FileInputStream(requestFile);
/* Read and send file in blocks.*/
byte[] fileData = new byte[READ_BLOCK];
for (int i=0; i<requestFile.length(); i+=READ_BLOCK) {
int bytesRead = file.read(fileData);
response.rawOut.write(fileData, 0, bytesRead);
}
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/** Handles an HTTP HEAD request from the client.*/
private void handleHeadRequest() throws HTTPException {
describeFile();
try {
response.finishHeaders();
} catch (IOException e) {
e.printStackTrace();
}
}
/** Handles an HTTP POST request from the client. Not
* implemented yet.
*/
private void handlePostRequest() throws HTTPException {
throw new HTTPException(HTTP.NOT_IMPLEMENTED);
}
/** Handles an HTTP PUT request from the client. Not
* implemented yet.
*/
private void handlePutRequest() throws HTTPException {
throw new HTTPException(HTTP.NOT_IMPLEMENTED);
}
/** Handles an HTTP OPTIONS request from the client. Not
* implemented yet.
*/
private void handleOptionsRequest() throws HTTPException {
throw new HTTPException(HTTP.NOT_IMPLEMENTED);
}
/** Handles an HTTP DELETE request from the client. Not
* implemented yet.
*/
private void handleDeleteRequest() throws HTTPException {
throw new HTTPException(HTTP.NOT_IMPLEMENTED);
}
/** Handles an HTTP TRACE request from the client.*/
private void handleTraceRequest() throws HTTPException {
try {
sendStatus(HTTP.OK);
sendBasicHeaders();
response.sendHeader("Content-Type: message/http");
response.finishHeaders();
// echo the client's request back to them
response.out.write(request.getRawRequest());
} catch (IOException e) {
e.printStackTrace();
}
}
/** Handles an HTTP CONNECT request from the client. Not
* implemented yet.
*/
private void handleConnectRequest() throws HTTPException {
throw new HTTPException(HTTP.NOT_IMPLEMENTED);
}
/** Sends the headers about the URI the client asked for. This method
* does the "legwork" when dealing with files: it takes the URI from
* the client, uses {@link #translateURI(String)} to get a
* <code>File</code>, checks for errors, and then sends the
* relevant headers to the client about the specified URI. It is
* used by both the HTTP GET and HEAD methods.
*/
private void describeFile() throws HTTPException {
requestFile = translateURI(request.getURI());
if (requestFile.exists() == false)
throw new HTTPException(HTTP.NOT_FOUND);
if (requestFile.canRead() == false)
throw new HTTPException(HTTP.FORBIDDEN);
try {
sendStatus(HTTP.OK);
sendBasicHeaders();
response.sendHeader("Content-Length: " + requestFile.length());
response.sendHeader("Last-Modified: " + HTTP.formatDate(
new Date(requestFile.lastModified())));
response.sendHeader("Content-Type: " +
Tornado.mime.getContentType(requestFile));
} catch (IOException e) {
e.printStackTrace();
}
}
/** Concludes the work with the client and informs the ServerPool.*/
private void finishConnection() {
if (response != null) {
try {
response.finishResponse();
} catch (IOException e) {
e.printStackTrace();
}
}
serverPool.decrementBusyThreads();
}
/** Sends the specified HTTP error code page to the client.*/
private void sendErrorPage(HTTPException httpE) {
try {
sendStatus(httpE.getCode());
sendBasicHeaders();
response.sendHeader("Content-Type: text/html");
response.finishHeaders();
response.out.write(httpE.getErrorPage());
} catch (IOException e) {
e.printStackTrace();
}
}
/** Sends the specified HTTP status code to the client. This is just
* a simple wrapper over {@link tornado.Response#sendStatus(int)},
* with one additional function: it notes the status code in the access
* log before sending it.
*/
private void sendStatus(int statusCode) throws IOException {
accessLog.setStatusCode(statusCode);
response.sendStatus(statusCode);
}
/** Sends the HTTP headers to the client that are always sent. These
* headers are those used in common by all HTTP responses.
*/
private void sendBasicHeaders() throws IOException {
response.sendHeader("Date: " + HTTP.formatDate(new Date()));
response.sendHeader("Server: " + Tornado.config.getVersionSig());
response.sendHeader("Connection: close");
}
/** Translates the URI to a filename. This takes an <b>absolute</b>
* URI, performs some security checks, and translates this URI into
* the designated file on the local filesystem. It then returns this
* file.
*/
private File translateURI(String uri) throws HTTPException {
String relURI = uri.substring(uri.indexOf('/', 7));
if (uri.indexOf("..", 1) != -1) {
throw new HTTPException(HTTP.NOT_FOUND);
}
return new File(Tornado.config.getDocumentRoot() + relURI);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -