wa-lang.org/wazero@v1.0.2/imports/proxywasm/types/context.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 types
    16  
    17  // There are four types of these interfaces which you are supposed to implement in order to extend your network proxies.
    18  // They are VMContext, PluginContext, TcpContext and HttpContext, and their relationship can be described as the following diagram:
    19  //
    20  //	                        Wasm Virtual Machine(VM)
    21  //	                   (corresponds to VM configuration)
    22  //	┌────────────────────────────────────────────────────────────────────────────┐
    23  //	│                                                      TcpContext            │
    24  //	│                                                  ╱ (Each Tcp stream)       │
    25  //	│                                                 ╱                          │
    26  //	│                      1: N                      ╱ 1: N                      │
    27  //	│       VMContext  ──────────  PluginContext                                 │
    28  //	│  (VM configuration)     (Plugin configuration) ╲ 1: N                      │
    29  //	│                                                 ╲                          │
    30  //	│                                                  ╲   HttpContext           │
    31  //	│                                                   (Each Http stream)       │
    32  //	└────────────────────────────────────────────────────────────────────────────┘
    33  //
    34  // To summarize,
    35  //
    36  // 1) VMContext corresponds to each Wasm Virtual Machine, and only one VMContext exists in each VM.
    37  // Note that in Envoy, Wasm VMs are created per "vm_config" field in envoy.yaml. For example having different "vm_config.configuration" fields
    38  // results in multiple VMs being created and each of them corresponds to each "vm_config.configuration".
    39  //
    40  // 2) VMContext is parent of PluginContext, and is responsible for creating arbitrary number of PluginContexts.
    41  //
    42  // 3) PluginContext corresponds to each plugin configuration in the host. In Envoy, each plugin configuration is given at HttpFilter or NetworkFilter
    43  // on listeners. That said, a plugin context corresponds to an Http or Network filter on a listener and is in charge of creating the "filter instances" for
    44  // each Http or Tcp stream. These "filter instances" are represented by HttpContexts or TcpContexts.
    45  //
    46  // 4) PluginContext is a parent of TcpContext and HttpContext, and is responsible for creating arbitrary number of these contexts.
    47  //
    48  // 5) TcpContext is responsible for handling individual Tcp stream events.
    49  //
    50  // 6) HttpContext is responsible for handling individual Http stream events.
    51  
    52  // VMContext corresponds to a Wasm VM machine and its configuration.
    53  // It's the entrypoint for extending the network proxy.
    54  // Its lifetime matches the Wasm Virtual Machines on the host.
    55  type VMContext interface {
    56  	// OnVMStart is called after the VM is created and main function is called.
    57  	// During this call, GetVMConfiguration hostcall is available and can be used to
    58  	// retrieve the configuration set at vm_config.configuration in the host configuration.
    59  	// This is mainly used for doing Wasm VM-wide initialization.
    60  	OnVMStart(vmConfigurationSize int) OnVMStartStatus
    61  
    62  	// NewPluginContext is used for creating PluginContext for each plugin configuration.
    63  	NewPluginContext(contextID uint32) PluginContext
    64  }
    65  
    66  // PluginContext corresponds to different plugin configurations (config.configuration).
    67  // Each configuration is typically given at the HTTP/TCP filter in a listener in the hosts.
    68  // PluginContext is responsible for creating the "filter instances" for each TCP/HTTP stream on the listener.
    69  type PluginContext interface {
    70  	// OnPluginStart is called for all plugin contexts (after OnVmStart if this is the VM context).
    71  	// During this call, GetPluginConfiguration is available and can be used to
    72  	// retrieve the configuration set at config.configuration in the host configuration.
    73  	OnPluginStart(pluginConfigurationSize int) OnPluginStartStatus
    74  
    75  	// OnPluginDone is called right before the plugin contexts are deleted by hosts.
    76  	// Return false to indicate plugin is in a pending state and there's more work left.
    77  	// In that case you must call PluginDone() function once the work is completed to indicate that
    78  	// hosts can kill this context.
    79  	OnPluginDone() bool
    80  
    81  	// OnQueueReady is called when the queue is ready after calling the RegisterQueue hostcall.
    82  	// Note that the queue might be dequeued by another VM running in another thread, so it's
    83  	// possible queue will be empty during the OnQueueReady even if it is not dequeued by this VM.
    84  	OnQueueReady(queueID uint32)
    85  
    86  	// OnTick is called when SetTickPeriodMilliSeconds hostcall is called by this plugin context.
    87  	// This can be used to do asynchronous tasks in parallel to the stream processing.
    88  	OnTick()
    89  
    90  	// The following functions are used for creating contexts on streams,
    91  	// and developers *must* implement either of them corresponding to
    92  	// extension points. For example, if you configure this plugin context is running
    93  	// at Http filters, then NewHttpContext must be implemented. Same goes for
    94  	// Tcp filters.
    95  
    96  	// NewTcpContext is used for creating TcpContext for each Tcp stream.
    97  	// Return nil to indicate this PluginContext is not for TcpContext.
    98  	NewTcpContext(contextID uint32) TcpContext
    99  
   100  	// NewHttpContext is used for creating HttpContext for each Http stream.
   101  	// Return nil to indicate this PluginContext is not for HttpContext.
   102  	NewHttpContext(contextID uint32) HttpContext
   103  }
   104  
   105  // TcpContext corresponds to each Tcp stream and is created by PluginContext via NewTcpContext.
   106  type TcpContext interface {
   107  	// OnNewConnection is called when the Tcp connection is established between downstream and upstream.
   108  	OnNewConnection() Action
   109  
   110  	// OnDownstreamData is called when a data frame arrives from the downstream connection.
   111  	OnDownstreamData(dataSize int, endOfStream bool) Action
   112  
   113  	// OnDownstreamClose is called when the downstream connection is closed.
   114  	OnDownstreamClose(peerType PeerType)
   115  
   116  	// OnUpstreamData is called when a data frame arrives from the upstream connection.
   117  	OnUpstreamData(dataSize int, endOfStream bool) Action
   118  
   119  	// OnUpstreamClose is called when the upstream connection is closed.
   120  	OnUpstreamClose(peerType PeerType)
   121  
   122  	// OnStreamDone is called before the host deletes this context.
   123  	// You can retrieve the stream information (such as remote addresses, etc.) during this call.
   124  	// This can be used to implement logging features.
   125  	OnStreamDone()
   126  }
   127  
   128  // HttpContext corresponds to each Http stream and is created by PluginContext via NewHttpContext.
   129  type HttpContext interface {
   130  	// OnHttpRequestHeaders is called when request headers arrive.
   131  	// Return types.ActionPause if you want to stop sending headers to the upstream.
   132  	OnHttpRequestHeaders(numHeaders int, endOfStream bool) Action
   133  
   134  	// OnHttpRequestBody is called when a request body *frame* arrives.
   135  	// Note that this is potentially called multiple times until we see end_of_stream = true.
   136  	// Return types.ActionPause if you want to buffer the body and stop sending body to the upstream.
   137  	// Even after returning types.ActionPause, this will be called when an unseen frame arrives.
   138  	OnHttpRequestBody(bodySize int, endOfStream bool) Action
   139  
   140  	// OnHttpRequestTrailers is called when request trailers arrive.
   141  	// Return types.ActionPause if you want to stop sending trailers to the upstream.
   142  	OnHttpRequestTrailers(numTrailers int) Action
   143  
   144  	// OnHttpResponseHeaders is called when response headers arrive.
   145  	// Return types.ActionPause if you want to stop sending headers to downstream.
   146  	OnHttpResponseHeaders(numHeaders int, endOfStream bool) Action
   147  
   148  	// OnHttpResponseBody is called when a response body *frame* arrives.
   149  	// Note that this is potentially called multiple times until we see end_of_stream = true.
   150  	// Return types.ActionPause if you want to buffer the body and stop sending body to the downtream.
   151  	// Even after returning types.ActionPause, this will be called when an unseen frame arrives.
   152  	OnHttpResponseBody(bodySize int, endOfStream bool) Action
   153  
   154  	// OnHttpResponseTrailers is called when response trailers arrive.
   155  	// Return types.ActionPause if you want to stop sending trailers to the downstream.
   156  	OnHttpResponseTrailers(numTrailers int) Action
   157  
   158  	// OnHttpStreamDone is called before the host deletes this context.
   159  	// You can retrieve the HTTP request/response information (such as headers, etc.) during this call.
   160  	// This can be used to implement logging features.
   161  	OnHttpStreamDone()
   162  }
   163  
   164  // DefaultContexts are a no-op implementation of contexts.
   165  // Users can embed them into their custom contexts, so that
   166  // they only have to implement methods they want.
   167  type (
   168  	// DefaultVMContext provides the no-op implementation of the VMContext interface.
   169  	DefaultVMContext struct{}
   170  
   171  	// DefaultPluginContext provides the no-op implementation of the PluginContext interface.
   172  	DefaultPluginContext struct{}
   173  
   174  	// DefaultTcpContext provides the no-op implementation of the TcpContext interface.
   175  	DefaultTcpContext struct{}
   176  
   177  	// DefaultHttpContext provides the no-op implementation of the HttpContext interface.
   178  	DefaultHttpContext struct{}
   179  )
   180  
   181  // impl VMContext
   182  
   183  func (*DefaultVMContext) OnVMStart(vmConfigurationSize int) OnVMStartStatus { return OnVMStartStatusOK }
   184  func (*DefaultVMContext) NewPluginContext(contextID uint32) PluginContext {
   185  	return &DefaultPluginContext{}
   186  }
   187  
   188  // impl PluginContext
   189  
   190  func (*DefaultPluginContext) OnQueueReady(uint32) {}
   191  func (*DefaultPluginContext) OnTick()             {}
   192  func (*DefaultPluginContext) OnPluginStart(int) OnPluginStartStatus {
   193  	return OnPluginStartStatusOK
   194  }
   195  func (*DefaultPluginContext) OnPluginDone() bool                { return true }
   196  func (*DefaultPluginContext) NewTcpContext(uint32) TcpContext   { return nil }
   197  func (*DefaultPluginContext) NewHttpContext(uint32) HttpContext { return nil }
   198  
   199  // impl TcpContext
   200  
   201  func (*DefaultTcpContext) OnDownstreamData(int, bool) Action { return ActionContinue }
   202  func (*DefaultTcpContext) OnDownstreamClose(PeerType)        {}
   203  func (*DefaultTcpContext) OnNewConnection() Action           { return ActionContinue }
   204  func (*DefaultTcpContext) OnUpstreamData(int, bool) Action   { return ActionContinue }
   205  func (*DefaultTcpContext) OnUpstreamClose(PeerType)          {}
   206  func (*DefaultTcpContext) OnStreamDone()                     {}
   207  
   208  // impl HttpContext
   209  
   210  func (*DefaultHttpContext) OnHttpRequestHeaders(int, bool) Action  { return ActionContinue }
   211  func (*DefaultHttpContext) OnHttpRequestBody(int, bool) Action     { return ActionContinue }
   212  func (*DefaultHttpContext) OnHttpRequestTrailers(int) Action       { return ActionContinue }
   213  func (*DefaultHttpContext) OnHttpResponseHeaders(int, bool) Action { return ActionContinue }
   214  func (*DefaultHttpContext) OnHttpResponseBody(int, bool) Action    { return ActionContinue }
   215  func (*DefaultHttpContext) OnHttpResponseTrailers(int) Action      { return ActionContinue }
   216  func (*DefaultHttpContext) OnHttpStreamDone()                      {}
   217  
   218  var (
   219  	_ VMContext     = &DefaultVMContext{}
   220  	_ PluginContext = &DefaultPluginContext{}
   221  	_ TcpContext    = &DefaultTcpContext{}
   222  	_ HttpContext   = &DefaultHttpContext{}
   223  )