|
RequestProcessor |
|
/*
** Luxor - XML User Interface Language (XUL) Toolkit
** Copyright (c) 2001, 2002 by Gerald Bauer
**
** This program is free software.
**
** You may redistribute it and/or modify it under the terms of the GNU
** General Public License as published by the Free Software Foundation.
** Version 2 of the license should be included with this distribution in
** the file LICENSE, as well as License.html. If the license is not
** included with this distribution, you may find a copy at the FSF web
** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
**
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
** REDISTRIBUTION OF THIS SOFTWARE.
**
*/
package luxor.http;
import java.io.*;
import java.net.*;
import java.util.*;
import luxor.constant.*;
import luxor.event.*;
import luxor.http.loader.*;
import luxor.http.resource.*;
import luxor.spi.*;
import luxor.status.*;
public class RequestProcessor implements Runnable
{
static Logger T = Logger.getLogger( RequestProcessor.class );
private static List _pool = new LinkedList();
private WebResourceLoader _loader;
private WebServer _server;
public RequestProcessor( WebServer server, WebResourceLoader loader )
{
// todo: should i use server to access loader?
// - only one para required
_server = server;
_loader = loader;
}
public static void processRequest( Socket request )
{
synchronized( _pool )
{
_pool.add( _pool.size(), request );
_pool.notifyAll();
}
}
public void run()
{
while( true )
{
Socket connection;
synchronized( _pool )
{
while( _pool.isEmpty() )
{
try
{
_pool.wait();
}
catch( InterruptedException ex )
{
}
}
connection = ( Socket ) _pool.remove( 0 );
}
RequestResponseInfo info = new RequestResponseInfo();
try
{
OutputStream raw = new BufferedOutputStream( connection.getOutputStream() );
Writer out = new OutputStreamWriter( raw );
BufferedReader in = new BufferedReader( new InputStreamReader( connection.getInputStream() ) );
String requestLine = in.readLine();
if( requestLine == null || requestLine.length() == 0 )
{
// socket died; no point nattering: nobody will hear you if you scream in cyperspace
Status.error( "*** [" + Thread.currentThread().getName() + "] request contains no data" );
return;
}
RequestInfo requestInfo = new RequestInfo( requestLine );
T.debug( "requestLine=" + requestLine );
info.setRequestInfo( requestInfo );
// read headers, up to the null line before the body
String headerLine;
while( ( headerLine = in.readLine() ) != null
&& headerLine.length() != 0 )
{
int pos;
if( ( pos = headerLine.indexOf( ':' ) ) != -1 )
{
String headerName = headerLine.substring( 0, pos );
String headerValue = headerLine.substring( pos + 1 ).trim();
requestInfo.addHeader( headerName, headerValue );
}
else
{
Status.error( "*** [" + Thread.currentThread().getName() + "] invalid header: "
+ headerLine );
}
}
WebResource resource = null;
String method = requestInfo.getMethod();
if( method.equals( Http.Method.GET ) ||
method.equals( Http.Method.HEAD ) )
{
resource = _loader.getResource( requestInfo.getPath() );
}
else
{
// method doesn't equal GET or HEAD
resource = new Error501Resource( method );
}
_server.fireRequestAccepted( info );
try
{
info.setResponseContentLength( resource.getContentLength() );
// fix: rename getHeader to getResponseHeaders()
// send header
out.write( resource.getHeader() );
out.flush();
if( !method.equals( Http.Method.HEAD ) )
{
// don't send content for HEAD requests
info.setResponseStatus( Transfer.Status.UPLOADING );
byte data[] = resource.getContent();
T.debug( "data.length=" + data.length );
// send file in chunks; it may be an image or other binary data
// so use the underlying output stream instead of the writer
int total_bytes_written = 0;
// aka offset
while( total_bytes_written < data.length )
{
int chunk_size = Math.min( 4096, data.length - total_bytes_written );
raw.write( data, total_bytes_written, chunk_size );
total_bytes_written += chunk_size;
info.setResponseTransferredSize( total_bytes_written );
}
// raw.write( data );
raw.flush();
}
info.setResponseCode( resource.getResponseCode() );
info.setResponseStatus( Transfer.Status.COMPLETED );
if( resource.getResponseCode() != 200 )
{
info.setResponseError( new Exception(
resource.getResponseCode() + " " + resource.getResponseMessage() ) );
}
// todo: should i close stream?
}
catch( IOException ioex )
{
info.addError( ioex );
info.setResponseError( ioex );
throw ioex;
// rethrow exception
}
}
catch( IOException ioex )
{
info.addError( ioex );
Status.error( "*** [" + Thread.currentThread().getName() + "] "
+ ioex.toString() );
// T.error( ioex.toString() );
}
finally
{
_server.fireRequestServiced( info );
try
{
connection.close();
}
catch( IOException ioex )
{
T.error( ioex.toString() );
}
}
}
// end while
}
// end run()
}
|
RequestProcessor |
|