-
Notifications
You must be signed in to change notification settings - Fork 0
/
Response.scala
56 lines (48 loc) · 1.66 KB
/
Response.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package compose.http
import java.io.{ InputStream, OutputStream, OutputStreamWriter }
import scala.annotation.implicitNotFound
import compose.http.Response.Renderer.Failure
case class Response(
version: Version,
status: Status,
headers: Headers,
body: InputStream,
) {
lazy val statusLine: String = s"${version} ${status}\r\n"
def writeTo(out: OutputStream): Unit = {
val writer = new OutputStreamWriter(out, Headers.encoding)
writer.write(statusLine)
writer.write(headers.render)
writer.write("\r\n\r\n")
writer.flush()
body.transferTo(out)
}
}
object Response {
def apply[B: Renderer](
rawBody: B,
version: Version = Version.HTTP_1_1,
status: Status = Status.OK,
headers: Headers = Headers.empty,
): Response = Renderer[B].render(rawBody) match {
case Renderer.Success(defaultHeaders, bodyStream) => Response(version, status, defaultHeaders.replace(headers), bodyStream)
case Renderer.Failure(errorMessage) =>
Response[String](
errorMessage,
version = version,
status = Status.InternalServerError,
headers = headers
)(compose.rendering.implicits.stringRenderer)
}
@implicitNotFound("No renderer found for type ${B}")
trait Renderer[-B] {
def render(body: B): Renderer.Result
}
object Renderer {
def instance[B](rf: B => Renderer.Result): Renderer[B] = new Renderer[B] { def render(body: B): Renderer.Result = rf(body) }
def apply[B](implicit r: Renderer[B]): Renderer[B] = r
sealed trait Result
case class Success(defaultHeaders: Headers, bodyStream: InputStream) extends Result
case class Failure(errorMessage: String) extends Result
}
}