//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.http2.client.http;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert;
import org.junit.Test;
public class PushedResourcesTest extends AbstractTest
{
@Test
public void testPushedResourceCancelled() throws Exception
{
String pushPath = "/secondary";
CountDownLatch latch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter()
{
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
HttpURI pushURI = new HttpURI("http://localhost:" + connector.getLocalPort() + pushPath);
MetaData.Request pushRequest = new MetaData.Request(HttpMethod.GET.asString(), pushURI, HttpVersion.HTTP_2, new HttpFields());
stream.push(new PushPromiseFrame(stream.getId(), 0, pushRequest), new Promise.Adapter<Stream>()
{
@Override
public void succeeded(Stream pushStream)
{
// Just send the normal response and wait for the reset.
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
}, new Stream.Listener.Adapter()
{
@Override
public void onReset(Stream stream, ResetFrame frame)
{
latch.countDown();
}
});
return null;
}
});
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
ContentResponse response = request
.pushListener((mainRequest, pushedRequest) -> null)
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@Test
public void testPushedResources() throws Exception
{
Random random = new Random();
byte[] bytes = new byte[512];
random.nextBytes(bytes);
byte[] pushBytes1 = new byte[1024];
random.nextBytes(pushBytes1);
byte[] pushBytes2 = new byte[2048];
random.nextBytes(pushBytes2);
String path1 = "/secondary1";
String path2 = "/secondary2";
start(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
if (target.equals(path1))
{
response.getOutputStream().write(pushBytes1);
}
else if (target.equals(path2))
{
response.getOutputStream().write(pushBytes2);
}
else
{
baseRequest.newPushBuilder()
.path(path1)
.push();
baseRequest.newPushBuilder()
.path(path2)
.push();
response.getOutputStream().write(bytes);
}
}
});
CountDownLatch latch1 = new CountDownLatch(1);
CountDownLatch latch2 = new CountDownLatch(1);
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
ContentResponse response = request
.pushListener((mainRequest, pushedRequest) -> new BufferingResponseListener()
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isSucceeded());
if (pushedRequest.getPath().equals(path1))
{
Assert.assertArrayEquals(pushBytes1, getContent());
latch1.countDown();
}
else if (pushedRequest.getPath().equals(path2))
{
Assert.assertArrayEquals(pushBytes2, getContent());
latch2.countDown();
}
}
})
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
Assert.assertArrayEquals(bytes, response.getContent());
Assert.assertTrue(latch1.await(5, TimeUnit.SECONDS));
Assert.assertTrue(latch2.await(5, TimeUnit.SECONDS));
}
@Test
public void testPushedResourceRedirect() throws Exception
{
Random random = new Random();
byte[] pushBytes = new byte[512];
random.nextBytes(pushBytes);
String oldPath = "/old";
String newPath = "/new";
start(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
if (target.equals(oldPath))
response.sendRedirect(newPath);
else if (target.equals(newPath))
response.getOutputStream().write(pushBytes);
else
baseRequest.newPushBuilder().path(oldPath).push();
}
});
CountDownLatch latch = new CountDownLatch(1);
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
ContentResponse response = request
.pushListener((mainRequest, pushedRequest) -> new BufferingResponseListener()
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isSucceeded());
Assert.assertEquals(oldPath, pushedRequest.getPath());
Assert.assertEquals(newPath, result.getRequest().getPath());
Assert.assertArrayEquals(pushBytes, getContent());
latch.countDown();
}
})
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
}