blob: 4df2e92be144a139cb7e739db027b5568acf815b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1999, 2005 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.http;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import javax.servlet.ServletException;
import org.eclipse.equinox.socket.SocketInterface;
/**
* The class provide a thread for processing HTTP requests.
*/
public class HttpThread extends Thread {
/** Master HTTP object */
protected Http http;
/** if true this thread must terminate */
protected volatile boolean running;
/** Pool to which this thread belongs. */
protected HttpThreadPool pool;
/** socket that this thread is operating */
private SocketInterface socket;
/** Listener this thread is working for */
private HttpListener listener;
/** if true, we support Keep-Alive for the socket */
private boolean supportKeepAlive;
/**
* HttpThread constructor.
*/
public HttpThread(Http http, HttpThreadPool pool, String name) {
super(pool, name);
this.http = http;
this.pool = pool;
setDaemon(true); /* mark thread as daemon thread */
}
/**
* Returns true if this thread has been closed.
* @return boolean
*/
public boolean isClosed() {
return (!running);
}
/**
* Close this thread.
*/
public synchronized void close() {
running = false;
if (socket == null) {
interrupt();
} else {
try {
socket.close();
} catch (IOException e) {
// TODO: consider logging
}
}
}
/**
* recall this thread.
*/
public synchronized void recall() {
if (Http.DEBUG) {
http.logDebug(getName() + ": recall on socket: " + socket); //$NON-NLS-1$
}
if ((socket != null) && !socket.isActive()) {
try {
if (Http.DEBUG) {
http.logDebug(getName() + ": Closing socket: " + socket); //$NON-NLS-1$
}
socket.close();
} catch (IOException e) {
// TODO: consider logging
}
}
supportKeepAlive = false;
}
public synchronized void handleConnection(HttpListener listenerParam, SocketInterface socketParam, int socketTimeout) {
if (running) {
this.listener = listenerParam;
this.socket = socketParam;
if (socketTimeout > 0) {
try {
socketParam.setSoTimeout(socketTimeout);
supportKeepAlive = true;
} catch (SocketException e) {
supportKeepAlive = false;
}
} else {
supportKeepAlive = false;
}
notify();
}
}
public void run() {
running = true;
while (running) {
if (socket == null) {
/*
synchronized (this)
{
pool.putThread(this);
* Synchronizing on this before putThread
* causes deadlock when security manager causes
* Thread.isAlive() calls
*/
pool.putThread(this);
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
// ignore and check exit condition
}
}
}
if (running && (socket != null)) {
boolean keepAlive = false;
try {
if (Http.DEBUG) {
http.logDebug(getName() + ": Processing request on socket: " + socket); //$NON-NLS-1$
}
socket.markInactive();
listener.handleConnection(socket);
keepAlive = supportKeepAlive && !socket.isClosed();
} catch (InterruptedIOException e) {
/* A read on the socket did not complete within the timeout period.
*/
keepAlive = false;
if (Http.DEBUG) {
http.logDebug(getName() + ": Read Timeout while processing connection on socket: " + socket, e); //$NON-NLS-1$
}
} catch (SocketException e) {
/* Most likely the user agent closed the socket.
*/
keepAlive = false;
if (Http.DEBUG) {
http.logDebug(getName() + ": Socket Exception while processing connection on socket: " + socket, e); //$NON-NLS-1$
}
}
// BUGBUG Need to handle UnavailableException
// Servlet 2.2 Section 3.3.3.2
// BUGBUG An unhandled exception should result in flushing the response
// buff and returning status code 500.
// Servlet 2.3 Section 9.9.2
catch (ServletException e) {
/* The Servlet threw a ServletException.
*/
keepAlive = false;
http.logWarning(HttpMsg.HTTP_SERVLET_EXCEPTION, e);
} catch (IOException e) {
/* The Servlet threw an IOException.
*/
keepAlive = false;
http.logWarning(HttpMsg.HTTP_CONNECTION_EXCEPTION, e);
} catch (Throwable t) {
/* Some exception has occurred. Log it and keep
* the thread working.
*/
keepAlive = false;
http.logError(HttpMsg.HTTP_CONNECTION_EXCEPTION, t);
} finally {
if (!keepAlive) {
if (!socket.isClosed()) {
try {
if (Http.DEBUG) {
http.logDebug(getName() + ": Closing socket: " + socket); //$NON-NLS-1$
}
socket.close();
} catch (IOException e) {
// TODO: consider logging
}
}
socket = null;
listener = null;
}
}
}
}
}
}