001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.http.header; 018 019import java.time.*; 020import java.util.function.*; 021 022import org.apache.juneau.http.annotation.*; 023 024/** 025 * Represents a parsed <l>If-Modified-Since</l> HTTP request header. 026 * 027 * <p> 028 * Allows a 304 Not Modified to be returned if content is unchanged. 029 * 030 * <h5 class='figure'>Example</h5> 031 * <p class='bcode'> 032 * If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT 033 * </p> 034 * 035 * <h5 class='topic'>RFC2616 Specification</h5> 036 * 037 * The If-Modified-Since request-header field is used with a method to make it conditional: 038 * if the requested variant has not been modified since the time specified in this field, an entity will not be returned 039 * from the server; instead, a 304 (not modified) response will be returned without any message-body. 040 * 041 * <p class='bcode'> 042 * If-Modified-Since = "If-Modified-Since" ":" HTTP-date 043 * </p> 044 * 045 * <p> 046 * An example of the field is: 047 * <p class='bcode'> 048 * If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT 049 * </p> 050 * 051 * <p> 052 * A GET method with an If-Modified-Since header and no Range header requests that the identified entity be transferred 053 * only if it has been modified since the date given by the If-Modified-Since header. 054 * The algorithm for determining this includes the following cases: 055 * <ol> 056 * <li>If the request would normally result in anything other than a 200 (OK) status, or if the passed 057 * If-Modified-Since date is invalid, the response is exactly the same as for a normal GET. 058 * A date which is later than the server's current time is invalid. 059 * <li>If the variant has been modified since the If-Modified-Since date, the response is exactly the same as for a 060 * normal GET. 061 * <li>If the variant has not been modified since a valid If-Modified-Since date, the server SHOULD return a 304 062 * (Not Modified) response. 063 * </ol> 064 * 065 * <p> 066 * The purpose of this feature is to allow efficient updates of cached information with a minimum amount of transaction 067 * overhead. 068 * 069 * <p> 070 * Note: The Range request-header field modifies the meaning of If-Modified-Since; see section 14.35 for full details. 071 * 072 * <p> 073 * Note: If-Modified-Since times are interpreted by the server, whose clock might not be synchronized with the client. 074 * 075 * <p> 076 * Note: When handling an If-Modified-Since header field, some servers will use an exact date comparison function, 077 * rather than a less-than function, for deciding whether to send a 304 (Not Modified) response. 078 * To get best results when sending an If-Modified-Since header field for cache validation, clients are 079 * advised to use the exact date string received in a previous Last-Modified header field whenever possible. 080 * 081 * <p> 082 * Note: If a client uses an arbitrary date in the If-Modified-Since header instead of a date taken from the 083 * Last-Modified header for the same request, the client should be aware of the fact that this date is interpreted in 084 * the server's understanding of time. 085 * The client should consider unsynchronized clocks and rounding problems due to the different encodings of time between 086 * the client and server. 087 * This includes the possibility of race conditions if the document has changed between the time it was first requested 088 * and the If-Modified-Since date of a subsequent request, and the possibility of clock-skew-related problems if the 089 * If-Modified-Since date is derived from the client's clock without correction to the server's clock. 090 * Corrections for different time bases between client and server are at best approximate due to network latency. 091 * The result of a request having both an If-Modified-Since header field and either an If-Match or an 092 * If-Unmodified-Since header fields is undefined by this specification. 093 * 094 * <h5 class='section'>See Also:</h5><ul> 095 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a> 096 * <li class='extlink'><a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616.html">Hypertext Transfer Protocol -- HTTP/1.1</a> 097 * </ul> 098 * 099 * @serial exclude 100 */ 101@Header("If-Modified-Since") 102public class IfModifiedSince extends BasicDateHeader { 103 104 //----------------------------------------------------------------------------------------------------------------- 105 // Static 106 //----------------------------------------------------------------------------------------------------------------- 107 108 private static final long serialVersionUID = 1L; 109 private static final String NAME = "If-Modified-Since"; 110 111 /** 112 * Static creator. 113 * 114 * @param value 115 * The header value. 116 * <br>Must be an RFC-1123 formated string (e.g. <js>"Sat, 29 Oct 1994 19:43:31 GMT"</js>). 117 * <br>Can be <jk>null</jk>. 118 * @return A new header bean, or <jk>null</jk> if the name is <jk>null</jk> or empty or the value is <jk>null</jk>. 119 */ 120 public static IfModifiedSince of(String value) { 121 return value == null ? null : new IfModifiedSince(value); 122 } 123 124 /** 125 * Static creator. 126 * 127 * @param value 128 * The header value. 129 * <br>Can be <jk>null</jk>. 130 * @return A new header bean, or <jk>null</jk> if the name is <jk>null</jk> or empty or the value is <jk>null</jk>. 131 */ 132 public static IfModifiedSince of(ZonedDateTime value) { 133 return value == null ? null : new IfModifiedSince(value); 134 } 135 136 /** 137 * Static creator with delayed value. 138 * 139 * <p> 140 * Header value is re-evaluated on each call to {@link #getValue()}. 141 * 142 * @param value 143 * The supplier of the header value. 144 * <br>Can be <jk>null</jk>. 145 * @return A new header bean, or <jk>null</jk> if the name is <jk>null</jk> or empty or the value is <jk>null</jk>. 146 */ 147 public static IfModifiedSince of(Supplier<ZonedDateTime> value) { 148 return value == null ? null : new IfModifiedSince(value); 149 } 150 151 //----------------------------------------------------------------------------------------------------------------- 152 // Instance 153 //----------------------------------------------------------------------------------------------------------------- 154 155 /** 156 * Constructor. 157 * 158 * @param value 159 * The header value. 160 * <br>Must be an RFC-1123 formated string (e.g. <js>"Sat, 29 Oct 1994 19:43:31 GMT"</js>). 161 * <br>Can be <jk>null</jk>. 162 */ 163 public IfModifiedSince(String value) { 164 super(NAME, value); 165 } 166 167 /** 168 * Constructor. 169 * 170 * @param value 171 * The header value. 172 * <br>Can be <jk>null</jk>. 173 */ 174 public IfModifiedSince(ZonedDateTime value) { 175 super(NAME, value); 176 } 177 178 /** 179 * Constructor with delayed value. 180 * 181 * <p> 182 * Header value is re-evaluated on each call to {@link #getValue()}. 183 * 184 * @param value 185 * The supplier of the header value. 186 * <br>Can be <jk>null</jk>. 187 */ 188 public IfModifiedSince(Supplier<ZonedDateTime> value) { 189 super(NAME, value); 190 } 191}