All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wasm.proxywasm.state.scala Maven / Gradle / Ivy

package otoroshi.wasm

import akka.util.ByteString
import com.sun.jna.Pointer
import org.extism.sdk.ExtismCurrentPlugin
import otoroshi.env.Env
import otoroshi.utils.syntax.implicits._
import otoroshi.wasm.proxywasm.BufferType._
import otoroshi.wasm.proxywasm.MapType._
import otoroshi.wasm.proxywasm.Result._
import otoroshi.wasm.proxywasm.Status._
import otoroshi.wasm.proxywasm.WasmUtils.traceVmHost
import otoroshi.wasm.proxywasm.{IoBuffer, _}
import play.api.Logger

import java.nio.charset.StandardCharsets
import java.util.concurrent.atomic.AtomicInteger

class ProxyWasmState(
    val rootContextId: Int,
    val contextId: AtomicInteger,
    logCallback: Option[Function3[org.slf4j.event.Level, String, VmData, Unit]],
    env: Env
) extends Api {

  val logger = Logger("otoroshi-proxy-wasm")

  val u32Len = 4

  def unimplementedFunction[A](name: String): A = {
    logger.error(s"unimplemented state function: '${name}'")
    throw new NotImplementedError(s"proxy state method '${name}' is not implemented")
  }

  override def proxyLog(
      plugin: ExtismCurrentPlugin,
      logLevel: Int,
      messageData: Int,
      messageSize: Int,
      data: VmData
  ): Result = {
    // println(s"proxyLog: $logLevel - $messageData - $messageSize")
    getMemory(plugin, messageData, messageSize)
      .fold(
        Error.toResult,
        r => {
          val message = r._2.utf8String
          logLevel match {
            case 0 =>
              logger.trace(message)
              logCallback.foreach(_.apply(org.slf4j.event.Level.TRACE, message, data))
            case 1 =>
              logger.debug(message)
              logCallback.foreach(_.apply(org.slf4j.event.Level.DEBUG, message, data))
            case 2 =>
              logger.info(message)
              logCallback.foreach(_.apply(org.slf4j.event.Level.INFO, message, data))
            case 3 =>
              logger.warn(message)
              logCallback.foreach(_.apply(org.slf4j.event.Level.WARN, message, data))
            case _ =>
              logger.error(message)
              logCallback.foreach(_.apply(org.slf4j.event.Level.ERROR, message, data))
          }
          ResultOk
        }
      )
  }

  override def proxyResumeStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result = {
    traceVmHost("proxy_resume_stream")
    null
  }

  override def proxyCloseStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result = {
    traceVmHost("proxy_close_stream")
    null
  }

  override def proxySendHttpResponse(
      plugin: ExtismCurrentPlugin,
      responseCode: Int,
      responseCodeDetailsData: Int,
      responseCodeDetailsSize: Int,
      responseBodyData: Int,
      responseBodySize: Int,
      additionalHeadersMapData: Int,
      additionalHeadersSize: Int,
      grpcStatus: Int,
      vmData: VmData
  ): Result = {
    traceVmHost(s"proxy_send_http_response: ${responseCode} - ${grpcStatus}")
    for {
      codeDetails <- getMemory(plugin, responseCodeDetailsData, responseCodeDetailsSize)
      body        <- getMemory(plugin, responseBodyData, responseBodySize)
      addHeaders  <- getMemory(plugin, additionalHeadersMapData, additionalHeadersSize)
    } yield {
      //WasmContextSlot.getCurrentContext().map(_.asInstanceOf[VmData]).foreach { vmdata =>
      // Json.obj(
      //   "http_status" -> responseCode,
      //   "grpc_code" -> grpcStatus,
      //   "details" -> codeDetails._2.utf8String,
      //   "body" -> body._2.utf8String,
      //   "headers" -> addHeaders._2.utf8String,
      // ).prettify.debugPrintln
      vmData.respRef.set(
        play.api.mvc.Results
          .Status(responseCode)(body._2)
          .withHeaders()    // TODO: read it
          .as("text/plain") // TODO: change it
      )
      //}
    }
    ResultOk
  }

  override def proxyResumeHttpStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result = {
    traceVmHost("proxy_resume_http_stream")
    null
  }

  override def proxyCloseHttpStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result = {
    traceVmHost("proxy_close_http_stream")
    null
  }

  override def getBuffer(plugin: ExtismCurrentPlugin, data: VmData, bufferType: BufferType): IoBuffer = {
    bufferType match {
      case BufferTypeHttpRequestBody      =>
        getHttpRequestBody(plugin, data)
      case BufferTypeHttpResponseBody     =>
        getHttpResponseBody(plugin, data)
      case BufferTypeDownstreamData       =>
        getDownStreamData(plugin, data)
      case BufferTypeUpstreamData         =>
        getUpstreamData(plugin, data)
      //            case BufferTypeHttpCalloutResponseBody:
      //                GetHttpCalloutResponseBody(plugin, data)
      case BufferTypePluginConfiguration  =>
        getPluginConfig(plugin, data)
      case BufferTypeVmConfiguration      =>
        getVmConfig(plugin, data)
      case BufferTypeHttpCallResponseBody =>
        getHttpCalloutResponseBody(plugin, data)
      case _                              =>
        getCustomBuffer(bufferType)
    }
  }

  override def proxyGetBuffer(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      bufferType: Int,
      offset: Int,
      mSize: Int,
      returnBufferData: Int,
      returnBufferSize: Int
  ): Result = {
    traceVmHost("proxy_get_buffer")

    getMemory(plugin)
      .fold(
        _ => ResultBadArgument,
        memory => {
          if (bufferType > BufferType.last) {
            return ResultBadArgument
          }
          val bufferTypePluginConfiguration = getBuffer(plugin, data, BufferType.valueToType(bufferType))

          var maxSize = mSize
          if (offset > offset + maxSize) {
            return ResultBadArgument
          }
          if (offset + maxSize > bufferTypePluginConfiguration.length) {
            maxSize = bufferTypePluginConfiguration.length - offset
          }

          bufferTypePluginConfiguration.drain(offset, offset + maxSize)

          //System.out.println(String.format("%s, %d,%d, %d, %d,", BufferType.valueToType(bufferType), offset, maxSize, returnBufferData, returnBufferSize))
          return copyIntoInstance(plugin, memory, bufferTypePluginConfiguration, returnBufferData, returnBufferSize)
        }
      )
  }

  override def proxySetBuffer(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      bufferType: Int,
      offset: Int,
      size: Int,
      bufferData: Int,
      bufferSize: Int
  ): Result = plugin.synchronized {
    traceVmHost("proxy_set_buffer")
    val buf = getBuffer(plugin, data, BufferType.valueToType(bufferType))
    if (buf == null) {
      return ResultBadArgument
    }

    val memory: Pointer = plugin.customMemoryGet()

    val content = new Array[Byte](bufferSize)
    memory.read(bufferData, content, 0, bufferSize)

    if (offset == 0) {
      if (size == 0 || size >= buf.length) {
        buf.drain(buf.length, -1)
        buf.write(ByteString(content))
      } else {
        return ResultBadArgument
      }
    } else if (offset >= buf.length) {
      buf.write(ByteString(content))
    } else {
      return ResultBadArgument
    }

    ResultOk
  }

  override def getMap(plugin: ExtismCurrentPlugin, vmData: VmData, mapType: MapType): Map[String, ByteString] = {
    mapType match {
      case MapTypeHttpRequestHeaders       => getHttpRequestHeader(plugin, vmData)
      case MapTypeHttpRequestTrailers      => getHttpRequestTrailer(plugin, vmData)
      case MapTypeHttpRequestMetadata      => getHttpRequestMetadata(plugin, vmData)
      case MapTypeHttpResponseHeaders      => getHttpResponseHeader(plugin, vmData)
      case MapTypeHttpResponseTrailers     => getHttpResponseTrailer(plugin, vmData)
      case MapTypeHttpResponseMetadata     => getHttpResponseMetadata(plugin, vmData)
      case MapTypeHttpCallResponseHeaders  => getHttpCallResponseHeaders(plugin, vmData)
      case MapTypeHttpCallResponseTrailers => getHttpCallResponseTrailer(plugin, vmData)
      case MapTypeHttpCallResponseMetadata => getHttpCallResponseMetadata(plugin, vmData)
      case _                               => getCustomMap(plugin, vmData, mapType)
    }
  }

  def copyMapIntoInstance(
      m: Map[String, String],
      plugin: ExtismCurrentPlugin,
      returnMapData: Int,
      returnMapSize: Int
  ): Unit = unimplementedFunction("copyMapIntoInstance")

  override def proxyGetHeaderMapPairs(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      mapType: Int,
      returnDataPtr: Int,
      returnDataSize: Int
  ): Int = {
    traceVmHost("proxy_get_map")
    val header = getMap(plugin, data, MapType.valueToType(mapType))

    if (header == null) {
      return ResultNotFound.value
    }

    var totalBytesLen = u32Len

    header.foreach(entry => {
      val key   = entry._1
      val value = entry._2

      totalBytesLen += u32Len + u32Len                     // keyLen + valueLen
      totalBytesLen += key.length() + 1 + value.length + 1 // key + \0 + value + \0
    })

    // TODO - try to call proxy_on_memory_allocate
    val addr = plugin.customMemoryAlloc(totalBytesLen)

    // TODO - manage error
//        if err != nil {
//            return int32(v2.ResultInvalidMemoryAccess)
//        }

    plugin.synchronized {

      val memory: Pointer = plugin.customMemoryGet()
      memory.setInt(addr, header.size)
      //        if err != nil {
      //            return int32(v2.ResultInvalidMemoryAccess)
      //        }

      var lenPtr  = addr + u32Len
      var dataPtr = lenPtr + (u32Len + u32Len) * header.size

      header.foreach(entry => {
        val k = entry._1
        val v = entry._2

        memory.setInt(lenPtr, k.length())
        lenPtr += u32Len
        memory.setInt(lenPtr, v.length)
        lenPtr += u32Len

        memory.write(dataPtr, k.getBytes(StandardCharsets.UTF_8), 0, k.length())
        dataPtr += k.length()
        memory.setByte(dataPtr, 0)
        dataPtr += 1

        memory.write(dataPtr, v.toArray, 0, v.length)
        dataPtr += v.length
        memory.setByte(dataPtr, 0)
        dataPtr += 1
      })

      memory.setInt(returnDataPtr, addr)
      //        if err != nil {
      //            return int32(v2.ResultInvalidMemoryAccess)
      //        }

      memory.setInt(returnDataSize, totalBytesLen)
      //        if err != nil {
      //            return int32(v2.ResultInvalidMemoryAccess)
      //        }

    }
    ResultOk.value
  }

  override def proxyGetHeaderMapValue(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      mapType: Int,
      keyData: Int,
      keySize: Int,
      valueData: Int,
      valueSize: Int
  ): Result = {
    traceVmHost("proxy_get_header_map_value")
    val m = getMap(plugin, data, MapType.valueToType(mapType))

    if (m == null || keySize == 0) {
      return ResultNotFound
    }

    getMemory(plugin, keyData, keySize)
      .fold(
        Error.toResult,
        mem => {
          val key = mem._2

          if (key.isEmpty) {
            ResultBadArgument
          } else {
            val value = m.get(key.utf8String)
            value
              .map(v => copyIntoInstance(plugin, mem._1, new IoBuffer(v), valueData, valueSize))
              .getOrElse(ResultNotFound)
          }
        }
      )
  }

  override def proxyReplaceHeaderMapValue(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      mapType: Int,
      keyData: Int,
      keySize: Int,
      valueData: Int,
      valueSize: Int
  ): Result = {
    traceVmHost("proxy_set_map_value")
    val m = getMap(plugin, data, MapType.valueToType(mapType))

    if (m == null || keySize == 0) {
      return ResultNotFound
    }

    val memKey   = getMemory(plugin, keyData, keySize)
    val memValue = getMemory(plugin, valueData, valueSize)

    memKey
      .fold(
        Error.toResult,
        key => {
          memValue.fold(
            Error.toResult,
            value => {
              if (key._2.isEmpty) {
                return ResultBadArgument
              }

              // TODO - not working
              m ++ Map(key._2.utf8String -> value._2)

              ResultOk
            }
          )
        }
      )
  }

  override def proxyOpenSharedKvstore(
      plugin: ExtismCurrentPlugin,
      kvstoreNameData: Int,
      kvstoreNameSiz: Int,
      createIfNotExist: Int,
      kvstoreID: Int
  ): Result = unimplementedFunction("proxyOpenSharedKvstore")

  override def proxyGetSharedKvstoreKeyValues(
      plugin: ExtismCurrentPlugin,
      kvstoreID: Int,
      keyData: Int,
      keySize: Int,
      returnValuesData: Int,
      returnValuesSize: Int,
      returnCas: Int
  ): Result = unimplementedFunction("proxyGetSharedKvstoreKeyValues")

  override def proxySetSharedKvstoreKeyValues(
      plugin: ExtismCurrentPlugin,
      kvstoreID: Int,
      keyData: Int,
      keySize: Int,
      valuesData: Int,
      valuesSize: Int,
      cas: Int
  ): Result = unimplementedFunction("proxySetSharedKvstoreKeyValues")

  override def proxyAddSharedKvstoreKeyValues(
      plugin: ExtismCurrentPlugin,
      kvstoreID: Int,
      keyData: Int,
      keySize: Int,
      valuesData: Int,
      valuesSize: Int,
      cas: Int
  ): Result = unimplementedFunction("proxyAddSharedKvstoreKeyValues")

  override def proxyRemoveSharedKvstoreKey(
      plugin: ExtismCurrentPlugin,
      kvstoreID: Int,
      keyData: Int,
      keySize: Int,
      cas: Int
  ): Result = unimplementedFunction("proxyRemoveSharedKvstoreKey")

  override def proxyDeleteSharedKvstore(plugin: ExtismCurrentPlugin, kvstoreID: Int): Result = unimplementedFunction(
    "proxyDeleteSharedKvstore"
  )

  override def proxyOpenSharedQueue(
      plugin: ExtismCurrentPlugin,
      queueNameData: Int,
      queueNameSize: Int,
      createIfNotExist: Int,
      returnQueueID: Int
  ): Result = unimplementedFunction("proxyOpenSharedQueue")

  override def proxyDequeueSharedQueueItem(
      plugin: ExtismCurrentPlugin,
      queueID: Int,
      returnPayloadData: Int,
      returnPayloadSize: Int
  ): Result = unimplementedFunction("proxyDequeueSharedQueueItem")

  override def proxyEnqueueSharedQueueItem(
      plugin: ExtismCurrentPlugin,
      queueID: Int,
      payloadData: Int,
      payloadSize: Int
  ): Result = unimplementedFunction("proxyEnqueueSharedQueueItem")

  override def proxyDeleteSharedQueue(plugin: ExtismCurrentPlugin, queueID: Int): Result = unimplementedFunction(
    "proxyDeleteSharedQueue"
  )

  override def proxyCreateTimer(plugin: ExtismCurrentPlugin, period: Int, oneTime: Int, returnTimerID: Int): Result =
    unimplementedFunction("proxyCreateTimer")

  override def proxyDeleteTimer(plugin: ExtismCurrentPlugin, timerID: Int): Result = unimplementedFunction(
    "proxyDeleteTimer"
  )

  override def proxyCreateMetric(
      plugin: ExtismCurrentPlugin,
      metricType: MetricType,
      metricNameData: Int,
      metricNameSize: Int,
      returnMetricID: Int
  ): MetricType = unimplementedFunction("proxyCreateMetric")

  override def proxyGetMetricValue(plugin: ExtismCurrentPlugin, metricID: Int, returnValue: Int): Result = {
    // TODO - get metricID
    val value = 10

    getMemory(plugin)
      .fold(
        _ => ResultBadArgument,
        mem => {
          mem.setInt(returnValue, value)
          ResultOk
        }
      )
  }

  override def proxySetMetricValue(plugin: ExtismCurrentPlugin, metricID: Int, value: Int): Result =
    unimplementedFunction("proxySetMetricValue")

  override def proxyIncrementMetricValue(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      metricID: Int,
      offset: Long
  ): Result = {
    traceVmHost("proxy_increment_metric")
    ResultOk
  }

  override def proxyDeleteMetric(plugin: ExtismCurrentPlugin, metricID: Int): Result = unimplementedFunction(
    "proxyDeleteMetric"
  )

  override def proxyDefineMetric(
      plugin: ExtismCurrentPlugin,
      metricType: Int,
      namePtr: Int,
      nameSize: Int,
      returnMetricId: Int
  ): Result = {
    traceVmHost("proxy_define_metric")
    if (metricType > MetricType.last) {
      ResultBadArgument
    } else {

      getMemory(plugin, namePtr, nameSize)
        .fold(
          _ => ResultBadArgument,
          mem => {
            // mid = ih.DefineMetric(v1.MetricType(metricType), mem._2.utf8String)

            val mid = 1
            mem._1.setInt(returnMetricId, mid)
            ResultOk
          }
        )
    }
  }

  override 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 = unimplementedFunction("proxyDispatchHttpCall")

  override 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 = unimplementedFunction("proxyDispatchGrpcCall")

  override def proxyOpenGrpcStream(
      plugin: ExtismCurrentPlugin,
      upstreamNameData: Int,
      upstreamNameSize: Int,
      serviceNameData: Int,
      serviceNameSize: Int,
      serviceMethodData: Int,
      serviceMethodSize: Int,
      initialMetadataMapData: Int,
      initialMetadataMapSize: Int,
      returnCalloutID: Int
  ): Result = unimplementedFunction("proxyOpenGrpcStream")

  override def proxySendGrpcStreamMessage(
      plugin: ExtismCurrentPlugin,
      calloutID: Int,
      grpcMessageData: Int,
      grpcMessageSize: Int
  ): Result = unimplementedFunction("proxySendGrpcStreamMessage")

  override def proxyCancelGrpcCall(plugin: ExtismCurrentPlugin, calloutID: Int): Result = unimplementedFunction(
    "proxyCancelGrpcCall"
  )

  override def proxyCloseGrpcCall(plugin: ExtismCurrentPlugin, calloutID: Int): Result = unimplementedFunction(
    "proxyCloseGrpcCall"
  )

  override def proxyCallCustomFunction(
      plugin: ExtismCurrentPlugin,
      customFunctionID: Int,
      parametersData: Int,
      parametersSize: Int,
      returnResultsData: Int,
      returnResultsSize: Int
  ): Result = unimplementedFunction("proxyCallCustomFunction")

  override def copyIntoInstance(
      plugin: ExtismCurrentPlugin,
      memory: Pointer,
      value: IoBuffer,
      retPtr: Int,
      retSize: Int
  ): Result = {
    val addr = plugin.customMemoryAlloc(value.length)

    memory.write(addr, value.buf.toArray, 0, value.length)

    memory.setInt(retPtr, addr)
    memory.setInt(retSize, value.length)

    ResultOk
  }

  override def proxyGetProperty(
      plugin: ExtismCurrentPlugin,
      data: VmData,
      pathPtr: Int,
      pathSize: Int,
      returnValueData: Int,
      returnValueSize: Int
  ): Result = {
    traceVmHost("proxy_get_property")
    val mem = getMemory(plugin, pathPtr, pathSize)

    mem.fold(
      _ => ResultBadArgument,
      m => {
        if (m._2.isEmpty) {
          ResultBadArgument
        } else {
          val path = m._2.utf8String
            .replace(Character.toString(0), ".")

          val value: Array[Byte] = data.properties.getOrElse(path, ByteString.empty.toArray)

          if (value == null) {
            return ResultNotFound
          }

          copyIntoInstance(plugin, m._1, new IoBuffer(ByteString(value)), returnValueData, returnValueSize)
        }
      }
    )
  }

  override def proxyRegisterSharedQueue(nameData: ByteString, nameSize: Int, returnID: Int): Status =
    unimplementedFunction("proxyRegisterSharedQueue")

  override def proxyResolveSharedQueue(
      vmIDData: ByteString,
      vmIDSize: Int,
      nameData: ByteString,
      nameSize: Int,
      returnID: Int
  ): Status = unimplementedFunction("proxyResolveSharedQueue")

  override def proxyEnqueueSharedQueue(queueID: Int, valueData: ByteString, valueSize: Int): Status =
    unimplementedFunction("proxyEnqueueSharedQueue")

  override def proxyDequeueSharedQueue(queueID: Int, returnValueData: ByteString, returnValueSize: Int): Status =
    unimplementedFunction("proxyDequeueSharedQueue")

  override def proxyDone(): Status = {
    StatusOK
  }

  override def proxySetTickPeriodMilliseconds(data: VmData, period: Int): Status = {
    // TODO - manage tick period
    // data.setTickPeriod(period)
    StatusOK
  }

  override def proxySetEffectiveContext(plugin: ExtismCurrentPlugin, contextID: Int): Status = {
    // TODO - manage context id changes
    // this.contextId = contextID
    StatusOK
  }

  override def getPluginConfig(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = {
    new IoBuffer(data.configuration)
  }

  override def getHttpRequestBody(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = {
    data.bodyIn match {
      case None       => new IoBuffer(ByteString.empty)
      case Some(body) => new IoBuffer(body)
    }
  }

  override def getHttpResponseBody(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = {
    data.bodyOut match {
      case None       => new IoBuffer(ByteString.empty)
      case Some(body) => new IoBuffer(body)
    }
  }

  override def getDownStreamData(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = unimplementedFunction(
    "getDownStreamData"
  )

  override def getUpstreamData(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = unimplementedFunction(
    "getUpstreamData"
  )

  override def getHttpCalloutResponseBody(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = unimplementedFunction(
    "getHttpCalloutResponseBody"
  )

  override def getVmConfig(plugin: ExtismCurrentPlugin, data: VmData): IoBuffer = unimplementedFunction("getVmConfig")

  override def getCustomBuffer(bufferType: BufferType): IoBuffer = unimplementedFunction("getCustomBuffer")

  override def getHttpRequestHeader(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] = {
    data.properties
      .filter(entry => entry._1.startsWith("request.headers.") || entry._1.startsWith(":"))
      .map(t => (t._1.replace("request.headers.", ""), ByteString(t._2)))
  }

  override def getHttpRequestTrailer(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] = {
    Map.empty
  }

  override def getHttpRequestMetadata(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] = {
    Map.empty
  }

  override def getHttpResponseHeader(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] = {
    data.properties
      .filter(entry => entry._1.startsWith("response.headers.") || entry._1.startsWith(":"))
      .map(t => (t._1.replace("response.headers.", ""), ByteString(t._2)))
  }

  override def getHttpResponseTrailer(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] =
    unimplementedFunction("getHttpResponseTrailer")

  override def getHttpResponseMetadata(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] =
    unimplementedFunction("getHttpResponseMetadata")

  override def getHttpCallResponseHeaders(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] =
    unimplementedFunction("getHttpCallResponseHeaders")

  override def getHttpCallResponseTrailer(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] =
    unimplementedFunction("getHttpCallResponseTrailer")

  override def getHttpCallResponseMetadata(plugin: ExtismCurrentPlugin, data: VmData): Map[String, ByteString] =
    unimplementedFunction("getHttpCallResponseMetadata")

  override def getCustomMap(plugin: ExtismCurrentPlugin, data: VmData, mapType: MapType): Map[String, ByteString] =
    unimplementedFunction("getCustomMap")

  override def getMemory(plugin: ExtismCurrentPlugin, addr: Int, size: Int): Either[Error, (Pointer, ByteString)] =
    plugin.synchronized {

      val memory: Pointer = plugin.customMemoryGet()
      if (memory == null) {
        return Error.ErrorExportsNotFound.left
      }

      // TODO - get memory size from RUST
//        long memoryLength = 1024 * 64 * 50// plugin.memoryLength(0)
//        if (addr > memoryLength || (addr+size) > memoryLength) {
//            return Either.left(Error.ErrAddrOverflow)
//        }

      (memory -> ByteString(memory.share(addr).getByteArray(0, size))).right[Error]
    }

  override def getMemory(plugin: ExtismCurrentPlugin): Either[Error, Pointer] = plugin.synchronized {

    val memory: Pointer = plugin.customMemoryGet()
    if (memory == null) {
      return Error.ErrorExportsNotFound.left
    }

    memory.right
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy