wa-lang.org/wazero@v1.0.2/imports/proxywasm/hostcall.go (about) 1 // Copyright 2020-2021 Tetrate 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package proxywasm 16 17 import ( 18 "errors" 19 "fmt" 20 "math" 21 22 "wa-lang.org/wazero/imports/proxywasm/internal" 23 "wa-lang.org/wazero/imports/proxywasm/types" 24 ) 25 26 // GetVMConfiguration is used for retrieving configurations given in the "vm_config.configuration" field. 27 // This hostcall is only available during types.PluginContext.OnVMStart call. 28 func GetVMConfiguration() ([]byte, error) { 29 return getBuffer(internal.BufferTypeVMConfiguration, 0, math.MaxInt32) 30 } 31 32 // GetPluginConfiguration is used for retrieving configurations given in the "config.configuration" field. 33 // This hostcall is only available during types.PluginContext.OnPluginStart call. 34 func GetPluginConfiguration() ([]byte, error) { 35 return getBuffer(internal.BufferTypePluginConfiguration, 0, math.MaxInt32) 36 } 37 38 // SetTickPeriodMilliSeconds sets the tick interval of types.PluginContext.OnTick calls. 39 // Only available for types.PluginContext. 40 func SetTickPeriodMilliSeconds(millSec uint32) error { 41 return internal.StatusToError(internal.ProxySetTickPeriodMilliseconds(millSec)) 42 } 43 44 // SetEffectiveContext sets the effective context to "context_id". 45 // This hostcall is usually used to change the context after receiving 46 // types.PluginContext.OnQueueReady or types.PluginContext.OnTick 47 func SetEffectiveContext(contextID uint32) error { 48 return internal.StatusToError(internal.ProxySetEffectiveContext(contextID)) 49 } 50 51 // RegisterSharedQueue registers the shared queue on this plugin context. 52 // "Register" means that OnQueueReady is called for this plugin context whenever a new item is enqueued on that queueID. 53 // Only available for types.PluginContext. The returned queueID can be used for Enqueue/DequeueSharedQueue. 54 // Note that "name" must be unique across all Wasm VMs which share the same "vm_id". 55 // That means you can use "vm_id" to separate shared queue namespace. 56 func RegisterSharedQueue(name string) (queueID uint32, err error) { 57 ptr := internal.StringBytePtr(name) 58 st := internal.ProxyRegisterSharedQueue(ptr, len(name), &queueID) 59 return queueID, internal.StatusToError(st) 60 } 61 62 // ResolveSharedQueue acquires the queueID for the given vmID and queueName. 63 // The returned queueID can be used for Enqueue/DequeueSharedQueue. 64 func ResolveSharedQueue(vmID, queueName string) (queueID uint32, err error) { 65 var ret uint32 66 st := internal.ProxyResolveSharedQueue(internal.StringBytePtr(vmID), 67 len(vmID), internal.StringBytePtr(queueName), len(queueName), &ret) 68 return ret, internal.StatusToError(st) 69 } 70 71 // EnqueueSharedQueue enqueues data to the shared queue of the given queueID. 72 // In order to get queue id for a target queue, use "ResolveSharedQueue" first. 73 func EnqueueSharedQueue(queueID uint32, data []byte) error { 74 return internal.StatusToError(internal.ProxyEnqueueSharedQueue(queueID, &data[0], len(data))) 75 } 76 77 // DequeueSharedQueue dequeues data from the shared queue of the given queueID. 78 // In order to get queue id for a target queue, use "ResolveSharedQueue" first. 79 func DequeueSharedQueue(queueID uint32) ([]byte, error) { 80 var raw *byte 81 var size int 82 st := internal.ProxyDequeueSharedQueue(queueID, &raw, &size) 83 if st != internal.StatusOK { 84 return nil, internal.StatusToError(st) 85 } 86 return internal.RawBytePtrToByteSlice(raw, size), nil 87 } 88 89 // PluginDone must be called when OnPluginDone returns false indicating that the plugin is in pending state 90 // right before deletion by the hosts. Only available for types.PluginContext. 91 func PluginDone() { 92 internal.ProxyDone() 93 } 94 95 // DispatchHttpCall is for dispatching HTTP calls to a remote cluster. This can be used by all contexts 96 // including Tcp and Root contexts. "cluster" arg specifies the remote cluster the host will send 97 // the request against with "headers", "body", and "trailers" arguments. "callBack" function is called if the host successfully 98 // made the request and received the response from the remote cluster. 99 // When the callBack function is called, the "GetHttpCallResponseHeaders", "GetHttpCallResponseBody", "GetHttpCallResponseTrailers" 100 // calls are available for accessing the response information. 101 func DispatchHttpCall( 102 cluster string, 103 headers [][2]string, 104 body []byte, 105 trailers [][2]string, 106 timeoutMillisecond uint32, 107 callBack func(numHeaders, bodySize, numTrailers int), 108 ) (calloutID uint32, err error) { 109 shs := internal.SerializeMap(headers) 110 hp := &shs[0] 111 hl := len(shs) 112 113 sts := internal.SerializeMap(trailers) 114 tp := &sts[0] 115 tl := len(sts) 116 117 var bodyPtr *byte 118 if len(body) > 0 { 119 bodyPtr = &body[0] 120 } 121 122 u := internal.StringBytePtr(cluster) 123 switch st := internal.ProxyHttpCall(u, len(cluster), 124 hp, hl, bodyPtr, len(body), tp, tl, timeoutMillisecond, &calloutID); st { 125 case internal.StatusOK: 126 internal.RegisterHttpCallout(calloutID, callBack) 127 return calloutID, nil 128 default: 129 return 0, internal.StatusToError(st) 130 } 131 } 132 133 // GetHttpCallResponseHeaders is used for retrieving HTTP response headers 134 // returned by a remote cluster in response to the DispatchHttpCall. 135 // Only available during "callback" function passed to the DispatchHttpCall. 136 func GetHttpCallResponseHeaders() ([][2]string, error) { 137 return getMap(internal.MapTypeHttpCallResponseHeaders) 138 } 139 140 // GetHttpCallResponseBody is used for retrieving HTTP response body 141 // returned by a remote cluster in response to the DispatchHttpCall. 142 // Only available during "callback" function passed to the DispatchHttpCall. 143 func GetHttpCallResponseBody(start, maxSize int) ([]byte, error) { 144 return getBuffer(internal.BufferTypeHttpCallResponseBody, start, maxSize) 145 } 146 147 // GetHttpCallResponseTrailers is used for retrieving HTTP response trailers 148 // returned by a remote cluster in response to the DispatchHttpCall. 149 // Only available during "callback" function passed to DispatchHttpCall. 150 func GetHttpCallResponseTrailers() ([][2]string, error) { 151 return getMap(internal.MapTypeHttpCallResponseTrailers) 152 } 153 154 // GetDownstreamData can be used for retrieving TCP downstream data buffered in the host. 155 // Returned bytes beginning from "start" to "start" + "maxSize" in the buffer. 156 // Only available during types.TcpContext.OnDownstreamData. 157 func GetDownstreamData(start, maxSize int) ([]byte, error) { 158 return getBuffer(internal.BufferTypeDownstreamData, start, maxSize) 159 } 160 161 // AppendDownstreamData appends the given bytes to the downstream TCP data buffered in the host. 162 // Only available during types.TcpContext.OnDownstreamData. 163 func AppendDownstreamData(data []byte) error { 164 return appendToBuffer(internal.BufferTypeDownstreamData, data) 165 } 166 167 // PrependDownstreamData prepends the given bytes to the downstream TCP data buffered in the host. 168 // Only available during types.TcpContext.OnDownstreamData. 169 func PrependDownstreamData(data []byte) error { 170 return prependToBuffer(internal.BufferTypeDownstreamData, data) 171 } 172 173 // ReplaceDownstreamData replaces the downstream TCP data buffered in the host 174 // with the given bytes. Only available during types.TcpContext.OnDownstreamData. 175 func ReplaceDownstreamData(data []byte) error { 176 return replaceBuffer(internal.BufferTypeDownstreamData, data) 177 } 178 179 // GetUpstreamData can be used for retrieving upstream TCP data buffered in the host. 180 // Returned bytes beginning from "start" to "start" + "maxSize" in the buffer. 181 // Only available during types.TcpContext.OnUpstreamData. 182 func GetUpstreamData(start, maxSize int) ([]byte, error) { 183 return getBuffer(internal.BufferTypeUpstreamData, start, maxSize) 184 } 185 186 // AppendUpstreamData appends the given bytes to the upstream TCP data buffered in the host. 187 // Only available during types.TcpContext.OnUpstreamData. 188 func AppendUpstreamData(data []byte) error { 189 return appendToBuffer(internal.BufferTypeUpstreamData, data) 190 } 191 192 // PrependUpstreamData prepends the given bytes to the upstream TCP data buffered in the host. 193 // Only available during types.TcpContext.OnUpstreamData. 194 func PrependUpstreamData(data []byte) error { 195 return prependToBuffer(internal.BufferTypeUpstreamData, data) 196 } 197 198 // ReplaceUpstreamData replaces the upstream TCP data buffered in the host 199 // with the given bytes. Only available during types.TcpContext.OnUpstreamData. 200 func ReplaceUpstreamData(data []byte) error { 201 return replaceBuffer(internal.BufferTypeUpstreamData, data) 202 } 203 204 // ContinueTcpStream continues interating on the TCP connection 205 // after types.Action.Pause was returned by types.TcpContext. 206 // Only available for types.TcpContext. 207 func ContinueTcpStream() error { 208 // Note that internal.ProxyContinueStream is not implemented in Envoy, 209 // so we intentionally choose to pass StreamTypeDownstream here while 210 // the name itself is not indicating "continue downstream". 211 return internal.StatusToError(internal.ProxyContinueStream(internal.StreamTypeDownstream)) 212 } 213 214 // CloseDownstream closes the downstream TCP connection for this Tcp context. 215 // Only available for types.TcpContext. 216 func CloseDownstream() error { 217 return internal.StatusToError(internal.ProxyCloseStream(internal.StreamTypeDownstream)) 218 } 219 220 // CloseUpstream closes the upstream TCP connection for this Tcp context. 221 // Only available for types.TcpContext. 222 func CloseUpstream() error { 223 return internal.StatusToError(internal.ProxyCloseStream(internal.StreamTypeUpstream)) 224 } 225 226 // GetHttpRequestHeaders is used for retrieving HTTP request headers. 227 // Only available during types.HttpContext.OnHttpRequestHeaders and 228 // types.HttpContext.OnHttpStreamDone. 229 func GetHttpRequestHeaders() ([][2]string, error) { 230 return getMap(internal.MapTypeHttpRequestHeaders) 231 } 232 233 // ReplaceHttpRequestHeaders is used for replacing HTTP request headers 234 // with given headers. Only available during 235 // types.HttpContext.OnHttpRequestHeaders. 236 func ReplaceHttpRequestHeaders(headers [][2]string) error { 237 return setMap(internal.MapTypeHttpRequestHeaders, headers) 238 } 239 240 // GetHttpRequestHeader is used for retrieving an HTTP request header value 241 // for given "key". Only available during types.HttpContext.OnHttpRequestHeaders and 242 // types.HttpContext.OnHttpStreamDone. 243 // If multiple values are present for the key, the "first" value found in the host is returned. 244 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/source/extensions/common/wasm/context.cc#L762-L763 245 // for detail. 246 func GetHttpRequestHeader(key string) (string, error) { 247 return getMapValue(internal.MapTypeHttpRequestHeaders, key) 248 } 249 250 // RemoveHttpRequestHeader is used for removing an HTTP request header with 251 // a given "key". Only available during types.HttpContext.OnHttpRequestHeaders. 252 func RemoveHttpRequestHeader(key string) error { 253 return removeMapValue(internal.MapTypeHttpRequestHeaders, key) 254 } 255 256 // ReplaceHttpRequestHeader replaces a value for given "key" from request headers. 257 // Only available during types.HttpContext.OnHttpRequestHeaders. 258 // If multiple values are present for the key, only the "first" value in the host is replaced. 259 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/envoy/http/header_map.h#L547-L549 260 // for detail. 261 func ReplaceHttpRequestHeader(key, value string) error { 262 return replaceMapValue(internal.MapTypeHttpRequestHeaders, key, value) 263 } 264 265 // AddHttpRequestHeader adds a value for given "key" to the request headers. 266 // Only available during types.HttpContext.OnHttpRequestHeaders. 267 func AddHttpRequestHeader(key, value string) error { 268 return addMapValue(internal.MapTypeHttpRequestHeaders, key, value) 269 } 270 271 // GetHttpRequestBody is used for retrieving the entire HTTP request body. 272 // Only available during types.HttpContext.OnHttpRequestBody. 273 func GetHttpRequestBody(start, maxSize int) ([]byte, error) { 274 return getBuffer(internal.BufferTypeHttpRequestBody, start, maxSize) 275 } 276 277 // AppendHttpRequestBody appends the given bytes to the HTTP request body buffer. 278 // Only available during types.HttpContext.OnHttpRequestBody. 279 // Please note that you must remove the "content-length" header during OnHttpRequestHeaders. 280 // Otherwise, the wrong content-length is sent to the upstream and that might result in a client crash. 281 func AppendHttpRequestBody(data []byte) error { 282 return appendToBuffer(internal.BufferTypeHttpRequestBody, data) 283 } 284 285 // PrependHttpRequestBody prepends the given bytes to the HTTP request body buffer. 286 // Only available during types.HttpContext.OnHttpRequestBody. 287 // Please note that you must remove the "content-length" header during OnHttpRequestHeaders. 288 // Otherwise, the wrong content-length is sent to the upstream and that might result in client crash. 289 func PrependHttpRequestBody(data []byte) error { 290 return prependToBuffer(internal.BufferTypeHttpRequestBody, data) 291 } 292 293 // ReplaceHttpRequestBody replaces the HTTP request body buffer with the given bytes. 294 // Only available during types.HttpContext.OnHttpRequestBody. 295 // Please note that you must remove the "content-length" header during OnHttpRequestHeaders. 296 // Otherwise, the wrong content-length is sent to the upstream and that might result in client crash, 297 // if the size of the data differs from the original size. 298 func ReplaceHttpRequestBody(data []byte) error { 299 return replaceBuffer(internal.BufferTypeHttpRequestBody, data) 300 } 301 302 // GetHttpRequestTrailers is used for retrieving HTTP request trailers. 303 // Only available during types.HttpContext.OnHttpRequestTrailers and 304 // types.HttpContext.OnHttpStreamDone. 305 func GetHttpRequestTrailers() ([][2]string, error) { 306 return getMap(internal.MapTypeHttpRequestTrailers) 307 } 308 309 // ReplaceHttpRequestTrailers is used for replacing HTTP request trailers 310 // with given trailers. Only available during 311 // types.HttpContext.OnHttpRequestTrailers. 312 func ReplaceHttpRequestTrailers(trailers [][2]string) error { 313 return setMap(internal.MapTypeHttpRequestTrailers, trailers) 314 } 315 316 // GetHttpRequestTrailer is used for retrieving HTTP request trailer value 317 // for given "key". Only available during types.HttpContext.OnHttpRequestTrailers and 318 // types.HttpContext.OnHttpStreamDone. 319 // If multiple values are present for the key, the "first" value found in the host is returned. 320 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/source/extensions/common/wasm/context.cc#L762-L763 321 // for detail. 322 func GetHttpRequestTrailer(key string) (string, error) { 323 return getMapValue(internal.MapTypeHttpRequestTrailers, key) 324 } 325 326 // RemoveHttpRequestTrailer removes all values for given "key" from the request trailers. 327 // Only available during types.HttpContext.OnHttpRequestTrailers. 328 func RemoveHttpRequestTrailer(key string) error { 329 return removeMapValue(internal.MapTypeHttpRequestTrailers, key) 330 } 331 332 // ReplaceHttpRequestTrailer replaces a value for given "key" from the request trailers. 333 // Only available during types.HttpContext.OnHttpRequestTrailers. 334 // If multiple values are present for the key, only the "first" value in the host is replaced. 335 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/envoy/http/header_map.h#L547-L549 336 // for detail. 337 func ReplaceHttpRequestTrailer(key, value string) error { 338 return replaceMapValue(internal.MapTypeHttpRequestTrailers, key, value) 339 } 340 341 // AddHttpRequestTrailer adds a value for given "key" to the request trailers. 342 // Only available during types.HttpContext.OnHttpRequestTrailers. 343 func AddHttpRequestTrailer(key, value string) error { 344 return addMapValue(internal.MapTypeHttpRequestTrailers, key, value) 345 } 346 347 // ResumeHttpRequest can be used for resuming HTTP request processing that was stopped 348 // after returning the types.Action.Pause. Only available during types.HttpContext. 349 func ResumeHttpRequest() error { 350 return internal.StatusToError(internal.ProxyContinueStream(internal.StreamTypeRequest)) 351 } 352 353 // GetHttpResponseHeaders is used for retrieving HTTP response headers. 354 // Only available during types.HttpContext.OnHttpResponseHeaders and 355 // types.HttpContext.OnHttpStreamDone. 356 func GetHttpResponseHeaders() ([][2]string, error) { 357 return getMap(internal.MapTypeHttpResponseHeaders) 358 } 359 360 // ReplaceHttpResponseHeaders is used for replacing HTTP response headers 361 // with given headers. Only available during 362 // types.HttpContext.OnHttpResponseHeaders. 363 func ReplaceHttpResponseHeaders(headers [][2]string) error { 364 return setMap(internal.MapTypeHttpResponseHeaders, headers) 365 } 366 367 // GetHttpResponseHeader is used for retrieving an HTTP response header value 368 // for a given "key". Only available during types.HttpContext.OnHttpResponseHeaders and 369 // types.HttpContext.OnHttpStreamDone. 370 // If multiple values are present for the key, the "first" value found in the host is returned. 371 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/source/extensions/common/wasm/context.cc#L762-L763 372 // for detail. 373 func GetHttpResponseHeader(key string) (string, error) { 374 return getMapValue(internal.MapTypeHttpResponseHeaders, key) 375 } 376 377 // RemoveHttpResponseHeader removes all values for given "key" from the response headers. 378 // Only available during types.HttpContext.OnHttpResponseHeaders. 379 func RemoveHttpResponseHeader(key string) error { 380 return removeMapValue(internal.MapTypeHttpResponseHeaders, key) 381 } 382 383 // ReplaceHttpResponseHeader replaces the value for given "key" from the response headers. 384 // Only available during types.HttpContext.OnHttpResponseHeaders. 385 // If multiple values are present for the key, only the "first" value in the host is replaced. 386 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/envoy/http/header_map.h#L547-L549 387 // for detail. 388 func ReplaceHttpResponseHeader(key, value string) error { 389 return replaceMapValue(internal.MapTypeHttpResponseHeaders, key, value) 390 } 391 392 // AddHttpResponseHeader adds a value for a given "key" to the response headers. 393 // Only available during types.HttpContext.OnHttpResponseHeaders. 394 func AddHttpResponseHeader(key, value string) error { 395 return addMapValue(internal.MapTypeHttpResponseHeaders, key, value) 396 } 397 398 // GetHttpResponseBody is used for retrieving the entire HTTP response body. 399 // Only available during types.HttpContext.OnHttpResponseBody. 400 func GetHttpResponseBody(start, maxSize int) ([]byte, error) { 401 return getBuffer(internal.BufferTypeHttpResponseBody, start, maxSize) 402 } 403 404 // AppendHttpResponseBody appends the given bytes to the HTTP response body buffer. 405 // Only available during types.HttpContext.OnHttpResponseBody. 406 // Please note that you must remove the "content-length" header during OnHttpResponseHeaders. 407 // Otherwise, the wrong content-length is sent to the upstream and that might result in client crash. 408 func AppendHttpResponseBody(data []byte) error { 409 return appendToBuffer(internal.BufferTypeHttpResponseBody, data) 410 } 411 412 // PrependHttpResponseBody prepends the given bytes to the HTTP response body buffer. 413 // Only available during types.HttpContext.OnHttpResponseBody. 414 // Please note that you must remove the "content-length" header during OnHttpResponseHeaders. 415 // Otherwise, the wrong content-length is sent to the upstream and that might result in client crash. 416 func PrependHttpResponseBody(data []byte) error { 417 return prependToBuffer(internal.BufferTypeHttpResponseBody, data) 418 } 419 420 // ReplaceHttpResponseBody replaces the http response body buffer with the given bytes. 421 // Only available during types.HttpContext.OnHttpResponseBody. 422 // Please note that you must remove "content-length" header during OnHttpResponseHeaders. 423 // Otherwise, the wrong content-length is sent to the upstream and that might result in client crash 424 // if the size of the data differs from the original one. 425 func ReplaceHttpResponseBody(data []byte) error { 426 return replaceBuffer(internal.BufferTypeHttpResponseBody, data) 427 } 428 429 // GetHttpResponseTrailers is used for retrieving HTTP response trailers. 430 // Only available during types.HttpContext.OnHttpResponseTrailers and 431 // types.HttpContext.OnHttpStreamDone. 432 func GetHttpResponseTrailers() ([][2]string, error) { 433 return getMap(internal.MapTypeHttpResponseTrailers) 434 } 435 436 // ReplaceHttpResponseTrailers is used for replacing HTTP response trailers 437 // with given trailers. Only available during 438 // types.HttpContext.OnHttpResponseTrailers. 439 func ReplaceHttpResponseTrailers(trailers [][2]string) error { 440 return setMap(internal.MapTypeHttpResponseTrailers, trailers) 441 } 442 443 // GetHttpResponseTrailer is used for retrieving an HTTP response trailer value 444 // for a given "key". Only available during types.HttpContext.OnHttpResponseTrailers and 445 // types.HttpContext.OnHttpStreamDone. 446 // If multiple values are present for the key, the "first" value found in the host is returned. 447 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/source/extensions/common/wasm/context.cc#L762-L763 448 // for detail. 449 func GetHttpResponseTrailer(key string) (string, error) { 450 return getMapValue(internal.MapTypeHttpResponseTrailers, key) 451 } 452 453 // RemoveHttpResponseTrailer removes all values for given "key" from the response trailers. 454 // Only available during types.HttpContext.OnHttpResponseTrailers. 455 func RemoveHttpResponseTrailer(key string) error { 456 return removeMapValue(internal.MapTypeHttpResponseTrailers, key) 457 } 458 459 // ReplaceHttpResponseTrailer replaces a value for given "key" from the response trailers. 460 // Only available during types.HttpContext.OnHttpResponseHeaders. 461 // If multiple values are present for the key, only the "first" value in the host is replaced. 462 // See https://github.com/envoyproxy/envoy/blob/72bf41fb0ecc039f196be02f534bfc2c9c69f348/envoy/http/header_map.h#L547-L549 463 // for detail. 464 func ReplaceHttpResponseTrailer(key, value string) error { 465 return replaceMapValue(internal.MapTypeHttpResponseTrailers, key, value) 466 } 467 468 // AddHttpResponseTrailer adds a value for given "key" to the response trailers. 469 // Only available during types.HttpContext.OnHttpResponseHeaders. 470 func AddHttpResponseTrailer(key, value string) error { 471 return addMapValue(internal.MapTypeHttpResponseTrailers, key, value) 472 } 473 474 // ResumeHttpResponse can be used to resume the HTTP response processing that was stopped 475 // after returning types.Action.Pause. Only available during types.HttpContext. 476 func ResumeHttpResponse() error { 477 return internal.StatusToError(internal.ProxyContinueStream(internal.StreamTypeResponse)) 478 } 479 480 // SendHttpResponse sends an HTTP response to the downstream with given information (headers, statusCode, body). 481 // The function returns an error if used outside the types.HttpContext. 482 // You cannot use this call after types.HttpContext.OnHttpResponseHeaders returns 483 // Continue because the response headers may have already arrived downstream, and 484 // there is no way to override the headers that were already sent. 485 // After you've invoked this function, you *must* return types.Action.Pause to 486 // stop further processing of the initial HTTP request/response. 487 // Note that the gRPCStatus can be set to -1 if this is a not gRPC stream. 488 func SendHttpResponse(statusCode uint32, headers [][2]string, body []byte, gRPCStatus int32) error { 489 shs := internal.SerializeMap(headers) 490 var bp *byte 491 if len(body) > 0 { 492 bp = &body[0] 493 } 494 hp := &shs[0] 495 hl := len(shs) 496 return internal.StatusToError( 497 internal.ProxySendLocalResponse( 498 statusCode, nil, 0, 499 bp, len(body), hp, hl, gRPCStatus, 500 ), 501 ) 502 } 503 504 // GetSharedData is used for retrieving the value for given "key". 505 // For thread-safe updates you must use the returned "cas" value 506 // when calling SetSharedData for the same key. 507 func GetSharedData(key string) (value []byte, cas uint32, err error) { 508 var raw *byte 509 var size int 510 511 st := internal.ProxyGetSharedData(internal.StringBytePtr(key), len(key), &raw, &size, &cas) 512 if st != internal.StatusOK { 513 return nil, 0, internal.StatusToError(st) 514 } 515 return internal.RawBytePtrToByteSlice(raw, size), cas, nil 516 } 517 518 // SetSharedData is used for setting key-value pairs in the shared data storage 519 // which is defined per "vm_config.vm_id" in the hosts. 520 // The function returns ErrorStatusCasMismatch when the given CAS value 521 // doesn't match the current value. The error indicates other Wasm VMs 522 // have already set a value on the same key, and the current CAS for the key gets incremented. 523 // Implementing a retry logic to handle this error is recommended. 524 // Setting the cas value to 0 will never return ErrorStatusCasMismatch, 525 // and the call will always succeed. However, it is not thread-safe. 526 // Another VM may have already incremented the value, and the value you 527 // see is already different from the one stored when you call this function. 528 func SetSharedData(key string, data []byte, cas uint32) error { 529 var dataPtr *byte 530 if len(data) > 0 { // Empty data is allowed to set, so we need this check. 531 dataPtr = &data[0] 532 } 533 st := internal.ProxySetSharedData(internal.StringBytePtr(key), len(key), dataPtr, len(data), cas) 534 return internal.StatusToError(st) 535 } 536 537 // GetProperty is used for retrieving property/metadata in the host 538 // for a given path. 539 // Available path and properties depend on the host implementation. 540 // For Envoy, please refer to https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes 541 // 542 // Note: if the target property is map-type, use GetPropertyMap instead. This GetProperty returns 543 // raw un-serialized bytes for such properties. For example, if you have the metadata as 544 // 545 // clusters: 546 // - name: web_service 547 // metadata: 548 // filter_metadata: 549 // foo: 550 // my_value: '1234' 551 // my_map: 552 // k1: v1 553 // k2: v2 554 // 555 // Then, 556 // - use GetPropertyMap for {"cluster_metadata", "filter_metadata", "foo", "my_map"}. 557 // - use GetProperty for {"cluster_metadata", "filter_metadata", "foo", "my_value"}. 558 // 559 // Note: you cannot get the raw bytes of protobuf. For example, accessing {"cluster_metadata", "filter_data", "foo"}) doesn't 560 // return the protobuf bytes, but instead this returns the serialized map of "foo". Therefore, we recommend to access individual 561 // "leaf" fields (not the middle or top field of metadata) to avoid the need to figure out the (host-dependent) encoding of properties. 562 func GetProperty(path []string) ([]byte, error) { 563 if len(path) == 0 { 564 return nil, errors.New("path must not be empty") 565 } 566 var ret *byte 567 var retSize int 568 raw := internal.SerializePropertyPath(path) 569 570 err := internal.StatusToError(internal.ProxyGetProperty(&raw[0], len(raw), &ret, &retSize)) 571 if err != nil { 572 return nil, err 573 } 574 return internal.RawBytePtrToByteSlice(ret, retSize), nil 575 } 576 577 // GetPropertyMap is the same as GetProperty but can be used to decode map-typed properties. 578 // See GetProperty for detail. 579 // 580 // Note: this operates under the assumption that the path is encoded as map, therefore this might 581 // cause panic if it is used on the non-map types. 582 func GetPropertyMap(path []string) ([][2]string, error) { 583 b, err := GetProperty(path) 584 if err != nil { 585 return nil, err 586 } 587 588 return internal.DeserializeMap(b), nil 589 } 590 591 // SetProperty is used for setting property/metadata in the host 592 // for a given path. 593 // Available path and properties depend on the host implementation. 594 // For Envoy, please refer to https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes 595 func SetProperty(path []string, data []byte) error { 596 if len(path) == 0 { 597 return errors.New("path must not be empty") 598 } else if len(data) == 0 { 599 return errors.New("data must not be empty") 600 } 601 raw := internal.SerializePropertyPath(path) 602 return internal.StatusToError(internal.ProxySetProperty( 603 &raw[0], len(raw), &data[0], len(data), 604 )) 605 } 606 607 // CallForeignFunction calls a foreign function of given funcName defined by host implementations. 608 // Foreign functions are host-specific functions, so please refer to the doc of your host implementation for detail. 609 func CallForeignFunction(funcName string, param []byte) (ret []byte, err error) { 610 f := internal.StringBytePtr(funcName) 611 612 var returnData *byte 613 var returnSize int 614 615 var paramPtr *byte 616 if len(param) != 0 { 617 paramPtr = ¶m[0] 618 } 619 620 switch st := internal.ProxyCallForeignFunction(f, len(funcName), paramPtr, len(param), &returnData, &returnSize); st { 621 case internal.StatusOK: 622 return internal.RawBytePtrToByteSlice(returnData, returnSize), nil 623 default: 624 return nil, internal.StatusToError(st) 625 } 626 } 627 628 // LogTrace emits a message as a log with Trace log level. 629 func LogTrace(msg string) { 630 internal.ProxyLog(internal.LogLevelTrace, internal.StringBytePtr(msg), len(msg)) 631 } 632 633 // LogTracef formats according to a format specifier and emits as a log with Trace log level. 634 // 635 // Note that not all combinations of format and args are supported by tinygo. 636 // For example, %v with a map will cause a panic. See 637 // https://tinygo.org/docs/reference/lang-support/stdlib/#fmt for more 638 // information. 639 func LogTracef(format string, args ...interface{}) { 640 msg := fmt.Sprintf(format, args...) 641 internal.ProxyLog(internal.LogLevelTrace, internal.StringBytePtr(msg), len(msg)) 642 } 643 644 // LogDebug emits a message as a log with Debug log level. 645 func LogDebug(msg string) { 646 internal.ProxyLog(internal.LogLevelDebug, internal.StringBytePtr(msg), len(msg)) 647 } 648 649 // LogDebugf formats according to a format specifier and emits as a log with Debug log level. 650 // 651 // Note that not all combinations of format and args are supported by tinygo. 652 // For example, %v with a map will cause a panic. See 653 // https://tinygo.org/docs/reference/lang-support/stdlib/#fmt for more 654 // information. 655 func LogDebugf(format string, args ...interface{}) { 656 msg := fmt.Sprintf(format, args...) 657 internal.ProxyLog(internal.LogLevelDebug, internal.StringBytePtr(msg), len(msg)) 658 } 659 660 // LogInfo emits a message as a log with Info log level. 661 func LogInfo(msg string) { 662 internal.ProxyLog(internal.LogLevelInfo, internal.StringBytePtr(msg), len(msg)) 663 } 664 665 // LogInfof formats according to a format specifier and emits as a log with Info log level. 666 // 667 // Note that not all combinations of format and args are supported by tinygo. 668 // For example, %v with a map will cause a panic. See 669 // https://tinygo.org/docs/reference/lang-support/stdlib/#fmt for more 670 // information. 671 func LogInfof(format string, args ...interface{}) { 672 msg := fmt.Sprintf(format, args...) 673 internal.ProxyLog(internal.LogLevelInfo, internal.StringBytePtr(msg), len(msg)) 674 } 675 676 // LogWarn emits a message as a log with Warn log level. 677 func LogWarn(msg string) { 678 internal.ProxyLog(internal.LogLevelWarn, internal.StringBytePtr(msg), len(msg)) 679 } 680 681 // LogWarnf formats according to a format specifier and emits as a log with Warn log level. 682 // 683 // Note that not all combinations of format and args are supported by tinygo. 684 // For example, %v with a map will cause a panic. See 685 // https://tinygo.org/docs/reference/lang-support/stdlib/#fmt for more 686 // information. 687 func LogWarnf(format string, args ...interface{}) { 688 msg := fmt.Sprintf(format, args...) 689 internal.ProxyLog(internal.LogLevelWarn, internal.StringBytePtr(msg), len(msg)) 690 } 691 692 // LogError emits a message as a log with Error log level. 693 func LogError(msg string) { 694 internal.ProxyLog(internal.LogLevelError, internal.StringBytePtr(msg), len(msg)) 695 } 696 697 // LogErrorf formats according to a format specifier and emits as a log with Error log level. 698 // 699 // Note that not all combinations of format and args are supported by tinygo. 700 // For example, %v with a map will cause a panic. See 701 // https://tinygo.org/docs/reference/lang-support/stdlib/#fmt for more 702 // information. 703 func LogErrorf(format string, args ...interface{}) { 704 msg := fmt.Sprintf(format, args...) 705 internal.ProxyLog(internal.LogLevelError, internal.StringBytePtr(msg), len(msg)) 706 } 707 708 // LogCritical emits a message as a log with Critical log level. 709 func LogCritical(msg string) { 710 internal.ProxyLog(internal.LogLevelCritical, internal.StringBytePtr(msg), len(msg)) 711 } 712 713 // LogCriticalf formats according to a format specifier and emits as a log with Critical log level. 714 // 715 // Note that not all combinations of format and args are supported by tinygo. 716 // For example, %v with a map will cause a panic. See 717 // https://tinygo.org/docs/reference/lang-support/stdlib/#fmt for more 718 // information. 719 func LogCriticalf(format string, args ...interface{}) { 720 msg := fmt.Sprintf(format, args...) 721 internal.ProxyLog(internal.LogLevelCritical, internal.StringBytePtr(msg), len(msg)) 722 } 723 724 type ( 725 // MetricCounter represents a counter metric. 726 // Use DefineCounterMetric for initialization. 727 MetricCounter uint32 728 // MetricGauge represents a gauge metric. 729 // Use DefineGaugeMetric for initialization. 730 MetricGauge uint32 731 // MetricHistogram represents a histogram metric. 732 // Use DefineHistogramMetric for initialization. 733 MetricHistogram uint32 734 ) 735 736 // DefineCounterMetric returns MetricCounter for a name. 737 func DefineCounterMetric(name string) MetricCounter { 738 var id uint32 739 ptr := internal.StringBytePtr(name) 740 st := internal.ProxyDefineMetric(internal.MetricTypeCounter, ptr, len(name), &id) 741 if err := internal.StatusToError(st); err != nil { 742 panic(fmt.Sprintf("define metric of name %s: %v", name, internal.StatusToError(st))) 743 } 744 return MetricCounter(id) 745 } 746 747 // Value returns the current value for this counter. 748 func (m MetricCounter) Value() uint64 { 749 var val uint64 750 st := internal.ProxyGetMetric(uint32(m), &val) 751 if err := internal.StatusToError(st); err != nil { 752 panic(fmt.Sprintf("get metric of %d: %v", uint32(m), internal.StatusToError(st))) 753 } 754 return val 755 } 756 757 // Increment increments the current value by an offset for this counter. 758 func (m MetricCounter) Increment(offset uint64) { 759 if err := internal.StatusToError(internal.ProxyIncrementMetric(uint32(m), int64(offset))); err != nil { 760 panic(fmt.Sprintf("increment %d by %d: %v", uint32(m), offset, err)) 761 } 762 } 763 764 // DefineCounterMetric returns MetricGauge for a name. 765 func DefineGaugeMetric(name string) MetricGauge { 766 var id uint32 767 ptr := internal.StringBytePtr(name) 768 st := internal.ProxyDefineMetric(internal.MetricTypeGauge, ptr, len(name), &id) 769 if err := internal.StatusToError(st); err != nil { 770 panic(fmt.Sprintf("error define metric of name %s: %v", name, internal.StatusToError(st))) 771 } 772 return MetricGauge(id) 773 } 774 775 // Value returns the current value for this gauge. 776 func (m MetricGauge) Value() int64 { 777 var val uint64 778 if err := internal.StatusToError(internal.ProxyGetMetric(uint32(m), &val)); err != nil { 779 panic(fmt.Sprintf("get metric of %d: %v", uint32(m), err)) 780 } 781 return int64(val) 782 } 783 784 // Add adds an offset to the current value for this gauge. 785 func (m MetricGauge) Add(offset int64) { 786 if err := internal.StatusToError(internal.ProxyIncrementMetric(uint32(m), offset)); err != nil { 787 panic(fmt.Sprintf("error adding %d by %d: %v", uint32(m), offset, err)) 788 } 789 } 790 791 // DefineHistogramMetric returns MetricHistogram for a name. 792 func DefineHistogramMetric(name string) MetricHistogram { 793 var id uint32 794 ptr := internal.StringBytePtr(name) 795 st := internal.ProxyDefineMetric(internal.MetricTypeHistogram, ptr, len(name), &id) 796 if err := internal.StatusToError(st); err != nil { 797 panic(fmt.Sprintf("error define metric of name %s: %v", name, internal.StatusToError(st))) 798 } 799 return MetricHistogram(id) 800 } 801 802 // Value returns the current value for this histogram. 803 func (m MetricHistogram) Value() uint64 { 804 var val uint64 805 st := internal.ProxyGetMetric(uint32(m), &val) 806 if err := internal.StatusToError(st); err != nil { 807 panic(fmt.Sprintf("get metric of %d: %v", uint32(m), internal.StatusToError(st))) 808 } 809 return val 810 } 811 812 // Record records a value for this histogram. 813 func (m MetricHistogram) Record(value uint64) { 814 if err := internal.StatusToError(internal.ProxyRecordMetric(uint32(m), value)); err != nil { 815 panic(fmt.Sprintf("error adding %d: %v", uint32(m), err)) 816 } 817 } 818 819 func setMap(mapType internal.MapType, headers [][2]string) error { 820 shs := internal.SerializeMap(headers) 821 hp := &shs[0] 822 hl := len(shs) 823 return internal.StatusToError(internal.ProxySetHeaderMapPairs(mapType, hp, hl)) 824 } 825 826 func getMapValue(mapType internal.MapType, key string) (string, error) { 827 var rvs int 828 var raw *byte 829 if st := internal.ProxyGetHeaderMapValue( 830 mapType, internal.StringBytePtr(key), len(key), &raw, &rvs, 831 ); st != internal.StatusOK { 832 return "", internal.StatusToError(st) 833 } 834 835 ret := internal.RawBytePtrToString(raw, rvs) 836 return ret, nil 837 } 838 839 func removeMapValue(mapType internal.MapType, key string) error { 840 return internal.StatusToError( 841 internal.ProxyRemoveHeaderMapValue(mapType, internal.StringBytePtr(key), len(key)), 842 ) 843 } 844 845 func replaceMapValue(mapType internal.MapType, key, value string) error { 846 return internal.StatusToError( 847 internal.ProxyReplaceHeaderMapValue( 848 mapType, internal.StringBytePtr(key), len(key), internal.StringBytePtr(value), len(value), 849 ), 850 ) 851 } 852 853 func addMapValue(mapType internal.MapType, key, value string) error { 854 return internal.StatusToError( 855 internal.ProxyAddHeaderMapValue( 856 mapType, internal.StringBytePtr(key), len(key), internal.StringBytePtr(value), len(value), 857 ), 858 ) 859 } 860 861 func getMap(mapType internal.MapType) ([][2]string, error) { 862 var rvs int 863 var raw *byte 864 865 st := internal.ProxyGetHeaderMapPairs(mapType, &raw, &rvs) 866 if st != internal.StatusOK { 867 return nil, internal.StatusToError(st) 868 } else if raw == nil { 869 return nil, types.ErrorStatusNotFound 870 } 871 872 bs := internal.RawBytePtrToByteSlice(raw, rvs) 873 return internal.DeserializeMap(bs), nil 874 } 875 876 func getBuffer(bufType internal.BufferType, start, maxSize int) ([]byte, error) { 877 var retData *byte 878 var retSize int 879 switch st := internal.ProxyGetBufferBytes(bufType, start, maxSize, &retData, &retSize); st { 880 case internal.StatusOK: 881 if retData == nil { 882 return nil, types.ErrorStatusNotFound 883 } 884 return internal.RawBytePtrToByteSlice(retData, retSize), nil 885 default: 886 return nil, internal.StatusToError(st) 887 } 888 } 889 890 func appendToBuffer(bufType internal.BufferType, buffer []byte) error { 891 var bufferData *byte 892 if len(buffer) != 0 { 893 bufferData = &buffer[0] 894 } 895 return internal.StatusToError(internal.ProxySetBufferBytes(bufType, math.MaxInt32, 0, bufferData, len(buffer))) 896 } 897 898 func prependToBuffer(bufType internal.BufferType, buffer []byte) error { 899 var bufferData *byte 900 if len(buffer) != 0 { 901 bufferData = &buffer[0] 902 } 903 return internal.StatusToError(internal.ProxySetBufferBytes(bufType, 0, 0, bufferData, len(buffer))) 904 } 905 906 func replaceBuffer(bufType internal.BufferType, buffer []byte) error { 907 var bufferData *byte 908 if len(buffer) != 0 { 909 bufferData = &buffer[0] 910 } 911 return internal.StatusToError( 912 internal.ProxySetBufferBytes(bufType, 0, math.MaxInt32, bufferData, len(buffer)), 913 ) 914 }