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  
40  import org.apache.http.HttpEntity;
41  import org.apache.http.HttpEntityEnclosingRequest;
42  import org.apache.http.HttpException;
43  import org.apache.http.HttpRequest;
44  import org.apache.http.HttpResponse;
45  import org.apache.http.entity.ContentType;
46  import org.apache.http.nio.entity.NByteArrayEntity;
47  import org.apache.http.nio.entity.NStringEntity;
48  import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
49  import org.apache.http.nio.protocol.UriHttpAsyncRequestHandlerMapper;
50  import org.apache.http.nio.reactor.ListenerEndpoint;
51  import org.apache.http.nio.testserver.HttpCoreNIOTestBase;
52  import org.apache.http.protocol.HTTP;
53  import org.apache.http.protocol.HttpContext;
54  import org.apache.http.protocol.HttpRequestHandler;
55  import org.apache.http.protocol.ImmutableHttpProcessor;
56  import org.apache.http.protocol.ResponseConnControl;
57  import org.apache.http.protocol.ResponseContent;
58  import org.apache.http.protocol.ResponseServer;
59  import org.apache.http.util.EntityUtils;
60  import org.junit.After;
61  import org.junit.Assert;
62  import org.junit.Before;
63  import org.junit.Test;
64  
65  /**
66   * Tests for handling pipelined requests.
67   */
68  public class TestServerSidePipelining extends HttpCoreNIOTestBase {
69  
70      @Before
71      public void setUp() throws Exception {
72          initServer();
73          this.server.setHttpProcessor(new ImmutableHttpProcessor(
74                  new ResponseServer("TEST-SERVER/1.1"), new ResponseContent(), new ResponseConnControl()));
75          final UriHttpAsyncRequestHandlerMapper registry = new UriHttpAsyncRequestHandlerMapper();
76          this.server.registerHandler("*", new BasicAsyncRequestHandler(new HttpRequestHandler() {
77  
78              @Override
79              public void handle(
80                      final HttpRequest request,
81                      final HttpResponse response,
82                      final HttpContext context) throws HttpException, IOException {
83                  final String content = "thank you very much";
84                  final NStringEntity entity = new NStringEntity(content, ContentType.DEFAULT_TEXT);
85                  response.setEntity(entity);
86              }
87  
88          }));
89          this.server.registerHandler("/goodbye", new BasicAsyncRequestHandler(new HttpRequestHandler() {
90  
91              @Override
92              public void handle(
93                      final HttpRequest request,
94                      final HttpResponse response,
95                      final HttpContext context) throws HttpException, IOException {
96                  final String content = "and goodbye";
97                  final NStringEntity entity = new NStringEntity(content, ContentType.DEFAULT_TEXT);
98                  response.setEntity(entity);
99                  response.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
100             }
101 
102         }));
103         this.server.registerHandler("/echo", new BasicAsyncRequestHandler(new HttpRequestHandler() {
104 
105             @Override
106             public void handle(
107                     final HttpRequest request,
108                     final HttpResponse response,
109                     final HttpContext context) throws HttpException, IOException {
110                 final HttpEntity responseEntity;
111                 if (request instanceof HttpEntityEnclosingRequest) {
112                     final HttpEntity requestEntity = ((HttpEntityEnclosingRequest) request).getEntity();
113                     final ContentType contentType = ContentType.getOrDefault(requestEntity);
114                     responseEntity = new NByteArrayEntity(
115                             EntityUtils.toByteArray(requestEntity), contentType);
116                 } else {
117                     responseEntity = new NStringEntity("Say what?", ContentType.DEFAULT_TEXT);
118                 }
119                 response.setEntity(responseEntity);
120             }
121 
122         }));
123     }
124 
125     @After
126     public void tearDown() throws Exception {
127         shutDownServer();
128     }
129 
130     @Test
131     public void testGetRequestPipelining() throws Exception {
132         this.server.start();
133 
134         final ListenerEndpoint endpoint = this.server.getListenerEndpoint();
135         endpoint.waitFor();
136 
137         final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
138         final Socket socket = new Socket("localhost", address.getPort());
139         try {
140             final OutputStream outstream = socket.getOutputStream();
141             final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outstream, "US-ASCII"));
142             writer.write("GET / HTTP/1.1\r\n");
143             writer.write("Host: localhost\r\n");
144             writer.write("\r\n");
145             writer.write("GET / HTTP/1.1\r\n");
146             writer.write("Host: localhost\r\n");
147             writer.write("\r\n");
148             writer.write("GET / HTTP/1.1\r\n");
149             writer.write("Host: localhost\r\n");
150             writer.write("\r\n");
151             writer.write("GET / HTTP/1.1\r\n");
152             writer.write("Host: localhost\r\n");
153             writer.write("Connection: close\r\n");
154             writer.write("\r\n");
155             writer.flush();
156             final InputStream instream = socket.getInputStream();
157             final BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "US-ASCII"));
158             final StringBuilder buf = new StringBuilder();
159             final char[] tmp = new char[1024];
160             int l;
161             while ((l = reader.read(tmp)) != -1) {
162                 buf.append(tmp, 0, l);
163             }
164             reader.close();
165             writer.close();
166             final String expected =
167                     "HTTP/1.1 200 OK\r\n" +
168                     "Server: TEST-SERVER/1.1\r\n" +
169                     "Content-Length: 19\r\n" +
170                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
171                     "\r\n" +
172                     "thank you very much" +
173                     "HTTP/1.1 200 OK\r\n" +
174                     "Server: TEST-SERVER/1.1\r\n" +
175                     "Content-Length: 19\r\n" +
176                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
177                     "\r\n" +
178                     "thank you very much" +
179                     "HTTP/1.1 200 OK\r\n" +
180                     "Server: TEST-SERVER/1.1\r\n" +
181                     "Content-Length: 19\r\n" +
182                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
183                     "\r\n" +
184                     "thank you very much" +
185                     "HTTP/1.1 200 OK\r\n" +
186                     "Server: TEST-SERVER/1.1\r\n" +
187                     "Content-Length: 19\r\n" +
188                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
189                     "Connection: close\r\n" +
190                     "\r\n" +
191                     "thank you very much";
192             Assert.assertEquals(expected, buf.toString());
193 
194         } finally {
195             socket.close();
196         }
197 
198     }
199 
200     @Test
201     public void testPostRequestPipelining() throws Exception {
202         this.server.start();
203 
204         final ListenerEndpoint endpoint = this.server.getListenerEndpoint();
205         endpoint.waitFor();
206 
207         final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
208         final Socket socket = new Socket("localhost", address.getPort());
209         try {
210             final OutputStream outstream = socket.getOutputStream();
211             final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outstream, "US-ASCII"));
212             writer.write("POST /echo HTTP/1.1\r\n");
213             writer.write("Host: localhost\r\n");
214             writer.write("Content-Length: 16\r\n");
215             writer.write("Content-Type: text/plain; charset=ISO-8859-1\r\n");
216             writer.write("\r\n");
217             writer.write("blah blah blah\r\n");
218             writer.write("POST /echo HTTP/1.1\r\n");
219             writer.write("Host: localhost\r\n");
220             writer.write("Transfer-Encoding: chunked\r\n");
221             writer.write("Content-Type: text/plain; charset=ISO-8859-1\r\n");
222             writer.write("\r\n");
223             writer.write("10\r\n");
224             writer.write("yada yada yada\r\n");
225             writer.write("\r\n");
226             writer.write("0\r\n");
227             writer.write("\r\n");
228             writer.write("GET / HTTP/1.1\r\n");
229             writer.write("Host: localhost\r\n");
230             writer.write("\r\n");
231             writer.write("GET /goodbye HTTP/1.1\r\n");
232             writer.write("Host: localhost\r\n");
233             writer.write("\r\n");
234             writer.flush();
235             final InputStream instream = socket.getInputStream();
236             final BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "US-ASCII"));
237             final StringBuilder buf = new StringBuilder();
238             final char[] tmp = new char[1024];
239             int l;
240             while ((l = reader.read(tmp)) != -1) {
241                 buf.append(tmp, 0, l);
242             }
243             reader.close();
244             writer.close();
245             final String expected =
246                     "HTTP/1.1 200 OK\r\n" +
247                     "Server: TEST-SERVER/1.1\r\n" +
248                     "Content-Length: 16\r\n" +
249                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
250                     "\r\n" +
251                     "blah blah blah\r\n" +
252                     "HTTP/1.1 200 OK\r\n" +
253                     "Server: TEST-SERVER/1.1\r\n" +
254                     "Content-Length: 16\r\n" +
255                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
256                     "\r\n" +
257                     "yada yada yada\r\n" +
258                     "HTTP/1.1 200 OK\r\n" +
259                     "Server: TEST-SERVER/1.1\r\n" +
260                     "Content-Length: 19\r\n" +
261                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
262                     "\r\n" +
263                     "thank you very much" +
264                     "HTTP/1.1 200 OK\r\n" +
265                     "Connection: Close\r\n" +
266                     "Server: TEST-SERVER/1.1\r\n" +
267                     "Content-Length: 11\r\n" +
268                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
269                     "\r\n" +
270                     "and goodbye";
271             Assert.assertEquals(expected, buf.toString());
272 
273         } finally {
274             socket.close();
275         }
276 
277     }
278 
279     @Test
280     public void testPostRequestPipeliningExpectContinue() throws Exception {
281         this.server.start();
282 
283         final ListenerEndpoint endpoint = this.server.getListenerEndpoint();
284         endpoint.waitFor();
285 
286         final InetSocketAddress address = (InetSocketAddress) endpoint.getAddress();
287         final Socket socket = new Socket("localhost", address.getPort());
288         try {
289             final OutputStream outstream = socket.getOutputStream();
290             final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outstream, "US-ASCII"));
291             writer.write("POST /echo HTTP/1.1\r\n");
292             writer.write("Host: localhost\r\n");
293             writer.write("Expect: 100-Continue\r\n");
294             writer.write("Content-Length: 16\r\n");
295             writer.write("Content-Type: text/plain; charset=ISO-8859-1\r\n");
296             writer.write("\r\n");
297             writer.write("blah blah blah\r\n");
298             writer.write("POST /echo HTTP/1.1\r\n");
299             writer.write("Host: localhost\r\n");
300             writer.write("Expect: 100-Continue\r\n");
301             writer.write("Content-Length: 16\r\n");
302             writer.write("Content-Type: text/plain; charset=ISO-8859-1\r\n");
303             writer.write("\r\n");
304             writer.write("yada yada yada\r\n");
305             writer.write("POST /echo HTTP/1.1\r\n");
306             writer.write("Host: localhost\r\n");
307             writer.write("Expect: 100-Continue\r\n");
308             writer.write("Content-Length: 16\r\n");
309             writer.write("Content-Type: text/plain; charset=ISO-8859-1\r\n");
310             writer.write("Connection: close\r\n");
311             writer.write("\r\n");
312             writer.write("booo booo booo\r\n");
313             writer.flush();
314             final InputStream instream = socket.getInputStream();
315             final BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "US-ASCII"));
316             final StringBuilder buf = new StringBuilder();
317             final char[] tmp = new char[1024];
318             int l;
319             while ((l = reader.read(tmp)) != -1) {
320                 buf.append(tmp, 0, l);
321             }
322             reader.close();
323             writer.close();
324             final String expected = "HTTP/1.1 200 OK\r\n" +
325                     "Server: TEST-SERVER/1.1\r\n" +
326                     "Content-Length: 16\r\n" +
327                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
328                     "\r\n" +
329                     "blah blah blah\r\n" +
330                     "HTTP/1.1 200 OK\r\n" +
331                     "Server: TEST-SERVER/1.1\r\n" +
332                     "Content-Length: 16\r\n" +
333                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
334                     "\r\n" +
335                     "yada yada yada\r\n" +
336                     "HTTP/1.1 200 OK\r\n" +
337                     "Server: TEST-SERVER/1.1\r\n" +
338                     "Content-Length: 16\r\n" +
339                     "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
340                     "Connection: close\r\n" +
341                     "\r\n" +
342                     "booo booo booo\r\n";
343             Assert.assertEquals(expected, buf.toString());
344 
345         } finally {
346             socket.close();
347         }
348     }
349 
350 }