public static final String HEADER_PRAGMA = "Pragma";
public static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
public static final String HEADER_IF_NONE_MATCH = "If-None-Match";
+ public static final String HEADER_RANGE = "Range";
private static final ThreadLocal<CacheMethodHandle> tl = new ThreadLocal<CacheMethodHandle>();
* 2616, Abschnitt 10.3.5} einen ETag-Header enthalten, wenn auch die
* 200-Antwort einen enthalten hätte.
*/
- if (eTag != null)
- response.setHeader(HEADER_ETAG, eTag);
+ if (eTag != null) {
+ StringBuilder builder = new StringBuilder();
+ if (controller.isETagWeak())
+ builder.append("W/");
+ builder.append('"');
+ builder.append(eTag);
+ builder.append('"');
+ response.setHeader(HEADER_ETAG, builder.toString());
+ }
if (ifModifiedSince >= lastModified && lastModified > 0) {
}
}
- if (ifNoneMatch != null && ifNoneMatch.equals(eTag)) {
- log.debug("{}: ETag {} not changed -> 304 ", url, ifNoneMatch);
- response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
- return false;
+ if (ifNoneMatch != null) {
+ boolean weak = false;
+ if (ifNoneMatch.startsWith("W/")) {
+ weak = true;
+ ifNoneMatch = ifNoneMatch.substring(3, ifNoneMatch.length() - 1);
+ }
+ else {
+ ifNoneMatch = ifNoneMatch.substring(1, ifNoneMatch.length() - 1);
+ }
+
+ if (!weak || (request.getMethod().equals("GET") && request.getHeader(HEADER_RANGE) == null)) {
+ /**
+ * Die Gleichheit gilt nur, wenn die ETag's der Anfrage _und_ der
+ * Antwort stark sind (starke Gleichheit!), oder wenn die Antwort nur
+ * schwache Gleichheit fordert...
+ */
+ if (ifNoneMatch.equals(eTag) && (controller.isETagWeak() || !weak)) {
+ log.debug("{}: ETag {} not changed -> 304 ", url, ifNoneMatch);
+ response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return false;
+ }
+ }
+ else {
+ log.warn("{}: ignoring weak ETag W/\"{}\", because the request was no GET-request or the Range-Header was present!", url, ifNoneMatch);
+ }
}
int getCacheSeconds(HttpServletRequest request) throws Exception;
long getLastModified(HttpServletRequest request) throws Exception;
String getETag(HttpServletRequest request) throws Exception;
+ boolean isETagWeak();
void cacheControl(HttpServletRequest request, Map<String, String> cacheControlMap) throws Exception;
}
private boolean isLastModifiedMethodDefined;
private boolean isETagMethodDefined;
private boolean isCacheControlMethodDefined;
+ private boolean weak;
ReflectionCacheMethodHandle(Object handler) throws NoSuchMethodException {
cacheSeconds = CacheControl.this.defaultCacheSeconds;
lastModified = CacheControl.this.defaultLastModified;
- eTag = null;
+ eTag = "";
/** Class-Level-Annotations auslesen */
for (Annotation annotation : handler.getClass().getAnnotations()) {
continue;
}
if (annotation.annotationType().equals(ETag.class)) {
- eTag = ((ETag)annotation).value();
+ ETag eTagAnnotation = (ETag)annotation;
+ eTag = eTagAnnotation.value();
+ weak = eTagAnnotation.weak();
isETagMethodDefined = true;
continue;
}
if (isETagMethodDefined)
throw new IllegalArgumentException("Die Annotation @ETag wurde in der Klasse " + handler.getClass().getSimpleName() + " mehrfach verwendet!");
eTagMethod = method;
+ weak = ((ETag)annotation).weak();
isETagMethodDefined = true;
continue;
}
return (String)eTagMethod.invoke(handler, request);
}
+ @Override
+ public boolean isETagWeak() {
+ return weak;
+ }
+
@Override
public void cacheControl(
HttpServletRequest request,