Further experimentation with PushBuilder
This commit is contained in:
parent
06b1efc182
commit
dfe9dc3115
|
@ -79,10 +79,12 @@ public class HttpTransportOverFCGI implements HttpTransport
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request)
|
||||
*/
|
||||
@Override
|
||||
public boolean isPushSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(org.eclipse.jetty.http.MetaData.Request request)
|
||||
{
|
||||
|
|
|
@ -94,15 +94,15 @@ public class HttpFields implements Iterable<HttpField>
|
|||
/**
|
||||
* Get Collection of header names.
|
||||
*/
|
||||
public Collection<String> getFieldNamesCollection()
|
||||
public Set<String> getFieldNamesCollection()
|
||||
{
|
||||
final Set<String> list = new HashSet<>(_size);
|
||||
final Set<String> set = new HashSet<>(_size);
|
||||
for (HttpField f : this)
|
||||
{
|
||||
if (f!=null)
|
||||
list.add(f.getName());
|
||||
set.add(f.getName());
|
||||
}
|
||||
return list;
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -113,6 +113,12 @@ public class HttpTransportOverHTTP2 implements HttpTransport
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPushSupported()
|
||||
{
|
||||
return stream.getSession().isPushEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(final MetaData.Request request)
|
||||
{
|
||||
|
|
|
@ -662,6 +662,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
getEndPoint().close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPushSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request)
|
||||
|
|
|
@ -20,15 +20,16 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
public interface HttpTransport
|
||||
{
|
||||
void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback);
|
||||
|
||||
boolean isPushSupported();
|
||||
|
||||
void push (MetaData.Request request);
|
||||
void push(MetaData.Request request);
|
||||
|
||||
void completed();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -57,36 +58,46 @@ public class PushBuilder
|
|||
return _method;
|
||||
}
|
||||
|
||||
public void setMethod(String method)
|
||||
public PushBuilder setMethod(String method)
|
||||
{
|
||||
_method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getQueryString()
|
||||
{
|
||||
return _queryString;
|
||||
}
|
||||
public void setQueryString(String queryString)
|
||||
|
||||
public PushBuilder setQueryString(String queryString)
|
||||
{
|
||||
_queryString = queryString;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSessionId()
|
||||
{
|
||||
return _sessionId;
|
||||
}
|
||||
public void setSessionId(String sessionId)
|
||||
|
||||
public PushBuilder setSessionId(String sessionId)
|
||||
{
|
||||
_sessionId = sessionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isConditional()
|
||||
{
|
||||
return _conditional;
|
||||
}
|
||||
public void setConditional(boolean conditional)
|
||||
|
||||
public PushBuilder setConditional(boolean conditional)
|
||||
{
|
||||
_conditional = conditional;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Collection<String> getHeaderNames()
|
||||
public Set<String> getHeaderNames()
|
||||
{
|
||||
return _fields.getFieldNamesCollection();
|
||||
}
|
||||
|
@ -96,15 +107,27 @@ public class PushBuilder
|
|||
return _fields.get(name);
|
||||
}
|
||||
|
||||
public void setHeader(String name,String value)
|
||||
public PushBuilder setHeader(String name,String value)
|
||||
{
|
||||
_fields.put(name,value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addHeader(String name,String value)
|
||||
{
|
||||
_fields.add(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Push a resource.
|
||||
* Equivalent to {@link #push(String, String, String)} with null etag and
|
||||
* lastModified.
|
||||
* @param uriInContext
|
||||
*/
|
||||
public void push(String uriInContext)
|
||||
{
|
||||
push(uriInContext,null,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Push a resource.
|
||||
|
@ -152,6 +175,4 @@ public class PushBuilder
|
|||
_request.getHttpChannel().getHttpTransport().push(push);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -213,6 +213,18 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
return _input;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isPush()
|
||||
{
|
||||
return Boolean.TRUE.equals(getAttribute("org.eclipse.jetty.pushed"));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isPushSupported()
|
||||
{
|
||||
return getHttpChannel().getHttpTransport().isPushSupported();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get a PushBuilder associated with this request initialized as follows:<ul>
|
||||
|
@ -253,6 +265,9 @@ public class Request implements HttpServletRequest
|
|||
*/
|
||||
public PushBuilder getPushBuilder()
|
||||
{
|
||||
if (!isPushSupported())
|
||||
throw new IllegalStateException();
|
||||
|
||||
HttpFields fields = new HttpFields(getHttpFields().size()+5);
|
||||
boolean conditional=false;
|
||||
UserIdentity user_identity=null;
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Collections;
|
|||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.Cookie;
|
||||
|
@ -89,6 +90,12 @@ public class ResponseTest
|
|||
callback.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPushSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(org.eclipse.jetty.http.MetaData.Request request)
|
||||
{
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class PushSessionCacheFilter implements Filter
|
||||
{
|
||||
private static final String TARGET_ATTR="PushCacheFilter.target";
|
||||
private static final String TIMESTAMP_ATTR="PushCacheFilter.timestamp";
|
||||
private static final Logger LOG = Log.getLogger(PushSessionCacheFilter.class);
|
||||
private final ConcurrentMap<String, Target> _cache = new ConcurrentHashMap<>();
|
||||
|
||||
|
@ -65,8 +66,11 @@ public class PushSessionCacheFilter implements Filter
|
|||
if (config.getInitParameter("associateDelay")!=null)
|
||||
_associateDelay=Long.valueOf(config.getInitParameter("associateDelay"));
|
||||
|
||||
// Add a listener that is used to collect information about associated resource,
|
||||
// etags and modified dates
|
||||
config.getServletContext().addListener(new ServletRequestListener()
|
||||
{
|
||||
// Collect information when request is destroyed.
|
||||
@Override
|
||||
public void requestDestroyed(ServletRequestEvent sre)
|
||||
{
|
||||
|
@ -93,8 +97,9 @@ public class PushSessionCacheFilter implements Filter
|
|||
Target referer_target = _cache.get(path_in_ctx);
|
||||
if (referer_target!=null)
|
||||
{
|
||||
String sessionId = request.getSession(true).getId();
|
||||
Long last = referer_target._timestamp.get(sessionId);
|
||||
HttpSession session = request.getSession();
|
||||
ConcurrentHashMap<String, Long> timestamps = (ConcurrentHashMap<String, Long>)session.getAttribute(TIMESTAMP_ATTR);
|
||||
Long last = timestamps.get(referer_target._path);
|
||||
if (last!=null && (System.currentTimeMillis()-last)<_associateDelay && !referer_target._associated.containsKey(path))
|
||||
{
|
||||
if (referer_target._associated.putIfAbsent(path,target)==null)
|
||||
|
@ -121,8 +126,15 @@ public class PushSessionCacheFilter implements Filter
|
|||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||
{
|
||||
// Get Jetty request as these APIs are not yet standard
|
||||
Request baseRequest = Request.getBaseRequest(request);
|
||||
|
||||
if (baseRequest.isPush())
|
||||
{
|
||||
LOG.info("PUSH {} if modified since {}",baseRequest,baseRequest.getHttpFields().get("If-Modified-Since"));
|
||||
}
|
||||
|
||||
|
||||
// Iterating over fields is more efficient than multiple gets
|
||||
HttpFields fields = baseRequest.getHttpFields();
|
||||
String referer=fields.get(HttpHeader.REFERER);
|
||||
|
@ -130,7 +142,6 @@ public class PushSessionCacheFilter implements Filter
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} {} referer={}%n",baseRequest.getMethod(),baseRequest.getRequestURI(),referer);
|
||||
|
||||
|
||||
HttpSession session = baseRequest.getSession(true);
|
||||
String sessionId = session.getId();
|
||||
String path = URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo());
|
||||
|
@ -143,22 +154,27 @@ public class PushSessionCacheFilter implements Filter
|
|||
target = _cache.putIfAbsent(path,t);
|
||||
target = target==null?t:target;
|
||||
}
|
||||
target._timestamp.put(sessionId,System.currentTimeMillis());
|
||||
|
||||
ConcurrentHashMap<String, Long> timestamps = (ConcurrentHashMap<String, Long>)session.getAttribute(TIMESTAMP_ATTR);
|
||||
if (timestamps==null)
|
||||
{
|
||||
timestamps=new ConcurrentHashMap<>();
|
||||
session.setAttribute(TIMESTAMP_ATTR,timestamps);
|
||||
}
|
||||
|
||||
timestamps.put(path,System.currentTimeMillis());
|
||||
request.setAttribute(TARGET_ATTR,target);
|
||||
|
||||
// push any associated resources
|
||||
if (target._associated.size()>0)
|
||||
if (baseRequest.isPushSupported() && target._associated.size()>0)
|
||||
{
|
||||
PushBuilder builder = baseRequest.getPushBuilder();
|
||||
if (!session.isNew())
|
||||
builder.setConditional(true);
|
||||
if (builder!=null)
|
||||
for (Target associated : target._associated.values())
|
||||
{
|
||||
for (Target associated : target._associated.values())
|
||||
{
|
||||
LOG.info("PUSH {}->{}",path,associated._path);
|
||||
builder.push(associated._path,associated._etag,associated._lastModified);
|
||||
}
|
||||
LOG.info("PUSH {}->{}",path,associated);
|
||||
builder.push(associated._path,associated._etag,associated._lastModified);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +196,6 @@ public class PushSessionCacheFilter implements Filter
|
|||
{
|
||||
final String _path;
|
||||
final ConcurrentMap<String,Target> _associated = new ConcurrentHashMap<>();
|
||||
final ConcurrentMap<String,Long> _timestamp = new ConcurrentHashMap<>();
|
||||
volatile String _etag;
|
||||
volatile String _lastModified;
|
||||
|
||||
|
@ -189,5 +204,10 @@ public class PushSessionCacheFilter implements Filter
|
|||
_path=path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("Target(p=%s,e=%s,m=%s)->%s",_path,_etag,_lastModified,_associated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,13 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isPushSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.HttpTransport#push(org.eclipse.jetty.http.MetaData.Request)
|
||||
|
|
Loading…
Reference in New Issue