Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model Access-Control-Allow-Headers header #3587

Merged
merged 1 commit into from Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -7,4 +7,28 @@
package org.http4s
package headers

object `Access-Control-Allow-Headers` extends HeaderKey.Default
import org.typelevel.ci.CIString
import org.http4s.parser.HttpHeaderParser
import org.http4s.util._
import cats.data.NonEmptyList

object `Access-Control-Allow-Headers`
extends HeaderKey.Internal[`Access-Control-Allow-Headers`]
with HeaderKey.Recurring {

override def parse(s: String): ParseResult[`Access-Control-Allow-Headers`] =
HttpHeaderParser.ACCESS_CONTROL_ALLOW_HEADERS(s)

private val ciStringRenderer: Renderer[CIString] = new Renderer[CIString] {
override def render(writer: Writer, ciString: CIString): writer.type =
writer << ciString
}
}

final case class `Access-Control-Allow-Headers`(values: NonEmptyList[CIString])
extends Header.RecurringRenderer {
override type Value = CIString

override implicit def renderer: Renderer[Value] = `Access-Control-Allow-Headers`.ciStringRenderer
override def key: `Access-Control-Allow-Headers`.type = `Access-Control-Allow-Headers`
}
Expand Up @@ -112,6 +112,7 @@ object HttpHeaderParser
addParser_(CIString("ACCEPT-LANGUAGE"), `ACCEPT_LANGUAGE`)
addParser_(CIString("ACCEPT-RANGES"), `ACCEPT_RANGES`)
addParser_(CIString("ACCESS-CONTROL-ALLOW-CREDENTIALS"), `ACCESS_CONTROL_ALLOW_CREDENTIALS`)
addParser_(CIString("ACCESS-CONTROL-ALLOW-HEADERS"), `ACCESS_CONTROL_ALLOW_HEADERS`)
addParser_(CIString("AGE"), `AGE`)
addParser_(CIString("ALLOW"), `ALLOW`)
addParser_(CIString("AUTHORIZATION"), `AUTHORIZATION`)
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/scala/org/http4s/parser/SimpleHeaders.scala
Expand Up @@ -51,6 +51,18 @@ private[parser] trait SimpleHeaders {
}
}.parse

def ACCESS_CONTROL_ALLOW_HEADERS(value: String): ParseResult[`Access-Control-Allow-Headers`] =
new Http4sHeaderParser[`Access-Control-Allow-Headers`](value) {
def entry =
rule {
oneOrMore(Token).separatedBy(ListSep) ~ EOL ~> { (tokens: Seq[String]) =>
`Access-Control-Allow-Headers`(
NonEmptyList.of(CIString(tokens.head), tokens.tail.map(CIString(_)): _*)
)
}
}
}.parse

def ALLOW(value: String): ParseResult[Allow] =
new Http4sHeaderParser[Allow](value) {
def entry =
Expand Down
Expand Up @@ -488,6 +488,14 @@ private[http4s] trait ArbitraryInstances {
} yield headers.Accept(NonEmptyList.of(values.head, values.tail: _*))
}

implicit val http4sTestingArbitraryForAccessControlAllowHeaders
: Arbitrary[headers.`Access-Control-Allow-Headers`] =
Arbitrary {
for {
values <- nonEmptyListOf(genToken.map(CIString(_)))
} yield headers.`Access-Control-Allow-Headers`(NonEmptyList.of(values.head, values.tail: _*))
}

implicit val http4sTestingArbitraryForRetryAfterHeader: Arbitrary[headers.`Retry-After`] =
Arbitrary {
for {
Expand Down
@@ -0,0 +1,12 @@
/*
* Copyright 2013-2020 http4s.org
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.http4s
package headers

final class AccessControlAllowHeadersSpec extends HeaderLaws {
checkAll("Access-Control-Allow-Headers", headerLaws(`Access-Control-Allow-Headers`))
}
15 changes: 15 additions & 0 deletions tests/src/test/scala/org/http4s/parser/SimpleHeadersSpec.scala
Expand Up @@ -30,6 +30,21 @@ class SimpleHeadersSpec extends Http4sSpec {
HttpHeaderParser.parseHeader(bad) must beLeft
}

"parse Access-Control-Allow-Headers" in {
val header = `Access-Control-Allow-Headers`(
NonEmptyList.of(
CIString("Accept"),
CIString("Expires"),
CIString("X-Custom-Header"),
CIString("*")
)
)
HttpHeaderParser.parseHeader(header.toRaw) must beRight(header)

val invalidHeader = Header(header.name.toString, "(non-token-name), non[&token]name")
HttpHeaderParser.parseHeader(invalidHeader) must beLeft
}

"parse Connection" in {
val header = Connection(CIString("closed"))
HttpHeaderParser.parseHeader(header.toRaw) must beRight(header)
Expand Down