All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.memcached.protocol.Command.scala Maven / Gradle / Ivy

There is a newer version: 21.2.0
Show newest version
package com.twitter.finagle.memcached.protocol

import com.twitter.finagle.memcached.util.Bufs
import com.twitter.io.Buf
import com.twitter.util.Time

private object KeyValidation {
  private val MaxKeyLength = 250

  private def tooLong(key: Buf): Boolean = key.length > MaxKeyLength

  /** Return -1 if no invalid bytes */
  private def invalidByteIndex(key: Buf): Int = {
    val bs = Buf.ByteArray.Owned.extract(key)
    var i = 0
    while (i < bs.length) {
      if (Bufs.INVALID_KEY_CHARACTERS.contains(bs(i)))
        return i
      i += 1
    }
    -1
  }

  private val KeyCheck: Buf => Unit =
    key => {
      if (key == null)
        throw new IllegalArgumentException("Invalid keys: key cannot be null")

      if (tooLong(key))
        throw new IllegalArgumentException(
          "Invalid keys: key cannot be longer than %d bytes (%d)".format(MaxKeyLength, key.length))

      val index = invalidByteIndex(key)
      if (index != -1) {
        val ch = Buf.ByteArray.Owned.extract(key)(index)
        throw new IllegalArgumentException(
          "Invalid keys: key cannot have whitespace or control characters: '0x%d'".format(ch))
      }
    }

}

/**
 * This trait contains cache command key validation logic.
 * The validation is done by searching each buffer for invalid character defined in
 * Bufs.INVALID_KEY_CHARACTER, during construction of this trait.
 *
 * All cache commands accepting key/keys should mixin this trait.
 */
trait KeyValidation {
  import KeyValidation._

  def keys: Seq[Buf]

  {
    // Validating keys
    val ks = keys
    if (ks == null)
      throw new IllegalArgumentException("Invalid keys: cannot have null for keys")

    ks.foreach(KeyCheck)
  }

  def badKey(key: Buf): Boolean = {
    if (key == null) true else {
      tooLong(key) || invalidByteIndex(key) != -1
    }
  }
}

sealed abstract class Command(val name: String)

abstract class StorageCommand(
    key: Buf,
    flags: Int,
    expiry: Time,
    value: Buf,
    name: String)
  extends Command(name)
  with KeyValidation {
  def keys: Seq[Buf] = Seq(key)
}

abstract class NonStorageCommand(name: String) extends Command(name)

abstract class ArithmeticCommand(
    key: Buf,
    delta: Long,
    name: String)
  extends NonStorageCommand(name)
  with KeyValidation {
  def keys: Seq[Buf] = Seq(key)
}

abstract class RetrievalCommand(name: String) extends NonStorageCommand(name) with KeyValidation {
  def keys: Seq[Buf]
}

// storage commands
case class Set(key: Buf, flags: Int, expiry: Time, value: Buf)
  extends StorageCommand(key, flags, expiry, value, "Set")
case class Add(key: Buf, flags: Int, expiry: Time, value: Buf)
  extends StorageCommand(key, flags, expiry, value, "Add")
case class Replace(key: Buf, flags: Int, expiry: Time, value: Buf)
  extends StorageCommand(key, flags, expiry, value, "Replace")
case class Append(key: Buf, flags: Int, expiry: Time, value: Buf)
  extends StorageCommand(key, flags, expiry, value, "Append")
case class Prepend(key: Buf, flags: Int, expiry: Time, value: Buf)
  extends StorageCommand(key, flags, expiry, value, "Prepend")
case class Cas(key: Buf, flags: Int, expiry: Time, value: Buf, casUnique: Buf)
  extends StorageCommand(key, flags, expiry, value, "Cas")

// retrieval commands
case class Get(keys: Seq[Buf]) extends RetrievalCommand("Get")
case class Gets(keys: Seq[Buf]) extends RetrievalCommand("Gets")

// arithmetic commands
case class Incr(key: Buf, value: Long) extends ArithmeticCommand(key, value, "Incr")
case class Decr(key: Buf, value: Long) extends ArithmeticCommand(key, -value, "Decr")

// other commands
case class Delete(key: Buf) extends Command("Delete") with KeyValidation {
  def keys: Seq[Buf] = Seq(key)
}
case class Stats(args: Seq[Buf]) extends NonStorageCommand("Stats")
case class Quit() extends Command("Quit")

// twemcache specific commands
case class Upsert(key: Buf, flags: Int, expiry: Time, value: Buf, version: Buf)
    extends StorageCommand(key, flags, expiry, value, "Upsert")
case class Getv(keys: Seq[Buf]) extends RetrievalCommand("Getv")




© 2015 - 2025 Weber Informatics LLC | Privacy Policy