|
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 |
|