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.hc.core5.testing.classic;
29  
30  import org.apache.hc.core5.http.ClassicHttpRequest;
31  import org.apache.hc.core5.http.ClassicHttpResponse;
32  import org.apache.hc.core5.http.ContentType;
33  import org.apache.hc.core5.http.HttpHost;
34  import org.apache.hc.core5.http.Method;
35  import org.apache.hc.core5.http.URIScheme;
36  import org.apache.hc.core5.http.impl.bootstrap.HttpRequester;
37  import org.apache.hc.core5.http.impl.bootstrap.RequesterBootstrap;
38  import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnectionFactory;
39  import org.apache.hc.core5.http.impl.io.MonitoringResponseOutOfOrderStrategy;
40  import org.apache.hc.core5.http.io.HttpRequestHandler;
41  import org.apache.hc.core5.http.io.SocketConfig;
42  import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
43  import org.apache.hc.core5.http.io.entity.EntityUtils;
44  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
45  import org.apache.hc.core5.http.protocol.HttpContext;
46  import org.apache.hc.core5.http.protocol.HttpCoreContext;
47  import org.apache.hc.core5.io.CloseMode;
48  import org.apache.hc.core5.testing.SSLTestContexts;
49  import org.apache.hc.core5.util.Timeout;
50  import org.junit.Assert;
51  import org.junit.Rule;
52  import org.junit.Test;
53  import org.junit.rules.ExternalResource;
54  import org.junit.runner.RunWith;
55  import org.junit.runners.Parameterized;
56  
57  import java.io.IOException;
58  import java.io.InputStream;
59  import java.io.OutputStream;
60  import java.util.Arrays;
61  import java.util.Collection;
62  
63  @RunWith(Parameterized.class)
64  public class MonitoringResponseOutOfOrderStrategyIntegrationTest {
65  
66      // Use a 16k buffer for consistent results across systems
67      private static final int BUFFER_SIZE = 16 * 1024;
68      private static final Timeout TIMEOUT = Timeout.ofSeconds(3);
69  
70      @Parameterized.Parameters(name = "{0}")
71      public static Collection<Object[]> protocols() {
72          return Arrays.asList(new Object[][]{
73                  { URIScheme.HTTP },
74                  { URIScheme.HTTPS }
75          });
76      }
77  
78      private final URIScheme scheme;
79      private ClassicTestServer server;
80      private HttpRequester requester;
81  
82      public MonitoringResponseOutOfOrderStrategyIntegrationTest(final URIScheme scheme) {
83          this.scheme = scheme;
84      }
85  
86      @Rule
87      public ExternalResource serverResource = new ExternalResource() {
88  
89          @Override
90          protected void before() throws Throwable {
91              server = new ClassicTestServer(
92                      scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null,
93                      SocketConfig.custom()
94                              .setSoTimeout(TIMEOUT)
95                              .setSndBufSize(BUFFER_SIZE)
96                              .setRcvBufSize(BUFFER_SIZE)
97                              .setSoKeepAlive(false)
98                              .build());
99          }
100 
101         @Override
102         protected void after() {
103             if (server != null) {
104                 try {
105                     server.shutdown(CloseMode.IMMEDIATE);
106                     server = null;
107                 } catch (final Exception ignore) {
108                 }
109             }
110         }
111 
112     };
113 
114     @Rule
115     public ExternalResource requesterResource = new ExternalResource() {
116 
117         @Override
118         protected void before() throws Throwable {
119             requester = RequesterBootstrap.bootstrap()
120                     .setSslContext(scheme == URIScheme.HTTPS  ? SSLTestContexts.createClientSSLContext() : null)
121                     .setSocketConfig(SocketConfig.custom()
122                             .setSoTimeout(TIMEOUT)
123                             .setRcvBufSize(BUFFER_SIZE)
124                             .setSndBufSize(BUFFER_SIZE)
125                             .setSoKeepAlive(false)
126                             .build())
127                     .setStreamListener(LoggingHttp1StreamListener.INSTANCE)
128                     .setConnPoolListener(LoggingConnPoolListener.INSTANCE)
129                     .setConnectionFactory(DefaultBHttpClientConnectionFactory.builder()
130                             .responseOutOfOrderStrategy(MonitoringResponseOutOfOrderStrategy.INSTANCE)
131                             .build())
132                     .create();
133         }
134 
135         @Override
136         protected void after() {
137             if (requester != null) {
138                 try {
139                     requester.close(CloseMode.IMMEDIATE);
140                     requester = null;
141                 } catch (final Exception ignore) {
142                 }
143             }
144         }
145 
146     };
147 
148     @Test(timeout = 5000) // Failures may hang
149     public void testResponseOutOfOrderWithDefaultStrategy() throws Exception {
150         this.server.registerHandler("*", new HttpRequestHandler() {
151 
152             @Override
153             public void handle(
154                     final ClassicHttpRequest request,
155                     final ClassicHttpResponse response,
156                     final HttpContext context) throws IOException {
157                 response.setCode(400);
158                 response.setEntity(new AllOnesHttpEntity(200000));
159             }
160 
161         });
162 
163         this.server.start(null, null, null);
164 
165         final HttpCoreContext context = HttpCoreContext.create();
166         final HttpHost host = new HttpHost(scheme.id, "localhost", this.server.getPort());
167 
168         final ClassicHttpRequest post = new BasicClassicHttpRequest(Method.POST, "/");
169         post.setEntity(new AllOnesHttpEntity(200000));
170 
171         try (final ClassicHttpResponse response = requester.execute(host, post, TIMEOUT, context)) {
172             Assert.assertEquals(400, response.getCode());
173             EntityUtils.consumeQuietly(response.getEntity());
174         }
175     }
176 
177     private static final class AllOnesHttpEntity extends AbstractHttpEntity {
178         private long remaining;
179 
180         protected AllOnesHttpEntity(final long length) {
181             super(ContentType.APPLICATION_OCTET_STREAM, null, true);
182             this.remaining = length;
183         }
184 
185         @Override
186         public InputStream getContent() {
187             throw new UnsupportedOperationException();
188         }
189 
190         @Override
191         public void writeTo(final OutputStream outStream) throws IOException {
192             final byte[] buf = new byte[1024];
193             while (remaining > 0) {
194                 final int writeLength = (int) Math.min(remaining, buf.length);
195                 outStream.write(buf, 0, writeLength);
196                 outStream.flush();
197                 remaining -= writeLength;
198             }
199         }
200 
201         @Override
202         public boolean isStreaming() {
203             return true;
204         }
205 
206         @Override
207         public void close() {
208         }
209 
210         @Override
211         public long getContentLength() {
212             return -1L;
213         }
214     }
215 }