/*
* 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;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static org.asynchttpclient.Dsl.*;
import static org.testng.Assert.*;
import io.netty.handler.codec.http.HttpHeaders;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.net.ServerSocketFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* @author Hubert Iwaniuk
*/
public class MultipleHeaderTest extends AbstractBasicTest {
private ExecutorService executorService;
private ServerSocket serverSocket;
private Future<?> voidFuture;
@BeforeClass
public void setUpGlobal() throws Exception {
serverSocket = ServerSocketFactory.getDefault().createServerSocket(0);
port1 = serverSocket.getLocalPort();
executorService = Executors.newFixedThreadPool(1);
voidFuture = executorService.submit(new Callable<Void>() {
public Void call() throws Exception {
Socket socket;
while ((socket = serverSocket.accept()) != null) {
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String req = reader.readLine().split(" ")[1];
int i = inputStream.available();
long l = inputStream.skip(i);
assertEquals(l, i);
socket.shutdownInput();
if (req.endsWith("MultiEnt")) {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
outputStreamWriter.append("HTTP/1.0 200 OK\n" + "Connection: close\n" + "Content-Type: text/plain; charset=iso-8859-1\n" + "Content-Length: 2\n"
+ "Content-Length: 1\n" + "\n0\n");
outputStreamWriter.flush();
socket.shutdownOutput();
} else if (req.endsWith("MultiOther")) {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
outputStreamWriter.append("HTTP/1.0 200 OK\n" + "Connection: close\n" + "Content-Type: text/plain; charset=iso-8859-1\n" + "Content-Length: 1\n"
+ "X-Forwarded-For: abc\n" + "X-Forwarded-For: def\n" + "\n0\n");
outputStreamWriter.flush();
socket.shutdownOutput();
}
}
return null;
}
});
}
@AfterClass(alwaysRun = true)
public void tearDownGlobal() throws Exception {
voidFuture.cancel(true);
executorService.shutdownNow();
serverSocket.close();
}
@Test(groups = "standalone")
public void testMultipleOtherHeaders() throws IOException, ExecutionException, TimeoutException, InterruptedException {
final String[] xffHeaders = new String[] { null, null };
try (AsyncHttpClient ahc = asyncHttpClient()) {
Request req = get("http://localhost:" + port1 + "/MultiOther").build();
final CountDownLatch latch = new CountDownLatch(1);
ahc.executeRequest(req, new AsyncHandler<Void>() {
public void onThrowable(Throwable t) {
t.printStackTrace(System.out);
}
public State onBodyPartReceived(HttpResponseBodyPart objectHttpResponseBodyPart) throws Exception {
return State.CONTINUE;
}
public State onStatusReceived(HttpResponseStatus objectHttpResponseStatus) throws Exception {
return State.CONTINUE;
}
public State onHeadersReceived(HttpHeaders response) throws Exception {
int i = 0;
for (String header : response.getAll("X-Forwarded-For")) {
xffHeaders[i++] = header;
}
latch.countDown();
return State.CONTINUE;
}
public Void onCompleted() throws Exception {
return null;
}
}).get(3, TimeUnit.SECONDS);
if (!latch.await(2, TimeUnit.SECONDS)) {
fail("Time out");
}
assertNotNull(xffHeaders[0]);
assertNotNull(xffHeaders[1]);
try {
assertEquals(xffHeaders[0], "abc");
assertEquals(xffHeaders[1], "def");
} catch (AssertionError ex) {
assertEquals(xffHeaders[1], "abc");
assertEquals(xffHeaders[0], "def");
}
}
}
@Test(groups = "standalone")
public void testMultipleEntityHeaders() throws IOException, ExecutionException, TimeoutException, InterruptedException {
final String[] clHeaders = new String[] { null, null };
try (AsyncHttpClient ahc = asyncHttpClient()) {
Request req = get("http://localhost:" + port1 + "/MultiEnt").build();
final CountDownLatch latch = new CountDownLatch(1);
ahc.executeRequest(req, new AsyncHandler<Void>() {
public void onThrowable(Throwable t) {
t.printStackTrace(System.out);
}
public State onBodyPartReceived(HttpResponseBodyPart objectHttpResponseBodyPart) throws Exception {
return State.CONTINUE;
}
public State onStatusReceived(HttpResponseStatus objectHttpResponseStatus) throws Exception {
return State.CONTINUE;
}
public State onHeadersReceived(HttpHeaders response) throws Exception {
try {
int i = 0;
for (String header : response.getAll(CONTENT_LENGTH)) {
clHeaders[i++] = header;
}
} finally {
latch.countDown();
}
return State.CONTINUE;
}
public Void onCompleted() throws Exception {
return null;
}
}).get(3, TimeUnit.SECONDS);
if (!latch.await(2, TimeUnit.SECONDS)) {
fail("Time out");
}
assertNotNull(clHeaders[0]);
assertNotNull(clHeaders[1]);
// We can predict the order
try {
assertEquals(clHeaders[0], "2");
assertEquals(clHeaders[1], "1");
} catch (Throwable ex) {
assertEquals(clHeaders[0], "1");
assertEquals(clHeaders[1], "2");
}
}
}
}