Bear in mind that caching is not the same as revalidation. A proxy server could cache an object forever, but revalidate it with the origin server every time a request is made for that object (i.e. make an If-Modified-Since or If-Match request which allows the origin server to indicate that the object hasn't changed without returning the object again). If the origin server indicates an expiry (i.e. sends an
Cache-Control: max-age header), the proxy can consider the object to be "fresh" for that period, which means that it doesn't need to revalidate it. If an object is not fresh, it is considered "stale", which means that it must revalidate the object.
Technically proxy servers are supposed to treat objects as stale if the origin server doesn't indicate an expiry, but it seems that most proxy servers treat objects as fresh for a certain period. Squid's default behaviour seems to be
refresh_pattern . 0 20% 4320
which means if the server sent a
Last-Modified header, the object is considered fresh for 20% of the difference between the current and last modified times up to a maximum of 4320s (3h), but is never fresh if a
Last-Modified header was not sent.