This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 3b48c5e  Adds a new configuration proxy.config.http.allow_multi_range
3b48c5e is described below

commit 3b48c5e42780b53c31445507fd05f8f54378efd1
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.
---
 doc/admin-guide/files/records.config.en.rst        | 16 +++++++
 .../api/functions/TSHttpOverridableConfig.en.rst   |  1 +
 .../api/types/TSOverridableConfigKey.en.rst        |  1 +
 lib/ts/apidefs.h.in                                |  3 +-
 mgmt/RecordsConfig.cc                              |  2 +
 plugins/experimental/ts_lua/ts_lua_http_config.c   |  2 +
 proxy/InkAPI.cc                                    |  5 +++
 proxy/InkAPITest.cc                                |  3 +-
 proxy/http/HttpConfig.cc                           |  2 +
 proxy/http/HttpConfig.h                            |  2 +
 proxy/http/HttpSM.cc                               | 49 ++++++++++++++++------
 11 files changed, 72 insertions(+), 14 deletions(-)

diff --git a/doc/admin-guide/files/records.config.en.rst 
b/doc/admin-guide/files/records.config.en.rst
index ae88333..75ae155 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -1739,6 +1739,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 5ef44ae..17e2a61 100644
--- a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
+++ b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
@@ -169,6 +169,7 @@ TSOverridableConfigKey Value                                
        Configuratio
 :c:macro:`TS_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS`               
:ts:cv:`proxy.config.http.parent_proxy.per_parent_connect_attempts`
 :c:macro:`TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT`            
:ts:cv:`proxy.config.http.parent_proxy.connect_attempts_timeout`
 :c:macro:`TS_CONFIG_HTTP_NORMALIZE_AE`                              
:ts:cv:`proxy.config.http.normalize_ae`
+:c:macro:`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 f33e869..10c9cd7 100644
--- a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
+++ b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
@@ -146,6 +146,7 @@ Enumeration Members
    .. c:macro:: TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT
    .. c:macro:: TS_CONFIG_HTTP_NORMALIZE_AE
    .. c:macro:: TS_CONFIG_HTTP_INSERT_FORWARDED
+   .. c:macro:: TS_CONFIG_HTTP_ALLOW_MULTI_RANGE
    
 Description
 ===========
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index d10126b..a34d2dc 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -763,6 +763,7 @@ typedef enum {
   TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT,
   TS_CONFIG_HTTP_NORMALIZE_AE,
   TS_CONFIG_HTTP_INSERT_FORWARDED,
+  TS_CONFIG_HTTP_ALLOW_MULTI_RANGE,
   TS_CONFIG_LAST_ENTRY
 } TSOverridableConfigKey;
 
@@ -885,7 +886,7 @@ typedef struct TSFetchUrlParams {
 
 // This is a duplicate of the SSL_MAX_SSL_SESSION_ID_LENGTH constant
 // Redefining here so we don't include the openssl/ssl.h file here
-#define TS_SSL_MAX_SSL_SESSION_ID_LENGTH        32
+#define TS_SSL_MAX_SSL_SESSION_ID_LENGTH 32
 
 // This mirrors the internal data structure SSLSessionID
 typedef struct TSSslSessionID_s {
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index b24e1f6..695759c 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -534,6 +534,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}
+  ,
   // This defaults to a special invalid value so the HTTP transaction handling 
code can tell that it was not explicitly set.
   {RECT_CONFIG, "proxy.config.http.normalize_ae", RECD_INT, "1", RECU_DYNAMIC, 
RR_NULL, RECC_INT, "[0-2]", 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 2619969..a7b365f 100644
--- a/plugins/experimental/ts_lua/ts_lua_http_config.c
+++ b/plugins/experimental/ts_lua/ts_lua_http_config.c
@@ -132,6 +132,7 @@ typedef enum {
   TS_LUA_CONFIG_HTTP_PARENT_PROXY_RETRY_TIME                  = 
TS_CONFIG_HTTP_PARENT_PROXY_RETRY_TIME,
   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_HTTP_ALLOW_MULTI_RANGE                        = 
TS_CONFIG_HTTP_ALLOW_MULTI_RANGE,
   TS_LUA_CONFIG_LAST_ENTRY                                    = 
TS_CONFIG_LAST_ENTRY,
 } TSLuaOverridableConfigKey;
 
@@ -256,6 +257,7 @@ ts_lua_var_item ts_lua_http_config_vars[] = {
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PARENT_PROXY_RETRY_TIME),
   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_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 eb59342..09641ae 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -8216,6 +8216,9 @@ _conf_to_memberp(TSOverridableConfigKey conf, 
OverridableHttpConfigParams *overr
   case TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT:
     ret = _memberp_to_generic(&overridableHttpConfig->parent_connect_timeout, 
typep);
     break;
+  case TS_CONFIG_HTTP_ALLOW_MULTI_RANGE:
+    ret = _memberp_to_generic(&overridableHttpConfig->allow_multi_range, 
typep);
+    break;
   // This helps avoiding compiler warnings, yet detect unhandled enum members.
   case TS_CONFIG_NULL:
   case TS_CONFIG_LAST_ENTRY:
@@ -8483,6 +8486,8 @@ TSHttpTxnConfigFind(const char *name, int length, 
TSOverridableConfigKey *conf,
   case 35:
     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;
 
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index d9f4d97..3f62d1f 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -7602,7 +7602,8 @@ const char *SDK_Overridable_Configs[TS_CONFIG_LAST_ENTRY] 
= {"proxy.config.url_r
                                                              
"proxy.config.http.parent_proxy.per_parent_connect_attempts",
                                                              
"proxy.config.http.parent_proxy.connect_attempts_timeout",
                                                              
"proxy.config.http.normalize_ae",
-                                                             
"proxy.config.http.insert_forwarded"};
+                                                             
"proxy.config.http.insert_forwarded",
+                                                             
"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 c4d3d72..a5fce9c 100644
--- a/proxy/http/HttpConfig.cc
+++ b/proxy/http/HttpConfig.cc
@@ -1131,6 +1131,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");
@@ -1386,6 +1387,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 e60fded..9126c23 100644
--- a/proxy/http/HttpConfig.h
+++ b/proxy/http/HttpConfig.h
@@ -435,6 +435,7 @@ struct OverridableHttpConfigParams {
       cache_required_headers(2),
       cache_range_lookup(1),
       cache_range_write(0),
+      allow_multi_range(1),
       cache_enable_default_vary_headers(0),
       ignore_accept_mismatch(0),
       ignore_accept_language_mismatch(0),
@@ -587,6 +588,7 @@ struct OverridableHttpConfigParams {
   MgmtByte cache_required_headers;
   MgmtByte cache_range_lookup;
   MgmtByte cache_range_write;
+  MgmtByte allow_multi_range;
 
   MgmtByte cache_enable_default_vary_headers;
 
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index 50a1f30..3a96156 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -4428,24 +4428,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.

Reply via email to