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/04/24 23:31:41 UTC

svn commit: r164502 - in /jakarta/httpclient/trunk/http-common/src: examples/org/apache/http/examples/ java/org/apache/http/ java/org/apache/http/entity/ java/org/apache/http/impl/

Author: olegk
Date: Sun Apr 24 14:31:41 2005
New Revision: 164502

URL: http://svn.apache.org/viewcvs?rev=164502&view=rev
Log:
Elemental HTTP server demo + some minor tweaks

Added:
    jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java   (with props)
    jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java   (with props)
Modified:
    jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpMutableResponse.java
    jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpResponse.java
    jakarta/httpclient/trunk/http-common/src/java/org/apache/http/entity/EntityConsumer.java
    jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/BasicHttpResponse.java
    jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/DefaultHttpServerConnection.java

Added: jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java?rev=164502&view=auto
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java (added)
+++ jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java Sun Apr 24 14:31:41 2005
@@ -0,0 +1,260 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.examples;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpMutableResponse;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpServerConnection;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolException;
+import org.apache.http.entity.EntityConsumer;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.BasicHttpResponse;
+import org.apache.http.impl.ConnectionClosedException;
+import org.apache.http.impl.ConnectionReuseStrategy;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.DefaultHttpParams;
+import org.apache.http.impl.DefaultHttpServerConnection;
+import org.apache.http.impl.MethodNotSupportedException;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+/**
+ * <p>
+ * </p>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision$
+ */
+public class ElementalHttpEchoServer {
+
+    private static final String TEST_SERVER = "Test server"; 
+    
+    public static void main(String[] args) throws Exception {
+        Thread t = new RequestListenerThread(8080);
+        t.setDaemon(false);
+        t.start();
+    }
+    
+    static class RequestHandler {
+        
+        public RequestHandler() {
+            super();
+        }
+        
+        public void handleRequest(final HttpRequest request, final HttpMutableResponse response) 
+                throws IOException {
+            StringBuffer buffer = new StringBuffer();
+            buffer.append("<html>");
+            buffer.append("<body>");
+            buffer.append("<p>Request method: ");
+            buffer.append(request.getRequestLine().getMethod());
+            buffer.append("</p>");
+            buffer.append("<p>Request URI: ");
+            buffer.append(request.getRequestLine().getUri());
+            buffer.append("</p>");
+            buffer.append("<p>Request Version: ");
+            buffer.append(request.getRequestLine().getHttpVersion());
+            buffer.append("</p>");
+            if (request instanceof HttpEntityEnclosingRequest) {
+                HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
+                buffer.append("<p>Content Type: ");
+                buffer.append(entity.getContentType());
+                buffer.append("</p>");
+                buffer.append("<p>Content Chunk-coded: ");
+                buffer.append(entity.isChunked());
+                buffer.append("</p>");
+                EntityConsumer consume = new EntityConsumer((HttpEntityEnclosingRequest)request);
+                if (entity.getContentType() != null 
+                        && entity.getContentType().toLowerCase().startsWith("text/")) {
+                    buffer.append("<p>");
+                    buffer.append(consume.asString());
+                    buffer.append("</p>");
+                } else {
+                    byte[] raw = consume.asByteArray();
+                    buffer.append("<p>");
+                    for (int i = 0; i < raw.length; i++) {
+                        buffer.append(Integer.toHexString(raw[i]).toLowerCase());
+                        if (i % 20 == 19) {
+                            buffer.append("<br>");
+                        } else {
+                            buffer.append(" ");
+                        }
+                    }
+                    buffer.append("</p>");
+                }
+            }
+            buffer.append("</body>");
+            buffer.append("</html>");
+            StringEntity body = new StringEntity(buffer.toString());
+            body.setContentType("text/html; charset=UTF-8");
+
+            response.setStatusCode(HttpStatus.SC_OK);
+            response.setHeader(new Header("Server", TEST_SERVER));
+            response.setHeader(new Header("Connection", "Keep-Alive"));
+            if (body.isChunked() || body.getContentLength() < 0) {
+                response.setHeader(new Header("Transfer-Encoding", "chunked"));
+            } else {
+                response.setHeader(new Header("Content-Length", 
+                        Long.toString(body.getContentLength())));
+            }
+            if (body.getContentType() != null) {
+                response.setHeader(new Header("Content-Type", body.getContentType())); 
+            }
+            response.setEntity(body);
+        }
+        
+        public void handleException(final HttpException ex, final HttpMutableResponse response) {
+            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", TEST_SERVER));
+            response.setHeader(new Header("Connection", "Close"));
+        }
+    }
+    
+    static class RequestListenerThread extends Thread {
+
+        private final ServerSocketChannel serverchannel;
+        private HttpParams params; 
+        
+        public RequestListenerThread(int port) throws IOException {
+            this.serverchannel = ServerSocketChannel.open();
+            this.serverchannel.socket().bind(new InetSocketAddress(port));
+            this.params = new DefaultHttpParams(null); 
+        }
+        
+        public void run() {
+            System.out.println("Listening on port " + this.serverchannel.socket().getLocalPort());
+            while (!Thread.interrupted()) {
+                try {
+                    SocketChannel channel = this.serverchannel.accept();
+                    Socket socket = channel.socket();
+                    HttpServerConnection conn = new DefaultHttpServerConnection();
+                    System.out.println("Incoming connection from " + socket.getRemoteSocketAddress());
+                    conn.bind(socket, this.params);
+                    Thread t = new HttpConnectionThread(conn);
+                    t.setDaemon(true);
+                    t.start();
+                } catch (InterruptedIOException ex) {
+                    break;
+                } catch (IOException e) {
+                    System.err.println("I/O error initialising connection thread: " 
+                            + e.getMessage());
+                    break;
+                }
+            }
+        }
+    }
+    
+    static class HttpConnectionThread extends Thread {
+
+        private final HttpServerConnection conn;
+        private final HttpParams params;
+        private final RequestHandler handler;
+        
+        public HttpConnectionThread(final HttpServerConnection conn) {
+            super();
+            this.conn = conn;
+            this.params = new DefaultHttpParams(null);
+            new HttpConnectionParams(this.params).setSoTimeout(15000); 
+            this.handler = new RequestHandler();
+        }
+        
+        public HttpParams getParams() {
+            return this.params;
+        }
+        
+        public void closeConnection() {
+            try {
+                this.conn.close();
+                System.out.println("Connection closed");
+            } catch (IOException ex) {
+                System.err.println("I/O error closing connection: " + ex.getMessage());
+            }
+        }
+        
+        public void run() {
+            System.out.println("New connection thread");
+            while (!Thread.interrupted()) {
+                BasicHttpResponse response = new BasicHttpResponse();
+                try {
+                    this.conn.setSocketTimeout(100);
+                    HttpRequest request = this.conn.receiveRequest(this.params);
+                    System.out.println("Request received");
+                    this.handler.handleRequest(request, response);
+                } catch (ConnectionClosedException ex) {
+                    System.out.println("Client closed connection");
+                    break;
+                } catch (HttpException ex) {
+                    this.handler.handleException(ex, response);
+                } catch (IOException ex) {
+                    System.err.println("I/O error receiving request: " + ex.getMessage());
+                    closeConnection();
+                    break;
+                }
+                try {
+                    this.conn.sendResponse(response);
+                    System.out.println("Response sent");
+                } catch (HttpException ex) {
+                    System.err.println("Malformed response: " + ex.getMessage());
+                    closeConnection();
+                } catch (IOException ex) {
+                    System.err.println("I/O error sending response: " + ex.getMessage());
+                    closeConnection();
+                    break;
+                }
+                ConnectionReuseStrategy connreuse = new DefaultConnectionReuseStrategy();
+                if (!connreuse.keepAlive(response)) {
+                    closeConnection();
+                    break;
+                } else {
+                    System.out.println("Connection kept alive");
+                }
+            }
+        }
+
+    }
+}

