Return-Path: Delivered-To: apmail-jakarta-httpclient-commits-archive@www.apache.org Received: (qmail 66574 invoked from network); 7 Aug 2005 22:07:34 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 7 Aug 2005 22:07:34 -0000 Received: (qmail 3386 invoked by uid 500); 7 Aug 2005 22:07:34 -0000 Mailing-List: contact httpclient-commits-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: httpclient-dev@jakarta.apache.org Delivered-To: mailing list httpclient-commits@jakarta.apache.org Received: (qmail 3373 invoked by uid 500); 7 Aug 2005 22:07:34 -0000 Delivered-To: apmail-jakarta-httpclient-cvs@jakarta.apache.org Received: (qmail 3370 invoked by uid 99); 7 Aug 2005 22:07:33 -0000 X-ASF-Spam-Status: No, hits=-9.8 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Sun, 07 Aug 2005 15:07:33 -0700 Received: (qmail 66571 invoked by uid 65534); 7 Aug 2005 22:07:33 -0000 Message-ID: <20050807220733.66570.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r230707 - in /jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote: ./ impl/ Date: Sun, 07 Aug 2005 22:07:32 -0000 To: httpclient-cvs@jakarta.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.3 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: olegk Date: Sun Aug 7 15:07:25 2005 New Revision: 230707 URL: http://svn.apache.org/viewcvs?rev=230707&view=rev Log: Coyote API proved to be more intrusive than I initially anticipated. The initial architecture has been heavily refactored to allow for callbacks from the container to the connector via the action hook interface Removed: jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/HttpService.java jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/CoyoteHttpService.java jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/CoyoteObjectConverter.java Modified: jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/HttpProtocolHandler.java jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/DefaultHttpConnectionManager.java jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/HttpConnectionProcessor.java Modified: jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/HttpProtocolHandler.java URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/HttpProtocolHandler.java?rev=230707&r1=230706&r2=230707&view=diff ============================================================================== --- jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/HttpProtocolHandler.java (original) +++ jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/HttpProtocolHandler.java Sun Aug 7 15:07:25 2005 @@ -39,7 +39,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.coyote.Adapter; import org.apache.coyote.ProtocolHandler; -import org.apache.http.coyote.impl.CoyoteHttpService; import org.apache.http.coyote.impl.DefaultHttpConnectionFactory; import org.apache.http.coyote.impl.DefaultHttpConnectionManager; import org.apache.http.coyote.params.CoyoteParams; @@ -114,9 +113,10 @@ this.minThreads, this.maxThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); - this.connmanager = new DefaultHttpConnectionManager( - new CoyoteHttpService(this.adapter, this.params), - this.requestExecutor); + this.connmanager = new DefaultHttpConnectionManager( + this.requestExecutor, + this.params, + this.adapter); this.listenerExecutor = new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.MILLISECONDS, Modified: jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/DefaultHttpConnectionManager.java URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/DefaultHttpConnectionManager.java?rev=230707&r1=230706&r2=230707&view=diff ============================================================================== --- jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/DefaultHttpConnectionManager.java (original) +++ jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/DefaultHttpConnectionManager.java Sun Aug 7 15:07:25 2005 @@ -36,11 +36,12 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.coyote.Adapter; import org.apache.http.HttpServerConnection; import org.apache.http.coyote.HttpConnectionManager; -import org.apache.http.coyote.HttpService; import org.apache.http.coyote.IOProcessingListener; import org.apache.http.coyote.IOProcessor; +import org.apache.http.params.HttpParams; /** *

