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 2007/02/22 16:00:20 UTC

svn commit: r510540 - in /jakarta/httpcomponents/httpcore/trunk/module-nio/src: main/java/org/apache/http/impl/nio/ main/java/org/apache/http/nio/ main/java/org/apache/http/nio/protocol/ test/java/org/apache/http/nio/mockup/ test/java/org/apache/http/n...

Author: olegk
Date: Thu Feb 22 07:00:14 2007
New Revision: 510540

URL: http://svn.apache.org/viewvc?view=rev&rev=510540
Log:
HTTPCORE-42: 

* Introduced methods to cancel pending entity enclosing HTTP request in case of the target server expectation failure to both client and server NHttpConnection interfaces
* Added more test cases

Modified:
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpClientConnection.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpServerConnection.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpClientHandler.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpServiceHandler.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/mockup/TestHttpServer.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/protocol/TestNIOHttp.java

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java Thu Feb 22 07:00:14 2007
@@ -194,4 +194,8 @@
         return this.request != null;
     }
 
+    public void cancelRequest() {
+        resetOutput();
+    }
+    
 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java Thu Feb 22 07:00:14 2007
@@ -194,4 +194,8 @@
         return this.response != null;
     }
 
+    public void cancelRequest() {
+        resetInput();
+    }
+    
 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpClientConnection.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpClientConnection.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpClientConnection.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpClientConnection.java Thu Feb 22 07:00:14 2007
@@ -59,4 +59,11 @@
      */
     boolean isRequestSubmitted();
     
+    /**
+     * Cancels pending HTTP request if it failed the target server expections
+     * (the target server responded with non 1xx status code during the
+     * 'expect: continue' handshake.
+     */
+    void cancelRequest();
+    
 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpServerConnection.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpServerConnection.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpServerConnection.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/NHttpServerConnection.java Thu Feb 22 07:00:14 2007
@@ -60,4 +60,11 @@
      */
     boolean isResponseSubmitted();
     
+    /**
+     * Cancels pending HTTP request if it failed the target server expections
+     * (the target server responded with non 1xx status code during the
+     * 'expect: continue' handshake).
+     */
+    void cancelRequest();
+    
 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpClientHandler.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpClientHandler.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpClientHandler.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpClientHandler.java Thu Feb 22 07:00:14 2007
@@ -274,6 +274,10 @@
             } else {
                 connState.setResponse(response);
                 connState.setInputState(ClientConnState.RESPONSE_RECEIVED);
+                
+                if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
+                    cancelRequest(conn, connState);
+                }
             }
             
             if (!canResponseHaveBody(request, response)) {
@@ -376,6 +380,17 @@
         prepareRequestBody((HttpEntityEnclosingRequest) request, connState);
         conn.requestOutput();
         connState.setOutputState(ClientConnState.REQUEST_SENT);
+    }
+    
+    private void cancelRequest(
+            final NHttpClientConnection conn, 
+            final ClientConnState connState) throws IOException {
+
+        int timeout = connState.getTimeout();
+        conn.setSocketTimeout(timeout);
+
+        conn.cancelRequest();
+        connState.resetOutput();
     }
     
     private void prepareRequestBody(

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpServiceHandler.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpServiceHandler.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpServiceHandler.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpServiceHandler.java Thu Feb 22 07:00:14 2007
@@ -193,6 +193,8 @@
                         conn.submitResponse(response);
                     } else {
                         // The request does not meet the server expections
+                        conn.cancelRequest();
+                        connState.resetInput();
                         sendResponse(conn, response);
                     }
                 }

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/mockup/TestHttpServer.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/mockup/TestHttpServer.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/mockup/TestHttpServer.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/mockup/TestHttpServer.java Thu Feb 22 07:00:14 2007
@@ -45,6 +45,7 @@
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpProtocolParams;
 import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpExpectationVerifier;
 import org.apache.http.protocol.HttpRequestHandler;
 import org.apache.http.protocol.HttpRequestHandlerRegistry;
 import org.apache.http.protocol.ResponseConnControl;