Propchange: jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/httpclient/trunk/http-common/src/examples/org/apache/http/examples/ElementalHttpEchoServer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpMutableResponse.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpMutableResponse.java?rev=164502&r1=164501&r2=164502&view=diff
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpMutableResponse.java (original)
+++ jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpMutableResponse.java Sun Apr 24 14:31:41 2005
@@ -40,6 +40,10 @@
  */
 public interface HttpMutableResponse extends HttpMutableMessage, HttpResponse {
 
-    void setEntity(HttpIncomingEntity entity);
+    void setStatusLine(StatusLine statusline);
+    
+    void setStatusCode(int code);
+    
+    void setEntity(HttpEntity entity);
     
 }

Modified: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpResponse.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpResponse.java?rev=164502&r1=164501&r2=164502&view=diff
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpResponse.java (original)
+++ jakarta/httpclient/trunk/http-common/src/java/org/apache/http/HttpResponse.java Sun Apr 24 14:31:41 2005
@@ -42,6 +42,6 @@
 
     StatusLine getStatusLine();
 
-    HttpIncomingEntity getEntity();
+    HttpEntity getEntity();
     
 }

Modified: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/entity/EntityConsumer.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/java/org/apache/http/entity/EntityConsumer.java?rev=164502&r1=164501&r2=164502&view=diff
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/java/org/apache/http/entity/EntityConsumer.java (original)
+++ jakarta/httpclient/trunk/http-common/src/java/org/apache/http/entity/EntityConsumer.java Sun Apr 24 14:31:41 2005
@@ -37,7 +37,9 @@
 
 import org.apache.http.HeaderElement;
 import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpIncomingEntity;
+import org.apache.http.HttpMessage;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
 import org.apache.http.params.HttpProtocolParams;
