|
| 1 | +// Copyright 2016-2019 Envoy Project Authors |
| 2 | +// Copyright 2020 Google LLC |
| 3 | +// |
| 4 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +// you may not use this file except in compliance with the License. |
| 6 | +// You may obtain a copy of the License at |
| 7 | +// |
| 8 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +// |
| 10 | +// Unless required by applicable law or agreed to in writing, software |
| 11 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +// See the License for the specific language governing permissions and |
| 14 | +// limitations under the License. |
| 15 | + |
| 16 | +#pragma once |
| 17 | + |
| 18 | +#include "include/proxy-wasm/compat.h" |
| 19 | + |
| 20 | +#include <time.h> |
| 21 | +#include <atomic> |
| 22 | +#include <iostream> |
| 23 | +#include <map> |
| 24 | +#include <memory> |
| 25 | +#include <vector> |
| 26 | + |
| 27 | +namespace proxy_wasm { |
| 28 | + |
| 29 | +#include "proxy_wasm_common.h" |
| 30 | +#include "proxy_wasm_enums.h" |
| 31 | + |
| 32 | +class WasmBase; |
| 33 | +class WasmVm; |
| 34 | + |
| 35 | +using Pairs = std::vector<std::pair<string_view, string_view>>; |
| 36 | +using PairsWithStringValues = std::vector<std::pair<string_view, std::string>>; |
| 37 | +using CallOnThreadFunction = std::function<void(std::function<void()>)>; |
| 38 | + |
| 39 | +struct BufferInterface { |
| 40 | + virtual ~BufferInterface() {} |
| 41 | + virtual size_t size() const = 0; |
| 42 | + // Returns true on success. |
| 43 | + virtual bool copyTo(WasmBase *wasm, size_t start, size_t length, uint64_t ptr_ptr, |
| 44 | + uint64_t size_ptr) const = 0; |
| 45 | +}; |
| 46 | + |
| 47 | +// Opaque context object. |
| 48 | +class StorageObject { |
| 49 | +public: |
| 50 | + virtual ~StorageObject() = default; |
| 51 | +}; |
| 52 | + |
| 53 | +struct PluginBase { |
| 54 | + PluginBase(string_view name, string_view root_id, string_view vm_id, |
| 55 | + string_view plugin_configuration) |
| 56 | + : name_(std::string(name)), root_id_(std::string(root_id)), vm_id_(std::string(vm_id)), |
| 57 | + plugin_configuration_(plugin_configuration) {} |
| 58 | + |
| 59 | + const std::string name_; |
| 60 | + const std::string root_id_; |
| 61 | + const std::string vm_id_; |
| 62 | + std::string plugin_configuration_; |
| 63 | + const std::string &log_prefix() const { return log_prefix_; } |
| 64 | + |
| 65 | +private: |
| 66 | + std::string makeLogPrefix() const; |
| 67 | + |
| 68 | + std::string log_prefix_; |
| 69 | +}; |
| 70 | + |
| 71 | +// A context which will be the target of callbacks for a particular session |
| 72 | +// e.g. a handler of a stream. |
| 73 | +class ContextBase { |
| 74 | +public: |
| 75 | + ContextBase(); // Testing. |
| 76 | + ContextBase(WasmBase *wasm); // Vm Context. |
| 77 | + ContextBase(WasmBase *wasm, std::shared_ptr<PluginBase> plugin); // Root Context. |
| 78 | + ContextBase(WasmBase *wasm, uint32_t root_context_id, |
| 79 | + std::shared_ptr<PluginBase> plugin); // Stream context. |
| 80 | + virtual ~ContextBase(); |
| 81 | + |
| 82 | + WasmBase *wasm() const { return wasm_; } |
| 83 | + uint32_t id() const { return id_; } |
| 84 | + bool isVmContext() { return id_ == 0; } |
| 85 | + bool isRootContext() { return root_context_id_ == 0; } |
| 86 | + ContextBase *root_context() { return root_context_; } |
| 87 | + string_view root_id() const { return plugin_->root_id_; } |
| 88 | + string_view log_prefix() const { return plugin_->log_prefix(); } |
| 89 | + WasmVm *wasmVm() const; |
| 90 | + |
| 91 | + // Called before deleting the context. |
| 92 | + virtual void destroy(); |
| 93 | + |
| 94 | + // |
| 95 | + // VM level downcalls into the WASM code on Context(id == 0). |
| 96 | + // |
| 97 | + virtual bool onStart(std::shared_ptr<PluginBase> plugin); |
| 98 | + virtual bool onConfigure(std::shared_ptr<PluginBase> plugin); |
| 99 | + |
| 100 | + // |
| 101 | + // Stream downcalls on Context(id > 0). |
| 102 | + // |
| 103 | + // General stream downcall on a new stream. |
| 104 | + virtual void onCreate(uint32_t root_context_id); |
| 105 | + // Network |
| 106 | + virtual FilterStatus onNetworkNewConnection(); |
| 107 | + virtual FilterStatus onDownstreamData(int data_length, bool end_of_stream); |
| 108 | + virtual FilterStatus onUpstreamData(int data_length, bool end_of_stream); |
| 109 | + enum class PeerType : uint32_t { |
| 110 | + Unknown = 0, |
| 111 | + Local = 1, |
| 112 | + Remote = 2, |
| 113 | + }; |
| 114 | + virtual void onDownstreamConnectionClose(PeerType); |
| 115 | + virtual void onUpstreamConnectionClose(PeerType); |
| 116 | + // HTTP Filter Stream Request Downcalls. |
| 117 | + virtual FilterHeadersStatus onRequestHeaders(); |
| 118 | + virtual FilterDataStatus onRequestBody(int body_buffer_length, bool end_of_stream); |
| 119 | + virtual FilterTrailersStatus onRequestTrailers(); |
| 120 | + virtual FilterMetadataStatus onRequestMetadata(); |
| 121 | + // HTTP Filter Stream Response Downcalls. |
| 122 | + virtual FilterHeadersStatus onResponseHeaders(); |
| 123 | + virtual FilterDataStatus onResponseBody(int body_buffer_length, bool end_of_stream); |
| 124 | + virtual FilterTrailersStatus onResponseTrailers(); |
| 125 | + virtual FilterMetadataStatus onResponseMetadata(); |
| 126 | + // Async call response. |
| 127 | + virtual void onHttpCallResponse(uint32_t token, uint32_t headers, uint32_t body_size, |
| 128 | + uint32_t trailers); |
| 129 | + // Inter-VM shared queue message arrival. |
| 130 | + virtual void onQueueReady(uint32_t token); |
| 131 | + // General stream downcall when the stream/vm has ended. |
| 132 | + virtual bool onDone(); |
| 133 | + // General stream downcall for logging. Occurs after onDone(). |
| 134 | + virtual void onLog(); |
| 135 | + // General stream downcall when no further stream calls will occur. |
| 136 | + virtual void onDelete(); |
| 137 | + |
| 138 | + virtual void error(string_view message) { |
| 139 | + std::cerr << message << "\n"; |
| 140 | + abort(); |
| 141 | + } |
| 142 | + virtual void unimplemented() { error("unimplemented proxy-wasm API"); } |
| 143 | + |
| 144 | + // |
| 145 | + // General Callbacks. |
| 146 | + // |
| 147 | + virtual WasmResult log(uint64_t /* level */, string_view /* message */) { |
| 148 | + return WasmResult::Unimplemented; |
| 149 | + } |
| 150 | + virtual WasmResult setTimerPeriod(std::chrono::milliseconds period); |
| 151 | + virtual uint64_t getCurrentTimeNanoseconds() { |
| 152 | + struct timespec tpe; |
| 153 | + clock_gettime(CLOCK_REALTIME, &tpe); |
| 154 | + uint64_t t = tpe.tv_sec; |
| 155 | + t *= 1000000000; |
| 156 | + t += tpe.tv_nsec; |
| 157 | + return t; |
| 158 | + } |
| 159 | + virtual std::pair<uint32_t, string_view> getStatus(); |
| 160 | + |
| 161 | + // Buffer |
| 162 | + virtual const BufferInterface *getBuffer(WasmBufferType type); |
| 163 | + virtual bool end_of_stream(); |
| 164 | + |
| 165 | + // HTTP |
| 166 | + // Returns a token which will be used with the corresponding onHttpCallResponse. |
| 167 | + virtual WasmResult httpCall(string_view /* target */, const Pairs & /*request_headers */, |
| 168 | + string_view /* request_body */, const Pairs & /* request_trailers */, |
| 169 | + int /* timeout_millisconds */, uint32_t * /* token_ptr */) { |
| 170 | + unimplemented(); |
| 171 | + return WasmResult::Unimplemented; |
| 172 | + } |
| 173 | + |
| 174 | + // gRPC |
| 175 | + // Returns a token which will be used with the corresponding onGrpc and grpc calls. |
| 176 | + virtual WasmResult grpcCall(string_view /* grpc_service */, string_view /* service_name */, |
| 177 | + string_view /* method_name */, string_view /* request */, |
| 178 | + const optional<std::chrono::milliseconds> & /* timeout */, |
| 179 | + uint32_t * /* token_ptr */) { |
| 180 | + unimplemented(); |
| 181 | + return WasmResult::Unimplemented; |
| 182 | + } |
| 183 | + virtual WasmResult grpcStream(string_view /* grpc_service */, string_view /* service_name */, |
| 184 | + string_view /* method_name */, uint32_t * /* token_ptr */) { |
| 185 | + unimplemented(); |
| 186 | + return WasmResult::Unimplemented; |
| 187 | + } |
| 188 | + virtual WasmResult grpcClose(uint32_t /* token */) { // cancel on call, close on stream. |
| 189 | + unimplemented(); |
| 190 | + return WasmResult::Unimplemented; |
| 191 | + } |
| 192 | + virtual WasmResult grpcCancel(uint32_t /* token */) { // cancel on call, reset on stream. |
| 193 | + unimplemented(); |
| 194 | + return WasmResult::Unimplemented; |
| 195 | + } |
| 196 | + virtual WasmResult grpcSend(uint32_t /* token */, string_view /* message */, |
| 197 | + bool /* end_stream */) { // stream only |
| 198 | + unimplemented(); |
| 199 | + return WasmResult::Unimplemented; |
| 200 | + } |
| 201 | + |
| 202 | + // Metrics |
| 203 | + virtual WasmResult defineMetric(MetricType type, string_view name, uint32_t *metric_id_ptr); |
| 204 | + virtual WasmResult incrementMetric(uint32_t metric_id, int64_t offset); |
| 205 | + virtual WasmResult recordMetric(uint32_t metric_id, uint64_t value); |
| 206 | + virtual WasmResult getMetric(uint32_t metric_id, uint64_t *value_ptr); |
| 207 | + |
| 208 | + // State accessors |
| 209 | + virtual WasmResult getProperty(string_view path, std::string *result); |
| 210 | + virtual WasmResult setProperty(string_view key, string_view serialized_value); |
| 211 | + |
| 212 | + // Continue |
| 213 | + virtual void continueRequest() { unimplemented(); } |
| 214 | + virtual void continueResponse() { unimplemented(); } |
| 215 | + virtual void sendLocalResponse(uint64_t /* response_code */, string_view /* body_text */, |
| 216 | + Pairs /* additional_headers */, uint64_t /* grpc_status */, |
| 217 | + string_view /* details */) { |
| 218 | + unimplemented(); |
| 219 | + } |
| 220 | + |
| 221 | + // Shared Data |
| 222 | + virtual WasmResult getSharedData(string_view /* key */, |
| 223 | + std::pair<std::string, uint32_t /* cas */> * /* data */); |
| 224 | + virtual WasmResult setSharedData(string_view /* key */, string_view /* value */, |
| 225 | + uint32_t /* cas */); |
| 226 | + |
| 227 | + // Shared Queue |
| 228 | + virtual uint32_t registerSharedQueue(string_view /* queue_name */); |
| 229 | + virtual WasmResult resolveSharedQueue(string_view /* vm_id */, string_view /* queue_name */, |
| 230 | + uint32_t * /* token */); |
| 231 | + virtual WasmResult dequeueSharedQueue(uint32_t /* token */, std::string * /* data */); |
| 232 | + virtual WasmResult enqueueSharedQueue(uint32_t /* token */, string_view /* value */); |
| 233 | + |
| 234 | + // Header/Trailer/Metadata Maps |
| 235 | + virtual void addHeaderMapValue(WasmHeaderMapType /* type */, string_view /* key */, |
| 236 | + string_view /* value */) { |
| 237 | + unimplemented(); |
| 238 | + } |
| 239 | + virtual string_view getHeaderMapValue(WasmHeaderMapType /* type */, string_view /* key */) { |
| 240 | + unimplemented(); |
| 241 | + return ""; |
| 242 | + } |
| 243 | + virtual Pairs getHeaderMapPairs(WasmHeaderMapType /* type */) { |
| 244 | + unimplemented(); |
| 245 | + return {}; |
| 246 | + } |
| 247 | + virtual void setHeaderMapPairs(WasmHeaderMapType /* type */, const Pairs & /* pairs */) { |
| 248 | + unimplemented(); |
| 249 | + } |
| 250 | + |
| 251 | + virtual void removeHeaderMapValue(WasmHeaderMapType /* type */, string_view /* key */) { |
| 252 | + unimplemented(); |
| 253 | + } |
| 254 | + virtual void replaceHeaderMapValue(WasmHeaderMapType /* type */, string_view /* key */, |
| 255 | + string_view /* value */) { |
| 256 | + unimplemented(); |
| 257 | + } |
| 258 | + |
| 259 | + virtual uint32_t getHeaderMapSize(WasmHeaderMapType /* type */) { |
| 260 | + unimplemented(); |
| 261 | + return 0; |
| 262 | + } |
| 263 | + |
| 264 | +protected: |
| 265 | + friend class WasmBase; |
| 266 | + |
| 267 | + virtual void initializeRoot(WasmBase *wasm, std::shared_ptr<PluginBase> plugin); |
| 268 | + std::string makeRootLogPrefix(string_view vm_id) const; |
| 269 | + |
| 270 | + WasmBase *wasm_{nullptr}; |
| 271 | + uint32_t id_{0}; |
| 272 | + uint32_t root_context_id_{0}; // 0 for roots and the general context. |
| 273 | + ContextBase *root_context_{nullptr}; // set in all contexts. |
| 274 | + std::string root_id_; // set only in root context. |
| 275 | + std::string root_log_prefix_; // set only in root context. |
| 276 | + std::shared_ptr<PluginBase> plugin_; |
| 277 | + bool in_vm_context_created_ = false; |
| 278 | + bool destroyed_ = false; |
| 279 | +}; |
| 280 | + |
| 281 | +uint32_t resolveQueueForTest(string_view vm_id, string_view queue_name); |
| 282 | + |
| 283 | +} // namespace proxy_wasm |
0 commit comments