aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Becker2012-10-31 14:18:56 (EDT)
committerThomas Becker2012-11-02 08:21:42 (EDT)
commit3d3e077509a4211a30e07740119b1061e9828d25 (patch)
treeccceae15eba1d44787b8dc3cade2de757abde046
parentce1c1107ebeccb33eb6003dcd51a8a5b17028abb (diff)
downloadorg.eclipse.jetty.project-3d3e077509a4211a30e07740119b1061e9828d25.zip
org.eclipse.jetty.project-3d3e077509a4211a30e07740119b1061e9828d25.tar.gz
org.eclipse.jetty.project-3d3e077509a4211a30e07740119b1061e9828d25.tar.bz2
393281: Add User-Agent filter to ReferrerPushStrategy
-rw-r--r--jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml62
-rw-r--r--jetty-spdy/spdy-example-webapp/src/main/config/etc/jetty-spdy.xml45
-rw-r--r--jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java95
-rw-r--r--jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java131
-rw-r--r--jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java36
5 files changed, 222 insertions, 147 deletions
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml
index cef6903..25ed116 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml
@@ -7,16 +7,19 @@
<!-- HttpChannel Configuration -->
<!-- =========================================================== -->
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
- <Set name="secureScheme">https</Set>
- <Set name="securePort"><SystemProperty name="jetty.spdy.port" default="8443"/></Set>
- <Set name="outputBufferSize">32768</Set>
- <Set name="requestHeaderSize">8192</Set>
- <Set name="responseHeaderSize">8192</Set>
- <Call name="addCustomizer">
- <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
- </Call>
+ <Set name="secureScheme">https</Set>
+ <Set name="securePort">
+ <SystemProperty name="jetty.spdy.port" default="8443"/>
+ </Set>
+ <Set name="outputBufferSize">32768</Set>
+ <Set name="requestHeaderSize">8192</Set>
+ <Set name="responseHeaderSize">8192</Set>
+ <Call name="addCustomizer">
+ <Arg>
+ <New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/>
+ </Arg>
+ </Call>
</New>
-
<!-- =========================================================== -->
@@ -44,18 +47,39 @@
</Ref>
<!-- =========================================================== -->
- <!-- Create a push strategy -->
+ <!-- Create a push strategy which can be used by reference by -->
+ <!-- individual connection factories below. -->
+ <!-- -->
+ <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy -->
+ <!-- for all configuration that may be set here. -->
<!-- =========================================================== -->
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
- <Arg type="List">
- <Array type="String">
- <Item>.*\.css</Item>
- <Item>.*\.js</Item>
- <Item>.*\.png</Item>
- <Item>.*\.jpg</Item>
- <Item>.*\.gif</Item>
- </Array>
- </Arg>
+ <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
+ user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
+ <!--
+ <Set name="BlacklistUserAgents">
+ <Array type="String">
+ <Item>.*(?i)firefox/14.*</Item>
+ <Item>.*(?i)firefox/15.*</Item>
+ <Item>.*(?i)firefox/16.*</Item>
+ </Array>
+ </Set>
+ -->
+
+ <!-- Uncomment to override default file extensions to push -->
+ <!--
+ <Set name="PushRegexps">
+ <Array type="String">
+ <Item>.*\.css</Item>
+ <Item>.*\.js</Item>
+ <Item>.*\.png</Item>
+ <Item>.*\.jpg</Item>
+ <Item>.*\.gif</Item>
+ </Array>
+ </Set>
+ -->
+ <Set name="referrerPushPeriod">5000</Set>
+ <Set name="maxAssociatedResources">32</Set>
</New>
<!-- =========================================================== -->
diff --git a/jetty-spdy/spdy-example-webapp/src/main/config/etc/jetty-spdy.xml b/jetty-spdy/spdy-example-webapp/src/main/config/etc/jetty-spdy.xml
index 3b1b54f..1c9b95b 100644
--- a/jetty-spdy/spdy-example-webapp/src/main/config/etc/jetty-spdy.xml
+++ b/jetty-spdy/spdy-example-webapp/src/main/config/etc/jetty-spdy.xml
@@ -25,7 +25,7 @@
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
<Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
</New>
-
+
<!-- =========================================================== -->
<!-- Create a TLS specific HttpConfiguration based on the -->
<!-- common HttpConfiguration defined in jetty.xml -->
@@ -38,7 +38,7 @@
<Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
</Call>
</New>
-
+
<!-- =========================================================== -->
<!-- Create a push strategy which can be used by reference by -->
<!-- individual connection factories below. -->
@@ -47,15 +47,30 @@
<!-- for all configuration that may be set here. -->
<!-- =========================================================== -->
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
- <Arg name="pushPatterns" type="List">
- <Array type="String">
- <Item>.*\.css</Item>
- <Item>.*\.js</Item>
- <Item>.*\.png</Item>
- <Item>.*\.jpg</Item>
- <Item>.*\.gif</Item>
- </Array>
- </Arg>
+ <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
+ user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
+ <!--
+ <Set name="BlacklistUserAgents">
+ <Array type="String">
+ <Item>.*(?i)firefox/14.*</Item>
+ <Item>.*(?i)firefox/15.*</Item>
+ <Item>.*(?i)firefox/16.*</Item>
+ </Array>
+ </Set>
+ -->
+
+ <!-- Uncomment to override default file extensions to push -->
+ <!--
+ <Set name="PushRegexps">
+ <Array type="String">
+ <Item>.*\.css</Item>
+ <Item>.*\.js</Item>
+ <Item>.*\.png</Item>
+ <Item>.*\.jpg</Item>
+ <Item>.*\.gif</Item>
+ </Array>
+ </Set>
+ -->
<Set name="referrerPushPeriod">5000</Set>
<Set name="maxAssociatedResources">32</Set>
</New>
@@ -64,7 +79,7 @@
<!-- Add a SPDY/HTTPS Connector. -->
<!-- Configure an o.e.j.server.ServerConnector with connection -->
<!-- factories for TLS (aka SSL), NPN, SPDY and HTTP to provide -->
- <!-- a connector that can accept HTTPS or SPDY connections. -->
+ <!-- a connector that can accept HTTPS or SPDY connections. -->
<!-- -->
<!-- All accepted TLS connections are initially wired to a NPN -->
<!-- connection, which attempts to use a TLS extension to -->
@@ -87,7 +102,7 @@
<Arg name="server"><Ref id="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
-
+
<!-- SSL Connection factory with NPN as next protocol -->
<Item>
<New class="org.eclipse.jetty.server.SslConnectionFactory">
@@ -113,7 +128,7 @@
<New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
<Arg name="version" type="int">3</Arg>
<Arg name="config"><Ref id="tlsHttpConfig" /></Arg>
- <Arg name="pushStrategy"><Ref id="pushStrategy"/></Arg>
+ <Arg name="pushStrategy"><Ref id="pushStrategy"/></Arg>
</New>
</Item>
@@ -133,7 +148,7 @@
</Item>
</Array>
</Arg>
-
+
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.tls.port" default="8443" /></Set>
<Set name="idleTimeout">30000</Set>
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
index 13dbe6e..9350f7c 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
@@ -33,32 +33,25 @@ import java.util.regex.Pattern;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
- * <p>A SPDY push strategy that auto-populates push metadata based on referrer URLs.</p>
- * <p>A typical request for a main resource such as <tt>index.html</tt> is immediately
- * followed by a number of requests for associated resources. Associated resource requests
- * will have a <tt>Referer</tt> HTTP header that points to <tt>index.html</tt>, which is
- * used 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 a proper value for {@link #getReferrerPushPeriod()}
- * has to be set. If the referrerPushPeriod for a main resource has elapsed, 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. 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
- * of the application itself, and by the
- * {@link #getMaxAssociatedResources() max associated resources} parameter.
- * This parameter limits the number of associated resources per each main resource, so
- * that if a main resource has hundreds of associated resources, only up to the number
- * specified by this parameter will be pushed.</p>
+ * <p>A SPDY push strategy that auto-populates push metadata based on referrer URLs.</p> <p>A typical request for a main
+ * resource such as <tt>index.html</tt> is immediately followed by a number of requests for associated resources.
+ * Associated resource requests will have a <tt>Referer</tt> HTTP header that points to <tt>index.html</tt>, which is
+ * used 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 a proper value for
+ * {@link #setReferrerPushPeriod(int)} has to be set. If the referrerPushPeriod for a main resource has elapsed,
+ * 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. 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 of the application itself, and by the {@link #setMaxAssociatedResources(int)} max associated resources}
+ * parameter. This parameter limits the number of associated resources per each main resource, so that if a main
+ * resource has hundreds of associated resources, only up to the number specified by this parameter will be pushed.</p>
*/
public class ReferrerPushStrategy implements PushStrategy
{
@@ -67,42 +60,56 @@ public class ReferrerPushStrategy implements PushStrategy
private final Set<Pattern> pushRegexps = new HashSet<>();
private final Set<String> pushContentTypes = new HashSet<>();
private final Set<Pattern> allowedPushOrigins = new HashSet<>();
+ private final Set<Pattern> userAgentBlacklist = new HashSet<>();
private volatile int maxAssociatedResources = 32;
private volatile int referrerPushPeriod = 5000;
public ReferrerPushStrategy()
{
- this(Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg", ".*\\.gif", ".*\\.ico"));
- }
+ List<String> defaultPushRegexps = Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg",
+ ".*\\.gif", ".*\\.ico");
+ addPushRegexps(defaultPushRegexps);
- public ReferrerPushStrategy(@Name("pushPatterns") List<String> pushRegexps)
- {
- this(pushRegexps, Arrays.asList(
+ List<String> defaultPushContentTypes = Arrays.asList(
"text/css",
"text/javascript", "application/javascript", "application/x-javascript",
"image/png", "image/x-png",
"image/jpeg",
"image/gif",
- "image/x-icon", "image/vnd.microsoft.icon"));
+ "image/x-icon", "image/vnd.microsoft.icon");
+ this.pushContentTypes.addAll(defaultPushContentTypes);
}
- public ReferrerPushStrategy(List<String> pushRegexps, List<String> pushContentTypes)
+ public void setPushRegexps(List<String> pushRegexps)
{
- this(pushRegexps, pushContentTypes, Collections.<String>emptyList());
+ pushRegexps.clear();
+ addPushRegexps(pushRegexps);
}
- public ReferrerPushStrategy(List<String> pushRegexps, List<String> pushContentTypes, List<String> allowedPushOrigins)
+ private void addPushRegexps(List<String> pushRegexps)
{
for (String pushRegexp : pushRegexps)
this.pushRegexps.add(Pattern.compile(pushRegexp));
- this.pushContentTypes.addAll(pushContentTypes);
+ }
+
+ public void setPushContentTypes(List<String> pushContentTypes)
+ {
+ pushContentTypes.clear();
+ pushContentTypes.addAll(pushContentTypes);
+ }
+
+ public void setAllowedPushOrigins(List<String> allowedPushOrigins)
+ {
+ allowedPushOrigins.clear();
for (String allowedPushOrigin : allowedPushOrigins)
this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*")));
}
- public int getMaxAssociatedResources()
+ public void setUserAgentBlacklist(List<String> userAgentPatterns)
{
- return maxAssociatedResources;
+ userAgentBlacklist.clear();
+ for (String userAgentPattern : userAgentPatterns)
+ userAgentBlacklist.add(Pattern.compile(userAgentPattern));
}
public void setMaxAssociatedResources(int maxAssociatedResources)
@@ -110,11 +117,6 @@ public class ReferrerPushStrategy implements PushStrategy
this.maxAssociatedResources = maxAssociatedResources;
}
- public int getReferrerPushPeriod()
- {
- return referrerPushPeriod;
- }
-
public void setReferrerPushPeriod(int referrerPushPeriod)
{
this.referrerPushPeriod = referrerPushPeriod;
@@ -125,7 +127,8 @@ public class ReferrerPushStrategy implements PushStrategy
{
Set<String> result = Collections.<String>emptySet();
short version = stream.getSession().getVersion();
- if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).value()))
+ if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD
+ .name(version)).value()) && !isUserAgentBlacklisted(requestHeaders))
{
String scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)).value();
String host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)).value();
@@ -197,6 +200,16 @@ public class ReferrerPushStrategy implements PushStrategy
return !isPushResource(url, responseHeaders);
}
+ public boolean isUserAgentBlacklisted(Fields headers)
+ {
+ Fields.Field userAgentHeader = headers.get("user-agent");
+ if (userAgentHeader != null)
+ for (Pattern userAgentPattern : userAgentBlacklist)
+ if (userAgentPattern.matcher(userAgentHeader.value()).matches())
+ return true;
+ return false;
+ }
+
private boolean isPushResource(String url, Fields responseHeaders)
{
for (Pattern pushRegexp : pushRegexps)
@@ -276,10 +289,8 @@ public class ReferrerPushStrategy implements PushStrategy
private boolean isPushOriginAllowed(String origin)
{
for (Pattern allowedPushOrigin : allowedPushOrigins)
- {
if (allowedPushOrigin.matcher(origin).matches())
return true;
- }
return false;
}
}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
index 430c6bc..220f5d8 100644
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
+++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.server.http;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
+import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
@@ -42,12 +43,21 @@ import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
import org.eclipse.jetty.util.Fields;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
{
private final String mainResource = "/index.html";
+ private final int referrerPushPeriod = 1000;
private final String cssResource = "/style.css";
+ private InetSocketAddress serverAddress;
+ private ReferrerPushStrategy pushStrategy;
+ private ConnectionFactory defaultFactory;
+ private Fields mainRequestHeaders;
public ReferrerPushStrategyTest(short version)
{
@@ -57,82 +67,63 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
@Override
protected HTTPSPDYServerConnector newHTTPSPDYServerConnector(short version)
{
- HTTPSPDYServerConnector connector =
- new HTTPSPDYServerConnector(server,version,new HttpConfiguration(),new ReferrerPushStrategy());
- return connector;
+ return new HTTPSPDYServerConnector(server, version, new HttpConfiguration(), new ReferrerPushStrategy());
}
- @Test
- public void testPushHeadersAreValid() throws Exception
+ @Before
+ public void setUp() throws Exception
{
- InetSocketAddress address = createServer();
-
- ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
- int referrerPushPeriod = 1000;
+ serverAddress = createServer();
+ pushStrategy = new ReferrerPushStrategy();
pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
- ConnectionFactory defaultFactory = new HTTPSPDYServerConnectionFactory(version,new HttpConfiguration(), pushStrategy);
+ defaultFactory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy);
connector.addConnectionFactory(defaultFactory);
- if (connector.getConnectionFactory(NPNServerConnectionFactory.class)!=null)
+ if (connector.getConnectionFactory(NPNServerConnectionFactory.class) != null)
connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol());
else
connector.setDefaultProtocol(defaultFactory.getProtocol());
+ mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
+ }
- connector.setDefaultProtocol(defaultFactory.getProtocol()); // TODO I don't think this is right
-
- Fields 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);
+ @Test
+ public void testPushHeadersAreValid() throws Exception
+ {
+ sendMainRequestAndCSSRequest();
+ run2ndClientRequests(true, true);
+ }
- run2ndClientRequests(address, mainRequestHeaders, true);
+ @Test
+ public void testUserAgentBlackList() throws Exception
+ {
+ pushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
+ sendMainRequestAndCSSRequest();
+ run2ndClientRequests(false, false);
}
@Test
public void testReferrerPushPeriod() throws Exception
{
- InetSocketAddress address = createServer();
-
- ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
- int referrerPushPeriod = 1000;
- pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
- ConnectionFactory defaultFactory = new HTTPSPDYServerConnectionFactory(version,new HttpConfiguration(), pushStrategy);
- connector.addConnectionFactory(defaultFactory);
- if (connector.getConnectionFactory(NPNServerConnectionFactory.class)!=null)
- connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol());
- else
- connector.setDefaultProtocol(defaultFactory.getProtocol());
-
- Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
- Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
+ Session session1 = sendMainRequestAndCSSRequest();
// Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
- Thread.sleep(referrerPushPeriod+1);
-
+ Thread.sleep(referrerPushPeriod + 1);
sendJSRequest(session1);
- run2ndClientRequests(address, mainRequestHeaders, false);
+ run2ndClientRequests(false, true);
}
@Test
public void testMaxAssociatedResources() throws Exception
{
- InetSocketAddress address = createServer();
-
- ReferrerPushStrategy pushStrategy = new ReferrerPushStrategy();
pushStrategy.setMaxAssociatedResources(1);
- ConnectionFactory defaultFactory = new HTTPSPDYServerConnectionFactory(version,new HttpConfiguration(), pushStrategy);
connector.addConnectionFactory(defaultFactory);
connector.setDefaultProtocol(defaultFactory.getProtocol()); // TODO I don't think this is right
- Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
- Session session1 = sendMainRequestAndCSSRequest(address, mainRequestHeaders);
+ Session session1 = sendMainRequestAndCSSRequest();
sendJSRequest(session1);
- run2ndClientRequests(address, mainRequestHeaders, false);
+ run2ndClientRequests(false, true);
}
private InetSocketAddress createServer() throws Exception
@@ -155,9 +146,9 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
});
}
- private Session sendMainRequestAndCSSRequest(InetSocketAddress address, Fields mainRequestHeaders) throws Exception
+ private Session sendMainRequestAndCSSRequest() throws Exception
{
- Session session1 = startClient(version, address, null);
+ Session session1 = startClient(version, serverAddress, null);
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
@@ -207,7 +198,8 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
Assert.assertTrue(associatedResourceLatch2.await(5, TimeUnit.SECONDS));
}
- private void run2ndClientRequests(InetSocketAddress address, Fields mainRequestHeaders, final boolean validateHeaders) throws Exception
+ private void run2ndClientRequests(final boolean validateHeaders,
+ boolean expectPushResource) throws Exception
{
// Create another client, and perform the same request for the main resource,
// we expect the css being pushed, but not the js
@@ -215,16 +207,20 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
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()
+ Session session2 = startClient(version, serverAddress, new SessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
- if(validateHeaders)
+ if (validateHeaders)
validateHeaders(synInfo.getHeaders(), pushSynHeadersValid);
- Assert.assertTrue(stream.isUnidirectional());
- Assert.assertTrue(synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).value().endsWith(".css"));
+ assertThat("Stream is unidirectional",stream.isUnidirectional(),is(true));
+ assertThat("URI header ends with css", synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version))
+ .value().endsWith
+ ("" +
+ ".css"),
+ is(true));
return new StreamFrameListener.Adapter()
{
@Override
@@ -243,7 +239,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
@Override
public void onReply(Stream stream, ReplyInfo replyInfo)
{
- Assert.assertFalse(replyInfo.isClose());
+ assertThat("replyInfo.isClose() is false", replyInfo.isClose(), is(false));
mainStreamLatch.countDown();
}
@@ -256,10 +252,13 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
}
});
- 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));
+ assertThat("Main request reply and/or data not received", mainStreamLatch.await(5, TimeUnit.SECONDS), is(true));
+ if (expectPushResource)
+ assertThat("Pushed data not received", pushDataLatch.await(5, TimeUnit.SECONDS), is(true));
+ else
+ assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
+ if (validateHeaders)
+ assertThat("Push syn headers not valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
}
@Test
@@ -758,7 +757,7 @@ public class ReferrerPushStrategyTest 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));
+ 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(Fields headers, CountDownLatch pushSynHeadersValid)
@@ -805,12 +804,14 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
private Fields createHeadersWithoutReferrer(String resource)
{
- Fields associatedRequestHeaders = new Fields();
- 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;
+ Fields requestHeaders = new Fields();
+ requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) " +
+ "Gecko/20100101 Firefox/16.0");
+ requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
+ requestHeaders.put(HTTPSPDYHeader.URI.name(version), resource);
+ requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
+ requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), "http");
+ requestHeaders.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
+ return requestHeaders;
}
}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java
index 28e7cb1..ab8fcb4 100644
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java
+++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java
@@ -18,6 +18,7 @@
package org.eclipse.jetty.spdy.server.http;
+import java.util.Arrays;
import java.util.Set;
import org.eclipse.jetty.spdy.api.SPDY;
@@ -44,7 +45,7 @@ public class ReferrerPushStrategyUnitTest
public static final String METHOD = "GET";
// class under test
- private ReferrerPushStrategy referrerPushStrategy;
+ private ReferrerPushStrategy referrerPushStrategy = new ReferrerPushStrategy();
@Mock
Stream stream;
@@ -55,7 +56,7 @@ public class ReferrerPushStrategyUnitTest
@Before
public void setup()
{
- referrerPushStrategy = new ReferrerPushStrategy();
+ referrerPushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
}
@Test
@@ -67,22 +68,45 @@ public class ReferrerPushStrategyUnitTest
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
+ // sleep to pretend that the user manually clicked on a linked resource instead the browser requesting sub
+ // resources immediately
Thread.sleep(referrerCallTimeout + 1);
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image2.jpg");
requestHeaders.put("referer", referrerUrl);
- pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
+ Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
assertThat("pushResources is empty", pushResources.size(), is(0));
requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
- // as the image2.jpg request has been a link and not a subresource, we expect that pushResources.size() is still 2
+ // as the image2.jpg request has been a link and not a sub resource, 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 testUserAgentFilter() throws InterruptedException
+ {
+ Fields requestHeaders = getBaseHeaders(VERSION);
+ setMockExpectations();
+
+ fillPushStrategyCache(requestHeaders);
+
+ Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
+ assertThat("pushResources contains two elements image.jpg and style.css as no user-agent header is present",
+ pushResources.size(), is(2));
+
+ requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4");
+ pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
+ assertThat("pushResources contains two elements image.jpg and style.css as chrome is not blacklisted",
+ pushResources.size(), is(2));
+
+ requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20100101 Firefox/16.0");
+ pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
+ assertThat("no resources are returned as we want to filter firefox", pushResources.size(), is(0));
+ }
+
private Fields getBaseHeaders(short version)
{
Fields requestHeaders = new Fields();