Permalink
Browse files

Added support for BytesContent in response (Resolves #78)

Added convenience support for Content.json to send Circe JSON easily
  • Loading branch information...
darkfrog26 committed Feb 2, 2019
1 parent 55bdb2e commit 43916a748f331a6ca3c4c2668954a80615b1fa2b
@@ -3,6 +3,7 @@ package io.youi.http.content
import java.io.File
import java.net.URL

import io.circe.{Json, Printer}
import io.youi.net.ContentType

import scala.xml.Elem
@@ -23,6 +24,10 @@ trait SharedContentHelpers {
val empty: Content = string("", ContentType.`text/plain`)
lazy val form: FormDataContent = FormDataContent(Nil)

def json(value: Json, pretty: Boolean = false): Content = {
val printer = if (pretty) Printer.spaces2 else Printer.noSpaces
bytes(value.pretty(printer).getBytes, ContentType.`application/json`)
}
def string(value: String, contentType: ContentType): Content = StringContent(value, contentType)
def bytes(value: Array[Byte], contentType: ContentType): Content = BytesContent(value, contentType)
def classPath(path: String): Content = classPathOption(path).getOrElse(throw new RuntimeException(s"Invalid URL or not found in class-loader: $path."))
@@ -2,9 +2,11 @@ package io.youi.example

import io.youi.app._
import io.youi.http._
import io.youi.http.content.Content
import io.youi.net._
import io.youi.server.handler.{CachingManager, ProxyCache}
import io.youi.server.dsl._
import profig.JsonUtil

import scala.concurrent.Future
import scribe.Execution.global
@@ -15,6 +17,8 @@ object ServerExampleApplication extends ExampleApplication with ServerApplicatio
override protected def applicationBasePath = s"app/youi-example"
override protected def applicationJSBasePath = s"/app/example"

case class Greeting(message: String, name: String)

override protected def init(): Future[Unit] = super.init().map { _ =>
// TODO: add support to `Connection` to add deltas so they may all be processed at the end
proxies += ProxyHandler(path.exact("/proxy.html")) { url =>
@@ -24,6 +28,7 @@ object ServerExampleApplication extends ExampleApplication with ServerApplicatio
filters(
path"/" / redirect(path"/ui-examples.html"),
path"/hello.txt" / CachingManager.MaxAge(120L) / "Hello, World!".withContentType(ContentType.`text/plain`),
path"/hello.json" / Content.json(JsonUtil.toJson(Greeting("Hello", "World"))),
combined.any(
path.matches("/examples/.*[.]html"),
path.exact("/ui-examples.html")
@@ -2,6 +2,7 @@ package io.youi.server

import java.io.IOException
import java.net.URI
import java.nio.ByteBuffer

import io.undertow.io.{IoCallback, Sender}
import io.undertow.predicate.Predicates
@@ -274,6 +275,7 @@ object UndertowServerImplementation extends ServerImplementationCreator {

// Set the Content-Length from Content if not already set on the response
if (Headers.`Content-Length`.value(response.headers).isEmpty && content.length != -1L) {
scribe.info(s"Setting content-length: ${content.length}")
response = response.withHeader(Headers.`Content-Length`(content.length))
}

@@ -322,6 +324,23 @@ object UndertowServerImplementation extends ServerImplementationCreator {
}
})
}
case c: BytesContent => {
val buffer = ByteBuffer.wrap(c.value)
exchange.getResponseSender.send(buffer, new IoCallback {
override def onComplete(exchange: HttpServerExchange, sender: Sender): Unit = {
sender.close()
}

override def onException(exchange: HttpServerExchange, sender: Sender, exception: IOException): Unit = {
sender.close()
if (exception.getMessage == "Stream closed") {
scribe.warn("Stream closed for BytesContent")
} else {
impl.server.error(exception)
}
}
})
}
case c: StreamContent => {
val runnable = new Runnable {
override def run(): Unit = try {

0 comments on commit 43916a7

Please sign in to comment.