<commit_before>/*
 * Copyright 2014 http4s.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.http4s.server.middleware

import cats._
import cats.syntax.all._
import cats.effect.{MonadThrow => _, _}
import cats.data._
import org.http4s._
import org.http4s.util.CaseInsensitiveString
import org.http4s.headers.{Date => HDate, _}
import scala.concurrent.duration._

/** Caching contains middlewares to support caching functionality.
  *
  * Helper functions to support [[Caching.cache]] can be found in
  * [[Caching.Helpers]]
  */
object Caching {

  /** Middleware that implies responses should NOT be cached.
    * This is a best attempt, many implementors of caching have done so differently.
    */
  def `no-store`[G[_]: Monad: Clock, F[_], A](
      http: Kleisli[G, A, Response[F]]): Kleisli[G, A, Response[F]] =
    Kleisli { (a: A) =>
      for {
        resp <- http(a)
        out <- `no-store-response`[G](resp)
      } yield out
    }

  /** Transform a Response so that it will not be cached.
    */
  def `no-store-response`[G[_]]: PartiallyAppliedNoStoreCache[G] =
    new PartiallyAppliedNoStoreCache[G] {
      def apply[F[_]](resp: Response[F])(implicit M: Monad[G], C: Clock[G]): G[Response[F]] =
        HttpDate.current[G].map(now => resp.putHeaders(HDate(now) :: noStoreStaticHeaders: _*))
    }

  // These never change, so don't recreate them each time.
  private val noStoreStaticHeaders = List(
    `Cache-Control`(
      NonEmptyList.of[CacheDirective](
        CacheDirective.`no-store`,
        CacheDirective.`private`(),
        CacheDirective.`no-cache`(),
        CacheDirective.`max-age`(0.seconds)
      )
    ),
    Header("Pragma", "no-cache"),
    Expires(HttpDate.Epoch) // Expire at the epoch for no time confusion
  )

  /** Helpers Contains the default arguments used to help construct middleware
    * with caching. They serve to support the default arguments for
    * [[publicCache]] and [[privateCache]].
    */
  object Helpers {
    def defaultStatusToSetOn(s: Status): Boolean =
      s match {
        case Status.NotModified => true
        case otherwise => otherwise.isSuccess<commit_msg>Remove private from no-cache set<commit_after>/*
 * Copyright 2014 http4s.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.http4s.server.middleware

import cats._
import cats.syntax.all._
import cats.effect.{MonadThrow => _, _}
import cats.data._
import org.http4s._
import org.http4s.util.CaseInsensitiveString
import org.http4s.headers.{Date => HDate, _}
import scala.concurrent.duration._

/** Caching contains middlewares to support caching functionality.
  *
  * Helper functions to support [[Caching.cache]] can be found in
  * [[Caching.Helpers]]
  */
object Caching {

  /** Middleware that implies responses should NOT be cached.
    * This is a best attempt, many implementors of caching have done so differently.
    */
  def `no-store`[G[_]: Monad: Clock, F[_], A](
      http: Kleisli[G, A, Response[F]]): Kleisli[G, A, Response[F]] =
    Kleisli { (a: A) =>
      for {
        resp <- http(a)
        out <- `no-store-response`[G](resp)
      } yield out
    }

  /** Transform a Response so that it will not be cached.
    */
  def `no-store-response`[G[_]]: PartiallyAppliedNoStoreCache[G] =
    new PartiallyAppliedNoStoreCache[G] {
      def apply[F[_]](resp: Response[F])(implicit M: Monad[G], C: Clock[G]): G[Response[F]] =
        HttpDate.current[G].map(now => resp.putHeaders(HDate(now) :: noStoreStaticHeaders: _*))
    }

  // These never change, so don't recreate them each time.
  private val noStoreStaticHeaders = List(
    `Cache-Control`(
      NonEmptyList.of[CacheDirective](
        CacheDirective.`no-store`,
        CacheDirective.`no-cache`(),
        CacheDirective.`max-age`(0.seconds)
      )
    ),
    Header("Pragma", "no-cache"),
    Expires(HttpDate.Epoch) // Expire at the epoch for no time confusion
  )

  /** Helpers Contains the default arguments used to help construct middleware
    * with caching. They serve to support the default arguments for
    * [[publicCache]] and [[privateCache]].
    */
  object Helpers {
    def defaultStatusToSetOn(s: Status): Boolean =
      s match {
        case Status.NotModified => true
        case otherwise => otherwise.isSuccess
{'fraction_non_alphanumeric': 0.11557977823717347, 'fraction_numerical': 0.005262168765269686, 'mean_word_length': 3.285024154589372, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3139588', 'n_tokens_mistral': 1619, 'n_tokens_neox': 1576, 'n_words': 516}