Skip to content

Commit

Permalink
add Obfuscated.fromString; improve Element
Browse files Browse the repository at this point in the history
  • Loading branch information
satorg committed Aug 12, 2020
1 parent d9297f7 commit f083958
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 4 deletions.
38 changes: 35 additions & 3 deletions core/src/main/scala/org/http4s/headers/Forwarded.scala
Expand Up @@ -23,7 +23,7 @@ object Forwarded
object Node {
def apply(nodeName: Name, nodePort: Port): Node = apply(nodeName, Some(nodePort))

sealed trait Name
sealed trait Name { _: Product => }

object Name {
final case class Ipv4(address: Uri.Ipv4Address) extends Name
Expand All @@ -40,7 +40,7 @@ object Forwarded
: Name = apply(Uri.Ipv6Address(a, b, c, d, e, f, g, h))
}

sealed trait Port
sealed trait Port { _: Product => }

object Port {
final case class Num(value: Int) extends Port
Expand All @@ -52,7 +52,26 @@ object Forwarded
}
}

final case class Obfuscated(value: String) extends Name with Port
sealed trait Obfuscated extends Name with Port { _: Product =>

/**
* Obfuscated value doesn't include the leading underscore symbol.
*/
def value: String
}
object Obfuscated {
def fromString(s: String): ParseResult[Obfuscated] =
new ModelNodeObfuscatedValueParser(s).parse.map(apply)

def unapply(o: Obfuscated): Option[String] = Some(o.value)

// Referenced by model parsers.
private[http4s] def apply(s: String): Obfuscated = C(s)

private[this] final case class C(value: String) extends Obfuscated {
override def productPrefix: String = "Obfuscated"
}
}

def fromString(s: String): ParseResult[Node] = new ModelNodeParser(s).parse
}
Expand All @@ -78,6 +97,11 @@ object Forwarded
def withFor(value: Node): Element
def withHost(value: Host): Element
def withProto(value: Proto): Element

def withoutBy: Element
def withoutFor: Element
def withoutHost: Element
def withoutProto: Element
}

/**
Expand All @@ -101,13 +125,21 @@ object Forwarded
def withHost(value: Host): Element = copy(`host` = Some(value))
def withProto(value: Proto): Element = copy(`proto` = Some(value))

def withoutBy: Element = copy(`by` = None)
def withoutFor: Element = copy(`for` = None)
def withoutHost: Element = copy(`host` = None)
def withoutProto: Element = copy(`proto` = None)

override def productPrefix: String = "Element"
}

def withBy(value: Node): Element = C(`by` = Some(value))
def withFor(value: Node): Element = C(`for` = Some(value))
def withHost(value: Host): Element = C(`host` = Some(value))
def withProto(value: Proto): Element = C(`proto` = Some(value))

def unapply(elem: Element): Option[(Option[Node], Option[Node], Option[Host], Option[Proto])] =
Some((elem.`by`, elem.`for`, elem.`host`, elem.`proto`))
}

override def parse(s: String): ParseResult[Forwarded] = HttpHeaderParser.FORWARDED(s)
Expand Down
Expand Up @@ -46,9 +46,14 @@ private[http4s] trait ForwardedModelParsing { model: Forwarded.type =>
} | ModelNodeObfuscated
}

protected final def ModelNodeObfuscatedValue: Rule1[String] =
rule {
capture(oneOrMore(AlphaNum | '.' | '_' | '-'))
}

protected final def ModelNodeObfuscated: Rule1[model.Node.Obfuscated] =
rule {
'_' ~ capture(oneOrMore(AlphaNum | '.' | '_' | '-')) ~> model.Node.Obfuscated
'_' ~ ModelNodeObfuscatedValue ~> { model.Node.Obfuscated(_: String) }
}

protected final def ModelHost: Rule1[model.Host] =
Expand All @@ -64,6 +69,13 @@ private[http4s] trait ForwardedModelParsing { model: Forwarded.type =>
override def main: Rule1[Node] = rule(ModelNode ~ EOI)
}

protected final class ModelNodeObfuscatedValueParser(s: String)
extends Http4sParser[String](s, "invalid obfuscated value")
with ModelParsers {

override def main: Rule1[String] = rule(ModelNodeObfuscatedValue ~ EOI)
}

protected final class ModelHostParser(s: String)
extends Http4sParser[model.Host](s, "invalid host")
with ModelParsers {
Expand Down
15 changes: 15 additions & 0 deletions tests/src/test/scala/org/http4s/headers/ForwardedSpec.scala
Expand Up @@ -64,6 +64,21 @@ class ForwardedSpec extends Specification with Tables {
}
}
}
"Node.Obfuscated" >> {
import Forwarded.Node.Obfuscated

"parse valid obfuscated values" in {
val validValues = Seq(
"1",
"a",
"_"
)

Result.foreach(validValues) { value =>
Obfuscated.fromString(value) must beRight((_: Obfuscated).value must_=== value)
}
}
}
"Host" >> {
import Forwarded.Host

Expand Down

0 comments on commit f083958

Please sign in to comment.