Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project
This commit is contained in:
commit
1801c4ebe8
|
@ -54,15 +54,18 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* and any 3 letter top-level domain (.com, .net, .org, etc.).</li>
|
* and any 3 letter top-level domain (.com, .net, .org, etc.).</li>
|
||||||
* <li><b>allowedMethods</b>, a comma separated list of HTTP methods that
|
* <li><b>allowedMethods</b>, a comma separated list of HTTP methods that
|
||||||
* are allowed to be used when accessing the resources. Default value is
|
* are allowed to be used when accessing the resources. Default value is
|
||||||
* <b>GET,POST</b></li>
|
* <b>GET,POST,HEAD</b></li>
|
||||||
* <li><b>allowedHeaders</b>, a comma separated list of HTTP headers that
|
* <li><b>allowedHeaders</b>, a comma separated list of HTTP headers that
|
||||||
* are allowed to be specified when accessing the resources. Default value
|
* are allowed to be specified when accessing the resources. Default value
|
||||||
* is <b>X-Requested-With</b></li>
|
* is <b>X-Requested-With,Content-Type,Accept,Origin</b></li>
|
||||||
* <li><b>preflightMaxAge</b>, the number of seconds that preflight requests
|
* <li><b>preflightMaxAge</b>, the number of seconds that preflight requests
|
||||||
* can be cached by the client. Default value is <b>1800</b> seconds, or 30
|
* can be cached by the client. Default value is <b>1800</b> seconds, or 30
|
||||||
* minutes</li>
|
* minutes</li>
|
||||||
* <li><b>allowCredentials</b>, a boolean indicating if the resource allows
|
* <li><b>allowCredentials</b>, a boolean indicating if the resource allows
|
||||||
* requests with credentials. Default value is <b>false</b></li>
|
* requests with credentials. Default value is <b>false</b></li>
|
||||||
|
* <li><b>exposeHeaders</b>, a comma separated list of HTTP headers that
|
||||||
|
* are allowed to be exposed on the client. Default value is the
|
||||||
|
* <b>empty list</b></li>
|
||||||
* </ul></p>
|
* </ul></p>
|
||||||
* <p>A typical configuration could be:
|
* <p>A typical configuration could be:
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -79,8 +82,6 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* ...
|
* ...
|
||||||
* </web-app>
|
* </web-app>
|
||||||
* </pre></p>
|
* </pre></p>
|
||||||
*
|
|
||||||
* @version $Revision$ $Date$
|
|
||||||
*/
|
*/
|
||||||
public class CrossOriginFilter implements Filter
|
public class CrossOriginFilter implements Filter
|
||||||
{
|
{
|
||||||
|
@ -96,12 +97,14 @@ public class CrossOriginFilter implements Filter
|
||||||
public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
|
public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
|
||||||
public static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
|
public static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
|
||||||
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
|
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
|
||||||
|
public static final String ACCESS_CONTROL_EXPOSE_HEADERS_HEADER = "Access-Control-Expose-Headers";
|
||||||
// Implementation constants
|
// Implementation constants
|
||||||
public static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
|
public static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
|
||||||
public static final String ALLOWED_METHODS_PARAM = "allowedMethods";
|
public static final String ALLOWED_METHODS_PARAM = "allowedMethods";
|
||||||
public static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
|
public static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
|
||||||
public static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
|
public static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
|
||||||
public static final String ALLOW_CREDENTIALS_PARAM = "allowCredentials";
|
public static final String ALLOW_CREDENTIALS_PARAM = "allowCredentials";
|
||||||
|
public static final String EXPOSED_HEADERS_PARAM = "exposedHeaders";
|
||||||
private static final String ANY_ORIGIN = "*";
|
private static final String ANY_ORIGIN = "*";
|
||||||
private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD");
|
private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD");
|
||||||
|
|
||||||
|
@ -109,6 +112,7 @@ public class CrossOriginFilter implements Filter
|
||||||
private List<String> allowedOrigins = new ArrayList<String>();
|
private List<String> allowedOrigins = new ArrayList<String>();
|
||||||
private List<String> allowedMethods = new ArrayList<String>();
|
private List<String> allowedMethods = new ArrayList<String>();
|
||||||
private List<String> allowedHeaders = new ArrayList<String>();
|
private List<String> allowedHeaders = new ArrayList<String>();
|
||||||
|
private List<String> exposedHeaders = new ArrayList<String>();
|
||||||
private int preflightMaxAge = 0;
|
private int preflightMaxAge = 0;
|
||||||
private boolean allowCredentials;
|
private boolean allowCredentials;
|
||||||
|
|
||||||
|
@ -163,6 +167,11 @@ public class CrossOriginFilter implements Filter
|
||||||
allowedCredentialsConfig = "true";
|
allowedCredentialsConfig = "true";
|
||||||
allowCredentials = Boolean.parseBoolean(allowedCredentialsConfig);
|
allowCredentials = Boolean.parseBoolean(allowedCredentialsConfig);
|
||||||
|
|
||||||
|
String exposedHeadersConfig = config.getInitParameter(EXPOSED_HEADERS_PARAM);
|
||||||
|
if (exposedHeadersConfig == null)
|
||||||
|
exposedHeadersConfig = "";
|
||||||
|
exposedHeaders.addAll(Arrays.asList(exposedHeadersConfig.split(",")));
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
{
|
{
|
||||||
LOG.debug("Cross-origin filter configuration: " +
|
LOG.debug("Cross-origin filter configuration: " +
|
||||||
|
@ -170,7 +179,9 @@ public class CrossOriginFilter implements Filter
|
||||||
ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
|
ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
|
||||||
ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
|
ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
|
||||||
PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
|
PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
|
||||||
ALLOW_CREDENTIALS_PARAM + " = " + allowedCredentialsConfig);
|
ALLOW_CREDENTIALS_PARAM + " = " + allowedCredentialsConfig + "," +
|
||||||
|
EXPOSED_HEADERS_PARAM + " = " + exposedHeadersConfig
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +316,8 @@ public class CrossOriginFilter implements Filter
|
||||||
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin);
|
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin);
|
||||||
if (allowCredentials)
|
if (allowCredentials)
|
||||||
response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
||||||
|
if (!exposedHeaders.isEmpty())
|
||||||
|
response.setHeader(ACCESS_CONTROL_EXPOSE_HEADERS_HEADER, commify(exposedHeaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePreflightResponse(HttpServletRequest request, HttpServletResponse response, String origin)
|
private void handlePreflightResponse(HttpServletRequest request, HttpServletResponse response, String origin)
|
||||||
|
|
|
@ -371,6 +371,27 @@ public class CrossOriginFilterTest
|
||||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleRequestWithExposedHeaders() throws Exception
|
||||||
|
{
|
||||||
|
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||||
|
filterHolder.setInitParameter("exposedHeaders", "Content-Length");
|
||||||
|
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||||
|
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||||
|
|
||||||
|
String request = "" +
|
||||||
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Origin: http://localhost\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
String response = tester.getResponses(request);
|
||||||
|
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||||
|
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_EXPOSE_HEADERS_HEADER));
|
||||||
|
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
public static class ResourceServlet extends HttpServlet
|
public static class ResourceServlet extends HttpServlet
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.eclipse.jetty.spdy.http;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -39,58 +39,80 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* <p>However, also following a hyperlink generates a HTTP request with a <tt>Referer</tt>
|
* <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
|
* HTTP header that points to <tt>index.html</tt>; therefore main resources and associated
|
||||||
* resources must be distinguishable.</p>
|
* resources must be distinguishable.</p>
|
||||||
* <p>This class distinguishes associated resources by their URL path suffix.
|
* <p>This class distinguishes associated resources by their URL path suffix and content
|
||||||
|
* type.
|
||||||
* CSS stylesheets, images and JavaScript files have recognizable URL path suffixes that
|
* CSS stylesheets, images and JavaScript files have recognizable URL path suffixes that
|
||||||
* are classified as associated resources.</p>
|
* are classified as associated resources.</p>
|
||||||
* <p>Note however, that CSS stylesheets may refer to images, and the CSS image request
|
* <p>When CSS stylesheets refer to images, the CSS image request will have the CSS
|
||||||
* will have the CSS stylesheet as referrer, so there is some degree of recursion that
|
* stylesheet as referrer. This implementation will push also the CSS image.</p>
|
||||||
* needs to be handled.</p>
|
* <p>The push metadata built by this implementation is limited by the number of pages
|
||||||
*
|
* of the application itself, and by the
|
||||||
* TODO: this class is kind-of leaking since the resources map is always adding entries
|
* {@link #getMaxAssociatedResources() max associated resources} parameter.
|
||||||
* TODO: although these entries will be limited by the number of application pages.
|
* This parameter limits the number of associated resources per each main resource, so
|
||||||
* TODO: however, there is no ConcurrentLinkedHashMap yet in JDK (there is in Guava though)
|
* that if a main resource has hundreds of associated resources, only up to the number
|
||||||
* TODO: so we cannot use the built-in LRU features of LinkedHashMap
|
* specified by this parameter will be pushed.</p>
|
||||||
*
|
|
||||||
* TODO: Wikipedia maps URLs like http://en.wikipedia.org/wiki/File:PNG-Gradient_hex.png
|
|
||||||
* TODO: to text/html, so perhaps we need to improve isPushResource() by looking at the
|
|
||||||
* TODO: response Content-Type header, and not only at the URL extension
|
|
||||||
*/
|
*/
|
||||||
public class ReferrerPushStrategy implements PushStrategy
|
public class ReferrerPushStrategy implements PushStrategy
|
||||||
{
|
{
|
||||||
private static final Logger logger = Log.getLogger(ReferrerPushStrategy.class);
|
private static final Logger logger = Log.getLogger(ReferrerPushStrategy.class);
|
||||||
private final ConcurrentMap<String, Set<String>> resources = new ConcurrentHashMap<>();
|
private final ConcurrentMap<String, Set<String>> resources = new ConcurrentHashMap<>();
|
||||||
private final Set<Pattern> pushRegexps = new LinkedHashSet<>();
|
private final Set<Pattern> pushRegexps = new HashSet<>();
|
||||||
private final Set<Pattern> allowedPushOrigins = new LinkedHashSet<>();
|
private final Set<String> pushContentTypes = new HashSet<>();
|
||||||
|
private final Set<Pattern> allowedPushOrigins = new HashSet<>();
|
||||||
|
private volatile int maxAssociatedResources = 32;
|
||||||
|
|
||||||
public ReferrerPushStrategy()
|
public ReferrerPushStrategy()
|
||||||
{
|
{
|
||||||
this(Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpg", ".*\\.gif"));
|
this(Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg", ".*\\.gif", ".*\\.ico"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferrerPushStrategy(List<String> pushRegexps)
|
public ReferrerPushStrategy(List<String> pushRegexps)
|
||||||
{
|
{
|
||||||
this(pushRegexps, Collections.<String>emptyList());
|
this(pushRegexps, 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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferrerPushStrategy(List<String> pushRegexps, List<String> allowedPushOrigins)
|
public ReferrerPushStrategy(List<String> pushRegexps, List<String> pushContentTypes)
|
||||||
|
{
|
||||||
|
this(pushRegexps, pushContentTypes, Collections.<String>emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReferrerPushStrategy(List<String> pushRegexps, List<String> pushContentTypes, List<String> allowedPushOrigins)
|
||||||
{
|
{
|
||||||
for (String pushRegexp : pushRegexps)
|
for (String pushRegexp : pushRegexps)
|
||||||
this.pushRegexps.add(Pattern.compile(pushRegexp));
|
this.pushRegexps.add(Pattern.compile(pushRegexp));
|
||||||
|
this.pushContentTypes.addAll(pushContentTypes);
|
||||||
for (String allowedPushOrigin : allowedPushOrigins)
|
for (String allowedPushOrigin : allowedPushOrigins)
|
||||||
this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*")));
|
this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxAssociatedResources()
|
||||||
|
{
|
||||||
|
return maxAssociatedResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAssociatedResources(int maxAssociatedResources)
|
||||||
|
{
|
||||||
|
this.maxAssociatedResources = maxAssociatedResources;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> apply(Stream stream, Headers requestHeaders, Headers responseHeaders)
|
public Set<String> apply(Stream stream, Headers requestHeaders, Headers responseHeaders)
|
||||||
{
|
{
|
||||||
Set<String> result = Collections.emptySet();
|
Set<String> result = Collections.emptySet();
|
||||||
String scheme = requestHeaders.get("scheme").value();
|
short version = stream.getSession().getVersion();
|
||||||
String host = requestHeaders.get("host").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 = new StringBuilder(scheme).append("://").append(host).toString();
|
||||||
String url = requestHeaders.get("url").value();
|
String url = requestHeaders.get(HTTPSPDYHeader.URI.name(version)).value();
|
||||||
String absoluteURL = new StringBuilder(origin).append(url).toString();
|
String absoluteURL = new StringBuilder(origin).append(url).toString();
|
||||||
logger.debug("Applying push strategy for {}", absoluteURL);
|
logger.debug("Applying push strategy for {}", absoluteURL);
|
||||||
if (isValidMethod(requestHeaders.get("method").value()))
|
if (isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).value()))
|
||||||
{
|
{
|
||||||
if (isMainResource(url, responseHeaders))
|
if (isMainResource(url, responseHeaders))
|
||||||
{
|
{
|
||||||
|
@ -129,7 +151,16 @@ public class ReferrerPushStrategy implements PushStrategy
|
||||||
for (Pattern pushRegexp : pushRegexps)
|
for (Pattern pushRegexp : pushRegexps)
|
||||||
{
|
{
|
||||||
if (pushRegexp.matcher(url).matches())
|
if (pushRegexp.matcher(url).matches())
|
||||||
return true;
|
{
|
||||||
|
Headers.Header header = responseHeaders.get("content-type");
|
||||||
|
if (header == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
String contentType = header.value().toLowerCase();
|
||||||
|
for (String pushContentType : pushContentTypes)
|
||||||
|
if (contentType.startsWith(pushContentType))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -154,8 +185,19 @@ public class ReferrerPushStrategy implements PushStrategy
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
pushResources = existing;
|
pushResources = existing;
|
||||||
}
|
}
|
||||||
pushResources.add(url);
|
// This check is not strictly concurrent-safe, but limiting
|
||||||
logger.debug("Built push metadata for {}: {}", referrer, pushResources);
|
// 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
|
||||||
|
{
|
||||||
|
logger.debug("Skipped store of push metadata {} for {}: max associated resources ({}) reached",
|
||||||
|
url, referrer, maxAssociatedResources);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,4 +113,9 @@ public abstract class AbstractHTTPSPDYTest
|
||||||
server.join();
|
server.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected short version()
|
||||||
|
{
|
||||||
|
return SPDY.V2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,10 @@ public class ConcurrentStreamsTest extends AbstractHTTPSPDYTest
|
||||||
|
|
||||||
// Perform slow request. This will wait on server side until the fast request wakes it up
|
// Perform slow request. This will wait on server side until the fast request wakes it up
|
||||||
Headers headers = new Headers();
|
Headers headers = new Headers();
|
||||||
headers.put("method", "GET");
|
headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||||
headers.put("url", "/slow");
|
headers.put(HTTPSPDYHeader.URI.name(version()), "/slow");
|
||||||
headers.put("version", "HTTP/1.1");
|
headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||||
headers.put("host", "localhost:" + connector.getLocalPort());
|
headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||||
final CountDownLatch slowClientLatch = new CountDownLatch(1);
|
final CountDownLatch slowClientLatch = new CountDownLatch(1);
|
||||||
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
|
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
|
||||||
{
|
{
|
||||||
|
@ -91,10 +91,10 @@ public class ConcurrentStreamsTest extends AbstractHTTPSPDYTest
|
||||||
|
|
||||||
// Perform the fast request. This will wake up the slow request
|
// Perform the fast request. This will wake up the slow request
|
||||||
headers.clear();
|
headers.clear();
|
||||||
headers.put("method", "GET");
|
headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET");
|
||||||
headers.put("url", "/fast");
|
headers.put(HTTPSPDYHeader.URI.name(version()), "/fast");
|
||||||
headers.put("version", "HTTP/1.1");
|
headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1");
|
||||||
headers.put("host", "localhost:" + connector.getLocalPort());
|
headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort());
|
||||||
final CountDownLatch fastClientLatch = new CountDownLatch(1);
|
final CountDownLatch fastClientLatch = new CountDownLatch(1);
|
||||||
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
|
session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,6 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.spdy.AsyncConnectionFactory;
|
import org.eclipse.jetty.spdy.AsyncConnectionFactory;
|
||||||
import org.eclipse.jetty.spdy.api.DataInfo;
|
import org.eclipse.jetty.spdy.api.DataInfo;
|
||||||
import org.eclipse.jetty.spdy.api.Headers;
|
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.Session;
|
||||||
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
||||||
import org.eclipse.jetty.spdy.api.Stream;
|
import org.eclipse.jetty.spdy.api.Stream;
|
||||||
|
@ -62,11 +61,6 @@ public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
|
||||||
private final long roundtrip = 100;
|
private final long roundtrip = 100;
|
||||||
private final int runs = 10;
|
private final int runs = 10;
|
||||||
|
|
||||||
protected short version()
|
|
||||||
{
|
|
||||||
return SPDY.V2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void benchmarkPushStrategy() throws Exception
|
public void benchmarkPushStrategy() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,463 +0,0 @@
|
||||||
package org.eclipse.jetty.spdy.http;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
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.server.Request;
|
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
|
||||||
import org.eclipse.jetty.spdy.AsyncConnectionFactory;
|
|
||||||
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.Session;
|
|
||||||
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
|
||||||
import org.eclipse.jetty.spdy.api.Stream;
|
|
||||||
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
|
||||||
import org.eclipse.jetty.spdy.api.SynInfo;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected SPDYServerConnector newHTTPSPDYServerConnector(short version)
|
|
||||||
{
|
|
||||||
SPDYServerConnector connector = super.newHTTPSPDYServerConnector(version);
|
|
||||||
AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version, connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, new ReferrerPushStrategy());
|
|
||||||
connector.setDefaultAsyncConnectionFactory(defaultFactory);
|
|
||||||
return connector;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAssociatedResourceIsPushed() throws Exception
|
|
||||||
{
|
|
||||||
InetSocketAddress address = startHTTPServer(new AbstractHandler()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
String url = request.getRequestURI();
|
|
||||||
PrintWriter output = response.getWriter();
|
|
||||||
if (url.endsWith(".html"))
|
|
||||||
output.print("<html><head/><body>HELLO</body></html>");
|
|
||||||
else if (url.endsWith(".css"))
|
|
||||||
output.print("body { background: #FFF; }");
|
|
||||||
baseRequest.setHandled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Session session1 = startClient(address, null);
|
|
||||||
|
|
||||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers mainRequestHeaders = new Headers();
|
|
||||||
mainRequestHeaders.put("method", "GET");
|
|
||||||
String mainResource = "/index.html";
|
|
||||||
mainRequestHeaders.put("url", mainResource);
|
|
||||||
mainRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
mainRequestHeaders.put("scheme", "http");
|
|
||||||
mainRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers associatedRequestHeaders = new Headers();
|
|
||||||
associatedRequestHeaders.put("method", "GET");
|
|
||||||
associatedRequestHeaders.put("url", "/style.css");
|
|
||||||
associatedRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
associatedRequestHeaders.put("scheme", "http");
|
|
||||||
associatedRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
|
||||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
associatedResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
// Create another client, and perform the same request for the main resource, we expect the css being pushed
|
|
||||||
|
|
||||||
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
|
||||||
final CountDownLatch pushDataLatch = new CountDownLatch(1);
|
|
||||||
Session session2 = startClient(address, new SessionFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
|
||||||
{
|
|
||||||
Assert.assertTrue(stream.isUnidirectional());
|
|
||||||
return new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
pushDataLatch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onReply(Stream stream, ReplyInfo replyInfo)
|
|
||||||
{
|
|
||||||
Assert.assertFalse(replyInfo.isClose());
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNestedAssociatedResourceIsPushed() throws Exception
|
|
||||||
{
|
|
||||||
InetSocketAddress address = startHTTPServer(new AbstractHandler()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
String url = request.getRequestURI();
|
|
||||||
PrintWriter output = response.getWriter();
|
|
||||||
if (url.endsWith(".html"))
|
|
||||||
output.print("<html><head/><body>HELLO</body></html>");
|
|
||||||
else if (url.endsWith(".css"))
|
|
||||||
output.print("body { background: #FFF; }");
|
|
||||||
else if (url.endsWith(".gif"))
|
|
||||||
output.print("\u0000");
|
|
||||||
baseRequest.setHandled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Session session1 = startClient(address, null);
|
|
||||||
|
|
||||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers mainRequestHeaders = new Headers();
|
|
||||||
mainRequestHeaders.put("method", "GET");
|
|
||||||
String mainResource = "/index.html";
|
|
||||||
mainRequestHeaders.put("url", mainResource);
|
|
||||||
mainRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
mainRequestHeaders.put("scheme", "http");
|
|
||||||
mainRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers associatedRequestHeaders = new Headers();
|
|
||||||
associatedRequestHeaders.put("method", "GET");
|
|
||||||
String associatedResource = "/style.css";
|
|
||||||
associatedRequestHeaders.put("url", associatedResource);
|
|
||||||
associatedRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
associatedRequestHeaders.put("scheme", "http");
|
|
||||||
associatedRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
|
||||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
associatedResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
final CountDownLatch nestedResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers nestedRequestHeaders = new Headers();
|
|
||||||
nestedRequestHeaders.put("method", "GET");
|
|
||||||
nestedRequestHeaders.put("url", "/image.gif");
|
|
||||||
nestedRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
nestedRequestHeaders.put("scheme", "http");
|
|
||||||
nestedRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
nestedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + associatedResource);
|
|
||||||
session1.syn(new SynInfo(nestedRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
nestedResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(nestedResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
// Create another client, and perform the same request for the main resource, we expect the css and the image being pushed
|
|
||||||
|
|
||||||
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
|
||||||
final CountDownLatch pushDataLatch = new CountDownLatch(2);
|
|
||||||
Session session2 = startClient(address, new SessionFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
|
||||||
{
|
|
||||||
Assert.assertTrue(stream.isUnidirectional());
|
|
||||||
return new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
pushDataLatch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onReply(Stream stream, ReplyInfo replyInfo)
|
|
||||||
{
|
|
||||||
Assert.assertFalse(replyInfo.isClose());
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMainResourceWithReferrerIsNotPushed() throws Exception
|
|
||||||
{
|
|
||||||
InetSocketAddress address = startHTTPServer(new AbstractHandler()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
String url = request.getRequestURI();
|
|
||||||
PrintWriter output = response.getWriter();
|
|
||||||
if (url.endsWith(".html"))
|
|
||||||
output.print("<html><head/><body>HELLO</body></html>");
|
|
||||||
baseRequest.setHandled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Session session1 = startClient(address, null);
|
|
||||||
|
|
||||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers mainRequestHeaders = new Headers();
|
|
||||||
mainRequestHeaders.put("method", "GET");
|
|
||||||
String mainResource = "/index.html";
|
|
||||||
mainRequestHeaders.put("url", mainResource);
|
|
||||||
mainRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
mainRequestHeaders.put("scheme", "http");
|
|
||||||
mainRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers associatedRequestHeaders = new Headers();
|
|
||||||
associatedRequestHeaders.put("method", "GET");
|
|
||||||
associatedRequestHeaders.put("url", "/home.html");
|
|
||||||
associatedRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
associatedRequestHeaders.put("scheme", "http");
|
|
||||||
associatedRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
|
||||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
associatedResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
// Create another client, and perform the same request for the main resource, we expect nothing being pushed
|
|
||||||
|
|
||||||
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
|
||||||
final CountDownLatch pushLatch = new CountDownLatch(1);
|
|
||||||
Session session2 = startClient(address, new SessionFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
|
||||||
{
|
|
||||||
pushLatch.countDown();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onReply(Stream stream, ReplyInfo replyInfo)
|
|
||||||
{
|
|
||||||
Assert.assertFalse(replyInfo.isClose());
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestWithIfModifiedSinceHeaderPreventsPush() throws Exception
|
|
||||||
{
|
|
||||||
InetSocketAddress address = startHTTPServer(new AbstractHandler()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
|
||||||
{
|
|
||||||
String url = request.getRequestURI();
|
|
||||||
PrintWriter output = response.getWriter();
|
|
||||||
if (url.endsWith(".html"))
|
|
||||||
output.print("<html><head/><body>HELLO</body></html>");
|
|
||||||
else if (url.endsWith(".css"))
|
|
||||||
output.print("body { background: #FFF; }");
|
|
||||||
baseRequest.setHandled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Session session1 = startClient(address, null);
|
|
||||||
|
|
||||||
final CountDownLatch mainResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers mainRequestHeaders = new Headers();
|
|
||||||
mainRequestHeaders.put("method", "GET");
|
|
||||||
String mainResource = "/index.html";
|
|
||||||
mainRequestHeaders.put("url", mainResource);
|
|
||||||
mainRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
mainRequestHeaders.put("scheme", "http");
|
|
||||||
mainRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
mainRequestHeaders.put("If-Modified-Since", "Tue, 27 Mar 2012 16:36:52 GMT");
|
|
||||||
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
|
|
||||||
Headers associatedRequestHeaders = new Headers();
|
|
||||||
associatedRequestHeaders.put("method", "GET");
|
|
||||||
associatedRequestHeaders.put("url", "/style.css");
|
|
||||||
associatedRequestHeaders.put("version", "HTTP/1.1");
|
|
||||||
associatedRequestHeaders.put("scheme", "http");
|
|
||||||
associatedRequestHeaders.put("host", "localhost:" + connector.getLocalPort());
|
|
||||||
associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + mainResource);
|
|
||||||
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
associatedResourceLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
|
||||||
|
|
||||||
// Create another client, and perform the same request for the main resource, we expect the css NOT being pushed as the main request contains an
|
|
||||||
// if-modified-since header
|
|
||||||
|
|
||||||
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
|
||||||
final CountDownLatch pushDataLatch = new CountDownLatch(1);
|
|
||||||
Session session2 = startClient(address, new SessionFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
|
||||||
{
|
|
||||||
Assert.assertTrue(stream.isUnidirectional());
|
|
||||||
return new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
pushDataLatch.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onReply(Stream stream, ReplyInfo replyInfo)
|
|
||||||
{
|
|
||||||
Assert.assertFalse(replyInfo.isClose());
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onData(Stream stream, DataInfo dataInfo)
|
|
||||||
{
|
|
||||||
dataInfo.consume(dataInfo.length());
|
|
||||||
if (dataInfo.isClose())
|
|
||||||
mainStreamLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,748 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable 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
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eclipse.jetty.spdy.http;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
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.server.Request;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.spdy.AsyncConnectionFactory;
|
||||||
|
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.Session;
|
||||||
|
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
||||||
|
import org.eclipse.jetty.spdy.api.Stream;
|
||||||
|
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
||||||
|
import org.eclipse.jetty.spdy.api.SynInfo;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ReferrerPushStrategyV2Test extends AbstractHTTPSPDYTest
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected SPDYServerConnector newHTTPSPDYServerConnector(short version)
|
||||||
|
{
|
||||||
|
SPDYServerConnector connector = super.newHTTPSPDYServerConnector(version);
|
||||||
|
AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version, connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, new ReferrerPushStrategy());
|
||||||
|
connector.setDefaultAsyncConnectionFactory(defaultFactory);
|
||||||
|
return connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMaxAssociatedResources() throws Exception
|
||||||
|
{
|
||||||
|
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
PrintWriter output = response.getWriter();
|
||||||
|
if (url.endsWith(".html"))
|
||||||
|
output.print("<html><head/><body>HELLO</body></html>");
|
||||||
|
else if (url.endsWith(".css"))
|
||||||
|
output.print("body { background: #FFF; }");
|
||||||
|
else if (url.endsWith(".js"))
|
||||||
|
output.print("function(){}();");
|
||||||
|
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);
|
||||||
|
|
||||||
|
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
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders1, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch1.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(associatedResourceLatch1.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders2, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch2.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(associatedResourceLatch2.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||||
|
{
|
||||||
|
Assert.assertTrue(stream.isUnidirectional());
|
||||||
|
Assert.assertTrue(synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version())).value().endsWith(".css"));
|
||||||
|
return new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
pushDataLatch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReply(Stream stream, ReplyInfo replyInfo)
|
||||||
|
{
|
||||||
|
Assert.assertFalse(replyInfo.isClose());
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssociatedResourceIsPushed() throws Exception
|
||||||
|
{
|
||||||
|
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
PrintWriter output = response.getWriter();
|
||||||
|
if (url.endsWith(".html"))
|
||||||
|
output.print("<html><head/><body>HELLO</body></html>");
|
||||||
|
else if (url.endsWith(".css"))
|
||||||
|
output.print("body { background: #FFF; }");
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Create another client, and perform the same request for the main resource, we expect the css being pushed
|
||||||
|
|
||||||
|
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
||||||
|
final CountDownLatch pushDataLatch = new CountDownLatch(1);
|
||||||
|
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||||
|
{
|
||||||
|
Assert.assertTrue(stream.isUnidirectional());
|
||||||
|
return new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
pushDataLatch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReply(Stream stream, ReplyInfo replyInfo)
|
||||||
|
{
|
||||||
|
Assert.assertFalse(replyInfo.isClose());
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssociatedResourceWithWrongContentTypeIsNotPushed() throws Exception
|
||||||
|
{
|
||||||
|
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
PrintWriter output = response.getWriter();
|
||||||
|
if (url.endsWith(".html"))
|
||||||
|
{
|
||||||
|
response.setContentType("text/html");
|
||||||
|
output.print("<html><head/><body>HELLO</body></html>");
|
||||||
|
}
|
||||||
|
else if (url.equals("/fake.png"))
|
||||||
|
{
|
||||||
|
response.setContentType("text/html");
|
||||||
|
output.print("<html><head/><body>IMAGE</body></html>");
|
||||||
|
}
|
||||||
|
else if (url.endsWith(".css"))
|
||||||
|
{
|
||||||
|
response.setContentType("text/css");
|
||||||
|
output.print("body { background: #FFF; }");
|
||||||
|
}
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(fakeAssociatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
fakeAssociatedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(fakeAssociatedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Create another client, and perform the same request for the main resource,
|
||||||
|
// we expect the css being pushed but not the fake PNG
|
||||||
|
|
||||||
|
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
||||||
|
final CountDownLatch pushDataLatch = new CountDownLatch(1);
|
||||||
|
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||||
|
{
|
||||||
|
Assert.assertTrue(stream.isUnidirectional());
|
||||||
|
Assert.assertTrue(synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version())).value().endsWith(".css"));
|
||||||
|
return new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
pushDataLatch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReply(Stream stream, ReplyInfo replyInfo)
|
||||||
|
{
|
||||||
|
Assert.assertFalse(replyInfo.isClose());
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNestedAssociatedResourceIsPushed() throws Exception
|
||||||
|
{
|
||||||
|
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
PrintWriter output = response.getWriter();
|
||||||
|
if (url.endsWith(".html"))
|
||||||
|
output.print("<html><head/><body>HELLO</body></html>");
|
||||||
|
else if (url.endsWith(".css"))
|
||||||
|
output.print("body { background: #FFF; }");
|
||||||
|
else if (url.endsWith(".gif"))
|
||||||
|
output.print("\u0000");
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(nestedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
nestedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(nestedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Create another client, and perform the same request for the main resource, we expect the css and the image being pushed
|
||||||
|
|
||||||
|
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
||||||
|
final CountDownLatch pushDataLatch = new CountDownLatch(2);
|
||||||
|
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||||
|
{
|
||||||
|
Assert.assertTrue(stream.isUnidirectional());
|
||||||
|
return new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
pushDataLatch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReply(Stream stream, ReplyInfo replyInfo)
|
||||||
|
{
|
||||||
|
Assert.assertFalse(replyInfo.isClose());
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMainResourceWithReferrerIsNotPushed() throws Exception
|
||||||
|
{
|
||||||
|
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
PrintWriter output = response.getWriter();
|
||||||
|
if (url.endsWith(".html"))
|
||||||
|
output.print("<html><head/><body>HELLO</body></html>");
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Create another client, and perform the same request for the main resource, we expect nothing being pushed
|
||||||
|
|
||||||
|
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
||||||
|
final CountDownLatch pushLatch = new CountDownLatch(1);
|
||||||
|
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||||
|
{
|
||||||
|
pushLatch.countDown();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReply(Stream stream, ReplyInfo replyInfo)
|
||||||
|
{
|
||||||
|
Assert.assertFalse(replyInfo.isClose());
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequestWithIfModifiedSinceHeaderPreventsPush() throws Exception
|
||||||
|
{
|
||||||
|
InetSocketAddress address = startHTTPServer(version(), new AbstractHandler()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
PrintWriter output = response.getWriter();
|
||||||
|
if (url.endsWith(".html"))
|
||||||
|
output.print("<html><head/><body>HELLO</body></html>");
|
||||||
|
else if (url.endsWith(".css"))
|
||||||
|
output.print("body { background: #FFF; }");
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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());
|
||||||
|
mainRequestHeaders.put("If-Modified-Since", "Tue, 27 Mar 2012 16:36:52 GMT");
|
||||||
|
session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
associatedResourceLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Create another client, and perform the same request for the main resource, we expect the css NOT being pushed as the main request contains an
|
||||||
|
// if-modified-since header
|
||||||
|
|
||||||
|
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
|
||||||
|
final CountDownLatch pushDataLatch = new CountDownLatch(1);
|
||||||
|
Session session2 = startClient(version(), address, new SessionFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||||
|
{
|
||||||
|
Assert.assertTrue(stream.isUnidirectional());
|
||||||
|
return new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
pushDataLatch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onReply(Stream stream, ReplyInfo replyInfo)
|
||||||
|
{
|
||||||
|
Assert.assertFalse(replyInfo.isClose());
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataInfo dataInfo)
|
||||||
|
{
|
||||||
|
dataInfo.consume(dataInfo.length());
|
||||||
|
if (dataInfo.isClose())
|
||||||
|
mainStreamLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable 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
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eclipse.jetty.spdy.http;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.spdy.api.SPDY;
|
||||||
|
|
||||||
|
public class ReferrerPushStrategyV3Test extends ReferrerPushStrategyV2Test
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected short version()
|
||||||
|
{
|
||||||
|
return SPDY.V3;
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,6 @@ import org.eclipse.jetty.spdy.api.BytesDataInfo;
|
||||||
import org.eclipse.jetty.spdy.api.DataInfo;
|
import org.eclipse.jetty.spdy.api.DataInfo;
|
||||||
import org.eclipse.jetty.spdy.api.Headers;
|
import org.eclipse.jetty.spdy.api.Headers;
|
||||||
import org.eclipse.jetty.spdy.api.ReplyInfo;
|
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.Session;
|
||||||
import org.eclipse.jetty.spdy.api.Stream;
|
import org.eclipse.jetty.spdy.api.Stream;
|
||||||
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
||||||
|
@ -52,11 +51,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
public class ServerHTTPSPDYv2Test extends AbstractHTTPSPDYTest
|
public class ServerHTTPSPDYv2Test extends AbstractHTTPSPDYTest
|
||||||
{
|
{
|
||||||
protected short version()
|
|
||||||
{
|
|
||||||
return SPDY.V2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleGET() throws Exception
|
public void testSimpleGET() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -239,23 +239,26 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
||||||
String servlet_class = node.getString("servlet-class", false, true);
|
String servlet_class = node.getString("servlet-class", false, true);
|
||||||
|
|
||||||
// Handle JSP
|
// Handle JSP
|
||||||
String jspServletName=null;
|
|
||||||
String jspServletClass=null;;
|
String jspServletClass=null;;
|
||||||
boolean hasJSP=false;
|
|
||||||
|
//Handle the default jsp servlet instance
|
||||||
if (id != null && id.equals("jsp"))
|
if (id != null && id.equals("jsp"))
|
||||||
{
|
{
|
||||||
jspServletName = servlet_name;
|
|
||||||
jspServletClass = servlet_class;
|
jspServletClass = servlet_class;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Loader.loadClass(this.getClass(), servlet_class);
|
Loader.loadClass(this.getClass(), servlet_class);
|
||||||
hasJSP = true;
|
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e)
|
catch (ClassNotFoundException e)
|
||||||
{
|
{
|
||||||
LOG.info("NO JSP Support for {}, did not find {}", context.getContextPath(), servlet_class);
|
LOG.info("NO JSP Support for {}, did not find {}", context.getContextPath(), servlet_class);
|
||||||
jspServletClass = servlet_class = "org.eclipse.jetty.servlet.NoJspServlet";
|
jspServletClass = servlet_class = "org.eclipse.jetty.servlet.NoJspServlet";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//could be more than 1 declaration of the jsp servlet, so configure them all
|
||||||
|
if (servlet_class != null && "org.apache.jasper.servlet.JspServlet".equals(servlet_class))
|
||||||
|
{
|
||||||
if (holder.getInitParameter("scratchdir") == null)
|
if (holder.getInitParameter("scratchdir") == null)
|
||||||
{
|
{
|
||||||
File tmp = context.getTempDirectory();
|
File tmp = context.getTempDirectory();
|
||||||
|
@ -316,12 +319,12 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler JSP file
|
// Handle JSP file
|
||||||
String jsp_file = node.getString("jsp-file", false, true);
|
String jsp_file = node.getString("jsp-file", false, true);
|
||||||
if (jsp_file != null)
|
if (jsp_file != null)
|
||||||
{
|
{
|
||||||
holder.setForcedPath(jsp_file);
|
holder.setForcedPath(jsp_file);
|
||||||
holder.setClassName(jspServletClass);
|
holder.setClassName(jspServletClass); //only use our default instance
|
||||||
//set the system classpath explicitly for the holder that will represent the JspServlet instance
|
//set the system classpath explicitly for the holder that will represent the JspServlet instance
|
||||||
holder.setInitParameter("com.sun.appserv.jsp.classpath", getSystemClassPath(context));
|
holder.setInitParameter("com.sun.appserv.jsp.classpath", getSystemClassPath(context));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue