Merge pull request #19685 from johanandren/wip-19674-http-header-request-or-response-audit-johanandren
!htt #19674 Audit HTTP headers and mark correctly as response or request
This commit is contained in:
commit
4116ba5d45
2 changed files with 100 additions and 13 deletions
|
|
@ -171,7 +171,7 @@ object `Accept-Ranges` extends ModeledCompanion[`Accept-Ranges`] {
|
|||
implicit val rangeUnitsRenderer = Renderer.defaultSeqRenderer[RangeUnit] // cache
|
||||
}
|
||||
final case class `Accept-Ranges`(rangeUnits: immutable.Seq[RangeUnit]) extends jm.headers.AcceptRanges
|
||||
with RequestHeader {
|
||||
with ResponseHeader {
|
||||
import `Accept-Ranges`.rangeUnitsRenderer
|
||||
def renderValue[R <: Rendering](r: R): r.type = if (rangeUnits.isEmpty) r ~~ "none" else r ~~ rangeUnits
|
||||
protected def companion = `Accept-Ranges`
|
||||
|
|
@ -400,7 +400,7 @@ object `Content-Range` extends ModeledCompanion[`Content-Range`] {
|
|||
def apply(byteContentRange: ByteContentRange): `Content-Range` = apply(RangeUnits.Bytes, byteContentRange)
|
||||
}
|
||||
final case class `Content-Range`(rangeUnit: RangeUnit, contentRange: ContentRange) extends jm.headers.ContentRange
|
||||
with RequestResponseHeader {
|
||||
with ResponseHeader {
|
||||
def renderValue[R <: Rendering](r: R): r.type = r ~~ rangeUnit ~~ ' ' ~~ contentRange
|
||||
protected def companion = `Content-Range`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@
|
|||
package akka.http.scaladsl.model.headers
|
||||
|
||||
import akka.http.impl.util._
|
||||
import org.scalatest.{ FreeSpec, MustMatchers }
|
||||
import org.scalatest._
|
||||
|
||||
import akka.http.scaladsl.model._
|
||||
|
||||
class HeaderSpec extends FreeSpec with MustMatchers {
|
||||
class HeaderSpec extends FreeSpec with Matchers {
|
||||
"ModeledCompanion should" - {
|
||||
"provide parseFromValueString method" - {
|
||||
"successful parse run" in {
|
||||
headers.`Cache-Control`.parseFromValueString("private, no-cache, no-cache=Set-Cookie, proxy-revalidate, s-maxage=1000") mustEqual
|
||||
headers.`Cache-Control`.parseFromValueString("private, no-cache, no-cache=Set-Cookie, proxy-revalidate, s-maxage=1000") shouldEqual
|
||||
Right(headers.`Cache-Control`(
|
||||
CacheDirectives.`private`(),
|
||||
CacheDirectives.`no-cache`,
|
||||
|
|
@ -23,8 +23,8 @@ class HeaderSpec extends FreeSpec with MustMatchers {
|
|||
}
|
||||
"failing parse run" in {
|
||||
val Left(List(ErrorInfo(summary, detail))) = headers.`Last-Modified`.parseFromValueString("abc")
|
||||
summary mustEqual "Illegal HTTP header 'Last-Modified': Invalid input 'a', expected IMF-fixdate, asctime-date or '0' (line 1, column 1)"
|
||||
detail mustEqual
|
||||
summary shouldEqual "Illegal HTTP header 'Last-Modified': Invalid input 'a', expected IMF-fixdate, asctime-date or '0' (line 1, column 1)"
|
||||
detail shouldEqual
|
||||
"""abc
|
||||
|^""".stripMarginWithNewline("\n")
|
||||
|
||||
|
|
@ -35,12 +35,12 @@ class HeaderSpec extends FreeSpec with MustMatchers {
|
|||
"MediaType should" - {
|
||||
"provide parse method" - {
|
||||
"successful parse run" in {
|
||||
MediaType.parse("application/gnutar") mustEqual Right(MediaTypes.`application/gnutar`)
|
||||
MediaType.parse("application/gnutar") shouldEqual Right(MediaTypes.`application/gnutar`)
|
||||
}
|
||||
"failing parse run" in {
|
||||
val Left(List(ErrorInfo(summary, detail))) = MediaType.parse("application//gnutar")
|
||||
summary mustEqual "Illegal HTTP header 'Content-Type': Invalid input '/', expected subtype (line 1, column 13)"
|
||||
detail mustEqual
|
||||
summary shouldEqual "Illegal HTTP header 'Content-Type': Invalid input '/', expected subtype (line 1, column 13)"
|
||||
detail shouldEqual
|
||||
"""application//gnutar
|
||||
| ^""".stripMarginWithNewline("\n")
|
||||
}
|
||||
|
|
@ -50,15 +50,102 @@ class HeaderSpec extends FreeSpec with MustMatchers {
|
|||
"ContentType should" - {
|
||||
"provide parse method" - {
|
||||
"successful parse run" in {
|
||||
ContentType.parse("text/plain; charset=UTF8") mustEqual Right(MediaTypes.`text/plain`.withCharset(HttpCharsets.`UTF-8`))
|
||||
ContentType.parse("text/plain; charset=UTF8") shouldEqual Right(MediaTypes.`text/plain`.withCharset(HttpCharsets.`UTF-8`))
|
||||
}
|
||||
"failing parse run" in {
|
||||
val Left(List(ErrorInfo(summary, detail))) = ContentType.parse("text/plain, charset=UTF8")
|
||||
summary mustEqual "Illegal HTTP header 'Content-Type': Invalid input ',', expected tchar, OWS, ws or 'EOI' (line 1, column 11)"
|
||||
detail mustEqual
|
||||
summary shouldEqual "Illegal HTTP header 'Content-Type': Invalid input ',', expected tchar, OWS, ws or 'EOI' (line 1, column 11)"
|
||||
detail shouldEqual
|
||||
"""text/plain, charset=UTF8
|
||||
| ^""".stripMarginWithNewline("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"All request headers should" - {
|
||||
|
||||
"render in request" in {
|
||||
val requestHeaders = Vector[HttpHeader](
|
||||
Accept(MediaRanges.`*/*`),
|
||||
`Accept-Charset`(HttpCharsetRange(HttpCharsets.`UTF-8`)),
|
||||
`Accept-Encoding`(HttpEncodingRange(HttpEncodings.gzip)),
|
||||
`Accept-Language`(LanguageRange(Language("sv_SE"))),
|
||||
`Access-Control-Request-Headers`("Host"),
|
||||
`Access-Control-Request-Method`(HttpMethods.GET),
|
||||
Authorization(BasicHttpCredentials("johan", "correcthorsebatterystaple")),
|
||||
`Cache-Control`(CacheDirectives.`max-age`(3000)),
|
||||
Connection("upgrade"),
|
||||
`Content-Length`(2000),
|
||||
`Content-Disposition`(ContentDispositionTypes.inline),
|
||||
`Content-Encoding`(HttpEncodings.gzip),
|
||||
`Content-Type`(ContentTypes.`text/xml(UTF-8)`),
|
||||
Cookie("cookie", "with-chocolate"),
|
||||
Date(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
Expect.`100-continue`,
|
||||
Host("example.com"),
|
||||
`If-Match`(EntityTag("hash")),
|
||||
`If-Modified-Since`(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
`If-None-Match`(EntityTagRange(EntityTag("hashhash"))),
|
||||
`If-Range`(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
`If-Unmodified-Since`(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
Link(Uri("http://example.com"), LinkParams.`title*`("example")),
|
||||
Origin(HttpOrigin("http", Host("example.com"))),
|
||||
`Proxy-Authorization`(BasicHttpCredentials("johan", "correcthorsebatterystaple")),
|
||||
Range(RangeUnits.Bytes, Vector(ByteRange(1, 1024))),
|
||||
Referer(Uri("http://example.com/")),
|
||||
`Sec-WebSocket-Protocol`(Vector("chat", "superchat")),
|
||||
`Sec-WebSocket-Key`("dGhlIHNhbXBsZSBub25jZQ"),
|
||||
`Sec-WebSocket-Version`(Vector(13)),
|
||||
`Transfer-Encoding`(TransferEncodings.chunked),
|
||||
Upgrade(Vector(UpgradeProtocol("HTTP", Some("2.0")))),
|
||||
`User-Agent`("Akka HTTP Client 2.4"),
|
||||
`X-Forwarded-For`(RemoteAddress("192.168.0.1")))
|
||||
|
||||
requestHeaders.foreach { header ⇒
|
||||
header shouldBe 'renderInRequests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"All response headers should" - {
|
||||
|
||||
"render in response" in {
|
||||
val responseHeaders = Vector[HttpHeader](
|
||||
`Accept-Ranges`(RangeUnits.Bytes),
|
||||
`Access-Control-Allow-Credentials`(true),
|
||||
`Access-Control-Allow-Headers`("X-Custom"),
|
||||
`Access-Control-Allow-Methods`(HttpMethods.GET),
|
||||
`Access-Control-Allow-Origin`(HttpOrigin("http://example.com")),
|
||||
`Access-Control-Expose-Headers`("X-Custom"),
|
||||
`Access-Control-Max-Age`(2000),
|
||||
Age(2000),
|
||||
Allow(HttpMethods.GET),
|
||||
`Cache-Control`(CacheDirectives.`no-cache`),
|
||||
Connection("close"),
|
||||
`Content-Length`(2000),
|
||||
`Content-Disposition`(ContentDispositionTypes.inline),
|
||||
`Content-Encoding`(HttpEncodings.gzip),
|
||||
`Content-Range`(ContentRange.Default(1, 20, None)),
|
||||
`Content-Type`(ContentTypes.`text/xml(UTF-8)`),
|
||||
Date(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
ETag("suchhashwow"),
|
||||
Expires(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
`Last-Modified`(DateTime(2016, 2, 4, 9, 9, 0)),
|
||||
Link(Uri("http://example.com"), LinkParams.`title*`("example")),
|
||||
Location(Uri("http://example.com")),
|
||||
`Proxy-Authenticate`(HttpChallenge("Basic", "example.com")),
|
||||
`Sec-WebSocket-Accept`("dGhlIHNhbXBsZSBub25jZQ"),
|
||||
`Sec-WebSocket-Extensions`(Vector(WebSocketExtension("foo"))),
|
||||
`Sec-WebSocket-Version`(Vector(13)),
|
||||
Server("Akka-HTTP/2.4"),
|
||||
`Set-Cookie`(HttpCookie("sessionId", "b0eb8b8b3ad246")),
|
||||
`Transfer-Encoding`(TransferEncodings.chunked),
|
||||
Upgrade(Vector(UpgradeProtocol("HTTP", Some("2.0")))),
|
||||
`WWW-Authenticate`(HttpChallenge("Basic", "example.com")))
|
||||
|
||||
responseHeaders.foreach { header ⇒
|
||||
header shouldBe 'renderInResponses
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue