You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2005/08/08 00:07:32 UTC
svn commit: r230707 - in
/jakarta/httpclient/trunk/coyote-httpconnector/src/java/org/apache/http/coyote:
./ impl/
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<Runnable>());
- 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;
/**
* <p>
@@ -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<IOProcessor> 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<IOProcessor>();
}
@@ -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;
/**
* <p>
@@ -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
+ }
+
}