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