Added support for ETag conditional GETs, streamlined support for
Last-Modified and If-Modified-Since
This commit is contained in:
parent
1690b6bf58
commit
5003588bb7
4 changed files with 131 additions and 59 deletions
|
@ -56,7 +56,7 @@ public class RequestBean implements Serializable {
|
|||
return req.getUsername ();
|
||||
}
|
||||
|
||||
public Date getLastModified () {
|
||||
/* public Date getLastModified () {
|
||||
long since = req.getIfModifiedSince ();
|
||||
if (since < 0)
|
||||
return null;
|
||||
|
@ -67,7 +67,7 @@ public class RequestBean implements Serializable {
|
|||
public void setLastModified () {
|
||||
throw new RuntimeException ("The lastModified property of the Request object is read-only. "+
|
||||
"Set lastModified on the Response object if you want to mark the last modification date of a resource.");
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,10 +26,9 @@ public class RequestTrans implements Externalizable {
|
|||
|
||||
// timestamp of client-cached version, if present in request
|
||||
private long ifModifiedSince = -1;
|
||||
|
||||
// set of ETags the client sent with If-None-Match header
|
||||
private Set etags;
|
||||
|
||||
// this is used to hold the EcmaScript form data object
|
||||
public transient Object data;
|
||||
// when was execution started on this request?
|
||||
public transient long startTime;
|
||||
|
||||
|
@ -130,6 +129,7 @@ public class RequestTrans implements Externalizable {
|
|||
values = (Map) s.readObject ();
|
||||
httpMethod = s.readByte ();
|
||||
ifModifiedSince = s.readLong ();
|
||||
etags = (Set) s.readObject ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,50 +141,78 @@ public class RequestTrans implements Externalizable {
|
|||
s.writeObject (values);
|
||||
s.writeByte (httpMethod);
|
||||
s.writeLong (ifModifiedSince);
|
||||
s.writeObject (etags);
|
||||
}
|
||||
|
||||
public void setIfModifiedSince (long since) {
|
||||
ifModifiedSince = since;
|
||||
}
|
||||
|
||||
|
||||
public long getIfModifiedSince () {
|
||||
return ifModifiedSince;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if ( httpUsername!=null )
|
||||
return httpUsername;
|
||||
String auth = (String)get("authorization");
|
||||
if ( auth==null || "".equals(auth) ) {
|
||||
return null;
|
||||
}
|
||||
decodeHttpAuth(auth);
|
||||
return httpUsername;
|
||||
public void setETags (String etagHeader) {
|
||||
etags = new HashSet();
|
||||
if (etagHeader.indexOf (",") > -1) {
|
||||
StringTokenizer st = new StringTokenizer (etagHeader, ", \r\n");
|
||||
while (st.hasMoreTokens())
|
||||
etags.add (st.nextToken ());
|
||||
} else {
|
||||
etags.add (etagHeader);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
if ( httpPassword!=null )
|
||||
return httpPassword;
|
||||
String auth = (String)get("authorization");
|
||||
if ( auth==null || "".equals(auth) ) {
|
||||
return null;
|
||||
}
|
||||
decodeHttpAuth(auth);
|
||||
return httpPassword;
|
||||
}
|
||||
public Set getETags () {
|
||||
return etags;
|
||||
}
|
||||
|
||||
private void decodeHttpAuth(String auth) {
|
||||
if ( auth==null )
|
||||
return;
|
||||
StringTokenizer tok;
|
||||
if( auth.startsWith("Basic ") )
|
||||
tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" );
|
||||
else
|
||||
tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" );
|
||||
try { httpUsername = tok.nextToken(); }
|
||||
catch ( NoSuchElementException e ) { httpUsername = null; }
|
||||
try { httpPassword = tok.nextToken(); }
|
||||
catch ( NoSuchElementException e ) { httpPassword = null; }
|
||||
public boolean hasETag (String etag) {
|
||||
if (etags == null || etag == null)
|
||||
return false;
|
||||
return etags.contains (etag);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if ( httpUsername!=null )
|
||||
return httpUsername;
|
||||
String auth = (String)get("authorization");
|
||||
if ( auth==null || "".equals(auth) ) {
|
||||
return null;
|
||||
}
|
||||
decodeHttpAuth(auth);
|
||||
return httpUsername;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
if ( httpPassword!=null )
|
||||
return httpPassword;
|
||||
String auth = (String)get("authorization");
|
||||
if ( auth==null || "".equals(auth) ) {
|
||||
return null;
|
||||
}
|
||||
decodeHttpAuth(auth);
|
||||
return httpPassword;
|
||||
}
|
||||
|
||||
private void decodeHttpAuth(String auth) {
|
||||
if ( auth==null )
|
||||
return;
|
||||
StringTokenizer tok;
|
||||
if( auth.startsWith("Basic ") )
|
||||
tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" );
|
||||
else
|
||||
tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" );
|
||||
try {
|
||||
httpUsername = tok.nextToken();
|
||||
} catch ( NoSuchElementException e ) {
|
||||
httpUsername = null;
|
||||
}
|
||||
try {
|
||||
httpPassword = tok.nextToken();
|
||||
} catch ( NoSuchElementException e ) {
|
||||
httpPassword = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,13 +97,6 @@ public class ResponseBean implements Serializable {
|
|||
res.contentType = contentType;
|
||||
}
|
||||
|
||||
public void setLastModified (Date date) {
|
||||
if (date == null)
|
||||
res.setLastModified (-1);
|
||||
else
|
||||
res.setLastModified (date.getTime());
|
||||
}
|
||||
|
||||
public Map getdata () {
|
||||
return res.getResponseData ();
|
||||
}
|
||||
|
@ -143,19 +136,34 @@ public class ResponseBean implements Serializable {
|
|||
public void setstatus (int status) {
|
||||
res.status = status;
|
||||
}
|
||||
|
||||
|
||||
public Date getLastModified () {
|
||||
long modified = res.getLastModified ();
|
||||
if (modified > -1)
|
||||
return new Date (modified);
|
||||
else
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void notModified () throws RedirectException {
|
||||
res.setNotModified (true);
|
||||
|
||||
public void setLastModified (Date date) {
|
||||
if (date == null)
|
||||
res.setLastModified (-1);
|
||||
else
|
||||
res.setLastModified (date.getTime());
|
||||
}
|
||||
|
||||
public String getETag () {
|
||||
return res.getETag ();
|
||||
}
|
||||
|
||||
public void setETag (String etag) {
|
||||
res.setETag (etag);
|
||||
}
|
||||
|
||||
/* public void notModified () throws RedirectException {
|
||||
res.setNotModified (true);
|
||||
} */
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ public final class ResponseTrans implements Externalizable {
|
|||
private long lastModified = -1;
|
||||
// flag to signal that resource has not been modified
|
||||
private boolean notModified = false;
|
||||
|
||||
// Entity Tag for this response, used for conditional GETs
|
||||
private String etag = null;
|
||||
|
||||
// cookies
|
||||
String cookieKeys[];
|
||||
|
@ -85,20 +86,26 @@ public final class ResponseTrans implements Externalizable {
|
|||
|
||||
static final int INITIAL_BUFFER_SIZE = 2048;
|
||||
|
||||
/**
|
||||
* JavaScript object to make the values Map accessible to
|
||||
* script code as res.data
|
||||
*/
|
||||
public transient Object data;
|
||||
|
||||
// the map of form and cookie data
|
||||
private transient Map values;
|
||||
|
||||
// the map of macro handlers
|
||||
private transient Map handlers;
|
||||
|
||||
// the request trans for this response
|
||||
private transient RequestTrans reqtrans;
|
||||
|
||||
|
||||
public ResponseTrans () {
|
||||
super ();
|
||||
title = head = body = message = error = null;
|
||||
values = new HashMap ();
|
||||
handlers = new HashMap ();
|
||||
}
|
||||
|
||||
public ResponseTrans (RequestTrans req) {
|
||||
this();
|
||||
reqtrans = req;
|
||||
}
|
||||
|
||||
|
||||
|
@ -320,6 +327,15 @@ public final class ResponseTrans implements Externalizable {
|
|||
error = true;
|
||||
response = buffer.toString ().getBytes ();
|
||||
}
|
||||
// if etag is not set, calc MD5 digest and check it
|
||||
if (etag == null && !notModified && redir == null) try {
|
||||
String digest = MD5Encoder.encode (response);
|
||||
etag = "\""+digest+"\"";
|
||||
if (reqtrans != null && reqtrans.hasETag (etag)) {
|
||||
response = new byte[0];
|
||||
notModified = true;
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
buffer = null; // make sure this is done only once, even with more requsts attached
|
||||
} else {
|
||||
response = new byte[0];
|
||||
|
@ -359,17 +375,35 @@ public final class ResponseTrans implements Externalizable {
|
|||
}
|
||||
|
||||
public void setLastModified (long modified) {
|
||||
if (modified > -1 && reqtrans != null &&
|
||||
reqtrans.getIfModifiedSince() >= modified)
|
||||
{
|
||||
notModified = true;
|
||||
throw new RedirectException (null);
|
||||
}
|
||||
lastModified = modified;
|
||||
}
|
||||
|
||||
|
||||
public long getLastModified () {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setNotModified (boolean notmod) throws RedirectException {
|
||||
|
||||
/* public void setNotModified (boolean notmod) throws RedirectException {
|
||||
notModified = notmod;
|
||||
if (notmod)
|
||||
throw new RedirectException (null);
|
||||
} */
|
||||
|
||||
public void setETag (String value) {
|
||||
etag = value == null ? null : "\""+value+"\"";
|
||||
if (etag != null && reqtrans != null && reqtrans.hasETag (etag)) {
|
||||
notModified = true;
|
||||
throw new RedirectException (null);
|
||||
}
|
||||
}
|
||||
|
||||
public String getETag () {
|
||||
return etag;
|
||||
}
|
||||
|
||||
public boolean getNotModified () {
|
||||
|
@ -460,6 +494,7 @@ public final class ResponseTrans implements Externalizable {
|
|||
lastModified = s.readLong ();
|
||||
notModified = s.readBoolean ();
|
||||
charset = (String) s.readObject ();
|
||||
etag = (String) s.readObject ();
|
||||
}
|
||||
|
||||
public void writeExternal (ObjectOutput s) throws IOException {
|
||||
|
@ -476,6 +511,7 @@ public final class ResponseTrans implements Externalizable {
|
|||
s.writeLong (lastModified);
|
||||
s.writeBoolean (notModified);
|
||||
s.writeObject (charset);
|
||||
s.writeObject (etag);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue