diff --git a/notifications/core/src/main/kotlin/org/opensearch/notifications/core/client/DestinationHttpClient.kt b/notifications/core/src/main/kotlin/org/opensearch/notifications/core/client/DestinationHttpClient.kt index 499bd582..1ef5e489 100644 --- a/notifications/core/src/main/kotlin/org/opensearch/notifications/core/client/DestinationHttpClient.kt +++ b/notifications/core/src/main/kotlin/org/opensearch/notifications/core/client/DestinationHttpClient.kt @@ -148,7 +148,7 @@ class DestinationHttpClient { @Throws(IOException::class) fun getResponseString(response: CloseableHttpResponse): String { val entity: HttpEntity = response.entity ?: return "{}" - val responseString = EntityUtils.toString(entity, PluginSettings.maxHttpResponseStrLength) + val responseString = EntityUtils.toString(entity, PluginSettings.maxHttpResponseSize / 2) // Java char is 2 bytes // DeliveryStatus need statusText must not be empty, convert empty response to {} return if (responseString.isNullOrEmpty()) "{}" else responseString } diff --git a/notifications/core/src/main/kotlin/org/opensearch/notifications/core/setting/PluginSettings.kt b/notifications/core/src/main/kotlin/org/opensearch/notifications/core/setting/PluginSettings.kt index b97cc99f..cb1af620 100644 --- a/notifications/core/src/main/kotlin/org/opensearch/notifications/core/setting/PluginSettings.kt +++ b/notifications/core/src/main/kotlin/org/opensearch/notifications/core/setting/PluginSettings.kt @@ -16,6 +16,7 @@ import org.opensearch.common.settings.Setting.Property.Final import org.opensearch.common.settings.Setting.Property.NodeScope import org.opensearch.common.settings.Settings import org.opensearch.core.common.settings.SecureString +import org.opensearch.http.HttpTransportSettings.SETTING_HTTP_MAX_CONTENT_LENGTH import org.opensearch.notifications.core.NotificationCorePlugin.Companion.LOG_PREFIX import org.opensearch.notifications.core.NotificationCorePlugin.Companion.PLUGIN_NAME import org.opensearch.notifications.core.utils.OpenForTesting @@ -84,7 +85,7 @@ internal object PluginSettings { /** * Setting for maximum string length of HTTP response, allows protection from DoS */ - private const val MAX_HTTP_RESPONSE_STRING_LENGTH_KEY = "$KEY_PREFIX.max_http_response_string_length" + private const val MAX_HTTP_RESPONSE_SIZE_KEY = "$KEY_PREFIX.max_http_response_size" /** * Legacy setting for list of host deny list in Alerting @@ -152,9 +153,9 @@ internal object PluginSettings { private const val DEFAULT_SOCKET_TIMEOUT_MILLISECONDS = 50000 /** - * Default maximum HTTP response string length, 50MB. Java char is 2 bytes, so max string length is 25000000 + * Default maximum HTTP response string length */ - private val DEFAULT_MAX_HTTP_RESPONSE_STRING_LENGTH = 25000000 + private val DEFAULT_MAX_HTTP_RESPONSE_SIZE = SETTING_HTTP_MAX_CONTENT_LENGTH.getDefault(Settings.EMPTY).getBytes().toInt() /** * Default email header length. minimum value from 100 reference emails @@ -237,7 +238,7 @@ internal object PluginSettings { * Maximum HTTP response string length */ @Volatile - var maxHttpResponseStrLength: Int + var maxHttpResponseSize: Int /** * Tooltip support @@ -289,7 +290,7 @@ internal object PluginSettings { connectionTimeout = (settings?.get(CONNECTION_TIMEOUT_MILLISECONDS_KEY)?.toInt()) ?: DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS socketTimeout = (settings?.get(SOCKET_TIMEOUT_MILLISECONDS_KEY)?.toInt()) ?: DEFAULT_SOCKET_TIMEOUT_MILLISECONDS - maxHttpResponseStrLength = (settings?.get(MAX_HTTP_RESPONSE_STRING_LENGTH_KEY)?.toInt()) ?: DEFAULT_MAX_HTTP_RESPONSE_STRING_LENGTH + maxHttpResponseSize = (settings?.get(MAX_HTTP_RESPONSE_SIZE_KEY)?.toInt()) ?: DEFAULT_MAX_HTTP_RESPONSE_SIZE allowedConfigTypes = settings?.getAsList(ALLOWED_CONFIG_TYPE_KEY, null) ?: DEFAULT_ALLOWED_CONFIG_TYPES tooltipSupport = settings?.getAsBoolean(TOOLTIP_SUPPORT_KEY, true) ?: DEFAULT_TOOLTIP_SUPPORT hostDenyList = settings?.getAsList(HOST_DENY_LIST_KEY, null) ?: DEFAULT_HOST_DENY_LIST @@ -303,7 +304,7 @@ internal object PluginSettings { MAX_CONNECTIONS_PER_ROUTE_KEY to maxConnectionsPerRoute.toString(DECIMAL_RADIX), CONNECTION_TIMEOUT_MILLISECONDS_KEY to connectionTimeout.toString(DECIMAL_RADIX), SOCKET_TIMEOUT_MILLISECONDS_KEY to socketTimeout.toString(DECIMAL_RADIX), - MAX_HTTP_RESPONSE_STRING_LENGTH_KEY to maxHttpResponseStrLength.toString(DECIMAL_RADIX), + MAX_HTTP_RESPONSE_SIZE_KEY to maxHttpResponseSize.toString(DECIMAL_RADIX), TOOLTIP_SUPPORT_KEY to tooltipSupport.toString() ) } @@ -351,9 +352,9 @@ internal object PluginSettings { Dynamic ) - val MAX_HTTP_RESPONSE_STRING_LENGTH: Setting = Setting.intSetting( - MAX_HTTP_RESPONSE_STRING_LENGTH_KEY, - defaultSettings[MAX_HTTP_RESPONSE_STRING_LENGTH_KEY]!!.toInt(), + val MAX_HTTP_RESPONSE_SIZE: Setting = Setting.intSetting( + MAX_HTTP_RESPONSE_SIZE_KEY, + defaultSettings[MAX_HTTP_RESPONSE_SIZE_KEY]!!.toInt(), NodeScope, Dynamic ) @@ -445,7 +446,7 @@ internal object PluginSettings { MAX_CONNECTIONS_PER_ROUTE, CONNECTION_TIMEOUT_MILLISECONDS, SOCKET_TIMEOUT_MILLISECONDS, - MAX_HTTP_RESPONSE_STRING_LENGTH, + MAX_HTTP_RESPONSE_SIZE, ALLOWED_CONFIG_TYPES, TOOLTIP_SUPPORT, HOST_DENY_LIST, @@ -466,7 +467,7 @@ internal object PluginSettings { maxConnectionsPerRoute = MAX_CONNECTIONS_PER_ROUTE.get(clusterService.settings) connectionTimeout = CONNECTION_TIMEOUT_MILLISECONDS.get(clusterService.settings) socketTimeout = SOCKET_TIMEOUT_MILLISECONDS.get(clusterService.settings) - maxHttpResponseStrLength = MAX_HTTP_RESPONSE_STRING_LENGTH.get(clusterService.settings) + maxHttpResponseSize = MAX_HTTP_RESPONSE_SIZE.get(clusterService.settings) tooltipSupport = TOOLTIP_SUPPORT.get(clusterService.settings) hostDenyList = HOST_DENY_LIST.get(clusterService.settings) destinationSettings = loadDestinationSettings(clusterService.settings) @@ -509,9 +510,9 @@ internal object PluginSettings { log.debug("$LOG_PREFIX:$SOCKET_TIMEOUT_MILLISECONDS_KEY -autoUpdatedTo-> $clusterSocketTimeout") socketTimeout = clusterSocketTimeout } - val clusterMaxHttpResponseStrLength = clusterService.clusterSettings.get(MAX_HTTP_RESPONSE_STRING_LENGTH) - if (clusterMaxHttpResponseStrLength != null) { - log.debug("$LOG_PREFIX:$MAX_HTTP_RESPONSE_STRING_LENGTH_KEY -autoUpdatedTo-> $clusterMaxHttpResponseStrLength") + val clusterMaxHttpResponseSize = clusterService.clusterSettings.get(MAX_HTTP_RESPONSE_SIZE) + if (clusterMaxHttpResponseSize != null) { + log.debug("$LOG_PREFIX:$MAX_HTTP_RESPONSE_SIZE_KEY -autoUpdatedTo-> $clusterMaxHttpResponseSize") socketTimeout = clusterSocketTimeout } val clusterAllowedConfigTypes = clusterService.clusterSettings.get(ALLOWED_CONFIG_TYPES) @@ -574,9 +575,9 @@ internal object PluginSettings { socketTimeout = it log.info("$LOG_PREFIX:$SOCKET_TIMEOUT_MILLISECONDS_KEY -updatedTo-> $it") } - clusterService.clusterSettings.addSettingsUpdateConsumer(MAX_HTTP_RESPONSE_STRING_LENGTH) { - maxHttpResponseStrLength = it - log.info("$LOG_PREFIX:$MAX_HTTP_RESPONSE_STRING_LENGTH_KEY -updatedTo-> $it") + clusterService.clusterSettings.addSettingsUpdateConsumer(MAX_HTTP_RESPONSE_SIZE) { + maxHttpResponseSize = it + log.info("$LOG_PREFIX:$MAX_HTTP_RESPONSE_SIZE_KEY -updatedTo-> $it") } clusterService.clusterSettings.addSettingsUpdateConsumer(TOOLTIP_SUPPORT) { tooltipSupport = it @@ -641,7 +642,7 @@ internal object PluginSettings { maxConnectionsPerRoute = DEFAULT_MAX_CONNECTIONS_PER_ROUTE connectionTimeout = DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS socketTimeout = DEFAULT_SOCKET_TIMEOUT_MILLISECONDS - maxHttpResponseStrLength = DEFAULT_MAX_HTTP_RESPONSE_STRING_LENGTH + maxHttpResponseSize = DEFAULT_MAX_HTTP_RESPONSE_SIZE allowedConfigTypes = DEFAULT_ALLOWED_CONFIG_TYPES tooltipSupport = DEFAULT_TOOLTIP_SUPPORT hostDenyList = DEFAULT_HOST_DENY_LIST diff --git a/notifications/core/src/test/kotlin/org/opensearch/notifications/core/settings/PluginSettingsTests.kt b/notifications/core/src/test/kotlin/org/opensearch/notifications/core/settings/PluginSettingsTests.kt index 698c423c..926c469c 100644 --- a/notifications/core/src/test/kotlin/org/opensearch/notifications/core/settings/PluginSettingsTests.kt +++ b/notifications/core/src/test/kotlin/org/opensearch/notifications/core/settings/PluginSettingsTests.kt @@ -16,6 +16,7 @@ import org.opensearch.cluster.ClusterName import org.opensearch.cluster.service.ClusterService import org.opensearch.common.settings.ClusterSettings import org.opensearch.common.settings.Settings +import org.opensearch.http.HttpTransportSettings.SETTING_HTTP_MAX_CONTENT_LENGTH import org.opensearch.notifications.core.NotificationCorePlugin import org.opensearch.notifications.core.setting.PluginSettings @@ -32,7 +33,7 @@ internal class PluginSettingsTests { private val httpMaxConnectionPerRouteKey = "$httpKeyPrefix.max_connection_per_route" private val httpConnectionTimeoutKey = "$httpKeyPrefix.connection_timeout" private val httpSocketTimeoutKey = "$httpKeyPrefix.socket_timeout" - private val maxHttpResponseStrLengthKey = "$keyPrefix.max_http_response_string_length" + private val maxHttpResponseSizeKey = "$keyPrefix.max_http_response_size" private val legacyAlertingHostDenyListKey = "opendistro.destination.host.deny_list" private val alertingHostDenyListKey = "plugins.destination.host.deny_list" private val httpHostDenyListKey = "$httpKeyPrefix.host_deny_list" @@ -49,7 +50,7 @@ internal class PluginSettingsTests { .put(httpMaxConnectionPerRouteKey, 20) .put(httpConnectionTimeoutKey, 5000) .put(httpSocketTimeoutKey, 50000) - .put(maxHttpResponseStrLengthKey, 25000000) + .put(maxHttpResponseSizeKey, SETTING_HTTP_MAX_CONTENT_LENGTH.getDefault(Settings.EMPTY).getBytes().toInt()) .putList(httpHostDenyListKey, emptyList()) .putList( allowedConfigTypeKey, @@ -93,7 +94,7 @@ internal class PluginSettingsTests { PluginSettings.MAX_CONNECTIONS_PER_ROUTE, PluginSettings.CONNECTION_TIMEOUT_MILLISECONDS, PluginSettings.SOCKET_TIMEOUT_MILLISECONDS, - PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH, + PluginSettings.MAX_HTTP_RESPONSE_SIZE, PluginSettings.ALLOWED_CONFIG_TYPES, PluginSettings.TOOLTIP_SUPPORT, PluginSettings.HOST_DENY_LIST @@ -122,8 +123,8 @@ internal class PluginSettingsTests { PluginSettings.socketTimeout.toString() ) Assertions.assertEquals( - defaultSettings[maxHttpResponseStrLengthKey], - PluginSettings.maxHttpResponseStrLength.toString() + defaultSettings[maxHttpResponseSizeKey], + PluginSettings.maxHttpResponseSize.toString() ) Assertions.assertEquals( defaultSettings[allowedConfigTypeKey], @@ -152,7 +153,7 @@ internal class PluginSettingsTests { .put(httpMaxConnectionPerRouteKey, 100) .put(httpConnectionTimeoutKey, 100) .put(httpSocketTimeoutKey, 100) - .put(maxHttpResponseStrLengthKey, 20000000) + .put(maxHttpResponseSizeKey, 20000000) .putList(httpHostDenyListKey, listOf("sample")) .putList(allowedConfigTypeKey, listOf("slack")) .put(tooltipSupportKey, false) @@ -171,7 +172,7 @@ internal class PluginSettingsTests { PluginSettings.MAX_CONNECTIONS_PER_ROUTE, PluginSettings.CONNECTION_TIMEOUT_MILLISECONDS, PluginSettings.SOCKET_TIMEOUT_MILLISECONDS, - PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH, + PluginSettings.MAX_HTTP_RESPONSE_SIZE, PluginSettings.ALLOWED_CONFIG_TYPES, PluginSettings.TOOLTIP_SUPPORT, PluginSettings.HOST_DENY_LIST, @@ -206,7 +207,7 @@ internal class PluginSettingsTests { ) Assertions.assertEquals( 20000000, - clusterService.clusterSettings.get(PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH) + clusterService.clusterSettings.get(PluginSettings.MAX_HTTP_RESPONSE_SIZE) ) Assertions.assertEquals( listOf("sample"), @@ -241,7 +242,7 @@ internal class PluginSettingsTests { PluginSettings.MAX_CONNECTIONS_PER_ROUTE, PluginSettings.CONNECTION_TIMEOUT_MILLISECONDS, PluginSettings.SOCKET_TIMEOUT_MILLISECONDS, - PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH, + PluginSettings.MAX_HTTP_RESPONSE_SIZE, PluginSettings.ALLOWED_CONFIG_TYPES, PluginSettings.TOOLTIP_SUPPORT, PluginSettings.HOST_DENY_LIST, @@ -275,8 +276,8 @@ internal class PluginSettingsTests { clusterService.clusterSettings.get(PluginSettings.SOCKET_TIMEOUT_MILLISECONDS).toString() ) Assertions.assertEquals( - defaultSettings[maxHttpResponseStrLengthKey], - clusterService.clusterSettings.get(PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH).toString() + defaultSettings[maxHttpResponseSizeKey], + clusterService.clusterSettings.get(PluginSettings.MAX_HTTP_RESPONSE_SIZE).toString() ) Assertions.assertEquals( defaultSettings[httpHostDenyListKey], @@ -316,7 +317,7 @@ internal class PluginSettingsTests { PluginSettings.MAX_CONNECTIONS_PER_ROUTE, PluginSettings.CONNECTION_TIMEOUT_MILLISECONDS, PluginSettings.SOCKET_TIMEOUT_MILLISECONDS, - PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH, + PluginSettings.MAX_HTTP_RESPONSE_SIZE, PluginSettings.ALLOWED_CONFIG_TYPES, PluginSettings.TOOLTIP_SUPPORT, PluginSettings.LEGACY_ALERTING_HOST_DENY_LIST, @@ -352,7 +353,7 @@ internal class PluginSettingsTests { PluginSettings.MAX_CONNECTIONS_PER_ROUTE, PluginSettings.CONNECTION_TIMEOUT_MILLISECONDS, PluginSettings.SOCKET_TIMEOUT_MILLISECONDS, - PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH, + PluginSettings.MAX_HTTP_RESPONSE_SIZE, PluginSettings.ALLOWED_CONFIG_TYPES, PluginSettings.TOOLTIP_SUPPORT, PluginSettings.LEGACY_ALERTING_HOST_DENY_LIST, @@ -387,7 +388,7 @@ internal class PluginSettingsTests { PluginSettings.MAX_CONNECTIONS_PER_ROUTE, PluginSettings.CONNECTION_TIMEOUT_MILLISECONDS, PluginSettings.SOCKET_TIMEOUT_MILLISECONDS, - PluginSettings.MAX_HTTP_RESPONSE_STRING_LENGTH, + PluginSettings.MAX_HTTP_RESPONSE_SIZE, PluginSettings.ALLOWED_CONFIG_TYPES, PluginSettings.TOOLTIP_SUPPORT, PluginSettings.LEGACY_ALERTING_HOST_DENY_LIST,