spdy: ReferrerPushStrategy configurable by SPDY version and add referrer push period
This commit is contained in:
parent
5e619ce525
commit
1ff0b18b94
|
@ -72,6 +72,11 @@
|
|||
<version>${slf4j-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -23,9 +23,11 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -37,12 +39,13 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* will have a <tt>Referer</tt> HTTP header that points to <tt>index.html</tt>, which we
|
||||
* use to link the associated resource to the main resource.</p>
|
||||
* <p>However, also following a hyperlink generates a HTTP request with a <tt>Referer</tt>
|
||||
* HTTP header that points to <tt>index.html</tt>; therefore main resources and associated
|
||||
* resources must be distinguishable.</p>
|
||||
* <p>This class distinguishes associated resources by their URL path suffix and content
|
||||
* HTTP header that points to <tt>index.html</tt>; therefore a proper value for {@link #getReferrerPushPeriod()}
|
||||
* has to be set. If the referrerPushPeriod for a main resource has been passed, no more
|
||||
* associated resources will be added for that main resource.</p>
|
||||
* <p>This class distinguishes associated main resources by their URL path suffix and content
|
||||
* type.
|
||||
* CSS stylesheets, images and JavaScript files have recognizable URL path suffixes that
|
||||
* are classified as associated resources.</p>
|
||||
* are classified as associated resources. The suffix regexs can be configured by constructor argument</p>
|
||||
* <p>When CSS stylesheets refer to images, the CSS image request will have the CSS
|
||||
* stylesheet as referrer. This implementation will push also the CSS image.</p>
|
||||
* <p>The push metadata built by this implementation is limited by the number of pages
|
||||
|
@ -55,11 +58,13 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class ReferrerPushStrategy implements PushStrategy
|
||||
{
|
||||
private static final Logger logger = Log.getLogger(ReferrerPushStrategy.class);
|
||||
private final ConcurrentMap<String, Set<String>> resources = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, MainResource> mainResources = new ConcurrentHashMap<>();
|
||||
private final Set<Pattern> pushRegexps = new HashSet<>();
|
||||
private final Set<String> pushContentTypes = new HashSet<>();
|
||||
private final Set<Pattern> allowedPushOrigins = new HashSet<>();
|
||||
private final HashSet<Short> supportedSPDYVersions = new HashSet<Short>();
|
||||
private volatile int maxAssociatedResources = 32;
|
||||
private volatile int referrerPushPeriod = 5000;
|
||||
|
||||
public ReferrerPushStrategy()
|
||||
{
|
||||
|
@ -89,6 +94,9 @@ public class ReferrerPushStrategy implements PushStrategy
|
|||
this.pushContentTypes.addAll(pushContentTypes);
|
||||
for (String allowedPushOrigin : allowedPushOrigins)
|
||||
this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*")));
|
||||
// by default we support v2 and v3
|
||||
supportedSPDYVersions.add(SPDY.V2);
|
||||
supportedSPDYVersions.add(SPDY.V3);
|
||||
}
|
||||
|
||||
public int getMaxAssociatedResources()
|
||||
|
@ -101,22 +109,51 @@ public class ReferrerPushStrategy implements PushStrategy
|
|||
this.maxAssociatedResources = maxAssociatedResources;
|
||||
}
|
||||
|
||||
public int getReferrerPushPeriod()
|
||||
{
|
||||
return referrerPushPeriod;
|
||||
}
|
||||
|
||||
public void setReferrerPushPeriod(int referrerPushPeriod)
|
||||
{
|
||||
this.referrerPushPeriod = referrerPushPeriod;
|
||||
}
|
||||
|
||||
public void removeSPDYVersionSupport(Short version)
|
||||
{
|
||||
supportedSPDYVersions.remove(version);
|
||||
}
|
||||
|
||||
public void addSPDYVersionSupport(Short version)
|
||||
{
|
||||
// consider to make SPDY.Vx an enum when we add support for more than two drafts
|
||||
if (version == SPDY.V2 || version == SPDY.V3)
|
||||
supportedSPDYVersions.add(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> apply(Stream stream, Headers requestHeaders, Headers responseHeaders)
|
||||
{
|
||||
Set<String> result = Collections.<String>emptySet();
|
||||
short version = stream.getSession().getVersion();
|
||||
if (!supportedSPDYVersions.contains(version))
|
||||
{
|
||||
logger.debug("SPDY version {} not supported. Returning empty Set.", version);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).value()))
|
||||
{
|
||||
String scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)).value();
|
||||
String host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)).value();
|
||||
String origin = new StringBuilder(scheme).append("://").append(host).toString();
|
||||
String origin = scheme + "://" + host;
|
||||
String url = requestHeaders.get(HTTPSPDYHeader.URI.name(version)).value();
|
||||
String absoluteURL = new StringBuilder(origin).append(url).toString();
|
||||
String absoluteURL = origin + url;
|
||||
logger.debug("Applying push strategy for {}", absoluteURL);
|
||||
if (isMainResource(url, responseHeaders))
|
||||
{
|
||||
result = pushResources(absoluteURL);
|
||||
MainResource mainResource = getOrCreateMainResource(absoluteURL);
|
||||
result = mainResource.getResources();
|
||||
}
|
||||
else if (isPushResource(url, responseHeaders))
|
||||
{
|
||||
|
@ -124,18 +161,44 @@ public class ReferrerPushStrategy implements PushStrategy
|
|||
if (referrerHeader != null)
|
||||
{
|
||||
String referrer = referrerHeader.value();
|
||||
Set<String> pushResources = resources.get(referrer);
|
||||
if (pushResources == null || !pushResources.contains(url))
|
||||
buildMetadata(origin, url, referrer);
|
||||
MainResource mainResource = mainResources.get(referrer);
|
||||
if (mainResource == null)
|
||||
mainResource = getOrCreateMainResource(referrer);
|
||||
|
||||
Set<String> pushResources = mainResource.getResources();
|
||||
if (!pushResources.contains(url))
|
||||
mainResource.addResource(url, origin, referrer);
|
||||
else
|
||||
result = pushResources(absoluteURL);
|
||||
result = getPushResources(absoluteURL);
|
||||
}
|
||||
}
|
||||
logger.debug("Push resources for {}: {}", absoluteURL, result);
|
||||
logger.debug("Pushing {} resources for {}: {}", result.size(), absoluteURL, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<String> getPushResources(String absoluteURL)
|
||||
{
|
||||
Set<String> result = Collections.emptySet();
|
||||
if (mainResources.get(absoluteURL) != null)
|
||||
result = mainResources.get(absoluteURL).getResources();
|
||||
return result;
|
||||
}
|
||||
|
||||
private MainResource getOrCreateMainResource(String absoluteURL)
|
||||
{
|
||||
MainResource mainResource = mainResources.get(absoluteURL);
|
||||
if (mainResource == null)
|
||||
{
|
||||
logger.debug("Creating new main resource for {}", absoluteURL);
|
||||
MainResource value = new MainResource(absoluteURL);
|
||||
mainResource = mainResources.putIfAbsent(absoluteURL, value);
|
||||
if (mainResource == null)
|
||||
mainResource = value;
|
||||
}
|
||||
return mainResource;
|
||||
}
|
||||
|
||||
private boolean isIfModifiedSinceHeaderPresent(Headers headers)
|
||||
{
|
||||
return headers.get("if-modified-since") != null;
|
||||
|
@ -170,49 +233,65 @@ public class ReferrerPushStrategy implements PushStrategy
|
|||
return false;
|
||||
}
|
||||
|
||||
private Set<String> pushResources(String absoluteURL)
|
||||
private class MainResource
|
||||
{
|
||||
Set<String> pushResources = resources.get(absoluteURL);
|
||||
if (pushResources == null)
|
||||
return Collections.emptySet();
|
||||
return Collections.unmodifiableSet(pushResources);
|
||||
}
|
||||
private final String name;
|
||||
private final long created = System.nanoTime();
|
||||
private final Set<String> resources = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||
|
||||
private void buildMetadata(String origin, String url, String referrer)
|
||||
{
|
||||
if (referrer.startsWith(origin) || isPushOriginAllowed(origin))
|
||||
MainResource(String name)
|
||||
{
|
||||
Set<String> pushResources = resources.get(referrer);
|
||||
if (pushResources == null)
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean addResource(String url, String origin, String referrer)
|
||||
{
|
||||
long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - created);
|
||||
if (!referrer.startsWith(origin) && !isPushOriginAllowed(origin))
|
||||
{
|
||||
pushResources = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||
Set<String> existing = resources.putIfAbsent(referrer, pushResources);
|
||||
if (existing != null)
|
||||
pushResources = existing;
|
||||
logger.debug("Skipped store of push metadata {} for {}: Origin: {} doesn't match or origin not allowed",
|
||||
url, name, origin);
|
||||
return false;
|
||||
}
|
||||
|
||||
// This check is not strictly concurrent-safe, but limiting
|
||||
// the number of associated resources is achieved anyway
|
||||
// although in rare cases few more resources will be stored
|
||||
if (pushResources.size() < getMaxAssociatedResources())
|
||||
{
|
||||
pushResources.add(url);
|
||||
logger.debug("Stored push metadata for {}: {}", referrer, pushResources);
|
||||
}
|
||||
else
|
||||
if (resources.size() >= maxAssociatedResources)
|
||||
{
|
||||
logger.debug("Skipped store of push metadata {} for {}: max associated resources ({}) reached",
|
||||
url, referrer, maxAssociatedResources);
|
||||
url, name, maxAssociatedResources);
|
||||
return false;
|
||||
}
|
||||
if (delay > referrerPushPeriod)
|
||||
{
|
||||
logger.debug("Delay: {}ms longer than referrerPushPeriod: {}ms. Not adding resource: {} for: {}", delay, referrerPushPeriod, url, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPushOriginAllowed(String origin)
|
||||
{
|
||||
for (Pattern allowedPushOrigin : allowedPushOrigins)
|
||||
{
|
||||
if (allowedPushOrigin.matcher(origin).matches())
|
||||
return true;
|
||||
logger.debug("Adding resource: {} for: {} with delay: {}ms.", url, name, delay);
|
||||
resources.add(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Set<String> getResources()
|
||||
{
|
||||
return Collections.unmodifiableSet(resources);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "MainResource: " + name + " associated resources:" + resources.size();
|
||||
}
|
||||
|
||||
private boolean isPushOriginAllowed(String origin)
|
||||
{
|
||||
for (Pattern allowedPushOrigin : allowedPushOrigins)
|
||||
{
|
||||
if (allowedPushOrigin.matcher(origin).matches())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.eclipse.jetty.spdy.api.Handler;
|
|||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.ReplyInfo;
|
||||
import org.eclipse.jetty.spdy.api.RstInfo;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.eclipse.jetty.spdy.api.StreamStatus;
|
||||
import org.eclipse.jetty.spdy.api.SynInfo;
|
||||
|
@ -411,19 +412,12 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
Headers.Header host = headers.get(HTTPSPDYHeader.HOST.name(version));
|
||||
Headers.Header uri = headers.get(HTTPSPDYHeader.URI.name(version));
|
||||
Set<String> pushResources = pushStrategy.apply(stream, headers, replyInfo.getHeaders());
|
||||
String referrer = new StringBuilder(scheme.value()).append("://").append(host.value()).append(uri.value()).toString();
|
||||
for (String pushURL : pushResources)
|
||||
|
||||
for (String pushResourcePath : pushResources)
|
||||
{
|
||||
final Headers pushHeaders = new Headers();
|
||||
pushHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushURL);
|
||||
pushHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
|
||||
pushHeaders.put(scheme);
|
||||
pushHeaders.put(host);
|
||||
pushHeaders.put("referer", referrer);
|
||||
pushHeaders.put("x-spdy-push", "true");
|
||||
// Remember support for gzip encoding
|
||||
pushHeaders.put(headers.get("accept-encoding"));
|
||||
final Headers requestHeaders = createRequestHeaders(scheme, host, uri, pushResourcePath);
|
||||
final Headers pushHeaders = createPushHeaders(scheme, host, pushResourcePath);
|
||||
|
||||
stream.syn(new SynInfo(pushHeaders, false), getMaxIdleTime(), TimeUnit.MILLISECONDS, new Handler.Adapter<Stream>()
|
||||
{
|
||||
@Override
|
||||
|
@ -431,13 +425,50 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
{
|
||||
ServerHTTPSPDYAsyncConnection pushConnection =
|
||||
new ServerHTTPSPDYAsyncConnection(getConnector(), getEndPoint(), getServer(), version, connection, pushStrategy, pushStream);
|
||||
pushConnection.beginRequest(pushHeaders, true);
|
||||
pushConnection.beginRequest(requestHeaders, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Headers createRequestHeaders(Headers.Header scheme, Headers.Header host, Headers.Header uri, String pushResourcePath)
|
||||
{
|
||||
final Headers requestHeaders = new Headers();
|
||||
requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
|
||||
requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
|
||||
requestHeaders.put(scheme);
|
||||
requestHeaders.put(host);
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
|
||||
String referrer = scheme.value() + "://" + host.value() + uri.value();
|
||||
requestHeaders.put("referer", referrer);
|
||||
// Remember support for gzip encoding
|
||||
requestHeaders.put(headers.get("accept-encoding"));
|
||||
return requestHeaders;
|
||||
}
|
||||
|
||||
private Headers createPushHeaders(Headers.Header scheme, Headers.Header host, String pushResourcePath)
|
||||
{
|
||||
final Headers pushHeaders = new Headers();
|
||||
if (version == SPDY.V2)
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), scheme.value() + "://" + host.value() + pushResourcePath);
|
||||
else
|
||||
{
|
||||
pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
|
||||
pushHeaders.put(scheme);
|
||||
pushHeaders.put(host);
|
||||
}
|
||||
pushHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200");
|
||||
pushHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
|
||||
pushHeaders.put("x-spdy-push", "true");
|
||||
return pushHeaders;
|
||||
}
|
||||
|
||||
private boolean isIfModifiedSinceHeaderPresent()
|
||||
{
|
||||
return headers.get("if-modified-since") != null;
|
||||
}
|
||||
|
||||
private Buffer consumeContent(long maxIdleTime) throws IOException, InterruptedException
|
||||
{
|
||||
while (true)
|
||||
|
|
|
@ -137,39 +137,21 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
|||
for (int i = 0; i < cssResources.length; ++i)
|
||||
{
|
||||
String path = "/" + i + ".css";
|
||||
exchange = new TestExchange();
|
||||
exchange.setMethod("GET");
|
||||
exchange.setRequestURI(path);
|
||||
exchange.setVersion("HTTP/1.1");
|
||||
exchange.setAddress(new Address("localhost", connector.getLocalPort()));
|
||||
exchange.setRequestHeader("Host", "localhost:" + connector.getLocalPort());
|
||||
exchange.setRequestHeader("referer", referrer);
|
||||
exchange = createExchangeWithReferrer(referrer, path);
|
||||
++result;
|
||||
httpClient.send(exchange);
|
||||
}
|
||||
for (int i = 0; i < jsResources.length; ++i)
|
||||
{
|
||||
String path = "/" + i + ".js";
|
||||
exchange = new TestExchange();
|
||||
exchange.setMethod("GET");
|
||||
exchange.setRequestURI(path);
|
||||
exchange.setVersion("HTTP/1.1");
|
||||
exchange.setAddress(new Address("localhost", connector.getLocalPort()));
|
||||
exchange.setRequestHeader("Host", "localhost:" + connector.getLocalPort());
|
||||
exchange.setRequestHeader("referer", referrer);
|
||||
exchange = createExchangeWithReferrer(referrer, path);
|
||||
++result;
|
||||
httpClient.send(exchange);
|
||||
}
|
||||
for (int i = 0; i < pngResources.length; ++i)
|
||||
{
|
||||
String path = "/" + i + ".png";
|
||||
exchange = new TestExchange();
|
||||
exchange.setMethod("GET");
|
||||
exchange.setRequestURI(path);
|
||||
exchange.setVersion("HTTP/1.1");
|
||||
exchange.setAddress(new Address("localhost", connector.getLocalPort()));
|
||||
exchange.setRequestHeader("Host", "localhost:" + connector.getLocalPort());
|
||||
exchange.setRequestHeader("referer", referrer);
|
||||
exchange = createExchangeWithReferrer(referrer, path);
|
||||
++result;
|
||||
httpClient.send(exchange);
|
||||
}
|
||||
|
@ -180,6 +162,19 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
|||
return result;
|
||||
}
|
||||
|
||||
private ContentExchange createExchangeWithReferrer(String referrer, String path)
|
||||
{
|
||||
ContentExchange exchange;
|
||||
exchange = new TestExchange();
|
||||
exchange.setMethod("GET");
|
||||
exchange.setRequestURI(path);
|
||||
exchange.setVersion("HTTP/1.1");
|
||||
exchange.setAddress(new Address("localhost", connector.getLocalPort()));
|
||||
exchange.setRequestHeader("Host", "localhost:" + connector.getLocalPort());
|
||||
exchange.setRequestHeader("referer", referrer);
|
||||
return exchange;
|
||||
}
|
||||
|
||||
|
||||
private void benchmarkSPDY(PushStrategy pushStrategy, Session session) throws Exception
|
||||
{
|
||||
|
@ -238,13 +233,7 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
|||
String path = "/" + i + ".css";
|
||||
if (pushedResources.contains(path))
|
||||
continue;
|
||||
headers = new Headers();
|
||||
headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
headers.put(HTTPSPDYHeader.URI.name(version()), path);
|
||||
headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
headers.put("referer", referrer);
|
||||
headers = createRequestHeaders(referrer, path);
|
||||
++result;
|
||||
session.syn(new SynInfo(headers, true), new DataListener());
|
||||
}
|
||||
|
@ -253,13 +242,7 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
|||
String path = "/" + i + ".js";
|
||||
if (pushedResources.contains(path))
|
||||
continue;
|
||||
headers = new Headers();
|
||||
headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
headers.put(HTTPSPDYHeader.URI.name(version()), path);
|
||||
headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
headers.put("referer", referrer);
|
||||
headers = createRequestHeaders(referrer, path);
|
||||
++result;
|
||||
session.syn(new SynInfo(headers, true), new DataListener());
|
||||
}
|
||||
|
@ -268,13 +251,7 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
|||
String path = "/" + i + ".png";
|
||||
if (pushedResources.contains(path))
|
||||
continue;
|
||||
headers = new Headers();
|
||||
headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
headers.put(HTTPSPDYHeader.URI.name(version()), path);
|
||||
headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
headers.put("referer", referrer);
|
||||
headers = createRequestHeaders(referrer, path);
|
||||
++result;
|
||||
session.syn(new SynInfo(headers, true), new DataListener());
|
||||
}
|
||||
|
@ -285,6 +262,19 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
|||
return result;
|
||||
}
|
||||
|
||||
private Headers createRequestHeaders(String referrer, String path)
|
||||
{
|
||||
Headers headers;
|
||||
headers = new Headers();
|
||||
headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
headers.put(HTTPSPDYHeader.URI.name(version()), path);
|
||||
headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
headers.put("referer", referrer);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private void sleep(long delay) throws ServletException
|
||||
{
|
||||
try
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package org.eclipse.jetty.spdy.http;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ReferrerPushStrategyUnitTest
|
||||
{
|
||||
public static final short VERSION = SPDY.V3;
|
||||
public static final String SCHEME = "http";
|
||||
public static final String HOST = "localhost";
|
||||
public static final String MAIN_URI = "/index.html";
|
||||
public static final String METHOD = "GET";
|
||||
|
||||
// class under test
|
||||
private ReferrerPushStrategy referrerPushStrategy;
|
||||
|
||||
@Mock
|
||||
Stream stream;
|
||||
@Mock
|
||||
Session session;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
referrerPushStrategy = new ReferrerPushStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReferrerCallsAfterTimeoutAreNotAddedAsPushResources() throws InterruptedException
|
||||
{
|
||||
Headers requestHeaders = getBaseHeaders(VERSION);
|
||||
int referrerCallTimeout = 1000;
|
||||
referrerPushStrategy.setReferrerPushPeriod(referrerCallTimeout);
|
||||
setMockExpectations();
|
||||
|
||||
String referrerUrl = fillPushStrategyCache(requestHeaders);
|
||||
Set<String> pushResources;
|
||||
|
||||
// sleep to pretend that the user manually clicked on a linked resource instead the browser requesting subresources immediately
|
||||
Thread.sleep(referrerCallTimeout + 1);
|
||||
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image2.jpg");
|
||||
requestHeaders.put("referer", referrerUrl);
|
||||
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("pushResources is empty", pushResources.size(), is(0));
|
||||
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
|
||||
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
// as the image2.jpg request has been a link and not a subresource, we expect that pushResources.size() is still 2
|
||||
assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisablePushByVersion() throws InterruptedException
|
||||
{
|
||||
referrerPushStrategy.removeSPDYVersionSupport(SPDY.V2);
|
||||
|
||||
Headers requestHeaders = getBaseHeaders(VERSION);
|
||||
setMockExpectations();
|
||||
|
||||
String referrerUrl = fillPushStrategyCache(requestHeaders);
|
||||
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
|
||||
Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2));
|
||||
|
||||
requestHeaders = getBaseHeaders(SPDY.V2);
|
||||
when(session.getVersion()).thenReturn(SPDY.V2);
|
||||
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("no push resources are returned for SPDY.V2", pushResources.size(), is(0));
|
||||
}
|
||||
|
||||
private Headers getBaseHeaders(short version)
|
||||
{
|
||||
Headers requestHeaders = new Headers();
|
||||
requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), SCHEME);
|
||||
requestHeaders.put(HTTPSPDYHeader.HOST.name(version), HOST);
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(version), MAIN_URI);
|
||||
requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), METHOD);
|
||||
return requestHeaders;
|
||||
}
|
||||
|
||||
private void setMockExpectations()
|
||||
{
|
||||
when(stream.getSession()).thenReturn(session);
|
||||
when(session.getVersion()).thenReturn(VERSION);
|
||||
}
|
||||
|
||||
private String fillPushStrategyCache(Headers requestHeaders)
|
||||
{
|
||||
Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("pushResources is empty", pushResources.size(), is(0));
|
||||
|
||||
String origin = SCHEME + "://" + HOST;
|
||||
String referrerUrl = origin + MAIN_URI;
|
||||
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image.jpg");
|
||||
requestHeaders.put("referer", referrerUrl);
|
||||
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("pushResources is empty", pushResources.size(), is(0));
|
||||
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "style.css");
|
||||
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("pushResources is empty", pushResources.size(), is(0));
|
||||
|
||||
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
|
||||
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Headers());
|
||||
assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2));
|
||||
return referrerUrl;
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* Unless required by ap‰plicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
|
@ -32,6 +32,7 @@ import org.eclipse.jetty.spdy.SPDYServerConnector;
|
|||
import org.eclipse.jetty.spdy.api.DataInfo;
|
||||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.ReplyInfo;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
|
@ -42,6 +43,10 @@ import org.junit.Test;
|
|||
|
||||
public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
||||
{
|
||||
|
||||
private final String mainResource = "/index.html";
|
||||
private final String cssResource = "/style.css";
|
||||
|
||||
@Override
|
||||
protected SPDYServerConnector newHTTPSPDYServerConnector(short version)
|
||||
{
|
||||
|
@ -51,10 +56,71 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
return connector;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushHeadersAreValid() throws Exception
|
||||
{
|
||||
InetSocketAddress address = createServer();
|
||||
|
||||
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
|
||||
int referrerPushPeriod = 1000;
|
||||
pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
|
||||
AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version(), connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, pushStrategy);
|
||||
connector.setDefaultAsyncConnectionFactory(defaultFactory);
|
||||
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
|
||||
|
||||
// Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
|
||||
Thread.sleep(referrerPushPeriod + 1);
|
||||
|
||||
sendJSRequest(session1);
|
||||
|
||||
run2ndClientRequests(address, mainRequestHeaders, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReferrerPushPeriod() throws Exception
|
||||
{
|
||||
InetSocketAddress address = createServer();
|
||||
|
||||
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
|
||||
int referrerPushPeriod = 1000;
|
||||
pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
|
||||
AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version(), connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, pushStrategy);
|
||||
connector.setDefaultAsyncConnectionFactory(defaultFactory);
|
||||
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
|
||||
|
||||
// Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
|
||||
Thread.sleep(referrerPushPeriod+1);
|
||||
|
||||
sendJSRequest(session1);
|
||||
|
||||
run2ndClientRequests(address, mainRequestHeaders, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxAssociatedResources() throws Exception
|
||||
{
|
||||
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||
InetSocketAddress address = createServer();
|
||||
|
||||
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
|
||||
pushStrategy.setMaxAssociatedResources(1);
|
||||
AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version(), connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, pushStrategy);
|
||||
connector.setDefaultAsyncConnectionFactory(defaultFactory);
|
||||
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
|
||||
|
||||
sendJSRequest(session1);
|
||||
|
||||
run2ndClientRequests(address, mainRequestHeaders, false);
|
||||
}
|
||||
|
||||
private InetSocketAddress createServer() throws Exception
|
||||
{
|
||||
return startHTTPServer(version(), new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
|
@ -70,21 +136,13 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
baseRequest.setHandled(true);
|
||||
}
|
||||
});
|
||||
ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
|
||||
pushStrategy.setMaxAssociatedResources(1);
|
||||
AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version(), connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, pushStrategy);
|
||||
connector.setDefaultAsyncConnectionFactory(defaultFactory);
|
||||
}
|
||||
|
||||
private Session sendMainRequestAndCSSRequest(InetSocketAddress address, Headers mainRequestHeaders) throws Exception
|
||||
{
|
||||
Session session1 = startClient(version(), address, null);
|
||||
|
||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
||||
Headers mainRequestHeaders = new Headers();
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String mainResource = "/index.html";
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), mainResource);
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -98,13 +156,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch associatedResourceLatch1 = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders1 = new Headers();
|
||||
associatedRequestHeaders1.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders1.put(HTTPSPDYHeader.URI.name(version()), "/style.css");
|
||||
associatedRequestHeaders1.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders1.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders1.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders1.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
Headers associatedRequestHeaders1 = createHeaders(cssResource);
|
||||
session1.syn(new SynInfo(associatedRequestHeaders1, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -116,15 +168,15 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
}
|
||||
});
|
||||
Assert.assertTrue(associatedResourceLatch1.await(5, TimeUnit.SECONDS));
|
||||
return session1;
|
||||
}
|
||||
|
||||
|
||||
private void sendJSRequest(Session session1) throws InterruptedException
|
||||
{
|
||||
final CountDownLatch associatedResourceLatch2 = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders2 = new Headers();
|
||||
associatedRequestHeaders2.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders2.put(HTTPSPDYHeader.URI.name(version()), "/application.js");
|
||||
associatedRequestHeaders2.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders2.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders2.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders2.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
String jsResource = "/application.js";
|
||||
Headers associatedRequestHeaders2 = createHeaders(jsResource);
|
||||
session1.syn(new SynInfo(associatedRequestHeaders2, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -136,17 +188,24 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
}
|
||||
});
|
||||
Assert.assertTrue(associatedResourceLatch2.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private void run2ndClientRequests(InetSocketAddress address, Headers mainRequestHeaders, final boolean validateHeaders) throws Exception
|
||||
{
|
||||
// Create another client, and perform the same request for the main resource,
|
||||
// we expect the css being pushed, but not the js
|
||||
|
||||
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
||||
final CountDownLatch pushDataLatch = new CountDownLatch(1);
|
||||
final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
|
||||
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||
{
|
||||
if(validateHeaders)
|
||||
validateHeaders(synInfo.getHeaders(), pushSynHeadersValid);
|
||||
|
||||
Assert.assertTrue(stream.isUnidirectional());
|
||||
Assert.assertTrue(synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version())).value().endsWith(".css"));
|
||||
return new StreamFrameListener.Adapter()
|
||||
|
@ -180,8 +239,10 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
}
|
||||
});
|
||||
|
||||
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue("Main request reply and/or data not received", mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue("Pushed data not received", pushDataLatch.await(5, TimeUnit.SECONDS));
|
||||
if(validateHeaders)
|
||||
Assert.assertTrue("Push syn headers not valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -204,13 +265,8 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Session session1 = startClient(version(), address, null);
|
||||
|
||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
||||
Headers mainRequestHeaders = new Headers();
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String mainResource = "/index.html";
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), mainResource);
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
|
||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -224,13 +280,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders = new Headers();
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), "/style.css");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
Headers associatedRequestHeaders = createHeaders(cssResource);
|
||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -290,6 +340,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
@Test
|
||||
public void testAssociatedResourceWithWrongContentTypeIsNotPushed() throws Exception
|
||||
{
|
||||
final String fakeResource = "/fake.png";
|
||||
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
|
@ -302,7 +353,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
response.setContentType("text/html");
|
||||
output.print("<html><head/><body>HELLO</body></html>");
|
||||
}
|
||||
else if (url.equals("/fake.png"))
|
||||
else if (url.equals(fakeResource))
|
||||
{
|
||||
response.setContentType("text/html");
|
||||
output.print("<html><head/><body>IMAGE</body></html>");
|
||||
|
@ -318,13 +369,8 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Session session1 = startClient(version(), address, null);
|
||||
|
||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
||||
Headers mainRequestHeaders = new Headers();
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String mainResource = "/index.html";
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), mainResource);
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
|
||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -338,13 +384,8 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders = new Headers();
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), "/stylesheet.css");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
String cssResource = "/stylesheet.css";
|
||||
Headers associatedRequestHeaders = createHeaders(cssResource);
|
||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -358,13 +399,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch fakeAssociatedResourceLatch = new CountDownLatch(1);
|
||||
Headers fakeAssociatedRequestHeaders = new Headers();
|
||||
fakeAssociatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
fakeAssociatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), "/fake.png");
|
||||
fakeAssociatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
fakeAssociatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
fakeAssociatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
fakeAssociatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
Headers fakeAssociatedRequestHeaders = createHeaders(fakeResource);
|
||||
session1.syn(new SynInfo(fakeAssociatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -445,13 +480,8 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Session session1 = startClient(version(), address, null);
|
||||
|
||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
||||
Headers mainRequestHeaders = new Headers();
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String mainResource = "/index.html";
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), mainResource);
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
|
||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -465,14 +495,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders = new Headers();
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String associatedResource = "/style.css";
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), associatedResource);
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
Headers associatedRequestHeaders = createHeaders(cssResource);
|
||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -486,13 +509,9 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch nestedResourceLatch = new CountDownLatch(1);
|
||||
Headers nestedRequestHeaders = new Headers();
|
||||
nestedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
nestedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), "/image.gif");
|
||||
nestedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
nestedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
nestedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
nestedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + associatedResource);
|
||||
String imageUrl = "/image.gif";
|
||||
Headers nestedRequestHeaders = createHeaders(imageUrl, cssResource);
|
||||
|
||||
session1.syn(new SynInfo(nestedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -567,13 +586,8 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Session session1 = startClient(version(), address, null);
|
||||
|
||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
||||
Headers mainRequestHeaders = new Headers();
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String mainResource = "/index.html";
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), mainResource);
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
Headers mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
|
||||
|
||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -587,13 +601,9 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders = new Headers();
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), "/home.html");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
String associatedResource = "/home.html";
|
||||
Headers associatedRequestHeaders = createHeaders(associatedResource);
|
||||
|
||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -661,13 +671,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Session session1 = startClient(version(), address, null);
|
||||
|
||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
||||
Headers mainRequestHeaders = new Headers();
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
String mainResource = "/index.html";
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), mainResource);
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
mainRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
Headers mainRequestHeaders = createHeaders(mainResource);
|
||||
mainRequestHeaders.put("If-Modified-Since", "Tue, 27 Mar 2012 16:36:52 GMT");
|
||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
|
@ -682,13 +686,7 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
||||
Headers associatedRequestHeaders = new Headers();
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), "/style.css");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
||||
Headers associatedRequestHeaders = createHeaders(cssResource);
|
||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -745,4 +743,58 @@ public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
|||
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertFalse("We don't expect data to be pushed as the main request contained an if-modified-since header",pushDataLatch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private void validateHeaders(Headers headers, CountDownLatch pushSynHeadersValid)
|
||||
{
|
||||
if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version()), "200")
|
||||
&& validateHeader(headers, HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1")
|
||||
&& validateUriHeader(headers)
|
||||
&& validateHeader(headers, "x-spdy-push", "true"))
|
||||
pushSynHeadersValid.countDown();
|
||||
}
|
||||
|
||||
private boolean validateHeader(Headers headers, String name, String expectedValue)
|
||||
{
|
||||
Headers.Header header = headers.get(name);
|
||||
if (header != null && expectedValue.equals(header.value()))
|
||||
return true;
|
||||
System.out.println(name + " not valid! " + headers);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean validateUriHeader(Headers headers)
|
||||
{
|
||||
Headers.Header uriHeader = headers.get(HTTPSPDYHeader.URI.name(version()));
|
||||
if (uriHeader != null)
|
||||
if (version() == SPDY.V2 && uriHeader.value().startsWith("http://"))
|
||||
return true;
|
||||
else if (version() == SPDY.V3 && uriHeader.value().startsWith("/")
|
||||
&& headers.get(HTTPSPDYHeader.HOST.name(version())) != null && headers.get(HTTPSPDYHeader.SCHEME.name(version())) != null)
|
||||
return true;
|
||||
System.out.println(HTTPSPDYHeader.URI.name(version()) + " not valid!");
|
||||
return false;
|
||||
}
|
||||
|
||||
private Headers createHeaders(String resource)
|
||||
{
|
||||
return createHeaders(resource, mainResource);
|
||||
}
|
||||
|
||||
private Headers createHeaders(String resource, String referrer)
|
||||
{
|
||||
Headers associatedRequestHeaders = createHeadersWithoutReferrer(resource);
|
||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + referrer);
|
||||
return associatedRequestHeaders;
|
||||
}
|
||||
|
||||
private Headers createHeadersWithoutReferrer(String resource)
|
||||
{
|
||||
Headers associatedRequestHeaders = new Headers();
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.URI.name(version()), resource);
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.SCHEME.name(version()), "http");
|
||||
associatedRequestHeaders.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||
return associatedRequestHeaders;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue