Skip to content

Commit

Permalink
testing integration with http-wasm TCK
Browse files Browse the repository at this point in the history
  • Loading branch information
Zwiterrion committed May 24, 2024
1 parent 99393e6 commit 21428f9
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 27 deletions.
5 changes: 4 additions & 1 deletion otoroshi/app/wasm/httpwasm/HttpWasmState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ class HttpWasmState(env: Env) {

println(s"get protocol version $httpVersion")

// vmData.setRequest(vmData.request.copy(version = httpVersion))

this.writeStringIfUnderLimit (plugin, buf, bufLimit, httpVersion)
}

Expand Down Expand Up @@ -284,14 +286,15 @@ class HttpWasmState(env: Env) {
value: Int,
valueLen: Int
) = {
println("set header value call")
if (nameLen == 0) {
throw new RuntimeException("HTTP header name cannot be empty")
}

val n = this.mustReadString (plugin, "name", name, nameLen)
val v = this.mustReadString (plugin, "value", value, valueLen)

println(s"Set header with $kind - $name - $value")

vmData.setHeader (kind, n, Seq(v))
}

Expand Down
116 changes: 90 additions & 26 deletions otoroshi/app/wasm/httpwasm/httpwasm.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package otoroshi.wasm.httpwasm

import akka.stream.Materializer
import akka.stream.scaladsl.Source
import akka.util.ByteString
import io.otoroshi.wasm4s.scaladsl._
import org.extism.sdk.wasmotoroshi._
Expand All @@ -17,7 +18,7 @@ import play.api._
import play.api.libs.json._
import play.api.libs.typedmap.TypedKey
import play.api.mvc.Results.{Ok, Status}
import play.api.mvc.{RequestHeader, Results}
import play.api.mvc.{RequestHeader, Result, Results}

import java.util.Optional
import java.util.concurrent.atomic._
Expand All @@ -43,16 +44,13 @@ class HttpWasmPlugin(wasm: WasmConfig, key: String, env: Env) {
}

