/*
* 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.asynchttpclient.test.TestUtils.*;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class AuthTimeoutTest extends AbstractBasicTest {
private static final int REQUEST_TIMEOUT = 1000;
private static final int SHORT_FUTURE_TIMEOUT = 500; // shorter than REQUEST_TIMEOUT
private static final int LONG_FUTURE_TIMEOUT = 1500; // longer than REQUEST_TIMEOUT
private Server server2;
@BeforeClass(alwaysRun = true)
@Override
public void setUpGlobal() throws Exception {
server = new Server();
ServerConnector connector1 = addHttpConnector(server);
addBasicAuthHandler(server, configureHandler());
server.start();
port1 = connector1.getLocalPort();
server2 = new Server();
ServerConnector connector2 = addHttpConnector(server2);
addDigestAuthHandler(server2, configureHandler());
server2.start();
port2 = connector2.getLocalPort();
logger.info("Local HTTP server started successfully");
}
@AfterClass(alwaysRun = true)
public void tearDownGlobal() throws Exception {
super.tearDownGlobal();
server2.stop();
}
private class IncompleteResponseHandler extends AbstractHandler {
public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// NOTE: handler sends less bytes than are given in Content-Length, which should lead to timeout
response.setStatus(200);
OutputStream out = response.getOutputStream();
response.setIntHeader(CONTENT_LENGTH.toString(), 1000);
out.write(0);
out.flush();
try {
Thread.sleep(LONG_FUTURE_TIMEOUT + 100);
} catch (InterruptedException e) {
}
}
}
@Test(expectedExceptions = TimeoutException.class)
public void basicAuthTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, true, false).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw e.getCause();
}
}
@Test(expectedExceptions = TimeoutException.class)
public void basicPreemptiveAuthTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, true, true).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw e.getCause();
}
}
@Test(expectedExceptions = TimeoutException.class)
public void digestAuthTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, false, false).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw e.getCause();
}
}
@Test(expectedExceptions = TimeoutException.class, enabled = false)
public void digestPreemptiveAuthTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, false, true).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw e.getCause();
}
}
@Test(expectedExceptions = TimeoutException.class)
public void basicAuthFutureTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, true, false).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
@Test(expectedExceptions = TimeoutException.class)
public void basicPreemptiveAuthFutureTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, true, true).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
@Test(expectedExceptions = TimeoutException.class)
public void digestAuthFutureTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, false, false).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
@Test(expectedExceptions = TimeoutException.class, enabled = false)
public void digestPreemptiveAuthFutureTimeoutTest() throws Throwable {
try (AsyncHttpClient client = newClient()) {
execute(client, false, true).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
private AsyncHttpClient newClient() {
return asyncHttpClient(config().setRequestTimeout(REQUEST_TIMEOUT));
}
protected Future<Response> execute(AsyncHttpClient client, boolean basic, boolean preemptive) throws IOException {
Realm.Builder realm;
String url;
if (basic) {
realm = basicAuthRealm(USER, ADMIN);
url = getTargetUrl();
} else {
realm = digestAuthRealm(USER, ADMIN);
url = getTargetUrl2();
if (preemptive) {
realm.setRealmName("MyRealm");
realm.setAlgorithm("MD5");
realm.setQop("auth");
realm.setNonce("fFDVc60re9zt8fFDvht0tNrYuvqrcchN");
}
}
return client.prepareGet(url).setRealm(realm.setUsePreemptiveAuth(preemptive).build()).execute();
}
@Override
protected String getTargetUrl() {
return "http://localhost:" + port1 + "/";
}
@Override
protected String getTargetUrl2() {
return "http://localhost:" + port2 + "/";
}
@Override
public AbstractHandler configureHandler() throws Exception {
return new IncompleteResponseHandler();
}
}