View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.nio.integration;
29  
30  import java.io.BufferedReader;
31  import java.io.BufferedWriter;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.io.InputStreamReader;
35  import java.io.OutputStream;
36  import java.io.OutputStreamWriter;
37  import java.net.InetSocketAddress;
38  import java.net.Socket;
39  import java.util.concurrent.CountDownLatch;
40  import java.util.concurrent.TimeUnit;
41  
42  import org.apache.http.HttpCoreNIOTestBase;
43  import org.apache.http.HttpException;
44  import org.apache.http.HttpRequest;
45  import org.apache.http.HttpResponse;
46  import org.apache.http.HttpResponseInterceptor;
47  import org.apache.http.LoggingClientConnectionFactory;
48  import org.apache.http.LoggingServerConnectionFactory;
49  import org.apache.http.concurrent.Cancellable;
50  import org.apache.http.entity.ContentType;
51  import org.apache.http.impl.DefaultConnectionReuseStrategy;
52  import org.apache.http.impl.nio.DefaultNHttpClientConnection;
53  import org.apache.http.impl.nio.DefaultNHttpServerConnection;
54  import org.apache.http.nio.NHttpConnectionFactory;
55  import org.apache.http.nio.entity.NStringEntity;
56  import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
57  import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
58  import org.apache.http.nio.protocol.HttpAsyncExchange;
59  import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
60  import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
61  import org.apache.http.nio.protocol.HttpAsyncRequestHandlerRegistry;
62  import org.apache.http.nio.protocol.HttpAsyncService;
63  import org.apache.http.nio.reactor.IOReactorStatus;
64  import org.apache.http.nio.reactor.ListenerEndpoint;
65  import org.apache.http.params.HttpParams;
66  import org.apache.http.protocol.HttpContext;
67  import org.apache.http.protocol.HttpRequestHandler;
68  import org.apache.http.protocol.ImmutableHttpProcessor;
69  import org.apache.http.protocol.ResponseConnControl;
70  import org.apache.http.protocol.ResponseContent;
71  import org.apache.http.protocol.ResponseServer;
72  import org.junit.After;
73  import org.junit.Assert;
74  import org.junit.Before;
75  import org.junit.Test;
76  
77  /**
78   * Tests for handling pipelined requests.
79   */
80  public class TestPipelining extends HttpCoreNIOTestBase {
81  
82      @Before
83      public void setUp() throws Exception {
84          initServer();
85          this.serverHttpProc = new ImmutableHttpProcessor(new HttpResponseInterceptor[] {
86                  new ResponseServer(),
87                  new ResponseContent(),
88                  new ResponseConnControl()
89          });
90      }
91  
92      @After
93      public void tearDown() throws Exception {
94          shutDownServer();
95      }
96  
97      @Override
98      protected NHttpConnectionFactory<DefaultNHttpServerConnection> createServerConnectionFactory(
99              final HttpParams params) throws Exception {
100         return new LoggingServerConnectionFactory(params);
101     }
102 
103     @Override
104     protected NHttpConnectionFactory<DefaultNHttpClientConnection> createClientConnectionFactory(
105             final HttpParams params) throws Exception {
106         return new LoggingClientConnectionFactory(params);
107     }
108 
109     @Test
110     public void testBasicPipelining() throws Exception {
111         HttpAsyncRequestHandlerRegistry registry = new HttpAsyncRequestHandlerRegistry();
112         registry.register("*", new BasicAsyncRequestHandler(new HttpRequestHandler() {
113 
114             public void handle(
115                     final HttpRequest request,
116                     final HttpResponse response,
117                     final HttpContext context) throws HttpException, IOException {
118                 String content = "thank you very much";
119                 NStringEntity entity = new NStringEntity(content, ContentType.DEFAULT_TEXT);
120                 response.setEntity(entity);
121             }
122 
123         }));
124         HttpAsyncService serviceHandler = new HttpAsyncService(
125                 this.serverHttpProc,
126                 new DefaultConnectionReuseStrategy(),
127                 registry,
128                 this.serverParams);
129         this.server.start(serviceHandler);
130 
131         ListenerEndpoint endpoint = this.server.getListenerEndpoint();
132         endpoint.waitFor();
133 
134         Assert.assertEquals("Test server status", IOReactorStatus.ACTIVE, this.server.getStatus());
135 
136         InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
137         Socket socket = new Socket("localhost", address.getPort());
138         try {
139             OutputStream outstream = socket.getOutputStream();
140             BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outstream, "US-ASCII"));
141             writer.write("GET / HTTP/1.1\r\n");
142             writer.write("Host: localhost\r\n");
143             writer.write("\r\n");
144             writer.write("GET / HTTP/1.1\r\n");
145             writer.write("Host: localhost\r\n");
146             writer.write("Connection: close\r\n");
147             writer.write("\r\n");
148             writer.flush();
149             InputStream instream = socket.getInputStream();
150             BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "US-ASCII"));
151             StringBuilder buf = new StringBuilder();
152             char[] tmp = new char[1024];
153             int l;
154             while ((l = reader.read(tmp)) != -1) {
155                 buf.append(tmp, 0, l);
156             }
157             reader.close();
158             writer.close();
159 //            String expected =
160 //                    "HTTP/1.1 200 OK\r\n" +
161 //                    "Server: TEST-SERVER/1.1\r\n" +
162 //                    "Content-Length: 19\r\n" +
163 //                    "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
164 //                    "\r\n" +
165 //                    "thank you very much" +
166 //                    "HTTP/1.1 200 OK\r\n" +
167 //                    "Server: TEST-SERVER/1.1\r\n" +
168 //                    "Content-Length: 19\r\n" +
169 //                    "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
170 //                    "Connection: close\r\n" +
171 //                    "\r\n" +
172 //                    "thank you very much";
173             String expected =
174                     "HTTP/1.1 400 Bad Request\r\n" +
175                     "Connection: Close\r\n" +
176                     "Server: TEST-SERVER/1.1\r\n" +
177                     "Content-Length: 70\r\n" +
178                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
179                     "\r\n" +
180                     "Out of sequence request message detected (pipelining is not supported)";
181             Assert.assertEquals(expected, buf.toString());
182 
183         } finally {
184             socket.close();
185         }
186 
187     }
188 
189     @Test
190     public void testPipeliningWithCancellable() throws Exception {
191 
192         final CountDownLatch latch = new CountDownLatch(1);
193         final Cancellable cancellable = new Cancellable() {
194             
195             public boolean cancel() {
196                 latch.countDown();
197                 return true;
198             }
199         };
200 
201         HttpAsyncRequestHandlerRegistry registry = new HttpAsyncRequestHandlerRegistry();
202         registry.register("/long", new HttpAsyncRequestHandler<HttpRequest>() {
203 
204             public HttpAsyncRequestConsumer<HttpRequest> processRequest(final HttpRequest request,
205                     final HttpContext context) {
206                 return new BasicAsyncRequestConsumer();
207             }
208 
209             public void handle(
210                     final HttpRequest request,
211                     final HttpAsyncExchange httpexchange,
212                     final HttpContext context) throws HttpException, IOException {
213                 httpexchange.setCallback(cancellable);
214                 // do not submit a response;
215             }
216 
217         });
218         registry.register("/short", new BasicAsyncRequestHandler(new HttpRequestHandler() {
219 
220             public void handle(
221                     final HttpRequest request,
222                     final HttpResponse response,
223                     final HttpContext context) throws HttpException, IOException {
224                 String content = "thank you very much";
225                 NStringEntity entity = new NStringEntity(content, ContentType.DEFAULT_TEXT);
226                 response.setEntity(entity);
227             }
228 
229         }));
230         HttpAsyncService serviceHandler = new HttpAsyncService(
231                 this.serverHttpProc,
232                 new DefaultConnectionReuseStrategy(),
233                 registry,
234                 this.serverParams);
235         this.server.start(serviceHandler);
236 
237         ListenerEndpoint endpoint = this.server.getListenerEndpoint();
238         endpoint.waitFor();
239 
240         Assert.assertEquals("Test server status", IOReactorStatus.ACTIVE, this.server.getStatus());
241 
242         InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
243         Socket socket = new Socket("localhost", address.getPort());
244         try {
245             OutputStream outstream = socket.getOutputStream();
246             BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outstream, "US-ASCII"));
247             writer.write("GET /long HTTP/1.1\r\n");
248             writer.write("Host: localhost\r\n");
249             writer.write("\r\n");
250             writer.write("GET /short HTTP/1.1\r\n");
251             writer.write("Host: localhost\r\n");
252             writer.write("Connection: close\r\n");
253             writer.write("\r\n");
254             writer.flush();
255             InputStream instream = socket.getInputStream();
256             BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "US-ASCII"));
257             StringBuilder buf = new StringBuilder();
258             char[] tmp = new char[1024];
259             int l;
260             while ((l = reader.read(tmp)) != -1) {
261                 buf.append(tmp, 0, l);
262             }
263             reader.close();
264             writer.close();
265 
266             String expected =
267                     "HTTP/1.1 400 Bad Request\r\n" +
268                     "Connection: Close\r\n" +
269                     "Server: TEST-SERVER/1.1\r\n" +
270                     "Content-Length: 70\r\n" +
271                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
272                     "\r\n" +
273                     "Out of sequence request message detected (pipelining is not supported)";
274             Assert.assertEquals(expected, buf.toString());
275 
276         } finally {
277             socket.close();
278         }
279 
280         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
281     }
282 
283 }