def start(attrs: TypedMap): Future[Unit] = {
println("Create vm with custom functions")
pool.getPooledVm(WasmVmInitOptions(
importDefaultHostFunctions = false,
resetMemory = true,
addHostFunctions = createFunctions
)).flatMap { vm =>
println("VM created")
attrs.put(otoroshi.wasm.httpwasm.HttpWasmPluginKeys.HttpWasmVmKey -> vm)
vm.finitialize {
println("VM initialized")
Future.successful(())
}
}
Expand Down Expand Up @@ -86,7 +84,6 @@ class NgHttpWasm extends NgRequestTransformer {

private def handleResponse(vm: WasmVm, vmData: HttpWasmVmData, reqCtx: Int, isError: Int)
(implicit env: Env, ec: ExecutionContext) = {
println(s"calling handle_response with reqCtx $reqCtx")
vm.call(
WasmFunctionParameters.NoResult("handle_response", new Parameters(2).pushInts(reqCtx, isError)),
vmData.some
Expand Down Expand Up @@ -118,27 +115,18 @@ class NgHttpWasm extends NgRequestTransformer {
).map(r => Left(r))
}
case Right(res) =>
println("ending handle_Request and get result")
val ctxNext = res.results.getValue(0).v.i64

println(s"handle request has returned $ctxNext")

val data = vmData.get
if ((ctxNext & 0x1) != 0x1) {
println("returning response as guest asked")
Left(data.response.asResult).future
} else {
data.nextCalled = true

val reqCtx = ctxNext >> 32
handleResponse(vm, data, reqCtx.toInt, 0)

println(s"request has body ${data.request.hasBody}")

implicit val mat = env.otoroshiMaterializer
data.request.body.runFold(ByteString.empty)(_ ++ _).map { bodyRaw =>
println(bodyRaw)
}

if (data.request.hasBody) {
Right(ctx.otoroshiRequest.copy(
Expand All @@ -158,23 +146,99 @@ class NgHttpWasm extends NgRequestTransformer {
}
}

override def transformRequest(
ctx: NgTransformerRequestContext
)(implicit env: Env, ec: ExecutionContext, mat: Materializer):
Future[Either[mvc.Result, NgPluginHttpRequest]] = {
println("Calling transform request")
ctx.attrs.get(otoroshi.wasm.httpwasm.HttpWasmPluginKeys.HttpWasmVmKey) match {
case None =>
println("no vm found in attrs")
Future.failed(new RuntimeException("no vm found in attrs"))
case Some(vm) => execute(vm, ctx)
}
}
// override def transformRequest(
// ctx: NgTransformerRequestContext
// )(implicit env: Env, ec: ExecutionContext, mat: Materializer):
// Future[Either[mvc.Result, NgPluginHttpRequest]] = {
// println("Calling transform request")
// ctx.attrs.get(otoroshi.wasm.httpwasm.HttpWasmPluginKeys.HttpWasmVmKey) match {
// case None =>
// println("no vm found in attrs")
// Future.failed(new RuntimeException("no vm found in attrs"))
// case Some(vm) => execute(vm, ctx)
// }
// }

override def afterRequest(
ctx: NgAfterRequestContext
)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Future[Unit] = {
ctx.attrs.get(otoroshi.wasm.httpwasm.HttpWasmPluginKeys.HttpWasmVmKey).foreach(_.release())
().vfuture
}

override def transformResponse(
ctx: NgTransformerResponseContext
)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Future[Either[Result, NgPluginHttpResponse]] = {
ctx.attrs.get(otoroshi.wasm.httpwasm.HttpWasmPluginKeys.HttpWasmVmKey) match {
case None =>
println("no vm found in attrs")
Future.failed(new RuntimeException("no vm found in attrs"))
case Some(vm) =>
val vmData = HttpWasmVmData
.withRequest(NgPluginHttpRequest(
headers = ctx.otoroshiResponse.headers,
url = ctx.request.uri,
method = ctx.request.method,
version = ctx.request.version,
clientCertificateChain = () => None,
cookies = Seq.empty,
body = Source.empty,
backend = None
))
vmData.response = vmData.response.copy(
headers = ctx.otoroshiResponse.headers,
status = ctx.otoroshiResponse.status,
cookies = ctx.otoroshiResponse.cookies,
body = ctx.otoroshiResponse.body
)

vm.callWithParamsAndResult("handle_request",
new Parameters(0),
1,
None,
vmData.some
)
.flatMap {
case Left(error) => {
Errors.craftResponseResult(
error.toString(),
Status(401),
ctx.request,
None,
None,
attrs = TypedMap.empty
).map(r => Left(r))
}
case Right(res) =>
val ctxNext = res.results.getValue(0).v.i64

val data = vmData
if ((ctxNext & 0x1) != 0x1) {
Left(data.response.asResult).future
} else {
data.nextCalled = true

val reqCtx = ctxNext >> 32
handleResponse(vm, data, reqCtx.toInt, 0)

implicit val mat = env.otoroshiMaterializer

if (data.request.hasBody) {
Right(ctx.otoroshiResponse.copy(
headers = data.response.headers,
status = data.response.status,
cookies = data.response.cookies,
body = data.response.body,
)).future
} else {
Right(ctx.otoroshiResponse.copy(
headers = data.response.headers,
status = data.response.status,
cookies = data.response.cookies
)).future
}
}
}
}
}
}
Binary file removed otoroshi/conf/wasm/httpwasm/handle_response.wasm
Binary file not shown.
Binary file removed otoroshi/conf/wasm/httpwasm/header_names.wasm
Binary file not shown.
Binary file removed otoroshi/conf/wasm/httpwasm/header_value.wasm
Binary file not shown.
Binary file removed otoroshi/conf/wasm/httpwasm/method.wasm
Binary file not shown.
Binary file removed otoroshi/conf/wasm/httpwasm/router.wasm
Binary file not shown.

0 comments on commit 21428f9

Please sign in to comment.