@@ -54,21 +55,27 @@ private static Log LOG = LogFactory.getLog(DefaultHttpConnectionManager.class); private final Executor executor; - private final HttpService service; + private final HttpParams params; + private final Adapter adapter; private final List processors; public DefaultHttpConnectionManager( - final HttpService service, - final Executor executor) { + final Executor executor, + final HttpParams params, + final Adapter adapter) { super(); - if (service == null) { - throw new IllegalArgumentException("Http service may not be null"); - } if (executor == null) { throw new IllegalArgumentException("Executor may not be null"); } + if (params == null) { + throw new IllegalArgumentException("HTTP parameters may not be null"); + } + if (adapter == null) { + throw new IllegalArgumentException("Coyote adapter may not be null"); + } this.executor = executor; - this.service = service; + this.params = params; + this.adapter = adapter; this.processors = new LinkedList(); } @@ -113,7 +120,7 @@ }; HttpConnectionProcessor processor = new HttpConnectionProcessor( - conn, this.service, listener); + conn, this.params, this.adapter, listener); addProcessor(processor); this.executor.execute(processor); } Modified: jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/HttpConnectionProcessor.java URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/HttpConnectionProcessor.java?rev=230707&r1=230706&r2=230707&view=diff ============================================================================== --- jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/HttpConnectionProcessor.java (original) +++ jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote/impl/HttpConnectionProcessor.java Sun Aug 7 15:07:25 2005 @@ -30,20 +30,40 @@ package org.apache.http.coyote.impl; import java.io.IOException; +import java.net.InetAddress; import java.net.SocketTimeoutException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.Request; +import org.apache.coyote.Response; import org.apache.http.ConnectionClosedException; +import org.apache.http.Header; import org.apache.http.HttpException; +import org.apache.http.HttpMutableResponse; import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; import org.apache.http.HttpServerConnection; -import org.apache.http.coyote.HttpService; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; +import org.apache.http.MethodNotSupportedException; +import org.apache.http.ProtocolException; +import org.apache.http.RequestLine; import org.apache.http.coyote.IOProcessingListener; import org.apache.http.coyote.IOProcessor; +import org.apache.http.coyote.MalformedURIException; +import org.apache.http.coyote.UnsupportedHttpVersionException; +import org.apache.http.coyote.params.CoyoteParams; import org.apache.http.impl.BasicHttpResponse; import org.apache.http.impl.ConnectionReuseStrategy; import org.apache.http.impl.DefaultConnectionReuseStrategy; +import org.apache.http.params.HttpParams; /** *

@@ -52,37 +72,67 @@ * * @version $Revision$ */ -public class HttpConnectionProcessor implements IOProcessor { +public class HttpConnectionProcessor implements IOProcessor, ActionHook { private static Log LOG = LogFactory.getLog(HttpConnectionProcessor.class); private volatile boolean destroyed = false; private final HttpServerConnection conn; - private final HttpService service; + private final HttpParams params; + private final Adapter adapter; private final IOProcessingListener listener; + + private final Request coyotereq; + private final Response coyoteres; + + private HttpRequest httpreq = null; + private HttpResponse httpres = null; public HttpConnectionProcessor( final HttpServerConnection conn, - final HttpService service, + final HttpParams params, + final Adapter adapter, final IOProcessingListener listener) { super(); if (conn == null) { throw new IllegalArgumentException("HTTP connection may not be null"); } - if (service == null) { - throw new IllegalArgumentException("HTTP service may not be null"); + if (params == null) { + throw new IllegalArgumentException("HTTP parameters may not be null"); + } + if (adapter == null) { + throw new IllegalArgumentException("Coyote adapter may not be null"); } this.conn = conn; - this.service = service; + this.params = params; + this.adapter = adapter; this.listener = listener; + + this.coyotereq = new Request(); + this.coyoteres = new Response(); + this.coyoteres.setHook(this); + this.coyoteres.setRequest(this.coyotereq); } public void run() { try { while (this.conn.isOpen() && !Thread.interrupted()) { try { - process(); + try { + receiveHttpRequest(); + prepareCoyoteRequest(); + callServletContainer(); + sendHttpResponse(); + manageHttpConnection(); + } catch (HttpException ex) { + LOG.debug("Malformed HTTP requst"); + this.httpres = processHttpException(ex); + sendHttpResponse(); + } + } catch (ConnectionClosedException ex) { + LOG.debug("Client closed connection"); + break; } catch (SocketTimeoutException ex) { LOG.debug("Socket timeout"); break; @@ -102,41 +152,135 @@ } } - private void process() throws IOException { - BasicHttpResponse response = new BasicHttpResponse(); + private void receiveHttpRequest() throws IOException, HttpException { + this.httpreq = this.conn.receiveRequest(this.params); + LOG.debug("HTTP request received"); + } + + private HttpResponse processHttpException(final HttpException ex) { + LOG.debug("Processing HTTP exception"); + HttpMutableResponse response = new BasicHttpResponse(); + response.getParams().setDefaults(this.params); + if (ex instanceof MethodNotSupportedException) { + response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED); + } else if (ex instanceof ProtocolException) { + response.setStatusCode(HttpStatus.SC_BAD_REQUEST); + } else { + response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR); + } + response.setHeader(new Header("Server", "Jakarta HttpCommons")); + response.setHeader(new Header("Connection", "Close")); + return response; + } + + private void sendHttpResponse() throws IOException { + try { + this.conn.sendResponse(this.httpres); + LOG.debug("HTTP response sent"); + } catch (HttpException ex) { + LOG.error("Malformed HTTP response", ex); + this.conn.close(); + } + } + + private void prepareCoyoteRequest() throws HttpException { + // Convert the request line + RequestLine reqline = this.httpreq.getRequestLine(); + HttpVersion ver = reqline.getHttpVersion(); + if (!ver.lessEquals(HttpVersion.HTTP_1_1)) { + throw new UnsupportedHttpVersionException("Unsupported verion: " + ver); + } + this.coyotereq.method().setString(reqline.getMethod()); + this.coyotereq.unparsedURI().setString(reqline.getUri()); + + // Parse the request URI + URI uri = null; try { - HttpRequest request = this.conn.receiveRequest(this.service.getParams()); - LOG.debug("HTTP request received"); - this.service.process(request, response); - } catch (ConnectionClosedException ex) { - LOG.debug("Client closed connection"); - this.conn.close(); - return; - } catch (HttpException ex) { - this.service.process(ex, response); - } catch (IOException ex) { - LOG.warn("I/O error receiving HTTP request", ex); - this.conn.close(); - return; + uri = new URI(reqline.getUri()); + } catch (URISyntaxException ex) { + throw new MalformedURIException("Malformed URI: " + reqline.getUri(), ex); } + if (uri.isAbsolute()) { + // Absolute request URI. Ignore the 'host' header + this.coyotereq.scheme().setString(uri.getScheme()); + this.coyotereq.serverName().setString(uri.getHost()); + int port = uri.getPort(); + if (port < 0) { + port = 80; + } + this.coyotereq.setServerPort(port); + } else { + // Relative request URI. Parse the 'host' header + this.coyotereq.scheme().setString("http"); + Header header = httpreq.getFirstHeader("host"); + if (header != null) { + String s = header.getValue(); + int i = s.lastIndexOf(':'); + if (i != -1) { + this.coyotereq.serverName().setString(s.substring(0, i)); + try { + this.coyotereq.setServerPort(Integer.parseInt(s.substring(i + 1))); + } catch (NumberFormatException ex) { + throw new ProtocolException("Invalid target host: " + s); + } + } else { + this.coyotereq.serverName().setString(s); + } + } else { + if (ver.greaterEquals(HttpVersion.HTTP_1_1)) { + throw new ProtocolException("Target host not known"); + } + // HTTP/1.0 compatibility + // User the default host and port values + String defaulthost = null; + try { + InetAddress localhost = InetAddress.getLocalHost(); + defaulthost = localhost.getHostName(); + } catch (UnknownHostException ex) { + defaulthost = "localhost"; + } + this.coyotereq.setLocalHost(defaulthost); + this.coyotereq.serverName().setString(defaulthost); + this.coyotereq.setServerPort(CoyoteParams.getPort(httpreq.getParams())); + } + } + this.coyotereq.requestURI().setString(uri.getPath()); + if (uri.getQuery() != null) { + this.coyotereq.queryString().setString(uri.getQuery()); + } + this.coyotereq.protocol().setString(ver.toString()); + + // Convert the request headers + Header[] headers = httpreq.getAllHeaders(); + for (Header header: headers) { + this.coyotereq.getMimeHeaders().addValue(header.getName()).setString(header.getValue()); + } + } + + private void callServletContainer() throws IOException, HttpException { try { - this.conn.sendResponse(response); - LOG.debug("HTTP response sent"); - } catch (HttpException ex) { - LOG.debug("Malformed HTTP response: " + ex.getMessage()); - this.conn.close(); + this.adapter.service(this.coyotereq, this.coyoteres); } catch (IOException ex) { - LOG.warn("I/O error sending HTTP response", ex); - this.conn.close(); - return; - } - ConnectionReuseStrategy connreuse = new DefaultConnectionReuseStrategy(); - if (!connreuse.keepAlive(response)) { - this.conn.close(); - LOG.debug("Connection closed"); - } else { - LOG.debug("Connection kept alive"); + throw ex; + } catch (Exception ex) { + throw new HttpException(ex.getMessage(), ex); } + } + + private void manageHttpConnection() throws IOException { + if (this.conn.isOpen()) { + ConnectionReuseStrategy connreuse = new DefaultConnectionReuseStrategy(); + if (!connreuse.keepAlive(this.httpres)) { + this.conn.close(); + LOG.debug("Connection closed"); + } else { + LOG.debug("Connection kept alive"); + } + } + this.coyotereq.recycle(); + this.coyoteres.recycle(); + this.httpreq = null; + this.httpres = null; } public void close() throws IOException { @@ -156,4 +300,8 @@ return this.destroyed; } + public void action(final ActionCode actionCode, final Object param) { + // Process callbacks from the container + } + }