@@ -60,6 +61,7 @@
 public class TestHttpServer extends TestHttpServiceBase {
 
     private final HttpRequestHandlerRegistry reqistry;
+    private HttpExpectationVerifier expectationVerifier;
     private volatile SocketAddress address;
     private final Object mutex;
     
@@ -83,6 +85,10 @@
         this.reqistry.register(pattern, handler);
     }
     
+    public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
+        this.expectationVerifier = expectationVerifier;
+    }
+    
     protected void execute() throws IOException {
         synchronized (this.mutex) {
             this.address = ((ListeningIOReactor) this.ioReactor).listen(new InetSocketAddress(0));
@@ -101,7 +107,7 @@
                 this.params);
         
         serviceHandler.setEventListener(new EventLogger());
-        
+        serviceHandler.setExpectationVerifier(this.expectationVerifier);
         serviceHandler.setHandlerResolver(this.reqistry);
         
         IOEventDispatch ioEventDispatch = new DefaultServerIOEventDispatch(

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/protocol/TestNIOHttp.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/protocol/TestNIOHttp.java?view=diff&rev=510540&r1=510539&r2=510540
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/protocol/TestNIOHttp.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/nio/protocol/TestNIOHttp.java Thu Feb 22 07:00:14 2007
@@ -38,11 +38,13 @@
 import java.util.List;
 import java.util.Random;
 
+import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
 import org.apache.http.HttpVersion;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.entity.StringEntity;
@@ -55,7 +57,9 @@
 import org.apache.http.params.HttpProtocolParams;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.HttpExecutionContext;
+import org.apache.http.protocol.HttpExpectationVerifier;
 import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.util.EncodingUtils;
 import org.apache.http.util.EntityUtils;
 
 import junit.framework.Test;
@@ -220,8 +224,8 @@
         this.client.await(connNo, 1000);
         assertEquals(connNo, this.client.getConnCount());
         
-        this.server.await(connNo, 1000);
-        assertEquals(connNo, this.server.getConnCount());
+        this.client.shutdown();
+        this.server.shutdown();
 
         for (int c = 0; c < responseData.length; c++) {
             List receivedPackets = responseData[c];
@@ -363,8 +367,8 @@
         this.client.await(connNo, 1000);
         assertEquals(connNo, this.client.getConnCount());
         
-        this.server.await(connNo, 1000);
-        assertEquals(connNo, this.server.getConnCount());
+        this.client.shutdown();
+        this.server.shutdown();
 
         for (int c = 0; c < responseData.length; c++) {
             List receivedPackets = responseData[c];
@@ -507,8 +511,8 @@
         this.client.await(connNo, 1000);
         assertEquals(connNo, this.client.getConnCount());
         
-        this.server.await(connNo, 1000);
-        assertEquals(connNo, this.server.getConnCount());
+        this.client.shutdown();
+        this.server.shutdown();
 
         for (int c = 0; c < responseData.length; c++) {
             List receivedPackets = responseData[c];
@@ -654,8 +658,8 @@
         this.client.await(connNo, 1000);
         assertEquals(connNo, this.client.getConnCount());
         
-        this.server.await(connNo, 1000);
-        assertEquals(connNo, this.server.getConnCount());
+        this.client.shutdown();
+        this.server.shutdown();
 
         for (int c = 0; c < responseData.length; c++) {
             List receivedPackets = responseData[c];
@@ -800,8 +804,8 @@
         this.client.await(connNo, 1000);
         assertEquals(connNo, this.client.getConnCount());
         
-        this.server.await(connNo, 1000);
-        assertEquals(connNo, this.server.getConnCount());
+        this.client.shutdown();
+        this.server.shutdown();
 
         for (int c = 0; c < responseData.length; c++) {
             List receivedPackets = responseData[c];
@@ -820,5 +824,142 @@
         
     }
 
+    /**
+     * This test case executes a series of simple (non-pipelined) POST requests 
+     * over multiple connections that do not meet the target server expectations. 
+     */
+    public void testHttpPostsWithExpectationVerification() throws Exception {
+        
+        final int reqNo = 3;
+        final List responses = new ArrayList(reqNo);
+        
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                StringEntity outgoing = new StringEntity("No content"); 
+                response.setEntity(outgoing);
+            }
+            
+        });
+        
+        this.server.setExpectationVerifier(new HttpExpectationVerifier() {
+
+            public void verify(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException {
+                Header someheader = request.getFirstHeader("Secret");
+                if (someheader != null) {
+                    int secretNumber;
+                    try {
+                        secretNumber = Integer.parseInt(someheader.getValue());
+                    } catch (NumberFormatException ex) {
+                        response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
+                        return;
+                    }
+                    if (secretNumber < 2) {
+                        response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED);
+                        ByteArrayEntity outgoing = new ByteArrayEntity(
+                                EncodingUtils.getAsciiBytes("Wrong secret number")); 
+                        response.setEntity(outgoing);
+                    }
+                }
+            }
+            
+        });
+
+        // Activate 'expect: continue' handshake
+        this.client.getParams().setBooleanParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
+        // Initialize the client side request executor
+        this.client.setHttpRequestExecutionHandler(new HttpRequestExecutionHandler() {
+
+            public void initalizeContext(final HttpContext context, final Object attachment) {
+                context.setAttribute("LIST", (List) attachment);
+                context.setAttribute("STATUS", "ready");
+            }
+
+            public HttpRequest submitRequest(final HttpContext context) {
+                NHttpConnection conn = (NHttpConnection) context.getAttribute(
+                        HttpExecutionContext.HTTP_CONNECTION);
+                String status = (String) context.getAttribute("STATUS");
+                if (!status.equals("ready")) {
+                    return null;
+                }
+                int index = 0;
+                
+                Integer intobj = (Integer) context.getAttribute("INDEX");
+                if (intobj != null) {
+                    index = intobj.intValue();
+                }
+
+                HttpPost post = null;
+                if (index < reqNo) {
+                    post = new HttpPost("/");
+                    post.addHeader("Secret", Integer.toString(index));
+                    ByteArrayEntity outgoing = new ByteArrayEntity(
+                            EncodingUtils.getAsciiBytes("No content")); 
+                    post.setEntity(outgoing);
+                    
+                    context.setAttribute("INDEX", new Integer(index + 1));
+                    context.setAttribute("STATUS", "busy");
+                } else {
+                    try {
+                        conn.close();
+                    } catch (IOException ex) {
+                        ex.printStackTrace();
+                    }
+                }
+                
+                return post;
+            }
+            
+            public void handleResponse(final HttpResponse response, final HttpContext context) {
+                NHttpConnection conn = (NHttpConnection) context.getAttribute(
+                        HttpExecutionContext.HTTP_CONNECTION);
+                
+                HttpEntity entity = response.getEntity();
+                if (entity != null) {
+                    try {
+                        entity.consumeContent();
+                    } catch (IOException ex) {
+                        fail(ex.getMessage());
+                    }
+                }
+                
+                List list = (List) context.getAttribute("LIST");
+                list.add(response);
+                context.setAttribute("STATUS", "ready");
+                conn.requestInput();
+            }
+            
+        });
+        
+        this.server.start();
+        this.client.start();
+        
+        InetSocketAddress serverAddress = (InetSocketAddress) this.server.getSocketAddress();
+        
+        this.client.openConnection(
+                new InetSocketAddress("localhost", serverAddress.getPort()), 
+                responses);
+     
+        this.client.await(1, 1000);
+        
+        this.client.shutdown();
+        this.server.shutdown();
+
+        assertEquals(reqNo, responses.size());
+        HttpResponse response = (HttpResponse) responses.get(0);
+        assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
+        response = (HttpResponse) responses.get(1);
+        assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
+        response = (HttpResponse) responses.get(2);
+        assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+    }
     
 }