This is an automated email from the ASF dual-hosted git repository. zwoop pushed a commit to branch 7.1.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/7.1.x by this push: new bbcbb7c Adds a new configuration proxy.config.http.allow_multi_range bbcbb7c is described below commit bbcbb7cf7f25ebfe3a97d792e889de618e41a6a4 Author: Leif Hedstrom <zw...@apache.org> AuthorDate: Tue Feb 6 13:28:30 2018 -0800 Adds a new configuration proxy.config.http.allow_multi_range This is needed to prevent potential abuse with well formed multi- range requests. (cherry picked from commit 3b48c5e42780b53c31445507fd05f8f54378efd1) Conflicts: doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst doc/developer-guide/api/types/TSOverridableConfigKey.en.rst lib/ts/apidefs.h.in mgmt/RecordsConfig.cc plugins/experimental/ts_lua/ts_lua_http_config.c proxy/InkAPI.cc proxy/InkAPITest.cc proxy/http/HttpConfig.h --- doc/admin-guide/files/records.config.en.rst | 16 +++++++ .../api/functions/TSHttpOverridableConfig.en.rst | 1 + .../api/types/TSOverridableConfigKey.en.rst | 2 +- lib/ts/apidefs.h.in | 1 + mgmt/RecordsConfig.cc | 2 + plugins/experimental/ts_lua/ts_lua_http_config.c | 2 + proxy/InkAPI.cc | 5 +++ proxy/InkAPITest.cc | 1 + proxy/http/HttpConfig.cc | 2 + proxy/http/HttpConfig.h | 2 + proxy/http/HttpSM.cc | 49 ++++++++++++++++------ 11 files changed, 70 insertions(+), 13 deletions(-) diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index 12b9971..1609a8a 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -1686,6 +1686,22 @@ Security post body larger than this limit the response will be terminated with 413 - Request Entity Too Large and logged accordingly. +.. ts:cv:: CONFIG proxy.config.http.allow_multi_range INT 1 + :reloadable: + :overridable: + + This option allows the administrator to configure different behavior and + handling of requests with multiple ranges in the ``Range`` header. + + ===== ====================================================================== + Value Description + ===== ====================================================================== + ``0`` Do not allow multiple ranges, effectively ignoring the ``Range`` header + ``1`` Allows multiple ranges. This can be potentially dangerous since well + formed requests can cause excessive resource consumption on the server. + ``2`` Similar to 0, except return a 416 error code and no response body. + ===== ====================================================================== + Cache Control ============= diff --git a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst index 0f5094e..95999e7 100644 --- a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst +++ b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst @@ -172,6 +172,7 @@ c:member:`TS_CONFIG_HTTP_PARENT_PROXY_FAIL_THRESHOLD` :ts:cv:`prox c:member:`TS_CONFIG_HTTP_PARENT_PROXY_RETRY_TIME` :ts:cv:`proxy.config.http.parent_proxy.retry_time` c:member:`TS_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS` :ts:cv:`proxy.config.http.parent_proxy.per_parent_connect_attempts` c:member:`TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT` :ts:cv:`proxy.config.http.parent_proxy.connect_attempts_timeout` +c:member:`TS_CONFIG_HTTP_ALLOW_MULTI_RANGE` :ts:cv:`proxy.config.http.allow_multi_range` ================================================================== ==================================================================== Examples diff --git a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst index cba9f59..d089cb8 100644 --- a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst +++ b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst @@ -132,7 +132,7 @@ Enumeration Members .. c:member:: TSOverridableConfigKey TS_CONFIG_URL_REMAP_PRISTINE_HOST_HDR .. c:member:: TSOverridableConfigKey TS_CONFIG_WEBSOCKET_ACTIVE_TIMEOUT .. c:member:: TSOverridableConfigKey TS_CONFIG_WEBSOCKET_NO_ACTIVITY_TIMEOUT - +.. c:member:: TSOverridableConfigKey TS_CONFIG_HTTP_ALLOW_MULTI_RANGE Description =========== diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in index 2d3d5e8..7451aca 100644 --- a/lib/ts/apidefs.h.in +++ b/lib/ts/apidefs.h.in @@ -755,6 +755,7 @@ typedef enum { TS_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS, TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT, TS_CONFIG_SSL_CLIENT_VERIFY_SERVER, + TS_CONFIG_HTTP_ALLOW_MULTI_RANGE, TS_CONFIG_LAST_ENTRY } TSOverridableConfigKey; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 61c79cd..ede7bbb 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -604,6 +604,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http.enable_http_stats", RECD_INT, "1", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.http.allow_multi_range", RECD_INT, "1", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-2]", RECA_NULL} + , {RECT_CONFIG, "proxy.config.http.normalize_ae_gzip", RECD_INT, "1", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , diff --git a/plugins/experimental/ts_lua/ts_lua_http_config.c b/plugins/experimental/ts_lua/ts_lua_http_config.c index b16b4f1..c9b1541 100644 --- a/plugins/experimental/ts_lua/ts_lua_http_config.c +++ b/plugins/experimental/ts_lua/ts_lua_http_config.c @@ -129,6 +129,7 @@ typedef enum { TS_LUA_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS = TS_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS, TS_LUA_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT = TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT, TS_LUA_CONFIG_SSL_CLIENT_VERIFY_SERVER = TS_CONFIG_SSL_CLIENT_VERIFY_SERVER, + TS_LUA_CONFIG_HTTP_ALLOW_MULTI_RANGE = TS_CONFIG_HTTP_ALLOW_MULTI_RANGE, TS_LUA_CONFIG_LAST_ENTRY = TS_CONFIG_LAST_ENTRY, } TSLuaOverridableConfigKey; @@ -250,6 +251,7 @@ ts_lua_var_item ts_lua_http_config_vars[] = { TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT), TS_LUA_MAKE_VAR_ITEM(TS_CONFIG_SSL_CLIENT_VERIFY_SERVER), + TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_ALLOW_MULTI_RANGE), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_LAST_ENTRY), }; diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc index a23427f..6564bb5 100644 --- a/proxy/InkAPI.cc +++ b/proxy/InkAPI.cc @@ -8202,6 +8202,9 @@ _conf_to_memberp(TSOverridableConfigKey conf, OverridableHttpConfigParams *overr typ = OVERRIDABLE_TYPE_INT; ret = &overridableHttpConfig->parent_connect_timeout; break; + case TS_CONFIG_HTTP_ALLOW_MULTI_RANGE: + ret = &overridableHttpConfig->allow_multi_range; + break; // This helps avoiding compiler warnings, yet detect unhandled enum members. case TS_CONFIG_NULL: case TS_CONFIG_LAST_ENTRY: @@ -8471,6 +8474,8 @@ TSHttpTxnConfigFind(const char *name, int length, TSOverridableConfigKey *conf, case 'e': if (!strncmp(name, "proxy.config.http.cache.range.write", length)) { cnf = TS_CONFIG_HTTP_CACHE_RANGE_WRITE; + } else if (!strncmp(name, "proxy.config.http.allow_multi_range", length)) { + cnf = TS_CONFIG_HTTP_ALLOW_MULTI_RANGE; } break; case 'p': diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc index 5f67c69..bbeb12a 100644 --- a/proxy/InkAPITest.cc +++ b/proxy/InkAPITest.cc @@ -7614,6 +7614,7 @@ const char *SDK_Overridable_Configs[TS_CONFIG_LAST_ENTRY] = { "proxy.config.http.parent_proxy.per_parent_connect_attempts", "proxy.config.http.parent_proxy.connect_attempts_timeout", "proxy.config.ssl.client.verify.server", + "proxy.config.http.allow_multi_range", }; REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus) { diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc index a7d3371..7b60925 100644 --- a/proxy/http/HttpConfig.cc +++ b/proxy/http/HttpConfig.cc @@ -1089,6 +1089,7 @@ HttpConfig::startup() HttpEstablishStaticConfigByte(c.record_cop_page, "proxy.config.http.record_heartbeat"); HttpEstablishStaticConfigByte(c.oride.send_http11_requests, "proxy.config.http.send_http11_requests"); + HttpEstablishStaticConfigByte(c.oride.allow_multi_range, "proxy.config.http.allow_multi_range"); // HTTP Referer Filtering HttpEstablishStaticConfigByte(c.referer_filter_enabled, "proxy.config.http.referer_filter"); @@ -1358,6 +1359,7 @@ HttpConfig::reconfigure() params->oride.cache_required_headers = m_master.oride.cache_required_headers; params->oride.cache_range_lookup = INT_TO_BOOL(m_master.oride.cache_range_lookup); params->oride.cache_range_write = INT_TO_BOOL(m_master.oride.cache_range_write); + params->oride.allow_multi_range = m_master.oride.allow_multi_range; params->connect_ports_string = ats_strdup(m_master.connect_ports_string); params->connect_ports = parse_ports_list(params->connect_ports_string); diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h index 6f15f97..0463956 100644 --- a/proxy/http/HttpConfig.h +++ b/proxy/http/HttpConfig.h @@ -404,6 +404,7 @@ struct OverridableHttpConfigParams { cache_required_headers(2), cache_range_lookup(1), cache_range_write(0), + allow_multi_range(1), insert_request_via_string(1), insert_response_via_string(0), doc_in_cache_skip_dns(1), @@ -550,6 +551,7 @@ struct OverridableHttpConfigParams { MgmtByte cache_required_headers; MgmtByte cache_range_lookup; MgmtByte cache_range_write; + MgmtByte allow_multi_range; MgmtByte insert_request_via_string; MgmtByte insert_response_via_string; diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 62d374f..6bb2751 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -4515,24 +4515,49 @@ HttpSM::do_range_setup_if_necessary() do_range_parse(field); if (t_state.range_setup == HttpTransact::RANGE_REQUESTED) { + bool do_transform = false; + if (!t_state.range_in_cache) { Debug("http_range", "range can't be satisfied from cache, force origin request"); t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_MISS; return; } - // if only one range entry and pread is capable, no need transform range - if (t_state.num_range_fields == 1 && cache_sm.cache_read_vc->is_pread_capable()) { - t_state.range_setup = HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED; - } else if (api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == nullptr) { - Debug("http_trans", "Unable to accelerate range request, fallback to transform"); - content_type = t_state.cache_info.object_read->response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, - &field_content_type_len); - // create a Range: transform processor for requests of type Range: bytes=1-2,4-5,10-100 (eg. multiple ranges) - range_trans = transformProcessor.range_transform(mutex.get(), t_state.ranges, t_state.num_range_fields, - &t_state.hdr_info.transform_response, content_type, field_content_type_len, - t_state.cache_info.object_read->object_size_get()); - api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans); + if (t_state.num_range_fields > 1) { + if (0 == t_state.txn_conf->allow_multi_range) { + t_state.range_setup = HttpTransact::RANGE_NONE; // No Range required (not allowed) + t_state.hdr_info.client_request.field_delete(MIME_FIELD_RANGE, MIME_LEN_RANGE); // ... and nuke the Range header too + t_state.num_range_fields = 0; + } else if (1 == t_state.txn_conf->allow_multi_range) { + do_transform = true; + } else { + t_state.num_range_fields = 0; + t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE; + } + } else { + if (cache_sm.cache_read_vc->is_pread_capable()) { + // If only one range entry and pread is capable, no need transform range + t_state.range_setup = HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED; + } else { + do_transform = true; + } + } + + // We have to do the transform on (allowed) multi-range request, *or* if the VC is not pread capable + if (do_transform) { + if (api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == nullptr) { + Debug("http_trans", "Unable to accelerate range request, fallback to transform"); + content_type = t_state.cache_info.object_read->response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, + &field_content_type_len); + // create a Range: transform processor for requests of type Range: bytes=1-2,4-5,10-100 (eg. multiple ranges) + range_trans = transformProcessor.range_transform( + mutex.get(), t_state.ranges, t_state.num_range_fields, &t_state.hdr_info.transform_response, content_type, + field_content_type_len, t_state.cache_info.object_read->object_size_get()); + api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans); + } else { + // ToDo: Do we do something here? The theory is that multiple transforms do not behave well with + // the range transform needed here. + } } } } -- To stop receiving notification emails like this one, please contact zw...@apache.org.