/*
* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package org.asynchttpclient.request.body;
import static org.asynchttpclient.Dsl.*;
import static org.asynchttpclient.test.TestUtils.*;
import static org.testng.Assert.*;
import static org.testng.FileAssert.fail;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import org.asynchttpclient.AbstractBasicTest;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.DefaultAsyncHttpClientConfig;
import org.asynchttpclient.ListenableFuture;
import org.asynchttpclient.Request;
import org.asynchttpclient.Response;
import org.asynchttpclient.request.body.generator.FeedableBodyGenerator;
import org.asynchttpclient.request.body.generator.InputStreamBodyGenerator;
import org.asynchttpclient.request.body.generator.UnboundedQueueFeedableBodyGenerator;
import org.testng.annotations.Test;
public class ChunkingTest extends AbstractBasicTest {
// So we can just test the returned data is the image,
// and doesn't contain the chunked delimeters.
@Test(groups = "standalone")
public void testBufferLargerThanFileWithStreamBodyGenerator() throws Throwable {
doTestWithInputStreamBodyGenerator(new BufferedInputStream(Files.newInputStream(LARGE_IMAGE_FILE.toPath()), 400000));
}
@Test(groups = "standalone")
public void testBufferSmallThanFileWithStreamBodyGenerator() throws Throwable {
doTestWithInputStreamBodyGenerator(new BufferedInputStream(Files.newInputStream(LARGE_IMAGE_FILE.toPath())));
}
@Test(groups = "standalone")
public void testDirectFileWithStreamBodyGenerator() throws Throwable {
doTestWithInputStreamBodyGenerator(Files.newInputStream(LARGE_IMAGE_FILE.toPath()));
}
@Test(groups = "standalone")
public void testDirectFileWithFeedableBodyGenerator() throws Throwable {
doTestWithFeedableBodyGenerator(Files.newInputStream(LARGE_IMAGE_FILE.toPath()));
}
public void doTestWithInputStreamBodyGenerator(InputStream is) throws Throwable {
try {
try (AsyncHttpClient c = asyncHttpClient(httpClientBuilder())) {
ListenableFuture<Response> responseFuture = c.executeRequest(post(getTargetUrl()).setBody(new InputStreamBodyGenerator(is)));
waitForAndAssertResponse(responseFuture);
}
} finally {
is.close();
}
}
public void doTestWithFeedableBodyGenerator(InputStream is) throws Throwable {
try {
try (AsyncHttpClient c = asyncHttpClient(httpClientBuilder())) {
final FeedableBodyGenerator feedableBodyGenerator = new UnboundedQueueFeedableBodyGenerator();
Request r = post(getTargetUrl()).setBody(feedableBodyGenerator).build();
ListenableFuture<Response> responseFuture = c.executeRequest(r);
feed(feedableBodyGenerator, is);
waitForAndAssertResponse(responseFuture);
}
} finally {
is.close();
}
}
private void feed(FeedableBodyGenerator feedableBodyGenerator, InputStream is) throws Exception {
try (InputStream inputStream = is) {
byte[] buffer = new byte[512];
for (int i = 0; (i = inputStream.read(buffer)) > -1;) {
byte[] chunk = new byte[i];
System.arraycopy(buffer, 0, chunk, 0, i);
feedableBodyGenerator.feed(ByteBuffer.wrap(chunk), false);
}
}
feedableBodyGenerator.feed(ByteBuffer.allocate(0), true);
}
private DefaultAsyncHttpClientConfig.Builder httpClientBuilder() {
return config()//
.setKeepAlive(true)//
.setMaxConnectionsPerHost(1)//
.setMaxConnections(1)//
.setConnectTimeout(1000)//
.setRequestTimeout(1000)//
.setFollowRedirect(true);
}
private void waitForAndAssertResponse(ListenableFuture<Response> responseFuture) throws InterruptedException, java.util.concurrent.ExecutionException, IOException {
Response response = responseFuture.get();
if (500 == response.getStatusCode()) {
StringBuilder sb = new StringBuilder();
sb.append("==============\n");
sb.append("500 response from call\n");
sb.append("Headers:" + response.getHeaders() + "\n");
sb.append("==============\n");
logger.debug(sb.toString());
assertEquals(response.getStatusCode(), 500, "Should have 500 status code");
assertTrue(response.getHeader("X-Exception").contains("invalid.chunk.length"), "Should have failed due to chunking");
fail("HARD Failing the test due to provided InputStreamBodyGenerator, chunking incorrectly:" + response.getHeader("X-Exception"));
} else {
assertEquals(response.getResponseBodyAsBytes(), LARGE_IMAGE_BYTES);
}
}
}