<commit_before>package com.twitter.finagle.http

import com.twitter.finagle.http.cookie.{SameSite, supportSameSiteCodec}
import com.twitter.finagle.http.netty3.Netty3CookieCodec
import com.twitter.finagle.http.netty4.Netty4CookieCodec
import com.twitter.finagle.server.ServerInfo
import com.twitter.finagle.stats.{LoadedStatsReceiver, Verbosity}
import org.jboss.netty.handler.codec.http.HttpHeaders
import scala.collection.mutable

private[finagle] object CookieMap {

  val UseNetty4CookieCodec =
    Toggles("com.twitter.finagle.http.UseNetty4CookieCodec")

  private val serverIdHashCode = ServerInfo().id.hashCode()

  private def cookieCodec =
    if (UseNetty4CookieCodec(serverIdHashCode)) Netty4CookieCodec
    else Netty3CookieCodec

  // Note that this is a def to allow it to be toggled for unit tests.
  private[finagle] def includeSameSite: Boolean = supportSameSiteCodec()

  private[finagle] val flaglessSameSitesCounter =
    LoadedStatsReceiver.scope("http").scope("cookie").counter(Verbosity.Debug, "flagless_samesites")
  private[finagle] val silentlyDroppedSameSitesCounter =
    LoadedStatsReceiver.scope("http").scope("cookie").counter(Verbosity.Debug, "dropped_samesites")
}

/**
 * Adapt cookies of a Message to a mutable Map where cookies are indexed by
 * their name. Requests use the Cookie header and Responses use the Set-Cookie
 * header. If a cookie is added to the CookieMap, a header is automatically
 * added to the Message. You can add the same cookie more than once. Use getAll
 * to retrieve all of them, otherwise only the first one is returned. If a
 * cookie is removed from the CookieMap, a header is automatically removed from
 * the ''message''
 */
class CookieMap private[finagle] (message: Message, cookieCodec: CookieCodec)
    extends mutable.Map[String, Cookie]
    with mutable.MapLike[String, Cookie, CookieMap] {

  def this(message: Message) =
    this(message, CookieMap.cookieCodec)

  override def empty: CookieMap = new CookieMap(Request())

  private[this] val underlying =
    mutable.Map[String, Set[Cookie]]().withDefaultValue(Set.empty)

  /**
   * Checks if there was a parse error. Invalid cookies are ignored.
   */
  def isValid = _isValid
  private[this] var _isValid = true

  private[this] val cookieHeaderName =
    if (message.isRequest)
      HttpHeaders.Names.COOKIE
    else
      HttpHeaders.Names.SET_COOKIE

  private[this] def decodeCookies(header: String): Iterable[Cookie] = {
    val decoding =
      if (message.isRequest) cookieCodec.decodeServer(header)
      else cookieCodec.decodeClient(header)
    decoding match {
      case Some(decoding) =>
        decoding
      case None =>
        _isValid = false
        Nil
    }
  }

  protected def rewriteCookieHeaders(): Unit = {
    // Clear all cookies - there may be more than one with this name.
    message.headerMap.remove(cookieHeaderName)

    // Add cookies back again
    if (message.isRequest) {
      message.headerMap.setUnsafe(cookieHeaderName, cookieCodec.encodeClient(values))
    } else {
      foreach {
        case (_, cookie) => {
          message.headerMap.addUnsafe(cookieHeaderName, cookieCodec.encodeServer(cookie))
          if (!message.headerMap.toString.contains("SameSite")
            && cookie.sameSite != SameSite.Unset) {
            CookieMap.silentlyDroppedSameSitesCounter.incr()
          }
        }
      }<commit_msg>finagle/finatra: Validate more headers<commit_after>package com.twitter.finagle.http

import com.twitter.finagle.http.cookie.{SameSite, supportSameSiteCodec}
import com.twitter.finagle.http.netty3.Netty3CookieCodec
import com.twitter.finagle.http.netty4.Netty4CookieCodec
import com.twitter.finagle.server.ServerInfo
import com.twitter.finagle.stats.{LoadedStatsReceiver, Verbosity}
import org.jboss.netty.handler.codec.http.HttpHeaders
import scala.collection.mutable

private[finagle] object CookieMap {

  val UseNetty4CookieCodec =
    Toggles("com.twitter.finagle.http.UseNetty4CookieCodec")

  private val serverIdHashCode = ServerInfo().id.hashCode()

  private def cookieCodec =
    if (UseNetty4CookieCodec(serverIdHashCode)) Netty4CookieCodec
    else Netty3CookieCodec

  // Note that this is a def to allow it to be toggled for unit tests.
  private[finagle] def includeSameSite: Boolean = supportSameSiteCodec()

  private[finagle] val flaglessSameSitesCounter =
    LoadedStatsReceiver.scope("http").scope("cookie").counter(Verbosity.Debug, "flagless_samesites")
  private[finagle] val silentlyDroppedSameSitesCounter =
    LoadedStatsReceiver.scope("http").scope("cookie").counter(Verbosity.Debug, "dropped_samesites")
}

/**
 * Adapt cookies of a Message to a mutable Map where cookies are indexed by
 * their name. Requests use the Cookie header and Responses use the Set-Cookie
 * header. If a cookie is added to the CookieMap, a header is automatically
 * added to the Message. You can add the same cookie more than once. Use getAll
 * to retrieve all of them, otherwise only the first one is returned. If a
 * cookie is removed from the CookieMap, a header is automatically removed from
 * the ''message''
 */
class CookieMap private[finagle] (message: Message, cookieCodec: CookieCodec)
    extends mutable.Map[String, Cookie]
    with mutable.MapLike[String, Cookie, CookieMap] {

  def this(message: Message) =
    this(message, CookieMap.cookieCodec)

  override def empty: CookieMap = new CookieMap(Request())

  private[this] val underlying =
    mutable.Map[String, Set[Cookie]]().withDefaultValue(Set.empty)

  /**
   * Checks if there was a parse error. Invalid cookies are ignored.
   */
  def isValid = _isValid
  private[this] var _isValid = true

  private[this] val cookieHeaderName =
    if (message.isRequest)
      HttpHeaders.Names.COOKIE
    else
      HttpHeaders.Names.SET_COOKIE

  private[this] def decodeCookies(header: String): Iterable[Cookie] = {
    val decoding =
      if (message.isRequest) cookieCodec.decodeServer(header)
      else cookieCodec.decodeClient(header)
    decoding match {
      case Some(decoding) =>
        decoding
      case None =>
        _isValid = false
        Nil
    }
  }

  protected def rewriteCookieHeaders(): Unit = {
    // Clear all cookies - there may be more than one with this name.
    message.headerMap.remove(cookieHeaderName)

    // Add cookies back again
    if (message.isRequest) {
      message.headerMap.set(cookieHeaderName, cookieCodec.encodeClient(values))
    } else {
      foreach {
        case (_, cookie) => {
          message.headerMap.add(cookieHeaderName, cookieCodec.encodeServer(cookie))
          if (!message.headerMap.toString.contains("SameSite")
            && cookie.sameSite != SameSite.Unset) {
            CookieMap.silentlyDroppedSameSitesCounter.incr()
          }
        }
      }
{'fraction_non_alphanumeric': 0.09086898985443317, 'fraction_numerical': 0.002646669607410675, 'mean_word_length': 3.820694542877392, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '141084', 'n_tokens_mistral': 2007, 'n_tokens_neox': 1982, 'n_words': 527}