wasm.proxywasm.api.scala Maven / Gradle / Ivy
package otoroshi.wasm.proxywasm
import akka.util.ByteString
import com.sun.jna.Pointer
import io.otoroshi.wasm4s.scaladsl.WasmVmData
import org.extism.sdk.{ExtismCurrentPlugin, HostUserData}
import org.extism.sdk.wasmotoroshi._
import otoroshi.env.Env
import otoroshi.next.models.NgRoute
import otoroshi.next.plugins.api.NgPluginHttpResponse
import otoroshi.utils.TypedMap
import otoroshi.utils.http.RequestImplicits._
import otoroshi.utils.syntax.implicits._
import play.api.libs.json.JsValue
import play.api.mvc
import play.api.mvc.RequestHeader
import java.util.concurrent.atomic.AtomicReference
object VmData {
def empty(): VmData = VmData(
configuration = "",
properties = Map.empty,
tickPeriod = -1,
respRef = new AtomicReference[mvc.Result](null),
bodyInRef = new AtomicReference[ByteString](null),
bodyOutRef = new AtomicReference[ByteString](null),
requestRef = None,
routeRef = None
)
def withRules(rules: JsValue): VmData = VmData.empty().copy(configuration = rules.stringify)
def from(request: RequestHeader, route: Option[NgRoute], attrs: TypedMap)(implicit env: Env): VmData = {
val remote = request.headers
.get("remote-address")
.getOrElse(s"${request.connection.remoteAddress.toString.substring(1)}:${1234}")
new VmData(
configuration = "",
respRef = new AtomicReference[play.api.mvc.Result](null),
bodyInRef = new AtomicReference[ByteString](null),
bodyOutRef = new AtomicReference[ByteString](null),
requestRef = Some(request),
routeRef = route,
tickPeriod = -1,
properties = Map(
"plugin_name" -> "foo".bytes,
"plugin_root_id" -> "foo".bytes,
"plugin_vm_id" -> "foo".bytes,
"cluster_name" -> "foo".bytes,
"route_name" -> "foo".bytes,
"source.address" -> remote.bytes,
//"source.port" -> remote.split(":")(1).toLong.bytes,
"destination.address" -> s"${request.theDomain}:${env.httpPort}".bytes,
//"destination.port" -> env.httpPort.toLong.bytes,
"request.path" -> request.uri.bytes,
"request.url_path" -> request.thePath.bytes,
"request.host" -> request.host.bytes,
"request.scheme" -> request.theProtocol.bytes,
"request.method" -> request.method.bytes,
"request.protocol" -> request.version.bytes,
"request.query" -> request.rawQueryString.bytes,
":method" -> request.method.bytes,
":path" -> request.thePath.bytes,
":authority" -> request.host.bytes,
":scheme" -> request.theProtocol.bytes
)
.applyOnWithOpt(request.headers.get("x-request-id")) { case (props, value) =>
props ++ Map("request.id" -> value.bytes)
}
.applyOnWithOpt(request.headers.get("Referer")) { case (props, value) =>
props ++ Map("request.referer" -> value.bytes)
}
.applyOnWithOpt(request.headers.get("User-Agent")) { case (props, value) =>
props ++ Map("request.useragent" -> value.bytes)
}
.applyOnWithOpt(attrs.get(otoroshi.plugins.Keys.RequestTimestampKey)) { case (props, value) =>
props ++ Map("request.time" -> value.toDate.getTime.toString.bytes)
}
.applyOn { props =>
props ++ request.headers.toSimpleMap
.filterNot(_._1.toLowerCase() == "tls-session-info")
.filterNot(_._1.toLowerCase() == "timeout-access")
.map { case (key, value) =>
s"request.headers.${key.toLowerCase()}" -> value.bytes
}
}
)
}
}
case class VmData(
configuration: String,
properties: Map[String, Array[Byte]],
tickPeriod: Int = -1,
respRef: AtomicReference[play.api.mvc.Result],
bodyInRef: AtomicReference[ByteString],
bodyOutRef: AtomicReference[ByteString],
requestRef: Option[RequestHeader],
routeRef: Option[NgRoute]
) extends HostUserData
with WasmVmData {
def withRequest(request: RequestHeader, route: Option[NgRoute], attrs: TypedMap)(implicit env: Env): VmData = {
VmData
.from(request, route, attrs)
.copy(
configuration = configuration,
tickPeriod = tickPeriod,
respRef = respRef,
bodyInRef = bodyInRef,
bodyOutRef = bodyOutRef
)
}
def withResponse(response: NgPluginHttpResponse, attrs: TypedMap, body_bytes: Option[ByteString])(implicit
env: Env
): VmData = {
val newProps: Map[String, Array[Byte]] = properties ++ Map(
"response.code" -> response.status.bytes,
"response.code_details" -> "".bytes,
//"response.flags" -> -1.bytes,
//"response.grpc_status" -> -1.bytes,
":status" -> response.status.toString.bytes
)
.applyOnWithOpt(body_bytes.map(_.size).orElse(response.contentLength)) { case (props, len) =>
props ++ Map(
"response.size" -> len.toString.bytes,
"response.headers.content-length" -> len.toString.bytes
)
}
.applyOn { props =>
props ++ response.headers.map { case (key, value) =>
s"response.headers.${key.toLowerCase()}" -> value.bytes
}
}
copy(
configuration = configuration,
properties = newProps,
tickPeriod = tickPeriod,
respRef = respRef,
bodyInRef = bodyInRef,
bodyOutRef = bodyOutRef,
requestRef = requestRef,
routeRef = routeRef
)
}
def httpResponse: Option[play.api.mvc.Result] = Option(respRef.get())
def bodyIn: Option[ByteString] = Option(bodyInRef.get())
def bodyOut: Option[ByteString] = Option(bodyOutRef.get())
def request: Option[RequestHeader] = requestRef
def route: Option[NgRoute] = routeRef
}
trait Api {
def proxyLog(plugin: ExtismCurrentPlugin, logLevel: Int, messageData: Int, messageSize: Int, data: VmData): Result
def proxyResumeStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result
def proxyCloseStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result
def proxySendHttpResponse(
plugin: ExtismCurrentPlugin,
responseCode: Int,
responseCodeDetailsData: Int,
responseCodeDetailsSize: Int,
responseBodyData: Int,
responseBodySize: Int,
additionalHeadersMapData: Int,
additionalHeadersSize: Int,
grpcStatus: Int,
vmData: VmData
): Result
def proxyResumeHttpStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result
def proxyCloseHttpStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result
def getBuffer(plugin: ExtismCurrentPlugin, data: VmData, bufferType: BufferType): IoBuffer
def proxyGetBuffer(
plugin: ExtismCurrentPlugin,
data: VmData,
bufferType: Int,
offset: Int,
maxSize: Int,
returnBufferData: Int,
returnBufferSize: Int
): Result
def proxySetBuffer(
plugin: ExtismCurrentPlugin,
data: VmData,
bufferType: Int,
offset: Int,
size: Int,
bufferData: Int,
bufferSize: Int
): Result
def getMap(plugin: ExtismCurrentPlugin, data: VmData, mapType: MapType): Map[String, ByteString]
def copyMapIntoInstance(
m: Map[String, String],
plugin: ExtismCurrentPlugin,
returnMapData: Int,
returnMapSize: Int
): Unit
def proxyGetHeaderMapPairs(
plugin: ExtismCurrentPlugin,
data: VmData,
mapType: Int,
returnDataPtr: Int,
returnDataSize: Int
): Int
def proxyGetHeaderMapValue(
plugin: ExtismCurrentPlugin,
data: VmData,
mapType: Int,
keyData: Int,
keySize: Int,
valueData: Int,
valueSize: Int
): Result
def proxyReplaceHeaderMapValue(
plugin: ExtismCurrentPlugin,
data: VmData,
mapType: Int,
keyData: Int,
keySize: Int,
valueData: Int,
valueSize: Int
): Result
def proxyOpenSharedKvstore(
plugin: ExtismCurrentPlugin,
kvstoreNameData: Int,
kvstoreNameSiz: Int,
createIfNotExist: Int,
kvstoreID: Int
): Result
def proxyGetSharedKvstoreKeyValues(
plugin: ExtismCurrentPlugin,
kvstoreID: Int,
keyData: Int,
keySize: Int,
returnValuesData: Int,
returnValuesSize: Int,
returnCas: Int
): Result
def proxySetSharedKvstoreKeyValues(
plugin: ExtismCurrentPlugin,
kvstoreID: Int,
keyData: Int,
keySize: Int,
valuesData: Int,
valuesSize: Int,
cas: Int
): Result
def proxyAddSharedKvstoreKeyValues(
plugin: ExtismCurrentPlugin,
kvstoreID: Int,
keyData: Int,
keySize: Int,
valuesData: Int,
valuesSize: Int,
cas: Int
): Result
def proxyRemoveSharedKvstoreKey(
plugin: ExtismCurrentPlugin,
kvstoreID: Int,
keyData: Int,
keySize: Int,
cas: Int
): Result
def proxyDeleteSharedKvstore(plugin: ExtismCurrentPlugin, kvstoreID: Int): Result
def proxyOpenSharedQueue(
plugin: ExtismCurrentPlugin,
queueNameData: Int,
queueNameSize: Int,
createIfNotExist: Int,
returnQueueID: Int
): Result
def proxyDequeueSharedQueueItem(
plugin: ExtismCurrentPlugin,
queueID: Int,
returnPayloadData: Int,
returnPayloadSize: Int
): Result
def proxyEnqueueSharedQueueItem(
plugin: ExtismCurrentPlugin,
queueID: Int,
payloadData: Int,
payloadSize: Int
): Result
def proxyDeleteSharedQueue(plugin: ExtismCurrentPlugin, queueID: Int): Result
def proxyCreateTimer(plugin: ExtismCurrentPlugin, period: Int, oneTime: Int, returnTimerID: Int): Result
def proxyDeleteTimer(plugin: ExtismCurrentPlugin, timerID: Int): Result
def proxyCreateMetric(
plugin: ExtismCurrentPlugin,
metricType: MetricType,
metricNameData: Int,
metricNameSize: Int,
returnMetricID: Int
): MetricType
def proxyGetMetricValue(plugin: ExtismCurrentPlugin, metricID: Int, returnValue: Int): Result
def proxySetMetricValue(plugin: ExtismCurrentPlugin, metricID: Int, value: Int): Result
def proxyIncrementMetricValue(plugin: ExtismCurrentPlugin, data: VmData, metricID: Int, offset: Long): Result
def proxyDeleteMetric(plugin: ExtismCurrentPlugin, metricID: Int): Result
def proxyDefineMetric(
plugin: ExtismCurrentPlugin,
metricType: Int,
namePtr: Int,
nameSize: Int,
returnMetricId: Int
): Result
def proxyDispatchHttpCall(
plugin: ExtismCurrentPlugin,
upstreamNameData: Int,
upstreamNameSize: Int,
headersMapData: Int,
headersMapSize: Int,
bodyData: Int,
bodySize: Int,
trailersMapData: Int,
trailersMapSize: Int,
timeoutMilliseconds: Int,
returnCalloutID: Int
): Result
def proxyDispatchGrpcCall(
plugin: ExtismCurrentPlugin,
upstreamNameData: Int,
upstreamNameSize: Int,
serviceNameData: Int,
serviceNameSize: Int,
serviceMethodData: Int,
serviceMethodSize: Int,
initialMetadataMapData: Int,
initialMetadataMapSize: Int,
grpcMessageData: Int,
grpcMessageSize: Int,
timeoutMilliseconds: Int,
returnCalloutID: Int
): Result
def proxyOpenGrpcStream(
plugin: ExtismCurrentPlugin,
upstreamNameData: Int,
upstreamNameSize: Int,
serviceNameData: Int,
serviceNameSize: Int,
serviceMethodData: Int,
serviceMethodSize: Int,
initialMetadataMapData: Int,
initialMetadataMapSize: Int,
returnCalloutID: Int
): Result
def proxySendGrpcStreamMessage(
plugin: ExtismCurrentPlugin,
calloutID: Int,
grpcMessageData: Int,
grpcMessageSize: Int
): Result
def proxyCancelGrpcCall(plugin: ExtismCurrentPlugin, calloutID: Int): Result
def proxyCloseGrpcCall(plugin: ExtismCurrentPlugin, calloutID: Int): Result
def proxyCallCustomFunction(
plugin: ExtismCurrentPlugin,
customFunctionID: Int,
parametersData: Int,
parametersSize: Int,
returnResultsData: Int,
returnResultsSize: Int
): Result
def copyIntoInstance(
plugin: ExtismCurrentPlugin,
memory: Pointer,
value: IoBuffer,
retPtr: Int,
retSize: Int
): Result
def proxyGetProperty(
plugin: ExtismCurrentPlugin,
data: VmData,
keyPtr: Int,
keySize: Int,
returnValueData: Int,
returnValueSize: Int
): Result
def proxyRegisterSharedQueue(nameData: ByteString, nameSize: Int, returnID: Int): Status
def proxyResolveSharedQueue(
vmIDData: ByteString,
vmIDSize: Int,
nameData: ByteString,
nameSize: Int,
returnID: Int
): Status
def proxyEnqueueSharedQueue(queueID: Int, valueData: ByteString, valueSize: Int): Status
def proxyDequeueSharedQueue(queueID: Int, returnValueData: ByteString, returnValueSize: Int): Status
def proxyDone(): Status
def proxySetTickPeriodMilliseconds(data: VmData, period: Int): Status
def proxySetEffectiveContext(plugin: ExtismCurrentPlugin, contextID: Int): Status
def getPluginConfig(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getHttpRequestBody(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getHttpResponseBody(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getDownStreamData(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getUpstreamData(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getHttpCalloutResponseBody(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getVmConfig(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer
def getCustomBuffer(bufferType: BufferType): IoBuffer
def getHttpRequestHeader(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpRequestTrailer(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpRequestMetadata(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpResponseHeader(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpResponseTrailer(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpResponseMetadata(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpCallResponseHeaders(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpCallResponseTrailer(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getHttpCallResponseMetadata(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString]
def getCustomMap(plugin: ExtismCurrentPlugin, data: VmData, mapType: MapType): Map[String, ByteString]
def getMemory(plugin: ExtismCurrentPlugin, addr: Int, size: Int): Either[Error, (Pointer, ByteString)]
def getMemory(plugin: ExtismCurrentPlugin): Either[Error, Pointer]
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy