Skip to content

Commit

Permalink
Commit code for ticket 1542 Content-Encoding. (zio#1648)
Browse files Browse the repository at this point in the history
* Commit code for ticket 1542 Content-Encoding.

* Commit code removing duplicate test case.

* Commit code moving the import statement to address the build error.
  • Loading branch information
wpoosanguansit authored Oct 17, 2022
1 parent baaef88 commit 68ac888
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package zio.http.model.headers.values

import zio.Chunk

sealed trait ContentEncoding {
val encoding: String
}

object ContentEncoding {

/**
* InvalidEncoding is represented with ""
*/
case object InvalidEncoding extends ContentEncoding {
override val encoding: String = ""
}

/**
* A format using the Brotli algorithm.
*/
case object BrEncoding extends ContentEncoding {
override val encoding: String = "br"
}

/**
* A format using the Lempel-Ziv-Welch (LZW) algorithm. The value name was
* taken from the UNIX compress program, which implemented this algorithm.
* Like the compress program, which has disappeared from most UNIX
* distributions, this content-encoding is not used by many browsers today,
* partly because of a patent issue (it expired in 2003).
*/
case object CompressEncoding extends ContentEncoding {
override val encoding: String = "compress"
}

/**
* Using the zlib structure (defined in RFC 1950) with the deflate compression
* algorithm (defined in RFC 1951).
*/
case object DeflateEncoding extends ContentEncoding {
override val encoding: String = "deflate"
}

/**
* A format using the Lempel-Ziv coding (LZ77), with a 32-bit CRC. This is the
* original format of the UNIX gzip program. The HTTP/1.1 standard also
* recommends that the servers supporting this content-encoding should
* recognize x-gzip as an alias, for compatibility purposes.
*/
case object GZipEncoding extends ContentEncoding {
override val encoding: String = "gzip"
}

/**
* Maintains a list of ContentEncoding values.
*/
final case class MultipleEncodings(encodings: Chunk[ContentEncoding]) extends ContentEncoding {
override val encoding: String = encodings.map(_.encoding).mkString(",")
}

private def findEncoding(value: String): ContentEncoding = {
value.trim match {
case "br" => BrEncoding
case "compress" => CompressEncoding
case "deflate" => DeflateEncoding
case "gzip" => GZipEncoding
case _ => InvalidEncoding
}
}

/**
* @param value
* of string , seperated for multiple values
* @return
* ContentEncoding
*
* Note: This implementation ignores the invalid string that might occur in
* MultipleEncodings case.
*/
def toContentEncoding(value: String): ContentEncoding = {
val array = value.split(",")
array.foldLeft[ContentEncoding](InvalidEncoding)((accum, elem) => {
val encoding = findEncoding(elem)
(accum, encoding) match {
case (InvalidEncoding, InvalidEncoding) => InvalidEncoding
case (InvalidEncoding, other) => other
case (MultipleEncodings(encodings), InvalidEncoding) => MultipleEncodings(encodings)
case (MultipleEncodings(encodings), other) => MultipleEncodings(encodings ++ Chunk(other))
case (other, InvalidEncoding) => other
case (other, other1) => MultipleEncodings(Chunk(other, other1))
}
})
}

def fromContentEncoding(value: ContentEncoding): String = value.encoding

}
10 changes: 10 additions & 0 deletions zio-http/src/test/scala/zio/http/internal/HttpGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,14 @@ object HttpGen {
def connectionHeader: Gen[Any, Connection] =
Gen.elements(Connection.Close, Connection.KeepAlive, Connection.InvalidConnection)

def allowContentEncodingSingleValue: Gen[Any, ContentEncoding] = Gen.fromIterable(
List(
ContentEncoding.BrEncoding,
ContentEncoding.CompressEncoding,
ContentEncoding.GZipEncoding,
ContentEncoding.MultipleEncodings(Chunk(ContentEncoding.BrEncoding, ContentEncoding.CompressEncoding)),
ContentEncoding.DeflateEncoding,
ContentEncoding.InvalidEncoding,
),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package zio.http.model.headers.values

import zio.http.internal.HttpGen
import zio.http.model.headers.values.ContentEncoding.{InvalidEncoding, MultipleEncodings}
import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertTrue, check}
import zio.{Chunk, Scope}

object ContentEncodingSpec extends ZIOSpecDefault {
override def spec: Spec[TestEnvironment with Scope, Any] = suite("ContentEncoding suite")(
suite("ContentEncoding header value transformation should be symmetrical")(
test("gen single value") {
check(HttpGen.allowContentEncodingSingleValue) { value =>
assertTrue(ContentEncoding.toContentEncoding(ContentEncoding.fromContentEncoding(value)) == value)
}
},
test("single value") {
assertTrue(ContentEncoding.toContentEncoding("br") == ContentEncoding.BrEncoding) &&
assertTrue(ContentEncoding.toContentEncoding("compress") == ContentEncoding.CompressEncoding) &&
assertTrue(ContentEncoding.toContentEncoding("deflate") == ContentEncoding.DeflateEncoding) &&
assertTrue(
ContentEncoding.toContentEncoding("deflate, br, compress") == ContentEncoding.MultipleEncodings(
Chunk(ContentEncoding.DeflateEncoding, ContentEncoding.BrEncoding, ContentEncoding.CompressEncoding),
),
) &&
assertTrue(ContentEncoding.toContentEncoding("garbage") == ContentEncoding.InvalidEncoding)

},
test("edge cases") {
assertTrue(
ContentEncoding.toContentEncoding(
ContentEncoding.fromContentEncoding(MultipleEncodings(Chunk())),
) == InvalidEncoding,
) &&
assertTrue(
ContentEncoding.toContentEncoding(
ContentEncoding.fromContentEncoding(
MultipleEncodings(
Chunk(ContentEncoding.DeflateEncoding, ContentEncoding.BrEncoding, ContentEncoding.CompressEncoding),
),
),
) == ContentEncoding.MultipleEncodings(
Chunk(ContentEncoding.DeflateEncoding, ContentEncoding.BrEncoding, ContentEncoding.CompressEncoding),
),
) &&
assertTrue(
ContentEncoding.toContentEncoding(
ContentEncoding.fromContentEncoding(
MultipleEncodings(
Chunk(ContentEncoding.DeflateEncoding),
),
),
) == ContentEncoding.DeflateEncoding,
)
},
),
)
}

0 comments on commit 68ac888

Please sign in to comment.