Skip to content
File

Blob: src/workerd/util/autogate.c++

4.4 KB
1// Copyright (c) 2017-2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4#include "autogate.h"
5 
6#include <workerd/util/sentry.h>
7 
8#include <stdlib.h>
9 
10#include <capnp/message.h>
11#include <kj/common.h>
12#include <kj/debug.h>
13 
14namespace workerd::util {
15 
16kj::Maybe<Autogate> globalAutogate;
17 
18kj::StringPtr KJ_STRINGIFY(AutogateKey key) {
19 switch (key) {
20 case AutogateKey::TEST_WORKERD:
21 return "test-workerd"_kj;
22 case AutogateKey::TCP_SOCKET_CONNECT_OUTPUT_GATE:
23 return "tcp-socket-connect-output-gate"_kj;
24 case AutogateKey::V8_FAST_API:
25 return "v8-fast-api"_kj;
26 case AutogateKey::STREAMING_TAIL_WORKER:
27 return "streaming-tail-worker"_kj;
28 case AutogateKey::TAIL_STREAM_REFACTOR:
29 return "tail-stream-refactor"_kj;
30 case AutogateKey::RUST_BACKED_NODE_DNS:
31 return "rust-backed-node-dns"_kj;
32 case AutogateKey::RPC_USE_EXTERNAL_PUSHER:
33 return "rpc-use-external-pusher"_kj;
34 case AutogateKey::WASM_SHUTDOWN_SIGNAL_SHIM:
35 return "wasm-shutdown-signal-shim"_kj;
36 case AutogateKey::ENABLE_FAST_TEXTENCODER:
37 return "enable-fast-textencoder"_kj;
38 case AutogateKey::ENABLE_DRAINING_READ_ON_STANDARD_STREAMS:
39 return "enable-draining-read-on-standard-streams"_kj;
40 case AutogateKey::SQL_RESTRICT_RESERVED_NAMES:
41 return "sql-restrict-reserved-names"_kj;
42 case AutogateKey::INCREASE_SQLITE_HARD_HEAP_LIMIT:
43 return "increase-sqlite-hard-heap-limit"_kj;
44 case AutogateKey::USER_SPAN_CONTEXT_PROPAGATION:
45 return "user-span-context-propagation"_kj;
46 case AutogateKey::UPDATED_AUTO_ALLOCATE_CHUNK_SIZE:
47 return "updated-auto-allocate-chunk-size"_kj;
48 case AutogateKey::PYTHON_ABORT_ISOLATE_ON_FATAL_ERROR:
49 return "python-abort-isolate-on-fatal-error"_kj;
50 case AutogateKey::JSRPC_SESSION_HANDLE:
51 return "jsrpc-session-handle"_kj;
52 case AutogateKey::NumOfKeys:
53 KJ_FAIL_ASSERT("NumOfKeys should not be used in getName");
54 }
55}
56 
57Autogate::Autogate(capnp::List<capnp::Text>::Reader autogates) {
58 // gates array is zero-initialized by default.
59 for (auto name: autogates) {
60 if (!name.startsWith("workerd-autogate-")) {
61 LOG_ERROR_ONCE("Autogate configuration includes gate with invalid prefix.");
62 continue;
63 }
64 auto sliced = name.slice(17);
65 
66 // Parse the gate name into a AutogateKey.
67 for (AutogateKey i = AutogateKey(0); i < AutogateKey::NumOfKeys;
68 i = AutogateKey(static_cast<int>(i) + 1)) {
69 if (kj::str(i) == sliced) {
70 gates[static_cast<unsigned long>(i)] = true;
71 break;
72 }
73 }
74 }
75}
76 
77bool Autogate::isEnabled(AutogateKey key) {
78 KJ_IF_SOME(a, globalAutogate) {
79 return a.gates[static_cast<unsigned long>(key)];
80 }
81 
82 static const bool defaultResult = getenv("WORKERD_ALL_AUTOGATES") != nullptr;
83 return defaultResult;
84}
85 
86void Autogate::initAutogate(
87 capnp::List<capnp::Text>::Reader gates, IgnoreAllAutogatesEnv ignoreEnv) {
88 // If the WORKERD_ALL_AUTOGATES env var is set, enable all gates regardless of what
89 // was passed in. This ensures the @all-autogates test variant works even when
90 // initAutogate({}) is called early (e.g. by TestFixture), which would otherwise
91 // set globalAutogate to all-false and prevent isEnabled() from reaching its env var
92 // fallback.
93 //
94 // Callers (e.g. the production server) that manage the all-autogates behavior themselves and
95 // build selective gate configs can pass IgnoreAllAutogatesEnv::YES to skip this override.
96 if (!ignoreEnv && getenv("WORKERD_ALL_AUTOGATES") != nullptr) {
97 return initAllAutogates();
98 }
99 globalAutogate = Autogate(gates);
100}
101 
102void Autogate::deinitAutogate() {
103 globalAutogate = kj::none;
104}
105 
106void Autogate::initAllAutogates() {
107 Autogate autogate;
108 for (AutogateKey i = AutogateKey(0); i < AutogateKey::NumOfKeys;
109 i = AutogateKey(static_cast<int>(i) + 1)) {
110 autogate.gates[static_cast<unsigned long>(i)] = true;
111 }
112 globalAutogate = kj::mv(autogate);
113}
114 
115void Autogate::initAutogateNamesForTest(std::initializer_list<kj::StringPtr> gateNames) {
116 capnp::MallocMessageBuilder message;
117 auto orphanage = message.getOrphanage();
118 auto gatesOrphan = orphanage.newOrphan<capnp::List<capnp::Text>>(gateNames.size());
119 auto gates = gatesOrphan.get();
120 size_t count = 0;
121 for (auto name: gateNames) {
122 gates.set(count++, kj::str("workerd-autogate-", name));
123 }
124 Autogate::initAutogate(gates.asReader());
125}
126 
127} // namespace workerd::util