Prevent admins from using restart option which can leak DB connections. Adds timeouts to TTS HTTPS requests (rust-g version bump required). (#90182)

🆑
config: Added `TTS_HTTP_TIMEOUT_SECONDS` for setting the maximum
duration TTS HTTP requests can run for before being aborted.
/🆑

DNM because we need the rust-g PR to get released:
https://github.com/tgstation/rust-g/pull/210

Crit prio because rounds will not restart if there are hung TTS requests
and the TTS server is absolute dogshit and doesn't prevent them.
This commit is contained in:
Jordan Dominion
2025-03-28 19:31:23 -04:00
committed by GitHub
parent d04c75dff9
commit f776000677
7 changed files with 28 additions and 10 deletions

View File

@@ -457,6 +457,11 @@
/datum/config_entry/str_list/tts_voice_blacklist
/// Maximum timeout for http calls
/datum/config_entry/number/tts_http_timeout_seconds
default = 30
min_val = 0
/datum/config_entry/flag/give_tutorials_without_db
/datum/config_entry/string/new_player_alert_role_id

View File

@@ -58,7 +58,7 @@ SUBSYSTEM_DEF(tts)
var/datum/http_request/request = new()
var/list/headers = list()
headers["Authorization"] = CONFIG_GET(string/tts_http_token)
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-voices", "", headers)
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-voices", "", headers, timeout_seconds = CONFIG_GET(number/tts_http_timeout_seconds))
request.begin_async()
UNTIL(request.is_complete())
var/datum/http_response/response = request.into_response()
@@ -77,7 +77,7 @@ SUBSYSTEM_DEF(tts)
var/datum/http_request/request_pitch = new()
var/list/headers_pitch = list()
headers_pitch["Authorization"] = CONFIG_GET(string/tts_http_token)
request_pitch.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/pitch-available", "", headers_pitch)
request_pitch.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/pitch-available", "", headers_pitch, timeout_seconds = CONFIG_GET(number/tts_http_timeout_seconds))
request_pitch.begin_async()
UNTIL(request_pitch.is_complete())
pitch_enabled = TRUE
@@ -295,8 +295,8 @@ SUBSYSTEM_DEF(tts)
var/datum/http_request/request_blips = new()
var/file_name = "tmp/tts/[identifier].ogg"
var/file_name_blips = "tmp/tts/[identifier]_blips.ogg"
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name)
request_blips.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-blips?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name_blips)
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name, timeout_seconds = CONFIG_GET(number/tts_http_timeout_seconds))
request_blips.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-blips?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name_blips, timeout_seconds = CONFIG_GET(number/tts_http_timeout_seconds))
var/datum/tts_request/current_request = new /datum/tts_request(identifier, request, request_blips, shell_scrubbed_input, target, local, language, message_range, volume_offset, listeners, pitch)
var/list/player_queued_tts_messages = queued_tts_messages[target]
if(!player_queued_tts_messages)

View File

@@ -9,9 +9,12 @@
/// If present response body will be saved to this file.
var/output_file
/// If present request will timeout after this duration
var/timeout_seconds
var/_raw_response
/datum/http_request/proc/prepare(method, url, body = "", list/headers, output_file)
/datum/http_request/proc/prepare(method, url, body = "", list/headers, output_file, timeout_seconds)
if (!length(headers))
headers = ""
else
@@ -22,6 +25,7 @@
src.body = body
src.headers = headers
src.output_file = output_file
src.timeout_seconds = timeout_seconds
/datum/http_request/proc/execute_blocking()
_raw_response = rustg_http_request_blocking(method, url, body, headers, build_options())
@@ -39,9 +43,10 @@
in_progress = TRUE
/datum/http_request/proc/build_options()
if(output_file)
return json_encode(list("output_filename"=output_file,"body_filename"=null))
return null
return json_encode(list(
"output_filename"=(output_file ? output_file : null),
"body_filename"=null,
"timeout_seconds"=(timeout_seconds ? timeout_seconds : null)))
/datum/http_request/proc/is_complete()
if (isnull(id))

View File

@@ -22,7 +22,12 @@ ADMIN_VERB(toggle_hub, R_SERVER, "Toggle Hub", "Toggles the server's visilibilit
#define HARDEST_RESTART "Hardest Restart (No actions, just reboot)"
#define TGS_RESTART "Server Restart (Kill and restart DD)"
ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.", ADMIN_CATEGORY_SERVER)
var/list/options = list(REGULAR_RESTART, REGULAR_RESTART_DELAYED, HARD_RESTART, HARDEST_RESTART)
var/list/options = list(REGULAR_RESTART, REGULAR_RESTART_DELAYED, HARD_RESTART)
// this option runs a codepath that can leak db connections because it skips subsystem (specifically SSdbcore) shutdown
if(!SSdbcore.IsConnected())
options += HARDEST_RESTART
if(world.TgsAvailable())
options += TGS_RESTART;

View File

@@ -613,6 +613,9 @@ PR_ANNOUNCEMENTS_PER_ROUND 5
## The maximum number of concurrent tts http requests that can be made by the server at once.
#TTS_MAX_CONCURRENT_REQUESTS 4
## The number of seconds before tts https requests timeout (0 for infinite not recommended)
#TTS_HTTP_TIMEOUT_SECONDS 30
## Add voices to the TTS voice blacklist.
#TTS_VOICE_BLACKLIST Sans Undertale
#TTS_VOICE_BLACKLIST Papyrus Undertale

View File

@@ -8,7 +8,7 @@ export BYOND_MAJOR=515
export BYOND_MINOR=1647
#rust_g git tag
export RUST_G_VERSION=3.7.0
export RUST_G_VERSION=3.8.0
#node version
export NODE_VERSION_LTS=22.11.0

Binary file not shown.