bdy 1.22.92 → 1.22.93-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/distTs/package.json +1 -1
- package/distTs/src/agent/manager.js +30 -19
- package/distTs/src/index.js +1 -0
- package/distTs/src/output.js +12 -0
- package/distTs/src/texts.js +15 -10
- package/distTs/src/tunnel/http.js +32 -4
- package/distTs/src/tunnel/ssh/client.js +28 -0
- package/distTs/src/tunnel/tunnel.js +53 -1
- package/distTs/src/utils.js +7 -2
- package/package.json +1 -1
package/distTs/package.json
CHANGED
|
@@ -74,27 +74,38 @@ class AgentManagerClass {
|
|
|
74
74
|
this.load(id, host, token, port).then();
|
|
75
75
|
}
|
|
76
76
|
async tryFetch() {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
await this.disableAgentAndExit(texts_1.ERR_AGENT_NOT_FOUND);
|
|
77
|
+
let delay = utils_1.AGENT_FETCH_RETRY_MIN;
|
|
78
|
+
for (;;) {
|
|
79
|
+
try {
|
|
80
|
+
this.agent = await getApiBuddy().fetchAgent(this.id || '', this.host || '', this.token || '');
|
|
81
|
+
this.agent.manager = this;
|
|
82
|
+
this.agent.startRefreshingConfiguration((success) => {
|
|
83
|
+
if (success)
|
|
84
|
+
this.status = tunnel_1.TUNNEL_AGENT_STATUS.ENABLED;
|
|
85
|
+
else
|
|
86
|
+
this.status = tunnel_1.TUNNEL_AGENT_STATUS.FETCH_FAILED;
|
|
87
|
+
});
|
|
88
|
+
await this.agent.start();
|
|
89
|
+
this.status = tunnel_1.TUNNEL_AGENT_STATUS.ENABLED;
|
|
90
|
+
return;
|
|
92
91
|
}
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
catch (err) {
|
|
93
|
+
if (err instanceof utils_1.ApiErrorAgentNotFound) {
|
|
94
|
+
await this.disableAgentAndExit(texts_1.ERR_AGENT_NOT_FOUND);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Full jitter, not just backoff: with Restart=always / RestartSec=3 a
|
|
98
|
+
// crash looping fleet re-enters this loop in lockstep, and every agent
|
|
99
|
+
// that sat out an outage would otherwise retry within the same few
|
|
100
|
+
// seconds of the API coming back. A loop rather than a recursive
|
|
101
|
+
// `return this.tryFetch()` so the retry chain does not keep every
|
|
102
|
+
// suspended frame alive for the whole outage.
|
|
103
|
+
const wait = Math.round(delay * (0.5 + Math.random() * 0.5));
|
|
95
104
|
this.status = tunnel_1.TUNNEL_AGENT_STATUS.FETCH_FAILED;
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
// One decimal, so the message never claims a delay it is not taking
|
|
106
|
+
output_1.default.normal((0, texts_1.AGENT_FETCH_RETRY)(Math.round(wait / 100) / 10));
|
|
107
|
+
await (0, utils_1.sleep)(wait);
|
|
108
|
+
delay = Math.min(delay * 2, utils_1.AGENT_FETCH_RETRY_MAX);
|
|
98
109
|
}
|
|
99
110
|
}
|
|
100
111
|
}
|
package/distTs/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const output_1 = __importDefault(require("./output"));
|
|
7
7
|
const logger_1 = __importDefault(require("./logger"));
|
|
8
8
|
const stream_1 = __importDefault(require("stream"));
|
|
9
|
+
output_1.default.muteNodeWarnings();
|
|
9
10
|
stream_1.default.setDefaultHighWaterMark(false, 65536);
|
|
10
11
|
process.title = 'bdy';
|
|
11
12
|
process.on('uncaughtException', (err) => {
|
package/distTs/src/output.js
CHANGED
|
@@ -597,6 +597,18 @@ class Output {
|
|
|
597
597
|
if (this._a)
|
|
598
598
|
this._a.destroy(() => { });
|
|
599
599
|
}
|
|
600
|
+
// Node prints warnings caused by the host environment rather than by anything
|
|
601
|
+
// the cli did - the common one being NODE_TLS_REJECT_UNAUTHORIZED=0 exported by
|
|
602
|
+
// a sandbox, emitted on the first TLS connection. They go to stderr and corrupt
|
|
603
|
+
// redirected output, --format json in particular. Muted on released builds
|
|
604
|
+
// only; every pre-release channel and DEBUG=1 still show everything.
|
|
605
|
+
static muteNodeWarnings() {
|
|
606
|
+
if (process.env.DEBUG === '1')
|
|
607
|
+
return;
|
|
608
|
+
if ((0, utils_1.getVersionEnv)() !== 'prod')
|
|
609
|
+
return;
|
|
610
|
+
process.emitWarning = () => { };
|
|
611
|
+
}
|
|
600
612
|
static clearTerminal() {
|
|
601
613
|
this.killSpinner();
|
|
602
614
|
if (!_terminal)
|
package/distTs/src/texts.js
CHANGED
|
@@ -9,15 +9,15 @@ exports.OPTION_PIPELINE_RUN_REVISION = exports.OPTION_PIPELINE_RUN_TAG = exports
|
|
|
9
9
|
exports.OPTION_FORCE = exports.OPTION_TOKEN = exports.OPTION_TIMEOUT = exports.OPTION_FOLLOW = exports.OPTION_SERVE = exports.OPTION_HEADER_USER_AGENT = exports.OPTION_RESPONSE_HEADER = exports.OPTION_HEADER = exports.OPTION_WHITELIST = exports.OPTION_REST_API_PER_PAGE = exports.OPTION_REST_API_PAGE = exports.OPTION_REST_API_PROJECT = exports.OPTION_REST_API_WORKSPACE = exports.OPTION_FORMAT_JSONL = exports.OPTION_FORMAT = exports.OPTION_VERSION = exports.OPTION_PIPELINE_RUN_NO_FOLLOW = exports.OPTION_PIPELINE_RUN_NO_WAIT = exports.OPTION_PIPELINE_RUN_ACTION = exports.OPTION_REST_API_TOKEN = exports.OPTION_ARTIFACT_DOWNLOAD_REPLACE = exports.OPTION_ARTIFACT_DOWNLOAD_MERGE = exports.OPTION_ARTIFACT_PUBLISH_OVERWRITE_VERSION = exports.OPTION_ARTIFACT_VERSION_FROM = exports.OPTION_ARTIFACT_PUBLISH_CREATE = exports.OPTION_ARTIFACT_ID = exports.OPTION_ARTIFACT_DOWNLOAD_PATH = exports.OPTION_ARTIFACT_PUBLISH_PATH = exports.OPTION_PIPELINE_RUN_ACTION_ID = exports.OPTION_PIPELINE_RUN_ID = exports.OPTION_PIPELINE_YAML = exports.TXT_PIPELINE_DELETED = exports.TXT_PIPELINE_DELETE_CONFIRM = exports.TXT_PIPELINE_UPDATED = exports.TXT_PIPELINE_CREATED = exports.OPTION_PIPELINE_NAME = exports.OPTION_PIPELINE_IDENTIFIER = exports.OPTION_PIPELINE_RUN_ARTIFACT = exports.OPTION_PIPELINE_RUN_ENVIRONMENT = exports.OPTION_PIPELINE_RUN_DELAY = exports.ERR_RUN_VAR_FILE_INVALID = exports.ERR_RUN_VAR_FILE_NOT_FOUND = exports.OPTION_RUN_SINGLE_VAR_FILE = exports.OPTION_RUN_VAR_FILE = exports.OPTION_RUN_VAR = exports.OPTION_PIPELINE_RUN_PRIORITY = exports.OPTION_PIPELINE_RUN_CLEAR_CACHE = exports.OPTION_PIPELINE_RUN_REFRESH = exports.OPTION_PIPELINE_RUN_COMMENT = exports.OPTION_PIPELINE_RUN_PULL_REQUEST = void 0;
|
|
10
10
|
exports.OPTION_CRAWL_FULL_PAGE = exports.OPTION_CRAWL_QUALITY = exports.OPTION_CRAWL_OUTPUT_TYPE = exports.OPTION_CRAWL_FOLLOW = exports.OPTION_CRAWL_URL = exports.OPTION_COMPARE_WAIT_FOR = exports.OPTION_COMPARE_DELAY = exports.OPTION_COMPARE_HEADER = exports.OPTION_COMPARE_COOKIE = exports.OPTION_COMPARE_IGNORE = exports.OPTION_COMPARE_IGNORE_URLS = exports.OPTION_COMPARE_DRY_RUN = exports.OPTION_COMPARE_URLS_FILE = exports.OPTION_COMPARE_SITEMAP = exports.OPTION_COMPARE_URLS = exports.OPTION_COMPARE_RESPECT_ROBOTS = exports.OPTION_COMPARE_FOLLOW = exports.OPTION_EXEC_PARALLEL = exports.OPTION_EXEC_ONE_BY_ONE = exports.OPTION_EXEC_SKIP_DISCOVERY = exports.OPTION_EXEC_COMMAND = exports.OPTION_AGENT_DEBUG = exports.OPTION_AGENT_PORT = exports.OPTION_AGENT_TAG = exports.OPTION_AGENT_TUNNELING = exports.OPTION_AGENT_PROXY = exports.OPTION_AGENT_TARGET = exports.OPTION_PASS = exports.OPTION_APP = exports.OPTION_USER = exports.OPTION_AGENT_TOKEN = exports.OPTION_AGENT_START = exports.OPTION_AGENT_ID = exports.OPTION_ID = exports.OPTION_NAME = exports.OPTION_TARGET = exports.OPTION_TLS_TERMINATE = exports.OPTION_TLS_CA = exports.OPTION_TLS_CERT = exports.OPTION_TLS_KEY = exports.OPTION_HTTP_CIRCUIT_BREAKER = exports.OPTION_HTTP_COMPRESSION = exports.OPTION_HTTP_2 = exports.OPTION_HTTP_VERIFY = exports.OPTION_HTTP_LOG = exports.OPTION_HTTP_AUTH_BUDDY = exports.OPTION_HTTP_AUTH = exports.OPTION_HTTP_HOST = exports.OPTION_CONFIRM_DOMAIN_BUY = exports.OPTION_CONFIRM_FORCE = void 0;
|
|
11
11
|
exports.LOG_HTTP1_REQUEST = exports.LOG_HTTP1_CONNECTION = exports.LOG_ERROR = exports.LOG_STOPPING_TUNNEL = exports.LOG_STARTING_TUNNEL = exports.LOG_ENABLING_AGENT_TUNNELING = exports.LOG_ENABLING_AGENT_PROXY = exports.LOG_ENABLING_AGENT_TARGET = exports.LOG_DISABLING_AGENT_TUNNELING = exports.LOG_DISABLING_AGENT_PROXY = exports.LOG_DISABLING_AGENT_TARGET = exports.LOG_REMOVING_TUNNEL = exports.LOG_TUNNEL_REGISTERED = exports.LOG_ERROR_WHILE_REFRESHING_AGENT = exports.LOG_REGISTERING_TUNNEL = exports.LOG_GETTING_AGENT = exports.LOG_UNREGISTERING_AGENT = exports.LOG_REGION_DETECTED = exports.LOG_AGENT_REGISTERED = exports.LOG_SOCKET_DISCONNECTED = exports.LOG_SOCKET_CONNECTED = exports.LOG_AGENT_NSSM_CLEARING = exports.LOG_AGENT_NSSM_EXTRACTING = exports.LOG_AGENT_NSSM_DOWNLOADING = exports.LOG_AGENT_ENABLED = exports.LOG_AGENT_STARTING_SYSTEM = exports.LOG_AGENT_STOPPING_SYSTEM = exports.LOG_AGENT_ENABLING_SYSTEM = exports.LOG_AGENT_SYSTEM_SERVICE_CONFIG = exports.LOG_AGENT_EXTRACTING_ARCHIVE = exports.LOG_AGENT_DOWNLOADING_ARCHIVE = exports.LOG_AGENT_SYSTEM_DIR = exports.LOG_ERROR_SAVING_AGENT_LOCAL_CONFIG = exports.LOG_ERROR_REMOVING_AGENT_STANDALONE_LOCK_FILE = exports.LOG_ERROR_SAVING_AGENT_STANDALONE_CONFIG = exports.LOG_ERROR_SAVING_AGENT_SYSTEM_CONFIG = exports.LOG_SAVING_AGENT_LOCAL_CONFIG = exports.LOG_REMOVING_AGENT_PROC_ID = exports.LOG_SAVING_AGENT_PROC_ID = exports.LOG_SAVING_AGENT_SYSTEM_CONFIG = exports.LOG_REGISTERING_AGENT = exports.OPTION_CRAWL_OUTPUT_TYPES = exports.OPTION_CRAWL_OUTPUT_DIR = exports.OPTION_CRAWL_DELAY = exports.OPTION_CRAWL_LOCAL_STORAGE = exports.OPTION_CRAWL_DEVICES = exports.OPTION_CRAWL_BROWSERS = exports.OPTION_CRAWL_COLOR_SCHEME = exports.OPTION_CRAWL_XPATH_SELECTOR = exports.OPTION_CRAWL_CSS_SELECTOR = void 0;
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
15
|
-
exports.
|
|
16
|
-
exports.
|
|
17
|
-
exports.
|
|
18
|
-
exports.
|
|
19
|
-
exports.
|
|
20
|
-
exports.EXAMPLE_CRAWL_LINK = exports.EXAMPLE_CRAWL_RUN = exports.EXAMPLE_TESTS_CAPTURE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CLOSE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CREATE = exports.EXAMPLE_TESTS_VISUAL_LINK = exports.EXAMPLE_TESTS_VISUAL_UPLOAD = exports.EXAMPLE_TESTS_VISUAL_SETUP = exports.EXAMPLE_TESTS_UNIT_LINK = exports.EXAMPLE_TESTS_UNIT_UPLOAD = exports.EXAMPLE_ARTIFACT_VERSION_DELETE = exports.EXAMPLE_ARTIFACT_VERSION_GET = exports.EXAMPLE_ARTIFACT_VERSION_LIST = exports.EXAMPLE_ARTIFACT_CREATE = exports.EXAMPLE_ARTIFACT_DELETE = exports.EXAMPLE_ARTIFACT_DOWNLOAD = exports.EXAMPLE_ARTIFACT_PUBLISH = exports.EXAMPLE_ARTIFACT_VERSION_CREATE = exports.EXAMPLE_PIPELINE_RUN_RETRY = exports.EXAMPLE_PIPELINE_RUN_LIST = exports.EXAMPLE_PIPELINE_LIST = exports.EXAMPLE_PIPELINE_YML = exports.EXAMPLE_PIPELINE_GET = exports.EXAMPLE_PIPELINE_UPDATE = exports.EXAMPLE_PIPELINE_DELETE = exports.EXAMPLE_PIPELINE_CREATE = exports.EXAMPLE_PIPELINE_RUN_CANCEL = exports.EXAMPLE_PIPELINE_RUN_APPLY = void 0;
|
|
12
|
+
exports.DESC_COMMAND_SANDBOX_DESTROY = exports.DESC_COMMAND_SANDBOX_GET = exports.DESC_COMMAND_SANDBOX_LIST = exports.DESC_COMMAND_SANDBOX_UPDATE = exports.DESC_COMMAND_SANDBOX_GET_YAML = exports.DESC_COMMAND_SANDBOX_CREATE = exports.DESC_COMMAND_SANDBOX = exports.DEBUG_WAIT_FOR_IDLE_TIMEOUT = exports.DEBUG_WAIT_FOR_IDLE = exports.DEBUG_RESOURCE_DISCOVERY_TIMEOUT = exports.DEBUG_AUTO_WIDTH = exports.DEBUG_AUTO_SCROLL = exports.DEBUG_RESOURCE_CRAWLING_URL = exports.DEBUG_SNAPSHOT_PROCESSING = exports.DEBUG_SNAPSHOTS_PROCESSING = exports.DEBUG_EXEC_COMMAND = exports.DEBUG_EXEC_TEST_COMMAND = exports.LOG_INSTALLED_BROWSER = exports.LOG_SESSION_LINK = exports.LOG_SENDING_DATA = exports.LOG_SENDING_REQUEST = exports.LOG_PROCESSING_SNAPSHOTS = exports.LOG_RUNNING_EXEC_COMMAND = exports.LOG_TUNNEL_SSH_STREAM = exports.LOG_TUNNEL_TLS_AGENT_STREAM = exports.LOG_TUNNEL_TLS_REGION_STREAM = exports.LOG_TUNNEL_TLS_TARGET_STREAM = exports.LOG_TUNNEL_HTTP2_STREAM = exports.LOG_TUNNEL_HTTP1_STREAM = exports.LOG_TUNNEL_TCP_STREAM = exports.LOG_TUNNEL_HTTP_WRONG_USER_AGENTS = exports.LOG_TUNNEL_HTTP_CIRCUIT_BREAKER_OPEN = exports.LOG_TUNNEL_HTTP_MAX_INFLIGHT = exports.LOG_TUNNEL_HTTP_RATE_LIMIT = exports.LOG_TUNNEL_HTTP_WRON_AUTH = exports.LOG_TUNNEL_IDENTIFIED = exports.LOG_TUNNEL_DISCONNECTED = exports.LOG_TUNNEL_FAILED = exports.LOG_TUNNEL_CONNECTED = exports.LOG_AGENT_STARTED = exports.LOG_AGENT_SERVER_STARTED = exports.LOG_ERROR_STARTING_AGENT_SERVER = exports.LOG_SSH_CONNECTION = exports.LOG_LATE_TARGET_ERROR = exports.LOG_LATE_CHANNEL_ERROR = exports.LOG_HANDSHAKE_TIMEOUT = exports.LOG_WRONG_STREAM = exports.LOG_DETECTED_STREAM = exports.LOG_HTTP2_REQUEST = exports.LOG_HTTP2_CONNECTION = void 0;
|
|
13
|
+
exports.TXT_SANDBOX_WAITING_STOP = exports.TXT_SANDBOX_WAITING_APPS = exports.TXT_SANDBOX_WAITING_SETUP = exports.TXT_SANDBOX_WAITING_RUNNING = exports.TXT_SANDBOX_STOPPED = exports.TXT_SANDBOX_STARTED = exports.TXT_SANDBOX_DESTROYED = exports.TXT_SANDBOX_DESTROY_CONFIRM = exports.TXT_SANDBOX_UPDATED = exports.TXT_SANDBOX_CREATED = exports.TXT_SANDBOX_CREATING = exports.TXT_SANDBOX_APP_STARTED = exports.TXT_SANDBOX_APP_STOPPED = exports.OPTION_SANDBOX_WAIT = exports.OPTION_SANDBOX_WAIT_APPS = exports.OPTION_SANDBOX_WAIT_CONFIGURED = exports.OPTION_SANDBOX_WAIT_RUNNING = exports.ERR_SANDBOX_STOP_FAILED = exports.ERR_SANDBOX_NO_COMMANDS = exports.ERR_SANDBOX_RUNNING_FAILED = exports.ERR_SANDBOX_STOP_TIMEOUT = exports.ERR_SANDBOX_SNAPSHOT_TIMEOUT = exports.ERR_SANDBOX_RUNNING_TIMEOUT = exports.ERR_SANDBOX_APPS_TIMEOUT = exports.ERR_SANDBOX_SETUP_TIMEOUT = exports.ERR_SANDBOX_APP_FAILED = exports.ERR_SANDBOX_SETUP_FAILED = exports.ERR_SANDBOX_INVALID_RESOURCES = exports.ERR_SANDBOX_APP_NOT_FOUND = exports.ERR_SANDBOX_NOT_FOUND = exports.OPTION_SANDBOX_RUNTIME = exports.OPTION_SANDBOX_TIMEOUT = exports.OPTION_SANDBOX_FETCH = exports.OPTION_SANDBOX_APP_DIR = exports.OPTION_SANDBOX_APP_COMMAND = exports.OPTION_SANDBOX_YAML = exports.OPTION_SANDBOX_TAGS = exports.OPTION_SANDBOX_INSTALL_SCRIPT = exports.OPTION_SANDBOX_INSTALL_COMMANDS = exports.OPTION_SANDBOX_RESOURCES = exports.OPTION_SANDBOX_OS = exports.OPTION_SANDBOX_NAME = exports.OPTION_SANDBOX_IDENTIFIER = exports.DESC_COMMAND_SANDBOX_APP = exports.DESC_COMMAND_SANDBOX_EXEC = exports.DESC_COMMAND_SANDBOX_STATUS = exports.DESC_COMMAND_SANDBOX_LOGS = exports.DESC_COMMAND_SANDBOX_RESTART = exports.DESC_COMMAND_SANDBOX_STOP = exports.DESC_COMMAND_SANDBOX_START = void 0;
|
|
14
|
+
exports.DESC_COMMAND_SANDBOX_CP = exports.ERR_SANDBOX_ENDPOINTS_NOT_FOUND = exports.ERR_SANDBOX_ENDPOINT_NOT_FOUND = exports.ERR_SANDBOX_ENDPOINT_EXISTS = exports.TXT_SANDBOX_ENDPOINT_DELETED = exports.TXT_SANDBOX_ENDPOINT_DELETE_CONFIRM = exports.TXT_SANDBOX_ENDPOINT_ADDED = exports.TXT_SANDBOX_APP_REMOVED = exports.TXT_SANDBOX_APP_ADDED = exports.OPTION_SANDBOX_ENDPOINT_TYPE = exports.OPTION_SANDBOX_ENDPOINT_PORT = exports.OPTION_SANDBOX_ENDPOINT_NAME_ARG = exports.OPTION_SANDBOX_ENDPOINT_NAME = exports.DESC_COMMAND_SANDBOX_ENDPOINT_DELETE = exports.DESC_COMMAND_SANDBOX_ENDPOINT_ADD = exports.DESC_COMMAND_SANDBOX_ENDPOINT_GET = exports.DESC_COMMAND_SANDBOX_ENDPOINT_LIST = exports.DESC_COMMAND_SANDBOX_ENDPOINT = exports.ERR_SANDBOX_SNAPSHOTS_NOT_FOUND = exports.ERR_SANDBOX_SNAPSHOT_NOT_FOUND = exports.ERR_SANDBOX_SNAPSHOT_FAILED = exports.TXT_SANDBOX_SNAPSHOT_WAITING = exports.TXT_SANDBOX_SNAPSHOT_DELETE_CONFIRM = exports.TXT_SANDBOX_SNAPSHOT_DELETED = exports.TXT_SANDBOX_SNAPSHOT_CREATED = exports.OPTION_SANDBOX_FROM_SNAPSHOT = exports.OPTION_SANDBOX_SNAPSHOT_NAME_ARG = exports.OPTION_SANDBOX_SNAPSHOT_NAME = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_DELETE = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_GET = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_CREATE = exports.DESC_COMMAND_SANDBOX_SNAPSHOT_LIST = exports.DESC_COMMAND_SANDBOX_SNAPSHOT = exports.TXT_SANDBOX_COMMAND_KILLED = exports.OPTION_SANDBOX_COMMAND_KILL_CONFIRM = exports.OPTION_SANDBOX_LOGS_LIMIT = exports.OPTION_SANDBOX_APP_ID = exports.OPTION_SANDBOX_COMMAND_ID = exports.DESC_COMMAND_SANDBOX_EXEC_KILL = exports.DESC_COMMAND_SANDBOX_EXEC_LOGS = exports.DESC_COMMAND_SANDBOX_APP_START = exports.DESC_COMMAND_SANDBOX_APP_STOP = exports.DESC_COMMAND_SANDBOX_APP_STATUS = exports.DESC_COMMAND_SANDBOX_APP_LOGS = exports.DESC_COMMAND_SANDBOX_EXEC_STATUS = exports.DESC_COMMAND_SANDBOX_EXEC_LIST = exports.DESC_COMMAND_SANDBOX_APP_REMOVE = exports.DESC_COMMAND_SANDBOX_APP_ADD = exports.DESC_COMMAND_SANDBOX_APP_LIST = exports.TXT_SANDBOX_WAITING_START = void 0;
|
|
15
|
+
exports.ERR_API_REQUEST_QUERY_VALUE = exports.ERR_API_REQUEST_INVALID_JSON = exports.ERR_API_REQUEST_FILE_ERROR = exports.ERR_API_REQUEST_OUTPUT_EXISTS = exports.DESC_COMMAND_API_INFO = exports.DESC_COMMAND_API_FORM = exports.DESC_COMMAND_API_JSON = exports.DESC_COMMAND_API_DATA = exports.DESC_COMMAND_API_OUTPUT = exports.DESC_COMMAND_API_REQUEST_QUERY = exports.DESC_COMMAND_API_PROJECT = exports.DESC_COMMAND_API_WORKSPACE = exports.DESC_COMMAND_API_REQUEST_URL = exports.DESC_COMMAND_API_GET = exports.DESC_COMMAND_API_PATCH = exports.DESC_COMMAND_API_DELETE = exports.DESC_COMMAND_API_PUT = exports.DESC_COMMAND_API_POST = exports.DESC_COMMAND_API_LIST = exports.DESC_COMMAND_API = exports.ERR_WHOAMI_LOGOUT = exports.TXT_WHOAMI_NO_WORKSPACE = exports.DESC_COMMAND_WHOAMI = exports.TXT_SANDBOX_EXEC_FAILED = exports.TXT_SANDBOX_EXEC_INPROGRESS = exports.TXT_SANDBOX_EXEC_SUCCESS = exports.TXT_SANDBOX_EXEC_BACKGROUND = exports.TXT_SANDBOX_EXEC_ID = exports.ERR_SANDBOX_CP_INVALID_SOURCE = exports.ERR_SANDBOX_CP_INVALID_DEST = exports.ERR_SANDBOX_CP_REPLACE = exports.ERR_SANDBOX_CP_MKDIR = exports.ERR_SANDBOX_CP_PATH_EXISTS = exports.ERR_SANDBOX_CP_NOT_EMPTY_DIR = exports.ERR_SANDBOX_CP_READDIR = exports.ERR_SANDBOX_CP_DEST_NOT_FOLDER = exports.ERR_SANDBOX_CP_SOURCE_NOT_FOUND = exports.TXT_SANDBOX_CP_DONE = exports.TXT_SANDBOX_CP_PROGRESS = exports.TXT_SANDBOX_UNZIPPING_COUNT = exports.TXT_SANDBOX_UNZIP_DONE = exports.TXT_SANDBOX_UNZIP = exports.TXT_SANDBOX_CP_DOWNLOAD_DONE = exports.TXT_SANDBOX_CP_DOWNLOAD = exports.OPTION_SANDBOX_CP_IGNORE = exports.OPTION_SANDBOX_CP_USER = exports.OPTION_SANDBOX_CP_DOWNLOAD_REPLACE = exports.OPTION_SANDBOX_CP_DOWNLOAD_MERGE = exports.OPTION_SANDBOX_CP_DEST = exports.OPTION_SANDBOX_CP_SOURCE = void 0;
|
|
16
|
+
exports.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN = exports.TXT_REGISTER_SUCCESS = exports.TXT_LOGIN_SUCCESS = exports.TXT_LOGIN_SELECT_WORKSPACE = exports.TXT_LOGIN_ENTER_BASE_URL = exports.TXT_LOGIN_PROVIDE_CODE = exports.TXT_REGISTER_OPEN_URL = exports.TXT_LOGIN_OPEN_URL = exports.TXT_REGISTER_OPENING_STAR = exports.TXT_LOGIN_OPENING_STAR = exports.TXT_REGISTER_OPENING = exports.TXT_LOGIN_OPENING = exports.TXT_LOGIN_SELECT_REGION = exports.TXT_WORKSPACE_NONE = exports.TXT_WORKSPACE_SET_SUCCESS = exports.ARG_COMMAND_WORKSPACE = exports.DESC_COMMAND_WORKSPACE_GET = exports.DESC_COMMAND_WORKSPACE_SET = exports.DESC_COMMAND_WORKSPACE_LIST = exports.DESC_COMMAND_WORKSPACE = exports.TXT_COMMAND_REGISTER_PROVIDE_NAME = exports.TXT_COMMAND_REGISTER_PROVIDE_EMAIL = exports.ERR_COMMAND_REGISTER_INVALID_NAME = exports.ERR_COMMAND_REGISTER_INVALID_EMAIL = exports.OPT_COMMAND_REGISTER_NAME = exports.OPT_COMMAND_REGISTER_EMAIL = exports.DESC_COMMAND_REGISTER = exports.TXT_LOGOUT_SUCCESS = exports.DESC_COMMAND_LOGOUT = exports.DESC_COMMAND_LOGIN = exports.HELP_COMMAND_MCP = exports.ERR_MCP_TOOL_FILTERED = exports.ERR_MCP_TOOLS_CATEGORY = exports.OPT_COMMAND_MCP_TOOLS = exports.ERR_MCP_REFRESH_FAILED = exports.ERR_MCP_URL_INVALID = exports.ERR_MCP_ENDPOINT = exports.DESC_COMMAND_MCP = exports.ERR_API_MEDIA_TYPE_NOT_IMPLEMENTED = exports.ERR_API_PARAMETER_NOT_REPLACED = exports.TXT_API_ENDPOINT_REQUIRED_SCOPES = exports.ERR_API_ENDPOINT_NOT_FOUND = exports.ERR_API_WRONG_METHOD = exports.ERR_SCHEMA_FETCH_FAILED = exports.OPT_COMMAND_API_INFO_URL = exports.OPT_COMMAND_API_INFO_SCHEMA = exports.OPT_COMMAND_API_INFO_METHOD = exports.OPT_COMMAND_API_LIST_SEARCH = exports.OPT_COMMAND_API_LIST_METHOD = exports.ERR_API_REQUEST_BODY_VALUE = void 0;
|
|
17
|
+
exports.OPT_COMMAND_DOMAIN_BUY_OWNER = exports.OPT_COMMAND_DOMAIN_BUY_TLD = exports.DESC_COMMAND_DOMAIN_GET = exports.DESC_COMMAND_DOMAIN_LIST = exports.DESC_COMMAND_DOMAIN_SEARCH = exports.DESC_COMMAND_DOMAIN_BUY = exports.DESC_COMMAND_DOMAIN = exports.ERR_ROUTE_NO_DEFAULT = exports.ERR_WRONG_ROUTE_TARGET = exports.ERR_COMMAND_ROUTE_NO_TARGET = exports.ERR_COMMAND_ROUTE_TYPE = exports.TXT_COMMAND_ROUTES_NOT_FOUND = exports.TXT_COMMAND_DISTROS_NOT_FOUND = exports.TXT_COMMAND_ROUTE_DELETED = exports.TXT_COMMAND_DISTRO_DELETED = exports.TXT_COMMAND_ROUTE_DELETE_CONFIRM = exports.TXT_COMMAND_DISTRO_DELETE_CONFIRM = exports.ERR_COMMAND_ROUTE_NO_UPDATE = exports.ERR_COMMAND_DISTRO_NOT_FOUND = exports.ERR_COMMAND_SCOPE = exports.TXT_COMMAND_ROUTE_UPDATED = exports.TXT_ROUTE_SERVE = exports.TXT_COMMAND_ROUTE_CREATED = exports.TXT_COMMAND_DISTRO_CREATED = exports.ERR_COMMAND_SCOPE_NO_PROJECT = exports.OPT_COMMAND_DISTRO_NAME = exports.OPT_COMMAND_ROUTE_TARGET = exports.OPT_COMMAND_ROUTE_PATH = exports.OPT_COMMAND_ROUTE_DOMAIN = exports.OPT_COMMAND_ROUTE_SUBDOMAIN = exports.OPT_COMMAND_ROUTE_TYPE = exports.OPT_COMMAND_ROUTE_ID = exports.OPT_COMMAND_DISTRO_IDENTIFIER = exports.OPT_COMMAND_SCOPE = exports.DESC_COMMAND_ROUTE = exports.DESC_COMMAND_ROUTE_UPDATE = exports.DESC_COMMAND_ROUTE_DELETE = exports.DESC_COMMAND_ROUTE_LIST = exports.DESC_COMMAND_DISTRO_LIST = exports.DESC_COMMAND_DISTRO_DELETE = exports.DESC_COMMAND_ROUTE_CREATE = exports.DESC_COMMAND_DISTRO_CREATE = exports.DESC_COMMAND_DISTRO = exports.ERR_API_MESSAGE_REPLACER = exports.ERR_LOGIN_INVALID_BASE_URL = exports.ERR_LOGIN_NO_WORKSPACE_FOUND = exports.ERR_LOGIN_NO_WORKSPACES = exports.ERR_REGISTER_HTTP_CANCEL = exports.ERR_LOGIN_HTTP_CANCEL = exports.ERR_LOGIN_HTTP_FAILED = void 0;
|
|
18
|
+
exports.TXT_COMMAND_PROJECT_LINK_GIT_REPO = exports.TXT_COMMAND_PROJECT_LINK_DIR_CONFIRM = exports.TXT_COMMAND_PROJECT_LINK_DIR_LINKED = exports.ERR_COMMAND_PROJECT_LINK_DIR_CREATE = exports.OPT_COMMAND_PROJECT_LINK_TRY_NOW = exports.OPT_COMMAND_PROJECT_LINK_SET_GIT_REMOTE = exports.OPT_COMMAND_PROJECT_LINK_HAS_REMOTE = exports.OPT_COMMAND_PROJECT_LINK_DIRECTORY = exports.OPT_COMMAND_PROJECT_LINK_GIT = exports.OPT_COMMAND_PROJECT_LINK_RELINK = exports.DESC_COMMAND_PROJECT_LINK = exports.DESC_COMMAND_PROJECT_LIST = exports.DESC_COMMAND_PROJECT_GIT = exports.DESC_COMMAND_PROJECT_GIT_CREDENTIAL = exports.DESC_COMMAND_PROJECT = exports.TXT_ARTIFACT_VERSION_DOWNLOAD = exports.TXT_ARTIFACT_PUBLISH = exports.TXT_ARTIFACT_CREATED = exports.TXT_ARTIFACT_VERSION_DELETED = exports.TXT_ARTIFACT_DELETED = exports.ERR_COMMAND_ARTIFACT_TYPE = exports.OPT_COMMAND_ARTIFACT_VERSION = exports.OPT_COMMAND_ARTIFACT_IDENTIFIER = exports.OPT_COMMAND_ARTIFACT_CREATE_IDENTIFIER = exports.OPT_COMMAND_ARTIFACT_NAME = exports.OPT_COMMAND_ARTIFACT_TYPE = exports.DESC_COMMAND_ARTIFACT_CREATE = exports.DESC_COMMAND_ARTIFACT_GET = exports.TXT_ARTIFACT_DOCKER_LOGIN_FAILED = exports.TXT_ARTIFACT_DOCKER_LOGIN_SUCCESS = exports.TXT_ARTIFACT_VERSION_DELETE_CONFIRM = exports.TXT_ARTIFACT_DELETE_CONFIRM = exports.DESC_COMMAND_ARTIFACT_DELETE = exports.ERR_COMMAND_ARTIFACT_NO_PROJECTS = exports.DESC_COMMAND_ARTIFACT_VERSION_GET = exports.DESC_COMMAND_ARTIFACT_VERSION_LIST = exports.DESC_COMMAND_ARTIFACT_VERSION_DELETE = exports.DESC_COMMAND_ARTIFACT_DOCKER_LOGIN = exports.DESC_COMMAND_ARTIFACT_LIST = exports.DESC_COMMAND_ARTIFACT_VERSION = exports.ERR_COMMAND_DOMAIN_UNAVAILABLE = exports.OPTION_COMMAND_DOMAIN_IDENTIFIER = exports.ERR_COMMAND_DOMAIN_NO_DOMAINS = exports.TXT_COMMAND_DOMAIN_PROMPT_REQUIRED = exports.TXT_COMMAND_DOMAIN_BUY_SELECT_DOMAIN = exports.TXT_COMMAND_DOMAIN_PROVIDE_PROMPT = exports.ERR_COMMAND_DOMAIN_NOT_FOUND = exports.OPT_COMMAND_DOMAIN_ONLY_AVAILABLE = exports.OPT_COMMAND_DOMAIN_SORT = exports.OPT_COMMAND_DOMAIN_PHRASE = void 0;
|
|
19
|
+
exports.EXAMPLE_SANDBOX_ENDPOINT_LIST = exports.EXAMPLE_SANDBOX_ENDPOINT_GET = exports.EXAMPLE_SANDBOX_ENDPOINT_DELETE = exports.EXAMPLE_SANDBOX_ENDPOINT_CREATE = exports.EXAMPLE_SANDBOX_SNAPSHOT_LIST = exports.EXAMPLE_SANDBOX_SNAPSHOT_GET = exports.EXAMPLE_SANDBOX_SNAPSHOT_DELETE = exports.EXAMPLE_SANDBOX_SNAPSHOT_CREATE = exports.EXAMPLE_SANDBOX_EXEC_STATUS = exports.EXAMPLE_SANDBOX_EXEC_LOGS = exports.EXAMPLE_SANDBOX_APP_STATUS = exports.EXAMPLE_SANDBOX_APP_STOP = exports.EXAMPLE_SANDBOX_APP_REMOVE = exports.EXAMPLE_SANDBOX_APP_ADD = exports.EXAMPLE_SANDBOX_APP_START = exports.EXAMPLE_SANDBOX_APP_LOGS = exports.EXAMPLE_SANDBOX_EXEC_LIST = exports.EXAMPLE_SANDBOX_APP_LIST = exports.EXAMPLE_SANDBOX_EXEC_KILL = exports.EXAMPLE_SANDBOX_EXEC_COMMAND = exports.EXAMPLE_TUNNEL_START = exports.EXAMPLE_TUNNEL_TCP = exports.EXAMPLE_TUNNEL_TLS = exports.EXAMPLE_AGENT_TUNNEL_START = exports.EXAMPLE_AGENT_TUNNEL_STATUS = exports.EXAMPLE_AGENT_TUNNEL_REMOVE = exports.EXAMPLE_AGENT_TUNNEL_LIST = exports.EXAMPLE_TUNNEL_HTTP = exports.EXAMPLE_SANDBOX_CREATE = exports.EXAMPLE_DISTRO_CREATE = exports.EXAMPLE_ROUTE_CREATE = exports.EXAMPLE_ROUTE_LIST = exports.EXAMPLE_ROUTE_UPDATE = exports.EXAMPLE_ROUTE_DELETE = exports.EXAMPLE_DISTRO_DELETE = exports.EXAMPLE_DISTRO_LIST = exports.EXAMPLE_SANDBOX_CP = exports.ERR_PROJECT_NO_PROJECTS = exports.TXT_LOGIN_SELECT_PROJECT = exports.TXT_COMMAND_PROJECT_CREATED = exports.TXT_COMMAND_PROJECT_LINK_NOT_FOUND = exports.TXT_COMMAND_PROJECT_LINK_NAME = exports.TXT_COMMAND_PROJECT_LINK_SELECT_PROJECT = exports.TXT_COMMAND_PROJECT_LINK_TO = exports.TXT_COMMAND_PROJECT_LINK_EXISTING_DESC = exports.TXT_COMMAND_PROJECT_LINK_EXISTING = exports.TXT_COMMAND_PROJECT_LINK_CREATE_NEW_DESC = exports.TXT_COMMAND_PROJECT_LINK_CREATE_NEW = exports.ERR_COMMAND_PROJECT_LINK_DIR_NOT_DIR = exports.TXT_COMMAND_PROJECT_LINK_GIT_REPO_INITIALIZED = void 0;
|
|
20
|
+
exports.EXAMPLE_CRAWL_LINK = exports.EXAMPLE_CRAWL_RUN = exports.EXAMPLE_TESTS_CAPTURE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CLOSE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CREATE = exports.EXAMPLE_TESTS_VISUAL_LINK = exports.EXAMPLE_TESTS_VISUAL_UPLOAD = exports.EXAMPLE_TESTS_VISUAL_SETUP = exports.EXAMPLE_TESTS_UNIT_LINK = exports.EXAMPLE_TESTS_UNIT_UPLOAD = exports.EXAMPLE_ARTIFACT_VERSION_DELETE = exports.EXAMPLE_ARTIFACT_VERSION_GET = exports.EXAMPLE_ARTIFACT_VERSION_LIST = exports.EXAMPLE_ARTIFACT_CREATE = exports.EXAMPLE_ARTIFACT_DELETE = exports.EXAMPLE_ARTIFACT_DOWNLOAD = exports.EXAMPLE_ARTIFACT_PUBLISH = exports.EXAMPLE_ARTIFACT_VERSION_CREATE = exports.EXAMPLE_PIPELINE_RUN_RETRY = exports.EXAMPLE_PIPELINE_RUN_LIST = exports.EXAMPLE_PIPELINE_LIST = exports.EXAMPLE_PIPELINE_YML = exports.EXAMPLE_PIPELINE_GET = exports.EXAMPLE_PIPELINE_UPDATE = exports.EXAMPLE_PIPELINE_DELETE = exports.EXAMPLE_PIPELINE_CREATE = exports.EXAMPLE_PIPELINE_RUN_CANCEL = exports.EXAMPLE_PIPELINE_RUN_APPLY = exports.EXAMPLE_PIPELINE_RUN_LOGS = exports.EXAMPLE_PIPELINE_RUN_JSONL = exports.EXAMPLE_PIPELINE_RUN_STATUS = exports.EXAMPLE_PIPELINE_RUN_START = void 0;
|
|
21
21
|
const utils_1 = require("./utils");
|
|
22
22
|
exports.ERR_CANCELLED = 'Cancelled';
|
|
23
23
|
exports.ERR_REST_API_GENERAL_ERROR = 'Something went wrong';
|
|
@@ -222,7 +222,8 @@ exports.TXT_AGENT_STANDALONE_AGENT_REGISTER_ERROR = 'Error';
|
|
|
222
222
|
exports.TXT_AGENT_STANDALONE_STARTED = 'Agent process started...';
|
|
223
223
|
exports.TXT_AGENT_STANDALONE_EXITING = 'Process exiting. Agent configuration remains...';
|
|
224
224
|
exports.NO_TUNNELS_STARTED = 'No tunnels started';
|
|
225
|
-
|
|
225
|
+
const AGENT_FETCH_RETRY = (seconds) => `Agent fetch failed. Retrying in ${seconds}s...`;
|
|
226
|
+
exports.AGENT_FETCH_RETRY = AGENT_FETCH_RETRY;
|
|
226
227
|
exports.DESC_COMMAND_CONFIG_ADD_HTTP = 'Add a new HTTP tunnel';
|
|
227
228
|
exports.DESC_COMMAND_CONFIG_ADD_TCP = 'Add a new TCP tunnel';
|
|
228
229
|
exports.DESC_COMMAND_CONFIG_ADD_TLS = 'Add a new TLS tunnel';
|
|
@@ -536,6 +537,9 @@ exports.LOG_HTTP2_REQUEST = LOG_HTTP2_REQUEST;
|
|
|
536
537
|
const LOG_DETECTED_STREAM = (type) => `Detected stream '${type}'`;
|
|
537
538
|
exports.LOG_DETECTED_STREAM = LOG_DETECTED_STREAM;
|
|
538
539
|
exports.LOG_WRONG_STREAM = 'Wrong stream type';
|
|
540
|
+
exports.LOG_HANDSHAKE_TIMEOUT = 'Stream handshake timed out';
|
|
541
|
+
exports.LOG_LATE_CHANNEL_ERROR = 'Late error on an already closed channel, ignored';
|
|
542
|
+
exports.LOG_LATE_TARGET_ERROR = 'Late error on a torn down target request, ignored';
|
|
539
543
|
exports.LOG_SSH_CONNECTION = 'New SSH TCP connection';
|
|
540
544
|
exports.LOG_ERROR_STARTING_AGENT_SERVER = 'Error while starting agent API server';
|
|
541
545
|
exports.LOG_AGENT_SERVER_STARTED = 'Agent server started';
|
|
@@ -550,6 +554,7 @@ const LOG_TUNNEL_IDENTIFIED = (id, type) => `Tunnel ${id} identified as ${type}`
|
|
|
550
554
|
exports.LOG_TUNNEL_IDENTIFIED = LOG_TUNNEL_IDENTIFIED;
|
|
551
555
|
exports.LOG_TUNNEL_HTTP_WRON_AUTH = 'HTTP request: HTTP BA failed';
|
|
552
556
|
exports.LOG_TUNNEL_HTTP_RATE_LIMIT = 'HTTP request: rate limited';
|
|
557
|
+
exports.LOG_TUNNEL_HTTP_MAX_INFLIGHT = 'HTTP request: too many in-flight requests, shedding';
|
|
553
558
|
exports.LOG_TUNNEL_HTTP_CIRCUIT_BREAKER_OPEN = 'HTTP request circuit breaker open';
|
|
554
559
|
exports.LOG_TUNNEL_HTTP_WRONG_USER_AGENTS = 'HTTP request wrong user-agents';
|
|
555
560
|
const LOG_TUNNEL_TCP_STREAM = (id) => `New TCP connection on tunnel '${id}' [streamed to target]`;
|
|
@@ -42,6 +42,7 @@ class TunnelHttp extends events_1.default {
|
|
|
42
42
|
proxyRes;
|
|
43
43
|
proxyReq;
|
|
44
44
|
decrementConcurrent;
|
|
45
|
+
resClose;
|
|
45
46
|
constructor({ req, res, proto, host, port, hostHeader, serve, timeout, httpIdentify, verify, noCache, httpLog, compression, headers, responseHeaders, auth = null, }) {
|
|
46
47
|
super();
|
|
47
48
|
this.id = (0, uuid_1.v4)();
|
|
@@ -393,7 +394,6 @@ class TunnelHttp extends events_1.default {
|
|
|
393
394
|
...this.headers,
|
|
394
395
|
...this.getRequestHeaders(true),
|
|
395
396
|
};
|
|
396
|
-
c.requests += 1;
|
|
397
397
|
c.concurrent += 1;
|
|
398
398
|
let concurrentDecremented = false;
|
|
399
399
|
const decrementConcurrent = () => {
|
|
@@ -414,6 +414,11 @@ class TunnelHttp extends events_1.default {
|
|
|
414
414
|
decrementConcurrent();
|
|
415
415
|
throw err;
|
|
416
416
|
}
|
|
417
|
+
// Counted only once the stream really exists. A throw above on a session
|
|
418
|
+
// that stays alive (malformed header name / pseudo-header) would otherwise
|
|
419
|
+
// burn a HTTP2_MAX_LIFETIME_REQUESTS slot on a request that never ran and
|
|
420
|
+
// retire the session early.
|
|
421
|
+
c.requests += 1;
|
|
417
422
|
if (this.httpLog) {
|
|
418
423
|
this.logRequest = this.httpLog.newRequest(method, headers, path, tunnel_1.TUNNEL_HTTP_IDENTIFY.HTTP2, this.req);
|
|
419
424
|
}
|
|
@@ -464,11 +469,31 @@ class TunnelHttp extends events_1.default {
|
|
|
464
469
|
this.req = null;
|
|
465
470
|
}
|
|
466
471
|
if (this.res) {
|
|
467
|
-
|
|
472
|
+
// Never removeAllListeners() here: outputEnd() calls clear() synchronously
|
|
473
|
+
// after res.end(), and res still carries node's own 'finish' listener
|
|
474
|
+
// (resOnFinish) - 'finish' is emitted a tick later, even though
|
|
475
|
+
// res.writableFinished already reads true. Dropping it leaves
|
|
476
|
+
// socket._httpMessage set forever, so the keep-alive connection (an ssh
|
|
477
|
+
// channel here) is never detached, never reaped by keepAliveTimeout and
|
|
478
|
+
// never answers another request. Only our own handler goes.
|
|
479
|
+
if (this.resClose) {
|
|
480
|
+
this.res.off('close', this.resClose);
|
|
481
|
+
this.resClose = null;
|
|
482
|
+
}
|
|
468
483
|
this.res = null;
|
|
469
484
|
}
|
|
470
485
|
if (this.proxyReq) {
|
|
471
486
|
this.proxyReq.removeAllListeners();
|
|
487
|
+
// A client-side request still emits 'error' after teardown: destroy() with
|
|
488
|
+
// no argument makes Node synthesize ECONNRESET "socket hang up", and a late
|
|
489
|
+
// target RST lands here too. pipeline() kept a listener on it, so dropping
|
|
490
|
+
// that with nothing in its place turns those into an uncaughtException
|
|
491
|
+
// (index.ts) and kills the whole agent. Server-side req/res need no such
|
|
492
|
+
// no-op - Node routes their socket failures to the socket, not the object.
|
|
493
|
+
this.proxyReq.on('error', (err) => {
|
|
494
|
+
logger_1.default.debug(texts_1.LOG_LATE_TARGET_ERROR);
|
|
495
|
+
logger_1.default.debug(err);
|
|
496
|
+
});
|
|
472
497
|
this.proxyReq = null;
|
|
473
498
|
}
|
|
474
499
|
if (this.proxyRes) {
|
|
@@ -610,7 +635,9 @@ class TunnelHttp extends events_1.default {
|
|
|
610
635
|
}
|
|
611
636
|
});
|
|
612
637
|
if (this.res) {
|
|
613
|
-
|
|
638
|
+
// Kept on the instance so clear() can detach exactly this listener
|
|
639
|
+
// instead of wiping every listener off res.
|
|
640
|
+
this.resClose = () => {
|
|
614
641
|
// Client disconnected before the target responded (e.g. a scraper
|
|
615
642
|
// that gave up). The upstream request is still queued/in-flight and
|
|
616
643
|
// would keep its pooled socket / stream slot forever. Once headers
|
|
@@ -635,7 +662,8 @@ class TunnelHttp extends events_1.default {
|
|
|
635
662
|
catch {
|
|
636
663
|
// do nothing
|
|
637
664
|
}
|
|
638
|
-
}
|
|
665
|
+
};
|
|
666
|
+
this.res.once('close', this.resClose);
|
|
639
667
|
}
|
|
640
668
|
if (this.logRequest) {
|
|
641
669
|
(0, node_stream_1.pipeline)(this.req, this.logRequest.requestBody, this.proxyReq, (err) => {
|
|
@@ -7,6 +7,7 @@ const ssh2_1 = require("ssh2");
|
|
|
7
7
|
const events_1 = __importDefault(require("events"));
|
|
8
8
|
const logger_1 = __importDefault(require("../../logger"));
|
|
9
9
|
const texts_1 = require("../../texts");
|
|
10
|
+
const utils_1 = require("../../utils");
|
|
10
11
|
const tunnel_1 = require("../../types/tunnel");
|
|
11
12
|
class SshClient extends events_1.default {
|
|
12
13
|
ip;
|
|
@@ -83,7 +84,23 @@ class SshClient extends events_1.default {
|
|
|
83
84
|
stream.allowHalfOpen = false;
|
|
84
85
|
if (stream.readableFlowing)
|
|
85
86
|
stream.pause();
|
|
87
|
+
// readStreamBytes() has no deadline and never settles once the channel hits
|
|
88
|
+
// EOF, so a peer that never sends its 50 byte header would hold the channel
|
|
89
|
+
// (and its ssh2 window) open for good. Drop it instead. Declared before the
|
|
90
|
+
// handlers below so every one of them can clear it: a pending timer is a GC
|
|
91
|
+
// root, and it would otherwise pin an already closed channel for the rest
|
|
92
|
+
// of the deadline.
|
|
93
|
+
const handshakeTimeout = setTimeout(() => {
|
|
94
|
+
logger_1.default.debug(texts_1.LOG_HANDSHAKE_TIMEOUT);
|
|
95
|
+
try {
|
|
96
|
+
stream.destroy();
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// do nothing
|
|
100
|
+
}
|
|
101
|
+
}, utils_1.SSH_HANDSHAKE_TIMEOUT);
|
|
86
102
|
stream.on('error', () => {
|
|
103
|
+
clearTimeout(handshakeTimeout);
|
|
87
104
|
try {
|
|
88
105
|
stream.removeAllListeners();
|
|
89
106
|
stream.once('error', () => { });
|
|
@@ -102,9 +119,18 @@ class SshClient extends events_1.default {
|
|
|
102
119
|
}, 1000);
|
|
103
120
|
});
|
|
104
121
|
stream.on('close', () => {
|
|
122
|
+
clearTimeout(handshakeTimeout);
|
|
105
123
|
stream.removeAllListeners();
|
|
124
|
+
// ssh2 emits 'close' on a channel it has NOT destroyed (onCHANNEL_CLOSE),
|
|
125
|
+
// so a later write-after-end or destroy(err) still emits 'error' here.
|
|
126
|
+
// With every listener gone that is an uncaught exception -> agent exit.
|
|
127
|
+
stream.on('error', (err) => {
|
|
128
|
+
logger_1.default.debug(texts_1.LOG_LATE_CHANNEL_ERROR);
|
|
129
|
+
logger_1.default.debug(err);
|
|
130
|
+
});
|
|
106
131
|
});
|
|
107
132
|
const triggerStream = (type, ip) => {
|
|
133
|
+
clearTimeout(handshakeTimeout);
|
|
108
134
|
stream.removeAllListeners();
|
|
109
135
|
this.emit(type, stream, info, ip);
|
|
110
136
|
};
|
|
@@ -119,6 +145,7 @@ class SshClient extends events_1.default {
|
|
|
119
145
|
ip = s[1];
|
|
120
146
|
}
|
|
121
147
|
catch (err) {
|
|
148
|
+
clearTimeout(handshakeTimeout);
|
|
122
149
|
stream.emit('error', err);
|
|
123
150
|
return;
|
|
124
151
|
}
|
|
@@ -147,6 +174,7 @@ class SshClient extends events_1.default {
|
|
|
147
174
|
triggerStream(tunnel_1.TUNNEL_SSH_EVENT.STREAM_SSH, ip);
|
|
148
175
|
return;
|
|
149
176
|
}
|
|
177
|
+
clearTimeout(handshakeTimeout);
|
|
150
178
|
logger_1.default.debug(texts_1.LOG_WRONG_STREAM);
|
|
151
179
|
stream.emit('error', new Error(texts_1.ERR_WRONG_STREAM));
|
|
152
180
|
}
|
|
@@ -72,6 +72,11 @@ class Tunnel extends events_1.default {
|
|
|
72
72
|
sshServer;
|
|
73
73
|
ssh;
|
|
74
74
|
started;
|
|
75
|
+
// A set rather than a counter: releasing by identity is idempotent, so a
|
|
76
|
+
// double 'close' or a reset while requests are still outstanding can never
|
|
77
|
+
// drift the value. A drifted counter would latch the tunnel into answering
|
|
78
|
+
// 503 forever with no way back short of restarting the agent.
|
|
79
|
+
inFlight = new Set();
|
|
75
80
|
constructor({ agent, id, sshHostKey, ...options }) {
|
|
76
81
|
super();
|
|
77
82
|
if (!sshHostKey)
|
|
@@ -195,6 +200,10 @@ class Tunnel extends events_1.default {
|
|
|
195
200
|
return this.config.targetAuth;
|
|
196
201
|
}
|
|
197
202
|
resetState() {
|
|
203
|
+
// Safe to drop wholesale: recreate() stops the servers first, so those
|
|
204
|
+
// responses are gone, and a late 'close' on one of them simply deletes
|
|
205
|
+
// nothing.
|
|
206
|
+
this.inFlight.clear();
|
|
198
207
|
this.connections = {};
|
|
199
208
|
this.totalConnections = 0;
|
|
200
209
|
this.status = tunnel_1.TUNNEL_STATUS.CLOSED;
|
|
@@ -385,7 +394,44 @@ class Tunnel extends events_1.default {
|
|
|
385
394
|
return this.http1server.retryRequest(logRequest);
|
|
386
395
|
}
|
|
387
396
|
}
|
|
397
|
+
httpShed(req, res) {
|
|
398
|
+
// Deliberately bypasses httpEndFast(): with request logging on it would pipe
|
|
399
|
+
// the body through TunnelHttpStream, which buffers up to
|
|
400
|
+
// TUNNEL_HTTP_LOG_MAX_BODY per request before answering - the shedding path
|
|
401
|
+
// itself would then be the thing that eats the memory. Answering straight
|
|
402
|
+
// away lets node _dump() the body, discarding it without buffering.
|
|
403
|
+
logger_1.default.debug(texts_1.LOG_TUNNEL_HTTP_MAX_INFLIGHT);
|
|
404
|
+
try {
|
|
405
|
+
// Still count it against the per-IP limit. Skipping httpLog.newRequest()
|
|
406
|
+
// means nothing else here does, and a flood that is shed for free would
|
|
407
|
+
// never push any address towards the 429 it deserves. Inside the try
|
|
408
|
+
// because a throw escaping here becomes an unhandled rejection (emit
|
|
409
|
+
// discards the promise) and index.ts turns that into exit(1).
|
|
410
|
+
if (this.httpLog)
|
|
411
|
+
this.httpLog.increaseRateLimit(req);
|
|
412
|
+
res.statusCode = 503;
|
|
413
|
+
res.setHeader('retry-after', utils_1.TUNNEL_HTTP_RETRY_AFTER);
|
|
414
|
+
res.end('Service Unavailable');
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
// do nothing
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
httpUpgradeClosed(res, socket) {
|
|
421
|
+
this.inFlight.delete(res);
|
|
422
|
+
this.httpConnectionClosed(socket);
|
|
423
|
+
}
|
|
388
424
|
async httpRequest(req, res) {
|
|
425
|
+
// Admission control: the per-IP rate limit does nothing against a spread out
|
|
426
|
+
// flood, and everything downstream (http1 agent sockets, the http2 pool)
|
|
427
|
+
// queues rather than sheds, so without a ceiling the excess piles up in
|
|
428
|
+
// memory until the agent dies.
|
|
429
|
+
if (this.inFlight.size >= utils_1.TUNNEL_HTTP_MAX_INFLIGHT) {
|
|
430
|
+
this.httpShed(req, res);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
this.inFlight.add(res);
|
|
434
|
+
res.once('close', () => this.inFlight.delete(res));
|
|
389
435
|
if (await this.auth.buddyAuthMe(req, res))
|
|
390
436
|
return;
|
|
391
437
|
const isAuth = (await this.auth.basicAuth(req, res)) &&
|
|
@@ -413,7 +459,13 @@ class Tunnel extends events_1.default {
|
|
|
413
459
|
httpIdentify: this.identify?.type,
|
|
414
460
|
httpLog: this.httpLog,
|
|
415
461
|
});
|
|
416
|
-
http.once(tunnel_1.TUNNEL_HTTP_SOCKET.CLOSED, (socket) =>
|
|
462
|
+
http.once(tunnel_1.TUNNEL_HTTP_SOCKET.CLOSED, (socket) =>
|
|
463
|
+
// Also the release path for upgraded connections: node routes an upgrade
|
|
464
|
+
// request to 'request' (ServerHttp1 registers no 'upgrade' listener), so
|
|
465
|
+
// a websocket does pass through here and take a slot - but upgrade() takes
|
|
466
|
+
// the socket over and strips its listeners, so res never emits 'close'.
|
|
467
|
+
// Without this every websocket would hold its slot until the agent dies.
|
|
468
|
+
this.httpUpgradeClosed(res, socket));
|
|
417
469
|
http.pipe().then();
|
|
418
470
|
}
|
|
419
471
|
tlsSocket(tlsSocket) {
|
package/distTs/src/utils.js
CHANGED
|
@@ -36,8 +36,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
40
|
-
exports.getGitName = exports.getGitEmail = exports.MCP_TOOL_CATEGORIES = exports.getBasicCommandTls = exports.getBasicCommandHttp = exports.getBasicCommandSandboxEndpoint = exports.getBasicCommandTcp = exports.getCurrentUser = exports.getServiceUser = exports.getRealTargetHost = exports.isWindows = exports.isLinux = exports.isOsx = exports.isDocker = exports.sleep = exports.getLatestVersion = exports.getVersionEnv = exports.getCurrentVersionWithoutEnv = exports.getVersionWithoutEnv = void 0;
|
|
39
|
+
exports.tryGetEmail = exports.execLocally = exports.getHomeDirectory = exports.isDomainAvailable = exports.newCommand = exports.formatBytes = exports.formatHelp = exports.getPlatform = exports.getHostname = exports.isStringRegExp = exports.getWorkingDir = exports.getRootDir = exports.TARGET_ONLY_PORT_REGEX = exports.TARGET_HTTP_REGEX = exports.TARGET_TCP_TLS_REGEX = exports.ApiErrorTunnelsDisabled = exports.ApiErrorWorkspaceFlagged = exports.ApiErrorTunnelLimitReached = exports.ApiErrorAgentLimitReached = exports.ApiErrorDomainRestricted = exports.ApiErrorTargetInvalid = exports.ApiErrorWrongToken = exports.ApiErrorFailedToConnect = exports.ApiErrorAgentNotFound = exports.ARTIFACT_AUTH_TYPE = exports.ARTIFACT_TYPE = exports.SANDBOX_SNAPSHOT_STATUS = exports.SANDBOX_APP_STATUS = exports.SANDBOX_SETUP_STATUS = exports.SANDBOX_EXEC_STATUS = exports.SANDBOX_EXEC_RUNTIME = exports.SANDBOX_STATUS = exports.REST_API_ENDPOINT = exports.REST_API_REGION = exports.DEFAULT_SANDBOX_CP_USER = exports.ARTIFACT_DEFAULT_VERSION = exports.SUGGESTED_BROWSER_VERSION = exports.AGENT_FETCH_RETRY_MAX = exports.AGENT_FETCH_RETRY_MIN = exports.SSH_HANDSHAKE_TIMEOUT = exports.DEFAULT_TIMEOUT = exports.TUNNEL_HTTP_RETRY_AFTER = exports.TUNNEL_HTTP_MAX_INFLIGHT = exports.TUNNEL_HTTP_CB_MIN_REQUESTS = exports.TUNNEL_HTTP_CB_WINDOW = exports.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC = exports.TUNNEL_HTTP_LOG_MAX_REQUESTS = exports.TUNNEL_HTTP_LOG_MAX_BODY = exports.TUNNEL_HTTP_RATE_WINDOW = exports.TUNNEL_HTTP_RATE_LIMIT = void 0;
|
|
40
|
+
exports.getGitName = exports.getGitEmail = exports.MCP_TOOL_CATEGORIES = exports.getBasicCommandTls = exports.getBasicCommandHttp = exports.getBasicCommandSandboxEndpoint = exports.getBasicCommandTcp = exports.getCurrentUser = exports.getServiceUser = exports.getRealTargetHost = exports.isWindows = exports.isLinux = exports.isOsx = exports.isDocker = exports.sleep = exports.getLatestVersion = exports.getVersionEnv = exports.getCurrentVersionWithoutEnv = exports.getVersionWithoutEnv = exports.getVersion = exports.isInstalledByChoco = exports.isInstalledByApt = exports.isInstalledByBrew = exports.isInstalledByNpm = void 0;
|
|
41
41
|
exports.apiErrorCodeToClass = apiErrorCodeToClass;
|
|
42
42
|
exports.isFile = isFile;
|
|
43
43
|
exports.getAppWorkspaceUrl = getAppWorkspaceUrl;
|
|
@@ -76,7 +76,12 @@ exports.TUNNEL_HTTP_LOG_MAX_REQUESTS = 20;
|
|
|
76
76
|
exports.TUNNEL_MAX_REQUEST_SIZE_TO_SYNC = 25600; // 25kB (1 request do frontu moze miec max 1MB, 20 requestow po req i res body)
|
|
77
77
|
exports.TUNNEL_HTTP_CB_WINDOW = 10000;
|
|
78
78
|
exports.TUNNEL_HTTP_CB_MIN_REQUESTS = 20;
|
|
79
|
+
exports.TUNNEL_HTTP_MAX_INFLIGHT = 2000;
|
|
80
|
+
exports.TUNNEL_HTTP_RETRY_AFTER = 30;
|
|
79
81
|
exports.DEFAULT_TIMEOUT = 30;
|
|
82
|
+
exports.SSH_HANDSHAKE_TIMEOUT = 10000;
|
|
83
|
+
exports.AGENT_FETCH_RETRY_MIN = 3000;
|
|
84
|
+
exports.AGENT_FETCH_RETRY_MAX = 60000;
|
|
80
85
|
exports.SUGGESTED_BROWSER_VERSION = '130.0.6723.69';
|
|
81
86
|
exports.ARTIFACT_DEFAULT_VERSION = 'latest';
|
|
82
87
|
exports.DEFAULT_SANDBOX_CP_USER = 'buddy';
|