@@ -53,14 +55,25 @@
  */
 public class EntityConsumer {
     
-    private final HttpResponse response;
+    private final HttpMessage message;
+    private final HttpIncomingEntity entity;
     
     public EntityConsumer(final HttpResponse response) {
         super();
         if (response == null) {
             throw new IllegalArgumentException("HTTP response may not be null");
         }
-        this.response = response;
+        this.message = response;
+        this.entity = (HttpIncomingEntity)response.getEntity();
+    }
+
+    public EntityConsumer(final HttpEntityEnclosingRequest request) {
+        super();
+        if (request == null) {
+            throw new IllegalArgumentException("HTTP request may not be null");
+        }
+        this.message = request;
+        this.entity = (HttpIncomingEntity)request.getEntity();
     }
 
     public static byte[] toByteArray(final HttpIncomingEntity entity) throws IOException {
@@ -137,20 +150,18 @@
     }
 
     public byte[] asByteArray() throws IOException {
-        HttpIncomingEntity entity = this.response.getEntity();
-        if (entity == null) {
+        if (this.entity == null) {
             return new byte[] {};
         }
-        return toByteArray(entity);
+        return toByteArray(this.entity);
     }
     
     public String asString() throws IOException {
-        HttpIncomingEntity entity = this.response.getEntity();
-        if (entity == null) {
+        if (this.entity == null) {
             return "";
         }
-        HttpProtocolParams params = new HttpProtocolParams(this.response.getParams());
-        return toString(entity, params.getContentCharset());
+        HttpProtocolParams params = new HttpProtocolParams(this.message.getParams());
+        return toString(this.entity, params.getContentCharset());
     }
     
 }

Modified: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/BasicHttpResponse.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/BasicHttpResponse.java?rev=164502&r1=164501&r2=164502&view=diff
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/BasicHttpResponse.java (original)
+++ jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/BasicHttpResponse.java Sun Apr 24 14:31:41 2005
@@ -29,9 +29,11 @@
 
 package org.apache.http.impl;
 
-import org.apache.http.HttpIncomingEntity;
+import org.apache.http.HttpEntity;
 import org.apache.http.HttpMutableResponse;
+import org.apache.http.HttpStatus;
 import org.apache.http.StatusLine;
+import org.apache.http.params.HttpProtocolParams;
 
 /**
  * <p>
@@ -45,25 +47,44 @@
 public class BasicHttpResponse extends BasicHttpMessage implements HttpMutableResponse {
     
     private StatusLine statusline = null;
-    private HttpIncomingEntity entity = null;
+    private HttpEntity entity = null;
     
+    public BasicHttpResponse() {
+        super();
+        setStatusCode(HttpStatus.SC_OK);
+    }
+
     public BasicHttpResponse(final StatusLine statusline) {
         super();
-        if (statusline == null) {
-            throw new IllegalArgumentException("Status line may not be null");
-        }
-        this.statusline = statusline;
+        setStatusLine(statusline);
     }
 
     public StatusLine getStatusLine() {
         return this.statusline; 
     }
 
-    public HttpIncomingEntity getEntity() {
+    public HttpEntity getEntity() {
         return this.entity;
     }
+
+    public void setStatusLine(final StatusLine statusline) {
+        if (statusline == null) {
+            throw new IllegalArgumentException("Status line may not be null");
+        }
+        this.statusline = statusline;
+    }
+    
+    public void setStatusCode(int code) {
+        if (code < 0) {
+            throw new IllegalArgumentException("Status line may not be null");
+        }
+        HttpProtocolParams params = new HttpProtocolParams(getParams()); 
+        this.statusline = new StatusLine(
+                params.getVersion(), 
+                code, HttpStatus.getStatusText(code));
+    }
     
-    public void setEntity(final HttpIncomingEntity entity) {
+    public void setEntity(final HttpEntity entity) {
         this.entity = entity;
     }
     

Added: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java?rev=164502&view=auto
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java (added)
+++ jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java Sun Apr 24 14:31:41 2005
@@ -0,0 +1,54 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl;
+
+import java.io.IOException;
+
+/**
+ * <p>
+ * </p>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision$
+ * 
+ * @since 4.0
+ */
+public class ConnectionClosedException extends IOException {
+
+    /**
+     * Creates a new MethodNotSupportedException with the specified detail message.
+     * 
+     * @param message The exception detail message
+     */
+    public ConnectionClosedException(final String message) {
+        super(message);
+    }
+
+}

Propchange: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/ConnectionClosedException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/DefaultHttpServerConnection.java
URL: http://svn.apache.org/viewcvs/jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/DefaultHttpServerConnection.java?rev=164502&r1=164501&r2=164502&view=diff
==============================================================================
--- jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/DefaultHttpServerConnection.java (original)
+++ jakarta/httpclient/trunk/http-common/src/java/org/apache/http/impl/DefaultHttpServerConnection.java Sun Apr 24 14:31:41 2005
@@ -98,8 +98,8 @@
                 validateRequest(request);
                 validated = true;
                 sendContinue(responsever);
-                receiveRequestBody((HttpMutableEntityEnclosingRequest)request);
             }
+            receiveRequestBody((HttpMutableEntityEnclosingRequest)request);
         }
         if (!validated) {
             validateRequest(request);
@@ -111,7 +111,7 @@
             throws HttpException, IOException {
         String line = this.datareceiver.readLine();
         if (line == null) {
-            throw new ProtocolException("Request line not found"); 
+            throw new ConnectionClosedException("Client closed connection"); 
         }
         RequestLine requestline = RequestLine.parse(line);
         if (isWirelogEnabled()) {