Skip to content

Commit 5791899

Browse files
authored
Refactor around VM failure check on Http/Tcp callbacks. (#155)
Refactored around VM failure check on Http and Tcp callbacks in order to handle the VM failure right after it happens. Previously, for example, when panic happens in OnResponseHeaders, then we return Continue since we didn't check the isFail after the Wasm calls. That means Envoy sends the response headers to the client even if the VM fails in OnResponseHeaders, and the failClose is called on OnResponseBody. This seems problematic and unintended. Relevant to envoyproxy/envoy#14947. Signed-off-by: Takeshi Yoneda <[email protected]>
1 parent 4b33df7 commit 5791899

File tree

2 files changed

+92
-74
lines changed

2 files changed

+92
-74
lines changed

include/proxy-wasm/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ class ContextBase : public RootInterface,
389389
std::shared_ptr<PluginBase> temp_plugin_; // Remove once ABI v0.1.0 is gone.
390390
bool in_vm_context_created_ = false;
391391
bool destroyed_ = false;
392+
bool stream_failed_ = false; // Set true after failStream is called in case of VM failure.
392393

393394
private:
394395
// helper functions

src/context.cc

Lines changed: 91 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -25,40 +25,22 @@
2525
#include "src/shared_data.h"
2626
#include "src/shared_queue.h"
2727

28-
#define CHECK_FAIL(_call, _stream_type, _return_open, _return_closed) \
28+
#define CHECK_FAIL(_stream_type, _stream_type2, _return_open, _return_closed) \
2929
if (isFailed()) { \
3030
if (plugin_->fail_open_) { \
3131
return _return_open; \
32-
} else { \
32+
} else if (!stream_failed_) { \
3333
failStream(_stream_type); \
34-
return _return_closed; \
35-
} \
36-
} else { \
37-
if (!wasm_->_call) { \
38-
return _return_open; \
39-
} \
40-
}
41-
42-
#define CHECK_FAIL2(_call1, _call2, _stream_type, _return_open, _return_closed) \
43-
if (isFailed()) { \
44-
if (plugin_->fail_open_) { \
45-
return _return_open; \
46-
} else { \
47-
failStream(_stream_type); \
48-
return _return_closed; \
49-
} \
50-
} else { \
51-
if (!wasm_->_call1 && !wasm_->_call2) { \
52-
return _return_open; \
34+
failStream(_stream_type2); \
35+
stream_failed_ = true; \
5336
} \
37+
return _return_closed; \
5438
}
5539

56-
#define CHECK_HTTP(_call, _return_open, _return_closed) \
57-
CHECK_FAIL(_call, WasmStreamType::Request, _return_open, _return_closed)
58-
#define CHECK_HTTP2(_call1, _call2, _return_open, _return_closed) \
59-
CHECK_FAIL2(_call1, _call2, WasmStreamType::Request, _return_open, _return_closed)
60-
#define CHECK_NET(_call, _return_open, _return_closed) \
61-
CHECK_FAIL(_call, WasmStreamType::Downstream, _return_open, _return_closed)
40+
#define CHECK_FAIL_HTTP(_return_open, _return_closed) \
41+
CHECK_FAIL(WasmStreamType::Request, WasmStreamType::Response, _return_open, _return_closed)
42+
#define CHECK_FAIL_NET(_return_open, _return_closed) \
43+
CHECK_FAIL(WasmStreamType::Downstream, WasmStreamType::Upstream, _return_open, _return_closed)
6244

6345
namespace proxy_wasm {
6446

@@ -263,30 +245,40 @@ void ContextBase::onForeignFunction(uint32_t foreign_function_id, uint32_t data_
263245
}
264246

265247
FilterStatus ContextBase::onNetworkNewConnection() {
266-
CHECK_NET(on_new_connection_, FilterStatus::Continue, FilterStatus::StopIteration);
267-
DeferAfterCallActions actions(this);
268-
if (wasm_->on_new_connection_(this, id_).u64_ == 0) {
248+
CHECK_FAIL_NET(FilterStatus::Continue, FilterStatus::StopIteration);
249+
if (!wasm_->on_new_connection_) {
269250
return FilterStatus::Continue;
270251
}
271-
return FilterStatus::StopIteration;
252+
DeferAfterCallActions actions(this);
253+
const auto result = wasm_->on_new_connection_(this, id_);
254+
CHECK_FAIL_NET(FilterStatus::Continue, FilterStatus::StopIteration);
255+
return result == 0 ? FilterStatus::Continue : FilterStatus::StopIteration;
272256
}
273257

274258
FilterStatus ContextBase::onDownstreamData(uint32_t data_length, bool end_of_stream) {
275-
CHECK_NET(on_downstream_data_, FilterStatus::Continue, FilterStatus::StopIteration);
259+
CHECK_FAIL_NET(FilterStatus::Continue, FilterStatus::StopIteration);
260+
if (!wasm_->on_downstream_data_) {
261+
return FilterStatus::Continue;
262+
}
276263
DeferAfterCallActions actions(this);
277264
auto result = wasm_->on_downstream_data_(this, id_, static_cast<uint32_t>(data_length),
278265
static_cast<uint32_t>(end_of_stream));
279266
// TODO(PiotrSikora): pull Proxy-WASM's FilterStatus values.
280-
return result.u64_ == 0 ? FilterStatus::Continue : FilterStatus::StopIteration;
267+
CHECK_FAIL_NET(FilterStatus::Continue, FilterStatus::StopIteration);
268+
return result == 0 ? FilterStatus::Continue : FilterStatus::StopIteration;
281269
}
282270

283271
FilterStatus ContextBase::onUpstreamData(uint32_t data_length, bool end_of_stream) {
284-
CHECK_NET(on_upstream_data_, FilterStatus::Continue, FilterStatus::StopIteration);
272+
CHECK_FAIL_NET(FilterStatus::Continue, FilterStatus::StopIteration);
273+
if (!wasm_->on_upstream_data_) {
274+
return FilterStatus::Continue;
275+
}
285276
DeferAfterCallActions actions(this);
286277
auto result = wasm_->on_upstream_data_(this, id_, static_cast<uint32_t>(data_length),
287278
static_cast<uint32_t>(end_of_stream));
288279
// TODO(PiotrSikora): pull Proxy-WASM's FilterStatus values.
289-
return result.u64_ == 0 ? FilterStatus::Continue : FilterStatus::StopIteration;
280+
CHECK_FAIL_NET(FilterStatus::Continue, FilterStatus::StopIteration);
281+
return result == 0 ? FilterStatus::Continue : FilterStatus::StopIteration;
290282
}
291283

292284
void ContextBase::onDownstreamConnectionClose(CloseType close_type) {
@@ -307,74 +299,99 @@ void ContextBase::onUpstreamConnectionClose(CloseType close_type) {
307299
template <typename P> static uint32_t headerSize(const P &p) { return p ? p->size() : 0; }
308300

309301
FilterHeadersStatus ContextBase::onRequestHeaders(uint32_t headers, bool end_of_stream) {
310-
CHECK_HTTP2(on_request_headers_abi_01_, on_request_headers_abi_02_, FilterHeadersStatus::Continue,
311-
FilterHeadersStatus::StopAllIterationAndWatermark);
302+
CHECK_FAIL_HTTP(FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark);
303+
if (!wasm_->on_request_headers_abi_01_ && !wasm_->on_request_headers_abi_02_) {
304+
return FilterHeadersStatus::Continue;
305+
}
312306
DeferAfterCallActions actions(this);
313-
return convertVmCallResultToFilterHeadersStatus(
314-
wasm_->on_request_headers_abi_01_
315-
? wasm_->on_request_headers_abi_01_(this, id_, headers).u64_
316-
: wasm_
317-
->on_request_headers_abi_02_(this, id_, headers,
318-
static_cast<uint32_t>(end_of_stream))
319-
.u64_);
307+
const auto result = wasm_->on_request_headers_abi_01_
308+
? wasm_->on_request_headers_abi_01_(this, id_, headers)
309+
: wasm_->on_request_headers_abi_02_(this, id_, headers,
310+
static_cast<uint32_t>(end_of_stream));
311+
CHECK_FAIL_HTTP(FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark);
312+
return convertVmCallResultToFilterHeadersStatus(result);
320313
}
321314

322315
FilterDataStatus ContextBase::onRequestBody(uint32_t data_length, bool end_of_stream) {
323-
CHECK_HTTP(on_request_body_, FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer);
316+
CHECK_FAIL_HTTP(FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer);
317+
if (!wasm_->on_request_body_) {
318+
return FilterDataStatus::Continue;
319+
}
324320
DeferAfterCallActions actions(this);
325-
return convertVmCallResultToFilterDataStatus(
326-
wasm_->on_request_body_(this, id_, data_length, static_cast<uint32_t>(end_of_stream)).u64_);
321+
const auto result =
322+
wasm_->on_request_body_(this, id_, data_length, static_cast<uint32_t>(end_of_stream));
323+
CHECK_FAIL_HTTP(FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer);
324+
return convertVmCallResultToFilterDataStatus(result);
327325
}
328326

329327
FilterTrailersStatus ContextBase::onRequestTrailers(uint32_t trailers) {
330-
CHECK_HTTP(on_request_trailers_, FilterTrailersStatus::Continue,
331-
FilterTrailersStatus::StopIteration);
328+
CHECK_FAIL_HTTP(FilterTrailersStatus::Continue, FilterTrailersStatus::StopIteration);
329+
if (!wasm_->on_request_trailers_) {
330+
return FilterTrailersStatus::Continue;
331+
}
332332
DeferAfterCallActions actions(this);
333-
return convertVmCallResultToFilterTrailersStatus(
334-
wasm_->on_request_trailers_(this, id_, trailers).u64_);
333+
const auto result = wasm_->on_request_trailers_(this, id_, trailers);
334+
CHECK_FAIL_HTTP(FilterTrailersStatus::Continue, FilterTrailersStatus::StopIteration);
335+
return convertVmCallResultToFilterTrailersStatus(result);
335336
}
336337

337338
FilterMetadataStatus ContextBase::onRequestMetadata(uint32_t elements) {
338-
CHECK_HTTP(on_request_metadata_, FilterMetadataStatus::Continue, FilterMetadataStatus::Continue);
339+
CHECK_FAIL_HTTP(FilterMetadataStatus::Continue, FilterMetadataStatus::Continue);
340+
if (!wasm_->on_request_metadata_) {
341+
return FilterMetadataStatus::Continue;
342+
}
339343
DeferAfterCallActions actions(this);
340-
return convertVmCallResultToFilterMetadataStatus(
341-
wasm_->on_request_metadata_(this, id_, elements).u64_);
344+
const auto result = wasm_->on_request_metadata_(this, id_, elements);
345+
CHECK_FAIL_HTTP(FilterMetadataStatus::Continue, FilterMetadataStatus::Continue);
346+
return convertVmCallResultToFilterMetadataStatus(result);
342347
}
343348

344349
FilterHeadersStatus ContextBase::onResponseHeaders(uint32_t headers, bool end_of_stream) {
345-
CHECK_HTTP2(on_response_headers_abi_01_, on_response_headers_abi_02_,
346-
FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark);
350+
CHECK_FAIL_HTTP(FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark);
351+
if (!wasm_->on_response_headers_abi_01_ && !wasm_->on_response_headers_abi_02_) {
352+
return FilterHeadersStatus::Continue;
353+
}
347354
DeferAfterCallActions actions(this);
348-
return convertVmCallResultToFilterHeadersStatus(
349-
wasm_->on_response_headers_abi_01_
350-
? wasm_->on_response_headers_abi_01_(this, id_, headers).u64_
351-
: wasm_
352-
->on_response_headers_abi_02_(this, id_, headers,
353-
static_cast<uint32_t>(end_of_stream))
354-
.u64_);
355+
const auto result = wasm_->on_response_headers_abi_01_
356+
? wasm_->on_response_headers_abi_01_(this, id_, headers)
357+
: wasm_->on_response_headers_abi_02_(
358+
this, id_, headers, static_cast<uint32_t>(end_of_stream));
359+
CHECK_FAIL_HTTP(FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark);
360+
return convertVmCallResultToFilterHeadersStatus(result);
355361
}
356362

357363
FilterDataStatus ContextBase::onResponseBody(uint32_t body_length, bool end_of_stream) {
358-
CHECK_HTTP(on_response_body_, FilterDataStatus::Continue,
359-
FilterDataStatus::StopIterationNoBuffer);
364+
CHECK_FAIL_HTTP(FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer);
365+
if (!wasm_->on_response_body_) {
366+
return FilterDataStatus::Continue;
367+
}
360368
DeferAfterCallActions actions(this);
361-
return convertVmCallResultToFilterDataStatus(
362-
wasm_->on_response_body_(this, id_, body_length, static_cast<uint32_t>(end_of_stream)).u64_);
369+
const auto result =
370+
wasm_->on_response_body_(this, id_, body_length, static_cast<uint32_t>(end_of_stream));
371+
CHECK_FAIL_HTTP(FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer);
372+
return convertVmCallResultToFilterDataStatus(result);
363373
}
364374

365375
FilterTrailersStatus ContextBase::onResponseTrailers(uint32_t trailers) {
366-
CHECK_HTTP(on_response_trailers_, FilterTrailersStatus::Continue,
367-
FilterTrailersStatus::StopIteration);
376+
CHECK_FAIL_HTTP(FilterTrailersStatus::Continue, FilterTrailersStatus::StopIteration);
377+
if (!wasm_->on_response_trailers_) {
378+
return FilterTrailersStatus::Continue;
379+
}
368380
DeferAfterCallActions actions(this);
369-
return convertVmCallResultToFilterTrailersStatus(
370-
wasm_->on_response_trailers_(this, id_, trailers).u64_);
381+
const auto result = wasm_->on_response_trailers_(this, id_, trailers);
382+
CHECK_FAIL_HTTP(FilterTrailersStatus::Continue, FilterTrailersStatus::StopIteration);
383+
return convertVmCallResultToFilterTrailersStatus(result);
371384
}
372385

373386
FilterMetadataStatus ContextBase::onResponseMetadata(uint32_t elements) {
374-
CHECK_HTTP(on_response_metadata_, FilterMetadataStatus::Continue, FilterMetadataStatus::Continue);
387+
CHECK_FAIL_HTTP(FilterMetadataStatus::Continue, FilterMetadataStatus::Continue);
388+
if (!wasm_->on_response_metadata_) {
389+
return FilterMetadataStatus::Continue;
390+
}
375391
DeferAfterCallActions actions(this);
376-
return convertVmCallResultToFilterMetadataStatus(
377-
wasm_->on_response_metadata_(this, id_, elements).u64_);
392+
const auto result = wasm_->on_response_metadata_(this, id_, elements);
393+
CHECK_FAIL_HTTP(FilterMetadataStatus::Continue, FilterMetadataStatus::Continue);
394+
return convertVmCallResultToFilterMetadataStatus(result);
378395
}
379396

380397
void ContextBase::onHttpCallResponse(uint32_t token, uint32_t headers, uint32_t body_size,

0 commit comments

Comments
 (0)