You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by so...@apache.org on 2016/05/20 16:49:32 UTC

[trafficserver] branch 6.2.x updated (92e7859 -> 8750db6)

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

sorber pushed a change to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git.

      from  92e7859   TS-4418: Update code with new .clang-format config change
       new  0d2214f   TS-4359 Deprecate the SPDY feature
       new  2bf7e58   TS-3535: Experimental Support of HTTP/2 Stream Priority feature
       new  071853a   TS-4388: Add an API test for TSHttpTxnParentProxySet.
       new  751c3da   TS-4388: Remove unused HttpConfig::parent_proxy_routing_enable.
       new  e7d515f   TS-4388: Fix global hook handling in API tests.
       new  b0378ee   TS-4388: Rename ParentResult:r.
       new  584a5eb   TS-4388: Refactor ParentResult initialization.
       new  ee5521d   TS-4388: TSHttpTxnParentProxySet crashes in parent selection.
       new  69ad8fe   TS-4413: Fix potential consistent hash iterator race.
       new  8e2e4e3   TS-4410 : Fixed compiler warning on i386 builds
       new  3a8a3c2   Remove double call to NetVConnection->do_io_read.
       new  c5cfb5b   TS-3485: Remove Warning message about ip-allow enforcement not being present for HTTP2.
       new  2a000a7   TS-3485: Support ip_allow config for HTTP2.  This closes #614.
       new  7fedb23   TS-4075: add a state check for sslHandshakeHookState after PreAcceptHookState checking.  This closes #374.
       new  8750db6   TS-4431: ATSCPPAPI needs a mutex for intercept plugins

The 15 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "adds" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |   1 +
 configure.ac                                       |   2 +-
 .../configuration/session-protocol.en.rst          |  13 +-
 doc/admin-guide/files/records.config.en.rst        |  16 +-
 doc/admin-guide/installation/index.en.rst          |   4 +-
 .../api/functions/TSHttpTxnParentProxySet.en.rst   |   2 +-
 iocore/hostdb/I_HostDBProcessor.h                  |   2 +-
 iocore/net/I_SessionAccept.h                       |   6 +
 iocore/net/Makefile.am                             |   1 +
 iocore/net/SSLNetVConnection.cc                    |  52 ++--
 iocore/net/{I_SessionAccept.h => SessionAccept.cc} |  27 +-
 iocore/net/Socks.cc                                |   6 +-
 lib/atscppapi/src/InterceptPlugin.cc               |   2 +-
 lib/records/RecHttp.cc                             |   2 -
 mgmt/RecordsConfig.cc                              |   4 +-
 proxy/InkAPI.cc                                    |   4 +-
 proxy/InkAPITest.cc                                | 233 ++++++++++++---
 proxy/InkAPITestTool.cc                            |  78 +++--
 proxy/ParentConsistentHash.cc                      |  34 +--
 proxy/ParentConsistentHash.h                       |   1 -
 proxy/ParentRoundRobin.cc                          |  26 +-
 proxy/ParentSelection.cc                           |  51 ++--
 proxy/ParentSelection.h                            | 115 ++++++--
 proxy/api/ts/ts.h                                  |   4 +-
 proxy/http/HttpConfig.cc                           |   3 -
 proxy/http/HttpConfig.h                            |   3 -
 proxy/http/HttpSM.cc                               |  14 +-
 proxy/http/HttpSessionAccept.cc                    |  19 +-
 proxy/http/HttpTransact.cc                         |  77 +++--
 proxy/http/HttpTransact.h                          |   8 +-
 proxy/http2/HTTP2.cc                               |  12 +-
 proxy/http2/HTTP2.h                                |  16 +-
 proxy/http2/Http2ClientSession.cc                  |  12 -
 proxy/http2/Http2ConnectionState.cc                | 309 +++++++++++++------
 proxy/http2/Http2ConnectionState.h                 |  22 +-
 proxy/http2/Http2DependencyTree.h                  | 308 +++++++++++++++++++
 proxy/http2/Http2SessionAccept.cc                  |  17 +-
 proxy/http2/Http2Stream.cc                         |  21 +-
 proxy/http2/Http2Stream.h                          |   7 +
 proxy/http2/Makefile.am                            |  15 +-
 proxy/http2/test_Http2DependencyTree.cc            | 327 +++++++++++++++++++++
 41 files changed, 1477 insertions(+), 399 deletions(-)
 copy iocore/net/{I_SessionAccept.h => SessionAccept.cc} (68%)
 create mode 100644 proxy/http2/Http2DependencyTree.h
 create mode 100644 proxy/http2/test_Http2DependencyTree.cc

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].

[trafficserver] 05/15: TS-4388: Fix global hook handling in API tests.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit e7d515f445d4e502fdb40e0383b7362bc6f6c32e
Author: James Peach <jp...@apache.org>
AuthorDate: Thu Apr 28 20:02:38 2016 +0000

    TS-4388: Fix global hook handling in API tests.
    
    Many of the API regression tests work by trampolining off a global
    hook (which is really what you have to do). However, there's no way
    to unregister a global hook, so once the test is done, it needs to
    be careful to co-operate with the remaining tests. We clear the
    continuation data, and if is is clear, we either ignore the event
    or re-enable the HTTP transaction.
    
    (cherry picked from commit 060b8e8bd0d794ee038595e42e3e104d6c89371a)
---
 proxy/InkAPITest.cc     | 110 ++++++++++++++++++++++++++----------------------
 proxy/InkAPITestTool.cc |  38 ++++++++++++-----
 2 files changed, 88 insertions(+), 60 deletions(-)

diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index d7d64dd..ac2e197 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -55,6 +55,39 @@
 
 #define UTDBG_TAG "sdk_ut"
 
+// Since there's no way to unregister global hooks, tests that register a hook
+// have to co-operate once they are complete by re-enabling and transactions
+// and getting out of the way.
+#define CHECK_SPURIOUS_EVENT(cont, event, edata)                     \
+  if (TSContDataGet(cont) == NULL) {                                 \
+    switch (event) {                                                 \
+    case TS_EVENT_IMMEDIATE:                                         \
+    case TS_EVENT_TIMEOUT:                                           \
+      return TS_EVENT_NONE;                                          \
+    case TS_EVENT_HTTP_SELECT_ALT:                                   \
+      return TS_EVENT_NONE;                                          \
+    case TS_EVENT_HTTP_READ_REQUEST_HDR:                             \
+    case TS_EVENT_HTTP_OS_DNS:                                       \
+    case TS_EVENT_HTTP_SEND_REQUEST_HDR:                             \
+    case TS_EVENT_HTTP_READ_CACHE_HDR:                               \
+    case TS_EVENT_HTTP_READ_RESPONSE_HDR:                            \
+    case TS_EVENT_HTTP_SEND_RESPONSE_HDR:                            \
+    case TS_EVENT_HTTP_REQUEST_TRANSFORM:                            \
+    case TS_EVENT_HTTP_RESPONSE_TRANSFORM:                           \
+    case TS_EVENT_HTTP_TXN_START:                                    \
+    case TS_EVENT_HTTP_TXN_CLOSE:                                    \
+    case TS_EVENT_HTTP_SSN_START:                                    \
+    case TS_EVENT_HTTP_SSN_CLOSE:                                    \
+    case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:                        \
+    case TS_EVENT_HTTP_PRE_REMAP:                                    \
+    case TS_EVENT_HTTP_POST_REMAP:                                   \
+      TSHttpTxnReenable((TSHttpTxn)(edata), TS_EVENT_HTTP_CONTINUE); \
+      return TS_EVENT_NONE;                                          \
+    default:                                                         \
+      break;                                                         \
+    }                                                                \
+  }
+
 /******************************************************************************/
 
 /* Use SDK_RPRINT to report failure or success for each test case */
@@ -2303,6 +2336,7 @@ mytest_handler(TSCont contp, TSEvent event, void *data)
       // transaction is over. clean up.
       synclient_txn_delete(test->browser);
       synserver_delete(test->os);
+      test->os = NULL;
 
       test->magic = MAGIC_DEAD;
       TSfree(test);
@@ -5804,6 +5838,7 @@ ssn_handler(TSCont contp, TSEvent event, void *edata)
       /* Don't need it as didn't initialize the server
          synserver_delete(data->os);
        */
+      data->os = NULL;
       data->magic = MAGIC_DEAD;
       TSfree(data);
       TSContDataSet(contp, NULL);
@@ -5871,9 +5906,12 @@ struct ParentTest {
 static int
 parent_proxy_handler(TSCont contp, TSEvent event, void *edata)
 {
-  ParentTest *ptest = (ParentTest *)TSContDataGet(contp);
+  ParentTest *ptest = NULL;
   TSHttpTxn txnp = (TSHttpTxn)edata;
 
+  CHECK_SPURIOUS_EVENT(contp, event, edata);
+  ptest = (ParentTest *)TSContDataGet(contp);
+
   switch (event) {
   case TS_EVENT_HTTP_READ_REQUEST_HDR:
     rprintf(ptest->regtest, "setting synserver parent proxy to %s:%d\n", "127.0.0.1", SYNSERVER_LISTEN_PORT);
@@ -5914,11 +5952,13 @@ parent_proxy_handler(TSCont contp, TSEvent event, void *edata)
       // Otherwise the test completed so clean up.
       RecSetRecordInt("proxy.config.http.parent_proxy_routing_enable", ptest->parent_proxy_routing_enable, REC_SOURCE_EXPLICIT);
 
-      ptest->magic = MAGIC_DEAD;
+      TSContDataSet(contp, NULL);
+
       synclient_txn_delete(ptest->browser);
       synserver_delete(ptest->os);
+      ptest->os = NULL;
+      ptest->magic = MAGIC_DEAD;
       TSfree(ptest);
-      TSContDataSet(contp, NULL);
     }
     break;
 
@@ -6017,20 +6057,10 @@ static int
 cache_hook_handler(TSCont contp, TSEvent event, void *edata)
 {
   TSHttpTxn txnp = NULL;
-  CacheTestData *data = (CacheTestData *)TSContDataGet(contp);
+  CacheTestData *data = NULL;
 
-  if (data == NULL) {
-    switch (event) {
-    case TS_EVENT_IMMEDIATE:
-    case TS_EVENT_TIMEOUT:
-      break;
-    case TS_EVENT_HTTP_READ_CACHE_HDR:
-    default:
-      TSHttpTxnReenable((TSHttpTxn)edata, TS_EVENT_HTTP_CONTINUE);
-      break;
-    }
-    return 0;
-  }
+  CHECK_SPURIOUS_EVENT(contp, event, edata);
+  data = (CacheTestData *)TSContDataGet(contp);
 
   switch (event) {
   case TS_EVENT_HTTP_READ_REQUEST_HDR:
@@ -6139,6 +6169,7 @@ cache_hook_handler(TSCont contp, TSEvent event, void *edata)
         data->first_time = false;
         /* Kill the origin server */
         synserver_delete(data->os);
+        data->os = NULL;
 
         /* Send another similar client request */
         synclient_txn_send_request(data->browser2, data->request);
@@ -6523,19 +6554,9 @@ transform_hook_handler(TSCont contp, TSEvent event, void *edata)
 {
   TSHttpTxn txnp = NULL;
   TransformTestData *data = NULL;
+
+  CHECK_SPURIOUS_EVENT(contp, event, edata);
   data = (TransformTestData *)TSContDataGet(contp);
-  if (data == NULL) {
-    switch (event) {
-    case TS_EVENT_IMMEDIATE:
-    case TS_EVENT_TIMEOUT:
-      break;
-    case TS_EVENT_HTTP_READ_RESPONSE_HDR:
-    default:
-      TSHttpTxnReenable((TSHttpTxn)edata, TS_EVENT_HTTP_CONTINUE);
-      break;
-    }
-    return 0;
-  }
 
   switch (event) {
   case TS_EVENT_HTTP_READ_REQUEST_HDR:
@@ -6651,6 +6672,7 @@ transform_hook_handler(TSCont contp, TSEvent event, void *edata)
         return 0;
       }
       synserver_delete(data->os);
+      data->os = NULL;
       data->req_no++;
       TSfree(data->request1);
       TSfree(data->request2);
@@ -6823,20 +6845,8 @@ altinfo_hook_handler(TSCont contp, TSEvent event, void *edata)
   AltInfoTestData *data = NULL;
   TSHttpTxn txnp = NULL;
 
+  CHECK_SPURIOUS_EVENT(contp, event, edata);
   data = (AltInfoTestData *)TSContDataGet(contp);
-  if (data == NULL) {
-    switch (event) {
-    case TS_EVENT_IMMEDIATE:
-    case TS_EVENT_TIMEOUT:
-      break;
-    case TS_EVENT_HTTP_SELECT_ALT:
-      break;
-    default:
-      TSHttpTxnReenable((TSHttpTxn)edata, TS_EVENT_HTTP_CONTINUE);
-      break;
-    }
-    return 0;
-  }
 
   switch (event) {
   case TS_EVENT_HTTP_READ_REQUEST_HDR:
@@ -6928,6 +6938,7 @@ altinfo_hook_handler(TSCont contp, TSEvent event, void *edata)
         data->first_time = false;
         /* Kill the origin server */
         synserver_delete(data->os);
+        data->os = NULL;
         // ink_release_assert(0);
         /* Send another similar client request */
         synclient_txn_send_request(data->browser3, data->request3);
@@ -7044,8 +7055,6 @@ EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpAltInfo)(RegressionTest *test, int /* atyp
 #define TEST_CASE_CONNECT_ID1 9  // TSHttpTxnIntercept
 #define TEST_CASE_CONNECT_ID2 10 // TSHttpTxnServerIntercept
 
-#define SYNSERVER_DUMMY_PORT -1
-
 typedef struct {
   RegressionTest *test;
   int *pstatus;
@@ -7061,9 +7070,12 @@ static int
 cont_test_handler(TSCont contp, TSEvent event, void *edata)
 {
   TSHttpTxn txnp = (TSHttpTxn)edata;
-  ConnectTestData *data = (ConnectTestData *)TSContDataGet(contp);
+  ConnectTestData *data = NULL;
   int request_id = -1;
 
+  CHECK_SPURIOUS_EVENT(contp, event, edata);
+  data = (ConnectTestData *)TSContDataGet(contp);
+
   TSReleaseAssert(data->magic == MAGIC_ALIVE);
   TSReleaseAssert((data->test_case == TEST_CASE_CONNECT_ID1) || (data->test_case == TEST_CASE_CONNECT_ID2));
 
@@ -7139,12 +7151,10 @@ cont_test_handler(TSCont contp, TSEvent event, void *edata)
       // transaction is over. clean it up.
       synclient_txn_delete(data->browser);
       synserver_delete(data->os);
-
-      // As we registered to a global hook, we may be called back again.
-      // Do not destroy the continuation...
-      // data->magic = MAGIC_DEAD;
-      // TSfree(data);
-      // TSContDataSet(contp, NULL);
+      data->os = NULL;
+      data->magic = MAGIC_DEAD;
+      TSfree(data);
+      TSContDataSet(contp, NULL);
     }
     break;
 
diff --git a/proxy/InkAPITestTool.cc b/proxy/InkAPITestTool.cc
index eb399fd..1ebac13 100644
--- a/proxy/InkAPITestTool.cc
+++ b/proxy/InkAPITestTool.cc
@@ -42,6 +42,7 @@
 #define MAGIC_DEAD 0xdeadbeef
 
 #define SYNSERVER_LISTEN_PORT 3300
+#define SYNSERVER_DUMMY_PORT -1
 
 #define PROXY_CONFIG_NAME_HTTP_PORT "proxy.config.http.server_port"
 #define PROXY_HTTP_DEFAULT_PORT 8080
@@ -762,6 +763,11 @@ synclient_txn_main_handler(TSCont contp, TSEvent event, void *data)
 SocketServer *
 synserver_create(int port)
 {
+  if (port != SYNSERVER_DUMMY_PORT) {
+    TSAssert(port > 0);
+    TSAssert(port < INT16_MAX);
+  }
+
   SocketServer *s = (SocketServer *)TSmalloc(sizeof(SocketServer));
   s->magic = MAGIC_ALIVE;
   s->accept_port = port;
@@ -775,7 +781,15 @@ static int
 synserver_start(SocketServer *s)
 {
   TSAssert(s->magic == MAGIC_ALIVE);
-  s->accept_action = TSNetAccept(s->accept_cont, s->accept_port, -1, 0);
+  TSAssert(s->accept_action == NULL);
+
+  if (s->accept_port != SYNSERVER_DUMMY_PORT) {
+    TSAssert(s->accept_port > 0);
+    TSAssert(s->accept_port < INT16_MAX);
+
+    s->accept_action = TSNetAccept(s->accept_cont, s->accept_port, AF_INET, 0);
+  }
+
   return 1;
 }
 
@@ -795,17 +809,21 @@ synserver_stop(SocketServer *s)
 static int
 synserver_delete(SocketServer *s)
 {
-  TSAssert(s->magic == MAGIC_ALIVE);
-  synserver_stop(s);
+  if (s != NULL) {
+    TSAssert(s->magic == MAGIC_ALIVE);
+    synserver_stop(s);
+
+    if (s->accept_cont) {
+      TSContDestroy(s->accept_cont);
+      s->accept_cont = NULL;
+      TSDebug(SDBG_TAG, "destroyed accept cont");
+    }
 
-  if (s->accept_cont) {
-    TSContDestroy(s->accept_cont);
-    s->accept_cont = NULL;
-    TSDebug(SDBG_TAG, "destroyed accept cont");
+    s->magic = MAGIC_DEAD;
+    TSfree(s);
+    TSDebug(SDBG_TAG, "deleted server");
   }
-  s->magic = MAGIC_DEAD;
-  TSfree(s);
-  TSDebug(SDBG_TAG, "deleted server");
+
   return 1;
 }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 04/15: TS-4388: Remove unused HttpConfig::parent_proxy_routing_enable.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 751c3da7e00762cc8f1c7c4dc712cd105c22667e
Author: James Peach <jp...@apache.org>
AuthorDate: Wed Apr 27 11:20:25 2016 -0700

    TS-4388: Remove unused HttpConfig::parent_proxy_routing_enable.
    
    (cherry picked from commit 0689f632cb40922b0c1aa5589f83059838d37047)
    
     Conflicts:
    	proxy/http/HttpConfig.h
---
 proxy/http/HttpConfig.cc | 3 ---
 proxy/http/HttpConfig.h  | 3 ---
 2 files changed, 6 deletions(-)

diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc
index 4d6a2c6..3cf91ee 100644
--- a/proxy/http/HttpConfig.cc
+++ b/proxy/http/HttpConfig.cc
@@ -888,8 +888,6 @@ HttpConfig::startup()
   HttpEstablishStaticConfigLongLong(c.origin_min_keep_alive_connections, "proxy.config.http.origin_min_keep_alive_connections");
   HttpEstablishStaticConfigLongLong(c.oride.attach_server_session_to_client, "proxy.config.http.attach_server_session_to_client");
 
-  HttpEstablishStaticConfigByte(c.parent_proxy_routing_enable, "proxy.config.http.parent_proxy_routing_enable");
-
   // Wank me.
   HttpEstablishStaticConfigByte(c.disable_ssl_parenting, "proxy.local.http.parent_proxy.disable_connect_tunneling");
   HttpEstablishStaticConfigByte(c.no_dns_forward_to_parent, "proxy.config.http.no_dns_just_forward_to_parent");
@@ -1169,7 +1167,6 @@ HttpConfig::reconfigure()
     params->origin_min_keep_alive_connections = params->oride.origin_max_connections;
   }
 
-  params->parent_proxy_routing_enable = INT_TO_BOOL(m_master.parent_proxy_routing_enable);
   params->enable_url_expandomatic = INT_TO_BOOL(m_master.enable_url_expandomatic);
 
   params->oride.insert_request_via_string = m_master.oride.insert_request_via_string;
diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h
index 1860550..8e2b66f 100644
--- a/proxy/http/HttpConfig.h
+++ b/proxy/http/HttpConfig.h
@@ -706,7 +706,6 @@ public:
   MgmtInt origin_min_keep_alive_connections; // TODO: This one really ought to be overridable, but difficult right now.
   MgmtInt max_websocket_connections;
 
-  MgmtByte parent_proxy_routing_enable;
   MgmtByte disable_ssl_parenting;
 
   MgmtByte enable_url_expandomatic;
@@ -922,11 +921,9 @@ inline HttpConfigParams::HttpConfigParams()
     server_max_connections(0),
     origin_min_keep_alive_connections(0),
     max_websocket_connections(-1),
-    parent_proxy_routing_enable(0),
     disable_ssl_parenting(0),
     enable_url_expandomatic(0),
     no_dns_forward_to_parent(0),
-    uncacheable_requests_bypass_parent(1),
     no_origin_server_dns(0),
     use_client_target_addr(0),
     use_client_source_port(0),

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 02/15: TS-3535: Experimental Support of HTTP/2 Stream Priority feature

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 2bf7e5850b55bbb9eca388540c71e68d172c38ea
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Fri Feb 12 16:07:10 2016 +0900

    TS-3535: Experimental Support of HTTP/2 Stream Priority feature
    
    - Add a option to enable this feature ( disabled in default ).
      `proxy.config.http2.stream_priority_enabled`
    - Parse priority parameters of HEADERS and PRIORITY frame correctly.
    - Add Http2DependencyTree and tests using `lib/ts/PriorityQueue.h`.
    - Create a dependency tree when clients send HEADERS frame with priority parameters or PRIORITY frame.
    - Separate `Http2ConnectionState::send_data_frame()` into `Http2ConnectionState::send_a_data_frame()`
      and `Http2ConnectionState::send_data_frames()`.
    - Schedule DATA frames using the WFQ algorithm.
    
    This closes #632
    
    (cherry picked from commit 16172a4e79865d1201a51e85aeb72df8b0609986)
---
 .gitignore                                  |   1 +
 doc/admin-guide/files/records.config.en.rst |   5 +
 mgmt/RecordsConfig.cc                       |   4 +-
 proxy/http2/HTTP2.cc                        |  12 +-
 proxy/http2/HTTP2.h                         |  16 +-
 proxy/http2/Http2ConnectionState.cc         | 309 ++++++++++++++++++--------
 proxy/http2/Http2ConnectionState.h          |  22 +-
 proxy/http2/Http2DependencyTree.h           | 308 ++++++++++++++++++++++++++
 proxy/http2/Http2Stream.cc                  |  21 +-
 proxy/http2/Http2Stream.h                   |   7 +
 proxy/http2/Makefile.am                     |  15 +-
 proxy/http2/test_Http2DependencyTree.cc     | 327 ++++++++++++++++++++++++++++
 12 files changed, 940 insertions(+), 107 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4a7b81c..af55f7b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -89,6 +89,7 @@ proxy/config/records.config.default
 proxy/config/storage.config.default
 proxy/hdrs/test_mime
 proxy/http2/test_Huffmancode
+proxy/http2/test_Http2DependencyTree
 
 plugins/header_rewrite/header_rewrite_test
 plugins/experimental/esi/*_test
diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index da23cb6..b5bc60a 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -2997,6 +2997,11 @@ HTTP/2 Configuration
    that the sender is prepared to accept blocks. The default value, which is
    the unsigned int maximum value in Traffic Server, implies unlimited size.
 
+.. ts:cv:: CONFIG proxy.config.http2.stream_priority_enabled INT 0
+   :reloadable:
+
+   Enable the experimental HTTP/2 Stream Priority feature.
+
 SPDY Configuration
 ==================
 
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index 8d17edb..6361971 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1972,7 +1972,9 @@ static const RecordElement RecordsConfig[] =
   //# HTTP/2 global configuration.
   //#
   //############
-  {RECT_CONFIG, "proxy.config.http2.enabled", RECD_INT, "0", RECU_RESTART_TM, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
+  {RECT_CONFIG, "proxy.config.http2.enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
+  ,
+  {RECT_CONFIG, "proxy.config.http2.stream_priority_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
   ,
   {RECT_CONFIG, "proxy.config.http2.max_concurrent_streams_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
   ,
diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc
index bcaad3b..4bee9ed 100644
--- a/proxy/http2/HTTP2.cc
+++ b/proxy/http2/HTTP2.cc
@@ -335,15 +335,19 @@ http2_parse_headers_parameter(IOVec iov, Http2HeadersParameter &params)
 }
 
 bool
-http2_parse_priority_parameter(IOVec iov, Http2Priority &params)
+http2_parse_priority_parameter(IOVec iov, Http2Priority &priority)
 {
   byte_pointer ptr(iov.iov_base);
   byte_addressable_value<uint32_t> dependency;
 
   memcpy_and_advance(dependency.bytes, ptr);
-  memcpy_and_advance(params.weight, ptr);
 
-  params.stream_dependency = ntohl(dependency.value);
+  priority.exclusive_flag = dependency.bytes[0] & 0x80;
+
+  dependency.bytes[0] &= 0x7f; // Clear the highest bit for exclusive flag
+  priority.stream_dependency = ntohl(dependency.value);
+
+  memcpy_and_advance(priority.weight, ptr);
 
   return true;
 }
@@ -666,6 +670,7 @@ uint32_t Http2::max_concurrent_streams_in = 100;
 uint32_t Http2::min_concurrent_streams_in = 10;
 uint32_t Http2::max_active_streams_in = 0;
 bool Http2::throttling = false;
+uint32_t Http2::stream_priority_enabled = 0;
 uint32_t Http2::initial_window_size = 1048576;
 uint32_t Http2::max_frame_size = 16384;
 uint32_t Http2::header_table_size = 4096;
@@ -681,6 +686,7 @@ Http2::init()
   REC_EstablishStaticConfigInt32U(max_concurrent_streams_in, "proxy.config.http2.max_concurrent_streams_in");
   REC_EstablishStaticConfigInt32U(min_concurrent_streams_in, "proxy.config.http2.min_concurrent_streams_in");
   REC_EstablishStaticConfigInt32U(max_active_streams_in, "proxy.config.http2.max_active_streams_in");
+  REC_EstablishStaticConfigInt32U(stream_priority_enabled, "proxy.config.http2.stream_priority_enabled");
   REC_EstablishStaticConfigInt32U(initial_window_size, "proxy.config.http2.initial_window_size_in");
   REC_EstablishStaticConfigInt32U(max_frame_size, "proxy.config.http2.max_frame_size");
   REC_EstablishStaticConfigInt32U(header_table_size, "proxy.config.http2.header_table_size");
diff --git a/proxy/http2/HTTP2.h b/proxy/http2/HTTP2.h
index 3cbb443..1fde5fc 100644
--- a/proxy/http2/HTTP2.h
+++ b/proxy/http2/HTTP2.h
@@ -60,6 +60,12 @@ const uint32_t HTTP2_MAX_FRAME_SIZE = 16384;
 const uint32_t HTTP2_HEADER_TABLE_SIZE = 4096;
 const uint32_t HTTP2_MAX_HEADER_LIST_SIZE = UINT_MAX;
 
+// [RFC 7540] 5.3.5 Default Priorities
+// The RFC says weight value is 1 to 256, but the value in TS is between 0 to 255
+// to use uint8_t. So the default weight is 16 minus 1.
+const uint32_t HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY = 0;
+const uint8_t HTTP2_PRIORITY_DEFAULT_WEIGHT = 15;
+
 // Statistics
 enum {
   HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT,  // Current # of active HTTP2
@@ -253,9 +259,14 @@ struct Http2SettingsParameter {
 
 // [RFC 7540] 6.3 PRIORITY Format
 struct Http2Priority {
-  Http2Priority() : stream_dependency(0), weight(15) {}
-  uint32_t stream_dependency;
+  Http2Priority()
+    : exclusive_flag(false), weight(HTTP2_PRIORITY_DEFAULT_WEIGHT), stream_dependency(HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY)
+  {
+  }
+
+  bool exclusive_flag;
   uint8_t weight;
+  uint32_t stream_dependency;
 };
 
 // [RFC 7540] 6.2 HEADERS Format
@@ -348,6 +359,7 @@ public:
   static uint32_t min_concurrent_streams_in;
   static uint32_t max_active_streams_in;
   static bool throttling;
+  static uint32_t stream_priority_enabled;
   static uint32_t initial_window_size;
   static uint32_t max_frame_size;
   static uint32_t header_table_size;
diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc
index da1f8d3..da294e4 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -192,6 +192,8 @@ rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
   }
 
   Http2Stream *stream = NULL;
+  bool new_stream = false;
+
   if (stream_id <= cstate.get_latest_stream_id()) {
     stream = cstate.find_stream(stream_id);
     if (stream == NULL || !stream->has_trailing_header()) {
@@ -199,6 +201,7 @@ rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
     }
   } else {
     // Create new stream
+    new_stream = true;
     stream = cstate.create_stream(stream_id);
     if (!stream) {
       return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
@@ -239,7 +242,6 @@ rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
   }
 
   // NOTE: Parse priority parameters if exists
-  // TODO: Currently priority is NOT supported. TS-3535 will fix this.
   if (frame.header().flags & HTTP2_FLAGS_HEADERS_PRIORITY) {
     uint8_t buf[HTTP2_PRIORITY_LEN] = {0};
 
@@ -256,6 +258,19 @@ rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
     header_block_fragment_length -= HTTP2_PRIORITY_LEN;
   }
 
+  if (new_stream && Http2::stream_priority_enabled) {
+    DependencyTree::Node *node = cstate.dependency_tree->find(stream_id);
+    if (node != NULL) {
+      stream->priority_node = node;
+    } else {
+      DebugHttp2Stream(cstate.ua_session, stream_id, "PRIORITY - dep: %d, weight: %d, excl: %d", params.priority.stream_dependency,
+                       params.priority.weight, params.priority.exclusive_flag);
+
+      stream->priority_node = cstate.dependency_tree->add(params.priority.stream_dependency, stream_id, params.priority.weight,
+                                                          params.priority.exclusive_flag, stream);
+    }
+  }
+
   stream->header_blocks = static_cast<uint8_t *>(ats_malloc(header_block_fragment_length));
   frame.reader()->memcpy(stream->header_blocks, header_block_fragment_length, header_block_fragment_offset);
 
@@ -305,25 +320,59 @@ rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
   return Http2Error(HTTP2_ERROR_CLASS_NONE);
 }
 
+/*
+ * [RFC 7540] 6.3 PRIORITY
+ *
+ */
 static Http2Error
 rcv_priority_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
 {
-  DebugHttp2Stream(cstate.ua_session, frame.header().streamid, "Received PRIORITY frame");
+  const Http2StreamId stream_id = frame.header().streamid;
+  const uint32_t payload_length = frame.header().length;
+
+  DebugHttp2Stream(cstate.ua_session, stream_id, "Received PRIORITY frame");
 
   // If a PRIORITY frame is received with a stream identifier of 0x0, the
   // recipient MUST respond with a connection error of type PROTOCOL_ERROR.
-  if (frame.header().streamid == 0) {
+  if (stream_id == 0) {
     return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
   }
 
   // A PRIORITY frame with a length other than 5 octets MUST be treated as
   // a stream error (Section 5.4.2) of type FRAME_SIZE_ERROR.
-  if (frame.header().length != HTTP2_PRIORITY_LEN) {
+  if (payload_length != HTTP2_PRIORITY_LEN) {
     return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_FRAME_SIZE_ERROR);
   }
 
-  // TODO Pick stream dependencies and weight
-  // Supporting PRIORITY is not essential so its temporarily ignored.
+  if (!Http2::stream_priority_enabled) {
+    return Http2Error(HTTP2_ERROR_CLASS_NONE);
+  }
+
+  uint8_t buf[HTTP2_PRIORITY_LEN] = {0};
+  frame.reader()->memcpy(buf, HTTP2_PRIORITY_LEN, 0);
+
+  Http2Priority priority;
+  if (!http2_parse_priority_parameter(make_iovec(buf, HTTP2_PRIORITY_LEN), priority)) {
+    return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
+  }
+
+  DebugHttp2Stream(cstate.ua_session, stream_id, "PRIORITY - dep: %d, weight: %d, excl: %d", priority.stream_dependency,
+                   priority.weight, priority.exclusive_flag);
+
+  DependencyTree::Node *node = cstate.dependency_tree->find(stream_id);
+
+  if (node != NULL) {
+    // [RFC 7540] 5.3.3 Reprioritization
+    DebugHttp2Stream(cstate.ua_session, stream_id, "Reprioritize");
+    cstate.dependency_tree->reprioritize(node, priority.stream_dependency, priority.exclusive_flag);
+  } else {
+    cstate.dependency_tree->add(priority.stream_dependency, stream_id, priority.weight, priority.exclusive_flag, NULL);
+
+    Http2Stream *stream = cstate.find_stream(stream_id);
+    if (stream != NULL) {
+      stream->priority_node = node;
+    }
+  }
 
   return Http2Error(HTTP2_ERROR_CLASS_NONE);
 }
@@ -536,30 +585,32 @@ rcv_window_update_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
 {
   char buf[HTTP2_WINDOW_UPDATE_LEN];
   uint32_t size;
-  const Http2StreamId sid = frame.header().streamid;
+  const Http2StreamId stream_id = frame.header().streamid;
 
   //  A WINDOW_UPDATE frame with a length other than 4 octets MUST be
   //  treated as a connection error of type FRAME_SIZE_ERROR.
   if (frame.header().length != HTTP2_WINDOW_UPDATE_LEN) {
-    DebugHttp2Stream(cstate.ua_session, sid, "Received WINDOW_UPDATE frame - length incorrect");
+    DebugHttp2Stream(cstate.ua_session, stream_id, "Received WINDOW_UPDATE frame - length incorrect");
     return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_FRAME_SIZE_ERROR);
   }
 
-  if (sid == 0) {
-    // Connection level window update
-    frame.reader()->memcpy(buf, sizeof(buf), 0);
-    http2_parse_window_update(make_iovec(buf, sizeof(buf)), size);
-
-    DebugHttp2Stream(cstate.ua_session, sid, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
-                     (cstate.client_rwnd + size), size);
+  frame.reader()->memcpy(buf, sizeof(buf), 0);
+  http2_parse_window_update(make_iovec(buf, sizeof(buf)), size);
 
-    // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a
-    // connection
-    // flow control window increment of 0 as a connection error of type
-    // PROTOCOL_ERROR;
-    if (size == 0) {
+  // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a flow
+  // control window increment of 0 as a connection error of type PROTOCOL_ERROR;
+  if (size == 0) {
+    if (stream_id == 0) {
       return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
+    } else {
+      return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
     }
+  }
+
+  if (stream_id == 0) {
+    // Connection level window update
+    DebugHttp2Stream(cstate.ua_session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
+                     (cstate.client_rwnd + size), size);
 
     // A sender MUST NOT allow a flow-control window to exceed 2^31-1
     // octets.  If a sender receives a WINDOW_UPDATE that causes a flow-
@@ -576,29 +627,19 @@ rcv_window_update_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
     cstate.restart_streams();
   } else {
     // Stream level window update
-    Http2Stream *stream = cstate.find_stream(sid);
+    Http2Stream *stream = cstate.find_stream(stream_id);
 
     if (stream == NULL) {
-      if (sid <= cstate.get_latest_stream_id()) {
+      if (stream_id <= cstate.get_latest_stream_id()) {
         return Http2Error(HTTP2_ERROR_CLASS_NONE);
       } else {
         return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, HTTP2_ERROR_PROTOCOL_ERROR);
       }
     }
 
-    frame.reader()->memcpy(buf, sizeof(buf), 0);
-    http2_parse_window_update(make_iovec(buf, sizeof(buf)), size);
-
-    DebugHttp2Stream(cstate.ua_session, sid, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
+    DebugHttp2Stream(cstate.ua_session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
                      (stream->client_rwnd + size), size);
 
-    // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an
-    // flow control window increment of 0 as a stream error of type
-    // PROTOCOL_ERROR;
-    if (size == 0) {
-      return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
-    }
-
     // A sender MUST NOT allow a flow-control window to exceed 2^31-1
     // octets.  If a sender receives a WINDOW_UPDATE that causes a flow-
     // control window to exceed this maximum, it MUST terminate either the
@@ -612,8 +653,9 @@ rcv_window_update_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
 
     stream->client_rwnd += size;
     ssize_t wnd = min(cstate.client_rwnd, stream->client_rwnd);
+
     if (stream->get_state() == HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE && wnd > 0) {
-      cstate.send_data_frame(stream);
+      stream->send_response_body();
     }
   }
 
@@ -756,6 +798,14 @@ Http2ConnectionState::main_event_handler(int event, void *edata)
     return 0;
   }
 
+  case HTTP2_SESSION_EVENT_XMIT: {
+    SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+    send_data_frames_depends_on_priority();
+    _scheduled = false;
+
+    return 0;
+  }
+
   // Parse received HTTP/2 frames
   case HTTP2_SESSION_EVENT_RECV: {
     const Http2Frame *frame = (Http2Frame *)edata;
@@ -796,6 +846,7 @@ Http2ConnectionState::main_event_handler(int event, void *edata)
 
     return 0;
   }
+
   default:
     DebugHttp2Con(ua_session, "unexpected event=%d edata=%p", event, edata);
     ink_release_assert(0);
@@ -855,13 +906,12 @@ Http2ConnectionState::find_stream(Http2StreamId id) const
 void
 Http2ConnectionState::restart_streams()
 {
-  // Currently lookup retryable streams sequentially.
-  // TODO considering to stream weight and dependencies.
   Http2Stream *s = stream_list.head;
+
   while (s) {
     Http2Stream *next = s->link.next;
     if (s->get_state() == HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE && min(this->client_rwnd, s->client_rwnd) > 0) {
-      this->send_data_frame(s);
+      s->send_response_body();
     }
     s = next;
   }
@@ -876,6 +926,7 @@ Http2ConnectionState::cleanup_streams()
     this->delete_stream(s);
     s = next;
   }
+
   client_streams_count = 0;
   if (!is_state_closed()) {
     ua_session->get_netvc()->add_to_keep_alive_queue();
@@ -885,6 +936,13 @@ Http2ConnectionState::cleanup_streams()
 void
 Http2ConnectionState::delete_stream(Http2Stream *stream)
 {
+  if (Http2::stream_priority_enabled) {
+    DependencyTree::Node *node = stream->priority_node;
+    if (node != NULL && node->active) {
+      dependency_tree->deactivate(node, 0);
+    }
+  }
+
   stream_list.remove(stream);
   stream->initiating_close();
 
@@ -906,74 +964,139 @@ Http2ConnectionState::update_initial_rwnd(Http2WindowSize new_size)
 }
 
 void
-Http2ConnectionState::send_data_frame(Http2Stream *stream)
+Http2ConnectionState::schedule_stream(Http2Stream *stream)
 {
-  size_t buf_len = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_DATA]) - HTTP2_FRAME_HEADER_LEN;
-  uint8_t payload_buffer[buf_len];
+  DebugHttp2Stream(ua_session, stream->get_id(), "Scheduled");
 
-  if (stream->get_state() == HTTP2_STREAM_STATE_CLOSED) {
+  DependencyTree::Node *node = stream->priority_node;
+  ink_release_assert(node != NULL);
+
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+  dependency_tree->activate(node);
+
+  if (!_scheduled) {
+    _scheduled = true;
+
+    SET_HANDLER(&Http2ConnectionState::main_event_handler);
+    this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_XMIT);
+  }
+}
+
+void
+Http2ConnectionState::send_data_frames_depends_on_priority()
+{
+  DependencyTree::Node *node = dependency_tree->top();
+
+  // No node to send or no connection level window left
+  if (node == NULL || client_rwnd <= 0) {
     return;
   }
 
-  for (;;) {
-    uint8_t flags = 0x00;
+  Http2Stream *stream = node->t;
+  ink_release_assert(stream != NULL);
+  DebugHttp2Stream(ua_session, stream->get_id(), "top node, point=%d", node->point);
 
-    size_t window_size = min(this->client_rwnd, stream->client_rwnd);
-    size_t send_size = min(buf_len, window_size);
-    size_t payload_length;
-    IOBufferReader *current_reader = stream->response_get_data_reader();
+  size_t len = 0;
+  Http2SendADataFrameResult result = send_a_data_frame(stream, len);
 
-    // Are we at the end?
-    // If we break here, we never send the END_STREAM in the case of a
-    // early terminating OS.  Ok if there is no body yet.  Otherwise
-    // continue on to delete the stream
-    if (stream->is_body_done() && current_reader && !current_reader->is_read_avail_more_than(0)) {
-      Debug("http2_con", "End of Stream id=%d no more data and body done", stream->get_id());
-      flags |= HTTP2_FLAGS_DATA_END_STREAM;
-      payload_length = 0;
-    } else {
-      // Select appropriate payload size
-      if (this->client_rwnd <= 0 || stream->client_rwnd <= 0)
-        break;
-      // Copy into the payload buffer.  Seems like we should be able to skip this
-      // copy step
-      payload_length = current_reader ? current_reader->read(payload_buffer, send_size) : 0;
-
-      if (payload_length == 0 && !stream->is_body_done()) {
-        break;
-      }
+  if (result != HTTP2_SEND_A_DATA_FRAME_NO_ERROR) {
+    // When no stream level window left, deactivate node once and wait window_update frame
+    dependency_tree->deactivate(node, len);
+    this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_XMIT);
+    return;
+  }
 
-      // Update window size
-      this->client_rwnd -= payload_length;
-      stream->client_rwnd -= payload_length;
+  // No response body to send
+  if (len == 0 && !stream->is_body_done()) {
+    dependency_tree->deactivate(node, len);
+    this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_XMIT);
+    return;
+  }
 
-      if (stream->is_body_done() && payload_length < send_size) {
-        flags |= HTTP2_FLAGS_DATA_END_STREAM;
-      }
-    }
+  if (stream->get_state() == HTTP2_STREAM_STATE_CLOSED) {
+    dependency_tree->deactivate(node, len);
+    delete_stream(stream);
+  } else {
+    dependency_tree->update(node, len);
+  }
 
-    // Create frame
-    DebugHttp2Stream(ua_session, stream->get_id(), "Send DATA frame - client window con: %zd stream: %zd payload: %zd", client_rwnd,
-                     stream->client_rwnd, payload_length);
-    Http2Frame data(HTTP2_FRAME_TYPE_DATA, stream->get_id(), flags);
-    data.alloc(buffer_size_index[HTTP2_FRAME_TYPE_DATA]);
-    http2_write_data(payload_buffer, payload_length, data.write());
-    data.finalize(payload_length);
-
-    stream->update_sent_count(payload_length);
-
-    // Change state to 'closed' if its end of DATAs.
-    if (flags & HTTP2_FLAGS_DATA_END_STREAM) {
-      DebugHttp2Stream(ua_session, stream->get_id(), "End of DATA frame");
-      // Setting to the same state shouldn't be erroneous
-      stream->change_state(data.header().type, data.header().flags);
-    }
+  this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_XMIT);
+}
 
-    // xmit event
-    SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
-    this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &data);
+Http2SendADataFrameResult
+Http2ConnectionState::send_a_data_frame(Http2Stream *stream, size_t &payload_length)
+{
+  const ssize_t window_size = min(this->client_rwnd, stream->client_rwnd);
+  if (window_size <= 0) {
+    return HTTP2_SEND_A_DATA_FRAME_NO_WINDOW;
+  }
+  const size_t buf_len = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_DATA]) - HTTP2_FRAME_HEADER_LEN;
+  const size_t available_size = min(buf_len, static_cast<size_t>(window_size));
+
+  uint8_t flags = 0x00;
+  uint8_t payload_buffer[buf_len];
+  IOBufferReader *current_reader = stream->response_get_data_reader();
+
+  SCOPED_MUTEX_LOCK(stream_lock, stream->mutex, this_ethread());
+
+  // Select appropriate payload length
+  if (current_reader && current_reader->is_read_avail_more_than(0)) {
+    // Copy into the payload buffer. Seems like we should be able to skip this copy step
+    payload_length = current_reader->read(payload_buffer, available_size);
+  } else {
+    payload_length = 0;
+  }
+
+  // Are we at the end?
+  // If we return here, we never send the END_STREAM in the case of a early terminating OS.
+  // OK if there is no body yet. Otherwise continue on to send a DATA frame and delete the stream
+  if (!stream->is_body_done() && payload_length == 0) {
+    return HTTP2_SEND_A_DATA_FRAME_NO_PAYLOAD;
+  }
+
+  if (stream->is_body_done() && payload_length < available_size) {
+    flags |= HTTP2_FLAGS_DATA_END_STREAM;
+  }
+
+  // Update window size
+  this->client_rwnd -= payload_length;
+  stream->client_rwnd -= payload_length;
+
+  // Create frame
+  DebugHttp2Stream(ua_session, stream->get_id(), "Send a DATA frame - client window con: %zd stream: %zd payload: %zd", client_rwnd,
+                   stream->client_rwnd, payload_length);
+
+  Http2Frame data(HTTP2_FRAME_TYPE_DATA, stream->get_id(), flags);
+  data.alloc(buffer_size_index[HTTP2_FRAME_TYPE_DATA]);
+  http2_write_data(payload_buffer, payload_length, data.write());
+  data.finalize(payload_length);
+
+  stream->update_sent_count(payload_length);
+
+  // Change state to 'closed' if its end of DATAs.
+  if (flags & HTTP2_FLAGS_DATA_END_STREAM) {
+    DebugHttp2Stream(ua_session, stream->get_id(), "End of DATA frame");
+    // Setting to the same state shouldn't be erroneous
+    stream->change_state(data.header().type, data.header().flags);
+  }
+
+  // xmit event
+  SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
+  this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &data);
+
+  return HTTP2_SEND_A_DATA_FRAME_NO_ERROR;
+}
+
+void
+Http2ConnectionState::send_data_frames(Http2Stream *stream)
+{
+  if (stream->get_state() == HTTP2_STREAM_STATE_CLOSED) {
+    return;
+  }
 
-    if (flags & HTTP2_FLAGS_DATA_END_STREAM) {
+  size_t len = 0;
+  while (send_a_data_frame(stream, len) == HTTP2_SEND_A_DATA_FRAME_NO_ERROR) {
+    if (stream->get_state() == HTTP2_STREAM_STATE_CLOSED) {
       // Delete a stream immediately
       // TODO its should not be deleted for a several time to handling
       // RST_STREAM and WINDOW_UPDATE.
diff --git a/proxy/http2/Http2ConnectionState.h b/proxy/http2/Http2ConnectionState.h
index c4dc5d5..584f0f8 100644
--- a/proxy/http2/Http2ConnectionState.h
+++ b/proxy/http2/Http2ConnectionState.h
@@ -27,9 +27,16 @@
 #include "HTTP2.h"
 #include "HPACK.h"
 #include "Http2Stream.h"
+#include "Http2DependencyTree.h"
 
 class Http2ClientSession;
 
+enum Http2SendADataFrameResult {
+  HTTP2_SEND_A_DATA_FRAME_NO_ERROR = 0,
+  HTTP2_SEND_A_DATA_FRAME_NO_WINDOW = 1,
+  HTTP2_SEND_A_DATA_FRAME_NO_PAYLOAD = 2,
+};
+
 class Http2ConnectionSettings
 {
 public:
@@ -106,12 +113,14 @@ public:
   Http2ConnectionState()
     : Continuation(NULL),
       ua_session(NULL),
+      dependency_tree(NULL),
       client_rwnd(HTTP2_INITIAL_WINDOW_SIZE),
       server_rwnd(Http2::initial_window_size),
       stream_list(),
       latest_streamid(0),
       client_streams_count(0),
-      continued_stream_id(0)
+      continued_stream_id(0),
+      _scheduled(false)
   {
     SET_HANDLER(&Http2ConnectionState::main_event_handler);
   }
@@ -119,6 +128,7 @@ public:
   Http2ClientSession *ua_session;
   HpackHandle *local_hpack_handle;
   HpackHandle *remote_hpack_handle;
+  DependencyTree *dependency_tree;
 
   // Settings.
   Http2ConnectionSettings server_settings;
@@ -132,6 +142,8 @@ public:
 
     continued_buffer.iov_base = NULL;
     continued_buffer.iov_len = 0;
+
+    dependency_tree = new DependencyTree();
   }
 
   void
@@ -144,6 +156,8 @@ public:
     delete remote_hpack_handle;
 
     ats_free(continued_buffer.iov_base);
+
+    delete dependency_tree;
   }
 
   // Event handlers
@@ -186,7 +200,10 @@ public:
   ssize_t client_rwnd, server_rwnd;
 
   // HTTP/2 frame sender
-  void send_data_frame(Http2Stream *stream);
+  void schedule_stream(Http2Stream *stream);
+  void send_data_frames_depends_on_priority();
+  void send_data_frames(Http2Stream *stream);
+  Http2SendADataFrameResult send_a_data_frame(Http2Stream *stream, size_t &payload_length);
   void send_headers_frame(Http2Stream *stream);
   void send_rst_stream_frame(Http2StreamId id, Http2ErrorCode ec);
   void send_settings_frame(const Http2ConnectionSettings &new_settings);
@@ -227,6 +244,7 @@ private:
   //     another CONTINUATION frame."
   Http2StreamId continued_stream_id;
   IOVec continued_buffer;
+  bool _scheduled;
 };
 
 #endif // __HTTP2_CONNECTION_STATE_H__
diff --git a/proxy/http2/Http2DependencyTree.h b/proxy/http2/Http2DependencyTree.h
new file mode 100644
index 0000000..8ea3bc2
--- /dev/null
+++ b/proxy/http2/Http2DependencyTree.h
@@ -0,0 +1,308 @@
+/** @file
+
+  HTTP/2 Dependency Tree
+
+  The original idea of Stream Priority Algorithm using Weighted Fair Queue (WFQ)
+  Scheduling is invented by Kazuho Oku (H2O project).
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#ifndef __HTTP2_DEP_TREE_H__
+#define __HTTP2_DEP_TREE_H__
+
+#include "ts/List.h"
+#include "ts/Diags.h"
+#include "ts/PriorityQueue.h"
+
+#include "HTTP2.h"
+
+// TODO: K is a constant, 256 is temporal value.
+const static int K = 256;
+
+template <typename T> class Http2DependencyTree
+{
+public:
+  class Node
+  {
+  public:
+    Node()
+      : active(false),
+        queued(false),
+        id(HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY),
+        weight(HTTP2_PRIORITY_DEFAULT_WEIGHT),
+        point(0),
+        parent(NULL),
+        t(NULL)
+    {
+      entry = new PriorityQueueEntry<Node *>(this);
+      queue = new PriorityQueue<Node *>();
+    }
+    Node(uint32_t i, uint32_t w, uint32_t p, Node *n, T t)
+      : active(false), queued(false), id(i), weight(w), point(p), parent(n), t(t)
+    {
+      entry = new PriorityQueueEntry<Node *>(this);
+      queue = new PriorityQueue<Node *>();
+    }
+
+    ~Node()
+    {
+      delete entry;
+      delete queue;
+
+      // delete all child nodes
+      if (!children.empty()) {
+        Node *node = children.head;
+        Node *next = NULL;
+        while (node) {
+          next = node->link.next;
+          children.remove(node);
+          delete node;
+          node = next;
+        }
+      }
+    }
+
+    LINK(Node, link);
+
+    bool
+    operator<(const Node &n) const
+    {
+      return point < n.point;
+    }
+    bool
+    operator>(const Node &n) const
+    {
+      return point > n.point;
+    }
+
+    bool active;
+    bool queued;
+    uint32_t id;
+    uint32_t weight;
+    uint32_t point;
+    Node *parent;
+    DLL<Node> children;
+    PriorityQueueEntry<Node *> *entry;
+    PriorityQueue<Node *> *queue;
+    T t;
+  };
+
+  Http2DependencyTree() { _root = new Node(); }
+  ~Http2DependencyTree() { delete _root; }
+  Node *find(uint32_t id);
+  Node *add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T t);
+  void reprioritize(uint32_t new_parent_id, uint32_t id, bool exclusive);
+  void reprioritize(Node *node, uint32_t id, bool exclusive);
+  Node *top();
+  void activate(Node *node);
+  void deactivate(Node *node, uint32_t sent);
+  void update(Node *node, uint32_t sent);
+
+private:
+  Node *_find(Node *node, uint32_t id);
+  Node *_top(Node *node);
+  void _change_parent(Node *new_parent, Node *node, bool exclusive);
+
+  Node *_root;
+};
+
+template <typename T>
+typename Http2DependencyTree<T>::Node *
+Http2DependencyTree<T>::_find(Node *node, uint32_t id)
+{
+  if (node->id == id) {
+    return node;
+  }
+
+  if (node->children.empty()) {
+    return NULL;
+  }
+
+  Node *result = NULL;
+  for (Node *n = node->children.head; n; n = n->link.next) {
+    result = _find(n, id);
+    if (result != NULL) {
+      break;
+    }
+  }
+
+  return result;
+}
+
+template <typename T>
+typename Http2DependencyTree<T>::Node *
+Http2DependencyTree<T>::find(uint32_t id)
+{
+  return _find(_root, id);
+}
+
+template <typename T>
+typename Http2DependencyTree<T>::Node *
+Http2DependencyTree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T t)
+{
+  Node *parent = find(parent_id);
+  if (parent == NULL) {
+    parent = _root;
+  }
+
+  // Use stream id as initial point
+  Node *node = new Node(id, weight, id, parent, t);
+
+  if (exclusive) {
+    while (Node *child = parent->children.pop()) {
+      node->children.push(child);
+      child->parent = node;
+    }
+  }
+
+  parent->children.push(node);
+
+  return node;
+}
+
+template <typename T>
+void
+Http2DependencyTree<T>::reprioritize(uint32_t id, uint32_t new_parent_id, bool exclusive)
+{
+  Node *node = find(id);
+  if (node == NULL) {
+    return;
+  }
+
+  reprioritize(node, new_parent_id, exclusive);
+}
+
+template <typename T>
+void
+Http2DependencyTree<T>::reprioritize(Node *node, uint32_t new_parent_id, bool exclusive)
+{
+  if (node == NULL) {
+    return;
+  }
+
+  Node *old_parent = node->parent;
+  if (old_parent->id == new_parent_id) {
+    // Do nothing
+    return;
+  }
+
+  Node *new_parent = find(new_parent_id);
+  if (new_parent == NULL) {
+    return;
+  }
+  _change_parent(new_parent, old_parent, false);
+  _change_parent(node, new_parent, exclusive);
+}
+
+// Change node's parent to new_parent
+template <typename T>
+void
+Http2DependencyTree<T>::_change_parent(Node *node, Node *new_parent, bool exclusive)
+{
+  node->parent->children.remove(node);
+  node->parent = NULL;
+
+  if (exclusive) {
+    while (Node *child = new_parent->children.pop()) {
+      node->children.push(child);
+      child->parent = node;
+    }
+  }
+
+  new_parent->children.push(node);
+  node->parent = new_parent;
+}
+
+template <typename T>
+typename Http2DependencyTree<T>::Node *
+Http2DependencyTree<T>::_top(Node *node)
+{
+  Node *child = node;
+
+  while (child != NULL) {
+    if (child->active) {
+      return child;
+    } else if (!child->queue->empty()) {
+      child = child->queue->top()->node;
+    } else {
+      return NULL;
+    }
+  }
+
+  return child;
+}
+
+template <typename T>
+typename Http2DependencyTree<T>::Node *
+Http2DependencyTree<T>::top()
+{
+  return _top(_root);
+}
+
+template <typename T>
+void
+Http2DependencyTree<T>::activate(Node *node)
+{
+  node->active = true;
+
+  while (node->parent != NULL && !node->queued) {
+    node->parent->queue->push(node->entry);
+    node->queued = true;
+    node = node->parent;
+  }
+}
+
+template <typename T>
+void
+Http2DependencyTree<T>::deactivate(Node *node, uint32_t sent)
+{
+  node->active = false;
+
+  while (node->queue->empty() && node->parent != NULL) {
+    ink_assert(node->parent->queue->top() == node->entry);
+
+    node->parent->queue->pop();
+    node->queued = false;
+
+    node = node->parent;
+  }
+
+  update(node, sent);
+}
+
+template <typename T>
+void
+Http2DependencyTree<T>::update(Node *node, uint32_t sent)
+{
+  while (node->parent != NULL) {
+    node->point += sent * K / (node->weight + 1);
+
+    if (node->queued) {
+      node->parent->queue->update(node->entry, true);
+    } else {
+      node->parent->queue->push(node->entry);
+      node->queued = true;
+    }
+
+    node = node->parent;
+  }
+}
+
+#endif // __HTTP2_DEP_TREE_H__
diff --git a/proxy/http2/Http2Stream.cc b/proxy/http2/Http2Stream.cc
index df35f1e..e54ed85 100644
--- a/proxy/http2/Http2Stream.cc
+++ b/proxy/http2/Http2Stream.cc
@@ -255,7 +255,7 @@ Http2Stream::do_io_close(int /* flags */)
 
     if (parent) {
       // Make sure any trailing end of stream frames are sent
-      static_cast<Http2ClientSession *>(parent)->connection_state.send_data_frame(this);
+      static_cast<Http2ClientSession *>(parent)->connection_state.send_data_frames(this);
 
       // Remove ourselves from the stream list
       static_cast<Http2ClientSession *>(parent)->connection_state.delete_stream(this);
@@ -444,7 +444,7 @@ Http2Stream::update_write_request(IOBufferReader *buf_reader, int64_t write_len,
             retval = false;
           }
           // Send the data frame
-          parent->connection_state.send_data_frame(this);
+          send_response_body();
         }
         break;
       }
@@ -459,11 +459,11 @@ Http2Stream::update_write_request(IOBufferReader *buf_reader, int64_t write_len,
         // Defer sending the write complete until the send_data_frame has sent it all
         // this_ethread()->schedule_imm(this, send_event, &write_vio);
         this->mark_body_done();
-        parent->connection_state.send_data_frame(this);
+        send_response_body();
         retval = false;
       } else {
         this_ethread()->schedule_imm(this, VC_EVENT_WRITE_READY, &write_vio);
-        parent->connection_state.send_data_frame(this);
+        send_response_body();
         // write_vio._cont->handleEvent(send_event, &write_vio);
       }
     }
@@ -474,6 +474,19 @@ Http2Stream::update_write_request(IOBufferReader *buf_reader, int64_t write_len,
 }
 
 void
+Http2Stream::send_response_body()
+{
+  Http2ClientSession *parent = static_cast<Http2ClientSession *>(this->get_parent());
+
+  if (Http2::stream_priority_enabled) {
+    parent->connection_state.schedule_stream(this);
+  } else {
+    // Send DATA frames directly
+    parent->connection_state.send_data_frames(this);
+  }
+}
+
+void
 Http2Stream::reenable(VIO *vio)
 {
   if (this->parent) {
diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h
index 5ef7818..51606f0 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -28,9 +28,13 @@
 #include "../ProxyClientTransaction.h"
 #include "Http2DebugNames.h"
 #include "../http/HttpTunnel.h" // To get ChunkedHandler
+#include "Http2DependencyTree.h"
 
+class Http2Stream;
 class Http2ConnectionState;
 
+typedef Http2DependencyTree<Http2Stream *> DependencyTree;
+
 class Http2Stream : public ProxyClientTransaction
 {
 public:
@@ -45,6 +49,7 @@ public:
       response_reader(NULL),
       request_reader(NULL),
       request_buffer(CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX),
+      priority_node(NULL),
       _id(sid),
       _state(HTTP2_STREAM_STATE_IDLE),
       trailing_header(false),
@@ -156,6 +161,7 @@ public:
   void update_read_request(int64_t read_len, bool send_update);
   bool update_write_request(IOBufferReader *buf_reader, int64_t write_len, bool send_update);
   void reenable(VIO *vio);
+  void send_response_body();
 
   // Stream level window size
   ssize_t client_rwnd, server_rwnd;
@@ -177,6 +183,7 @@ public:
   IOBufferReader *response_reader;
   IOBufferReader *request_reader;
   MIOBuffer request_buffer;
+  DependencyTree::Node *priority_node;
 
   EThread *
   get_thread()
diff --git a/proxy/http2/Makefile.am b/proxy/http2/Makefile.am
index 5912847..ad34798 100644
--- a/proxy/http2/Makefile.am
+++ b/proxy/http2/Makefile.am
@@ -42,6 +42,7 @@ libhttp2_a_SOURCES = \
   Http2ConnectionState.h \
   Http2DebugNames.cc \
   Http2DebugNames.h \
+  Http2DependencyTree.h \
   Http2Stream.cc \
   Http2Stream.h \
   Http2SessionAccept.cc \
@@ -55,9 +56,12 @@ if BUILD_TESTS
 endif
 
 noinst_PROGRAMS = \
-  test_Huffmancode
+  test_Huffmancode \
+  test_Http2DependencyTree
 
-TESTS = test_Huffmancode
+TESTS = \
+  test_Huffmancode \
+  test_Http2DependencyTree
 
 test_Huffmancode_LDADD = \
   $(top_builddir)/lib/ts/libtsutil.la
@@ -66,3 +70,10 @@ test_Huffmancode_SOURCES = \
   test_Huffmancode.cc \
   HuffmanCodec.cc \
   HuffmanCodec.h
+
+test_Http2DependencyTree_LDADD = \
+  $(top_builddir)/lib/ts/libtsutil.la
+
+test_Http2DependencyTree_SOURCES = \
+  test_Http2DependencyTree.cc \
+  Http2DependencyTree.h
diff --git a/proxy/http2/test_Http2DependencyTree.cc b/proxy/http2/test_Http2DependencyTree.cc
new file mode 100644
index 0000000..c94c373
--- /dev/null
+++ b/proxy/http2/test_Http2DependencyTree.cc
@@ -0,0 +1,327 @@
+/** @file
+
+    Unit tests for Http2DependencyTree
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+#include <iostream>
+#include <string.h>
+#include <sstream>
+
+#include "ts/TestBox.h"
+
+#include "Http2DependencyTree.h"
+
+using namespace std;
+
+typedef Http2DependencyTree<string *> Tree;
+
+/**
+ * Exclusive Dependency Creation
+ *
+ *       A            A
+ *      / \    =>     |
+ *     B   C          D
+ *                   / \
+ *                  B   C
+ */
+REGRESSION_TEST(Http2DependencyTree_1)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+  string a("A"), b("B"), c("C"), d("D");
+
+  tree->add(0, 1, 0, false, &b);
+  tree->add(0, 3, 0, false, &c);
+
+  Tree::Node *node_a = tree->find(0);
+  Tree::Node *node_b = tree->find(1);
+  Tree::Node *node_c = tree->find(3);
+
+  box.check(node_b->parent == node_a, "parent of B should be A");
+  box.check(node_c->parent == node_a, "parent of C should be A");
+
+  // Add node with exclusive flag
+  tree->add(0, 5, 0, true, &d);
+
+  Tree::Node *node_d = tree->find(5);
+
+  box.check(node_d->parent == node_a, "parent of D should be A");
+  box.check(node_b->parent == node_d, "parent of B should be D");
+  box.check(node_c->parent == node_d, "parent of C should be D");
+
+  delete tree;
+}
+
+/**
+ * Reprioritization (non-exclusive)
+ *
+ *    x                x
+ *    |                |
+ *    A                D
+ *   / \              / \
+ *  B   C     ==>    F   A
+ *     / \              / \
+ *    D   E            B   C
+ *    |                    |
+ *    F                    E
+ */
+REGRESSION_TEST(Http2DependencyTree_2)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+  string a("A"), b("B"), c("C"), d("D"), e("E"), f("F");
+
+  tree->add(0, 1, 0, false, &a);
+  tree->add(1, 3, 0, false, &b);
+  tree->add(1, 5, 0, false, &c);
+  tree->add(5, 7, 0, false, &d);
+  tree->add(5, 9, 0, false, &e);
+  tree->add(7, 11, 0, false, &f);
+
+  tree->reprioritize(1, 7, false);
+
+  Tree::Node *node_x = tree->find(0);
+  Tree::Node *node_a = tree->find(1);
+  Tree::Node *node_d = tree->find(7);
+  Tree::Node *node_f = tree->find(11);
+
+  box.check(node_a->parent == node_d, "parent of A should be D");
+  box.check(node_d->parent == node_x, "parent of D should be X");
+  box.check(node_f->parent == node_d, "parent of F should be D");
+
+  delete tree;
+}
+
+/**
+ * Reprioritization (exclusive)
+ *
+ *    x              x
+ *    |              |
+ *    A              D
+ *   / \             |
+ *  B   C     ==>    A
+ *     / \          /|\
+ *    D   E        B C F
+ *    |              |
+ *    F              E
+ */
+REGRESSION_TEST(Http2DependencyTree_3)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+  string a("A"), b("B"), c("C"), d("D"), e("E"), f("F");
+
+  tree->add(0, 1, 0, false, &a);
+  tree->add(1, 3, 0, false, &b);
+  tree->add(1, 5, 0, false, &c);
+  tree->add(5, 7, 0, false, &d);
+  tree->add(5, 9, 0, false, &e);
+  tree->add(7, 11, 0, false, &f);
+
+  tree->reprioritize(1, 7, true);
+
+  Tree::Node *node_x = tree->find(0);
+  Tree::Node *node_a = tree->find(1);
+  Tree::Node *node_d = tree->find(7);
+  Tree::Node *node_f = tree->find(11);
+
+  box.check(node_a->parent == node_d, "parent of A should be D");
+  box.check(node_d->parent == node_x, "parent of D should be X");
+  box.check(node_f->parent == node_a, "parent of F should be A");
+
+  delete tree;
+}
+
+/**
+ * Only One Node Tree
+ *      ROOT
+ *      /
+ *    A(1)
+ */
+REGRESSION_TEST(Http2DependencyTree_4)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+  string a("A");
+  tree->add(0, 1, 0, false, &a);
+
+  Tree::Node *node_a = tree->find(1);
+
+  box.check(tree->top() == NULL, "top should be NULL");
+
+  tree->activate(node_a);
+  box.check(tree->top() == node_a, "top should be A");
+
+  tree->deactivate(node_a, 0);
+  box.check(tree->top() == NULL, "top should be NULL");
+
+  delete tree;
+}
+
+/**
+ * Simple Tree
+ *      ROOT
+ *      /
+ *    A(3)
+ *   /
+ * B(5)
+ *
+ */
+REGRESSION_TEST(Http2DependencyTree_5)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+  string a("A"), b("B"), c("C");
+
+  tree->add(0, 3, 15, false, &a);
+  tree->add(3, 5, 15, false, &b);
+
+  Tree::Node *node_a = tree->find(3);
+  Tree::Node *node_b = tree->find(5);
+
+  box.check(tree->top() == NULL, "top should be NULL");
+
+  tree->activate(node_a);
+  tree->activate(node_b);
+  box.check(tree->top() == node_a, "top should be A");
+
+  tree->deactivate(node_a, 0);
+  box.check(tree->top() == node_b, "top should be B");
+
+  delete tree;
+}
+
+/**
+ * Basic Tree
+ *      ROOT
+ *      /  \
+ *    A(3)  D(9)
+ *   /  \
+ * B(5) C(7)
+ *
+ */
+REGRESSION_TEST(Http2DependencyTree_6)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+
+  string a("A"), b("B"), c("C"), d("D");
+
+  // NOTE, weight is actual weight - 1
+  tree->add(0, 3, 20, false, &a); // node_a is unused
+  Tree::Node *node_b = tree->add(3, 5, 10, false, &b);
+  Tree::Node *node_c = tree->add(3, 7, 10, false, &c);
+  Tree::Node *node_d = tree->add(0, 9, 20, false, &d);
+
+  // Activate B, C and D
+  tree->activate(node_b);
+  tree->activate(node_c);
+  tree->activate(node_d);
+
+  ostringstream oss;
+
+  for (int i = 0; i < 90; ++i) {
+    Tree::Node *node = tree->top();
+    oss << node->t->c_str();
+    tree->update(node, 100);
+  }
+
+  const string expect = "BDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBDCDBD";
+  box.check(oss.str() == expect, "\nExpect : %s\nActual : %s", expect.c_str(), oss.str().c_str());
+
+  delete tree;
+}
+
+/**
+ * Tree of Chrome 50
+ *
+ *       ROOT
+ *     /   |       \
+ *   A(3) B(5) ... I(19)
+ *
+ */
+REGRESSION_TEST(Http2DependencyTree_7)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  Tree *tree = new Tree();
+
+  string a("A"), b("B"), c("C"), d("D"), e("E"), f("F"), g("G"), h("H"), i("I");
+
+  Tree::Node *node_a = tree->add(0, 3, 255, false, &a);
+  Tree::Node *node_b = tree->add(0, 5, 255, false, &b);
+  Tree::Node *node_c = tree->add(0, 7, 255, false, &c);
+  Tree::Node *node_d = tree->add(0, 9, 182, false, &d);
+  Tree::Node *node_e = tree->add(0, 11, 182, false, &e);
+  Tree::Node *node_f = tree->add(0, 13, 182, false, &f);
+  Tree::Node *node_g = tree->add(0, 15, 146, false, &g);
+  Tree::Node *node_h = tree->add(0, 17, 146, false, &h);
+  Tree::Node *node_i = tree->add(0, 19, 146, false, &i);
+
+  // Activate A and B
+  tree->activate(node_a);
+  tree->activate(node_b);
+  tree->activate(node_c);
+  tree->activate(node_d);
+  tree->activate(node_e);
+  tree->activate(node_f);
+  tree->activate(node_g);
+  tree->activate(node_h);
+  tree->activate(node_i);
+
+  ostringstream oss;
+
+  for (int i = 0; i < 108; ++i) {
+    Tree::Node *node = tree->top();
+    oss << node->t->c_str();
+
+    tree->update(node, 16375);
+  }
+
+  const string expect =
+    "ABCDEFGHIABCDEFGHIABCDEFABCGHIABCDEFABCGHIDEFABCGHIDEFABCABCDEFGHIABCDEFABCGHIABCDEFABCGHIDEFABCGHIDEFABCABC";
+
+  box.check(oss.str() == expect, "\nExpect : %s\nActual : %s", expect.c_str(), oss.str().c_str());
+
+  delete tree;
+}
+
+int
+main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
+{
+  const char *name = "Http2DependencyTree";
+  RegressionTest::run(name);
+
+  return RegressionTest::final_status == REGRESSION_TEST_PASSED ? 0 : 1;
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 11/15: Remove double call to NetVConnection->do_io_read.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 3a8a3c2c5340b8b403c07a258e202f6fc03769c0
Author: David Calavera <da...@gmail.com>
AuthorDate: Fri May 13 14:12:22 2016 -0700

    Remove double call to NetVConnection->do_io_read.
    
    Signed-off-by: David Calavera <da...@gmail.com>
    (cherry picked from commit 58d4a14046d992487c5873a679125f8257f0ed79)
---
 proxy/http/HttpSM.cc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index e9eb3cb..97c4568 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -630,9 +630,9 @@ HttpSM::state_read_client_request_header(int event, void *data)
     return 0;
 
   // check to see if there was an EOS received on the SSL connection
-  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(ua_session->get_netvc());
+  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(netvc);
   if (ssl_vc && ssl_vc->isEosRcvd()) {
-    DebugSM("http", "EOS for ssl vc %p at read_first_btye state", ua_session->get_netvc());
+    DebugSM("http", "EOS for ssl vc %p at read_first_btye state", netvc);
     event = VC_EVENT_EOS;
   }
   switch (event) {
@@ -705,8 +705,8 @@ HttpSM::state_read_client_request_header(int event, void *data)
 
       // Turn off read eventing until we get the
       // blind tunnel infrastructure set up
-      ua_session->get_netvc()->do_io_read(this, 0, NULL);
-      netvc->do_io_read(this, 0, NULL);
+      if (netvc)
+        netvc->do_io_read(this, 0, NULL);
 
       /* establish blind tunnel */
       setup_blind_tunnel_port();

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 12/15: TS-3485: Remove Warning message about ip-allow enforcement not being present for HTTP2.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit c5cfb5bbc670c3c877d941932b737a78753a11fb
Author: shinrich <sh...@ieee.org>
AuthorDate: Tue May 3 18:02:00 2016 -0500

    TS-3485: Remove Warning message about ip-allow enforcement not being present for HTTP2.
    
    (cherry picked from commit 2dd1c4f02414f7639e6cddc580d26f1bc5f1502c)
---
 lib/records/RecHttp.cc            | 2 --
 proxy/http2/Http2SessionAccept.cc | 4 ----
 2 files changed, 6 deletions(-)

diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc
index dd91105..8620044 100644
--- a/lib/records/RecHttp.cc
+++ b/lib/records/RecHttp.cc
@@ -621,8 +621,6 @@ ts_session_protocol_well_known_name_indices_init()
   REC_ReadConfigInteger(http2_enabled, "proxy.config.http2.enabled");
   if (!http2_enabled) {
     DEFAULT_TLS_SESSION_PROTOCOL_SET.markOut(HTTP2_PROTOCOL_SET);
-  } else {
-    Warning("Be aware that access control checks for HTTP/2 connections are not active!");
   }
 
   DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET;
diff --git a/proxy/http2/Http2SessionAccept.cc b/proxy/http2/Http2SessionAccept.cc
index c32c9d9..7aeefc7 100644
--- a/proxy/http2/Http2SessionAccept.cc
+++ b/proxy/http2/Http2SessionAccept.cc
@@ -38,10 +38,6 @@ Http2SessionAccept::~Http2SessionAccept()
 void
 Http2SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader)
 {
-  // XXX we need to refactor the ACL checks from HttpSessionAccept so that we can invoke them here, and also in
-  // the SPDY protocol layer ...
-  // Warning("skipping access control checks for HTTP/2 connection");
-
   netvc->attributes = this->options.transport_type;
 
   const sockaddr *client_ip = netvc->get_remote_addr();

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 10/15: TS-4410 : Fixed compiler warning on i386 builds

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 8e2e4e3fe52c9b37c91a60be7d3ff05f2c7d380d
Author: Peter Chou <pb...@labs.att.com>
AuthorDate: Mon May 2 11:44:24 2016 -0700

    TS-4410 : Fixed compiler warning on i386 builds
    
    This is for unsigned-vs-signed int comparison.
    
    This closes #611
    
    (cherry picked from commit fc2a6feff5f866740f9297467c2850120b793b9a)
---
 iocore/hostdb/I_HostDBProcessor.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/iocore/hostdb/I_HostDBProcessor.h b/iocore/hostdb/I_HostDBProcessor.h
index 852794c..ebcd2dc 100644
--- a/iocore/hostdb/I_HostDBProcessor.h
+++ b/iocore/hostdb/I_HostDBProcessor.h
@@ -288,7 +288,7 @@ struct HostDBInfo {
       //  as to how far in the future we should tolerate bogus last
       //  failure times.  This sets the upper bound that we would ever
       //  consider a server down to 2*down_server_timeout
-      if (now + fail_window < last_failure) {
+      if ((unsigned int)(now + fail_window) < last_failure) {
         app.http_data.last_failure = 0;
         return false;
       }

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 09/15: TS-4413: Fix potential consistent hash iterator race.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 69ad8fe673ebb6950ced372afd08829f99fbd1f8
Author: John J. Rushford <Jo...@cable.comcast.com>
AuthorDate: Tue May 3 15:05:28 2016 +0000

    TS-4413: Fix potential consistent hash iterator race.
    
    (cherry picked from commit d01dc00218566e3e41b504de41a655cb80cf423b)
---
 proxy/ParentConsistentHash.cc | 10 +++++-----
 proxy/ParentConsistentHash.h  |  1 -
 proxy/ParentSelection.h       |  4 +++-
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/proxy/ParentConsistentHash.cc b/proxy/ParentConsistentHash.cc
index e145cbc..8ee81f9 100644
--- a/proxy/ParentConsistentHash.cc
+++ b/proxy/ParentConsistentHash.cc
@@ -120,7 +120,7 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
     path_hash = getPathHash(request_info, (ATSHash64 *)&hash);
     fhash = chash[PRIMARY];
     if (path_hash) {
-      prtmp = (pRecord *)fhash->lookup_by_hashval(path_hash, &chashIter[last_lookup], &wrap_around[last_lookup]);
+      prtmp = (pRecord *)fhash->lookup_by_hashval(path_hash, &result->chashIter[last_lookup], &wrap_around[last_lookup]);
       if (prtmp)
         pRec = (parents[last_lookup] + prtmp->idx);
     }
@@ -130,14 +130,14 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
       last_lookup = SECONDARY;
       fhash = chash[SECONDARY];
       path_hash = getPathHash(request_info, (ATSHash64 *)&hash);
-      prtmp = (pRecord *)fhash->lookup_by_hashval(path_hash, &chashIter[last_lookup], &wrap_around[last_lookup]);
+      prtmp = (pRecord *)fhash->lookup_by_hashval(path_hash, &result->chashIter[last_lookup], &wrap_around[last_lookup]);
       if (prtmp)
         pRec = (parents[last_lookup] + prtmp->idx);
     } else {
       last_lookup = PRIMARY;
       fhash = chash[PRIMARY];
       do { // search until we've selected a different parent.
-        prtmp = (pRecord *)fhash->lookup(NULL, &chashIter[last_lookup], &wrap_around[last_lookup], &hash);
+        prtmp = (pRecord *)fhash->lookup(NULL, &result->chashIter[last_lookup], &wrap_around[last_lookup], &hash);
         if (prtmp)
           pRec = (parents[last_lookup] + prtmp->idx);
       } while (prtmp && strcmp(prtmp->hostname, result->hostname) == 0);
@@ -172,10 +172,10 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
           last_lookup = PRIMARY;
         }
         if (firstCall) {
-          prtmp = (pRecord *)fhash->lookup_by_hashval(path_hash, &chashIter[last_lookup], &wrap_around[last_lookup]);
+          prtmp = (pRecord *)fhash->lookup_by_hashval(path_hash, &result->chashIter[last_lookup], &wrap_around[last_lookup]);
           firstCall = false;
         } else {
-          prtmp = (pRecord *)fhash->lookup(NULL, &chashIter[last_lookup], &wrap_around[last_lookup], &hash);
+          prtmp = (pRecord *)fhash->lookup(NULL, &result->chashIter[last_lookup], &wrap_around[last_lookup], &hash);
         }
 
         if (prtmp) {
diff --git a/proxy/ParentConsistentHash.h b/proxy/ParentConsistentHash.h
index e86a65e..443af78 100644
--- a/proxy/ParentConsistentHash.h
+++ b/proxy/ParentConsistentHash.h
@@ -43,7 +43,6 @@ class ParentConsistentHash : public ParentSelectionStrategy
   // and SECONDARY parents.
   ATSHash64Sip24 hash[2];
   ATSConsistentHash *chash[2];
-  ATSConsistentHashIter chashIter[2];
   pRecord *parents[2];
   bool foundParents[2][MAX_PARENTS];
   bool ignore_query;
diff --git a/proxy/ParentSelection.h b/proxy/ParentSelection.h
index 897e813..b72cbd8 100644
--- a/proxy/ParentSelection.h
+++ b/proxy/ParentSelection.h
@@ -267,7 +267,9 @@ private:
   uint32_t last_parent;
   uint32_t start_parent;
   bool wrap_around;
-  int last_lookup; // state for for consistent hash.
+  // state for consistent hash.
+  int last_lookup;
+  ATSConsistentHashIter chashIter[2];
 
   friend class ParentConsistentHash;
   friend class ParentRoundRobin;

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 08/15: TS-4388: TSHttpTxnParentProxySet crashes in parent selection.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit ee5521dfc621a26ed2da20195bdb6108ea9e27c7
Author: James Peach <jp...@apache.org>
AuthorDate: Wed Apr 27 15:16:32 2016 -0700

    TS-4388: TSHttpTxnParentProxySet crashes in parent selection.
    
    Fix ParentResult to handle the case where the parent is specified
    by the TSHttpTxnParentProxySet API. Encapsulate the internals of
    the result better so that it is easier for the HTTP state machine
    to do the right thing.
    
    (cherry picked from commit 7a590edc76843233524f6ba093e57e523d560ba3)
    
     Conflicts:
    	proxy/ParentSelection.h
---
 proxy/InkAPITest.cc           |  6 ---
 proxy/ParentConsistentHash.cc |  4 +-
 proxy/ParentRoundRobin.cc     |  4 +-
 proxy/ParentSelection.cc      |  2 +-
 proxy/ParentSelection.h       | 85 ++++++++++++++++++++++++++++++++++++++++++-
 proxy/http/HttpTransact.cc    | 49 ++++++++++++-------------
 proxy/http/HttpTransact.h     |  8 ++--
 7 files changed, 116 insertions(+), 42 deletions(-)

diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index ac2e197..5509328 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -5982,12 +5982,6 @@ parent_proxy_handler(TSCont contp, TSEvent event, void *edata)
 
 EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpParentProxySet)(RegressionTest *test, int level, int *pstatus)
 {
-  // Don't enable this test by default until it passes.
-  if (level < REGRESSION_TEST_FATAL) {
-    *pstatus = REGRESSION_TEST_NOT_RUN;
-    return;
-  }
-
   *pstatus = REGRESSION_TEST_INPROGRESS;
 
   TSCont cont = TSContCreate(parent_proxy_handler, TSMutexCreate());
diff --git a/proxy/ParentConsistentHash.cc b/proxy/ParentConsistentHash.cc
index 1b5e396..e145cbc 100644
--- a/proxy/ParentConsistentHash.cc
+++ b/proxy/ParentConsistentHash.cc
@@ -236,7 +236,7 @@ ParentConsistentHash::markParentDown(const ParentSelectionPolicy *policy, Parent
   }
   // If we were set through the API we currently have not failover
   //   so just return fail
-  if (result->rec == extApiRecord) {
+  if (result->is_api_result()) {
     return;
   }
 
@@ -312,7 +312,7 @@ ParentConsistentHash::markParentUp(ParentResult *result)
   }
   // If we were set through the API we currently have not failover
   //   so just return fail
-  if (result->rec == extApiRecord) {
+  if (result->is_api_result()) {
     ink_assert(0);
     return;
   }
diff --git a/proxy/ParentRoundRobin.cc b/proxy/ParentRoundRobin.cc
index 0716d78..c3ecf6d 100644
--- a/proxy/ParentRoundRobin.cc
+++ b/proxy/ParentRoundRobin.cc
@@ -198,7 +198,7 @@ ParentRoundRobin::markParentDown(const ParentSelectionPolicy *policy, ParentResu
   }
   // If we were set through the API we currently have not failover
   //   so just return fail
-  if (result->rec == extApiRecord) {
+  if (result->is_api_result()) {
     return;
   }
 
@@ -257,7 +257,7 @@ ParentRoundRobin::markParentUp(ParentResult *result)
   }
   // If we were set through the API we currently have not failover
   //   so just return fail
-  if (result->rec == extApiRecord) {
+  if (result->is_api_result()) {
     ink_assert(0);
     return;
   }
diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc
index b7e197c..41ccef5 100644
--- a/proxy/ParentSelection.cc
+++ b/proxy/ParentSelection.cc
@@ -201,7 +201,7 @@ ParentConfigParams::nextParent(HttpRequestData *rdata, ParentResult *result)
   }
   // If we were set through the API we currently have not failover
   //   so just return fail
-  if (result->rec == extApiRecord) {
+  if (result->is_api_result()) {
     Debug("parent_select", "Retry result for %s was %s", rdata->get_host(), ParentResultStr[result->result]);
     result->result = PARENT_FAIL;
     return;
diff --git a/proxy/ParentSelection.h b/proxy/ParentSelection.h
index bbc9182..897e813 100644
--- a/proxy/ParentSelection.h
+++ b/proxy/ParentSelection.h
@@ -124,7 +124,7 @@ public:
       parent_is_proxy(true),
       selection_strategy(NULL),
       unavailable_server_retry_responses(NULL),
-      parent_retry(0),
+      parent_retry(PARENT_RETRY_NONE),
       max_simple_retries(1),
       max_unavailable_server_retries(1)
   {
@@ -156,7 +156,7 @@ public:
   bool parent_is_proxy;
   ParentSelectionStrategy *selection_strategy;
   UnavailableServerResponseCodes *unavailable_server_retry_responses;
-  int parent_retry;
+  ParentRetry_t parent_retry;
   int max_simple_retries;
   int max_unavailable_server_retries;
 };
@@ -183,6 +183,82 @@ struct ParentResult {
     result = PARENT_UNDEFINED;
   }
 
+  bool
+  is_api_result() const
+  {
+    return rec == extApiRecord;
+  }
+
+  // Do we have some result?
+  bool
+  is_some() const
+  {
+    if (rec == NULL) {
+      // If we don't have a result, we either haven't done a parent
+      // lookup yet (PARENT_UNDEFINED), or the lookup didn't match
+      // anything (PARENT_DIRECT).
+      ink_assert(result == PARENT_UNDEFINED || result == PARENT_DIRECT);
+      return false;
+    }
+
+    return true;
+  }
+
+  bool
+  parent_is_proxy() const
+  {
+    // Parents set by the TSHttpTxnParentProxySet API are always considered proxies rather than origins.
+    return is_api_result() ? true : rec->parent_is_proxy;
+  }
+
+  unsigned
+  retry_type() const
+  {
+    return is_api_result() ? PARENT_RETRY_NONE : rec->parent_retry;
+  }
+
+  unsigned
+  max_retries(ParentRetry_t method) const
+  {
+    // There's no API for specifying the retries, so you get 0.
+    if (is_api_result()) {
+      return 0;
+    }
+
+    switch (method) {
+    case PARENT_RETRY_NONE:
+      return 0;
+    case PARENT_RETRY_SIMPLE:
+      return rec->max_simple_retries;
+    case PARENT_RETRY_UNAVAILABLE_SERVER:
+      return rec->max_unavailable_server_retries;
+    case PARENT_RETRY_BOTH:
+      return std::max(rec->max_unavailable_server_retries, rec->max_simple_retries);
+    }
+
+    return 0;
+  }
+
+  bool
+  response_is_retryable(HTTPStatus response_code) const
+  {
+    return (retry_type() & PARENT_RETRY_UNAVAILABLE_SERVER) && rec->unavailable_server_retry_responses->contains(response_code);
+  }
+
+  bool
+  bypass_ok() const
+  {
+    if (is_api_result()) {
+      return false;
+    } else {
+      // Caller should check for a valid result beforehand.
+      ink_assert(result != PARENT_UNDEFINED);
+      ink_assert(is_some());
+      return rec->bypass_ok();
+    }
+  }
+
+private:
   // Internal use only
   //   Not to be modified by HTTP
   int line_number;
@@ -192,6 +268,11 @@ struct ParentResult {
   uint32_t start_parent;
   bool wrap_around;
   int last_lookup; // state for for consistent hash.
+
+  friend class ParentConsistentHash;
+  friend class ParentRoundRobin;
+  friend class ParentConfigParams;
+  friend class ParentRecord;
 };
 
 struct ParentSelectionPolicy {
diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index d111737..d44ea88 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -68,21 +68,20 @@ static const char local_host_ip_str[] = "127.0.0.1";
 inline static void
 simple_or_unavailable_server_retry(HttpTransact::State *s)
 {
-  int server_response = 0;
-
-  HTTP_RELEASE_ASSERT(!s->parent_result.rec->parent_is_proxy);
+  HTTP_RELEASE_ASSERT(!s->parent_result.parent_is_proxy());
 
   // reponse is from a parent origin server.
-  server_response = http_hdr_status_get(s->hdr_info.server_response.m_http);
+  HTTPStatus server_response = http_hdr_status_get(s->hdr_info.server_response.m_http);
 
   DebugTxn("http_trans", "[simple_or_unavailabe_server_retry] server_response = %d, simple_retry_attempts: %d, numParents:%d \n",
            server_response, s->current.simple_retry_attempts, s->parent_params->numParents(&s->parent_result));
 
   // simple retry is enabled, 0x1
-  if ((s->parent_result.rec->parent_retry & HttpTransact::PARENT_ORIGIN_SIMPLE_RETRY) &&
-      (s->current.simple_retry_attempts < s->parent_result.rec->max_simple_retries && server_response == HTTP_STATUS_NOT_FOUND)) {
+  if ((s->parent_result.retry_type() & HttpTransact::PARENT_ORIGIN_SIMPLE_RETRY) &&
+      s->current.simple_retry_attempts < s->parent_result.max_retries(PARENT_RETRY_SIMPLE) &&
+      server_response == HTTP_STATUS_NOT_FOUND) {
     DebugTxn("parent_select", "RECEIVED A SIMPLE RETRY RESPONSE");
-    if (s->current.simple_retry_attempts < (int)s->parent_params->numParents(&s->parent_result)) {
+    if (s->current.simple_retry_attempts < s->parent_params->numParents(&s->parent_result)) {
       s->current.state = HttpTransact::PARENT_ORIGIN_RETRY;
       s->current.retry_type = HttpTransact::PARENT_ORIGIN_SIMPLE_RETRY;
       return;
@@ -92,11 +91,11 @@ simple_or_unavailable_server_retry(HttpTransact::State *s)
     }
   }
   // unavailable server retry is enabled 0x2
-  else if ((s->parent_result.rec->parent_retry & HttpTransact::PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY) &&
-           (s->current.unavailable_server_retry_attempts < s->parent_result.rec->max_unavailable_server_retries &&
-            s->parent_result.rec->unavailable_server_retry_responses->contains(server_response))) {
+  else if ((s->parent_result.retry_type() & HttpTransact::PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY) &&
+           s->current.unavailable_server_retry_attempts < s->parent_result.max_retries(PARENT_RETRY_UNAVAILABLE_SERVER) &&
+           s->parent_result.response_is_retryable(server_response)) {
     DebugTxn("parent_select", "RECEIVED A PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY RESPONSE");
-    if (s->current.unavailable_server_retry_attempts < (int)s->parent_params->numParents(&s->parent_result)) {
+    if (s->current.unavailable_server_retry_attempts < s->parent_params->numParents(&s->parent_result)) {
       s->current.state = HttpTransact::PARENT_ORIGIN_RETRY;
       s->current.retry_type = HttpTransact::PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY;
       return;
@@ -254,7 +253,7 @@ find_server_and_update_current_info(HttpTransact::State *s)
     s->parent_result.result = PARENT_DIRECT;
   } else if (s->method == HTTP_WKSIDX_CONNECT && s->http_config_param->disable_ssl_parenting) {
     s->parent_params->findParent(&s->request_data, &s->parent_result);
-    if (s->parent_result.rec == NULL || s->parent_result.rec->parent_is_proxy) {
+    if (!s->parent_result.is_some() || s->parent_result.is_api_result() || s->parent_result.parent_is_proxy()) {
       DebugTxn("http_trans", "request not cacheable, so bypass parent");
       s->parent_result.result = PARENT_DIRECT;
     }
@@ -267,7 +266,7 @@ find_server_and_update_current_info(HttpTransact::State *s)
     // with respect to whether a request is cacheable or not.
     // For example, the cache_urls_that_look_dynamic variable.
     s->parent_params->findParent(&s->request_data, &s->parent_result);
-    if (s->parent_result.rec == NULL || s->parent_result.rec->parent_is_proxy) {
+    if (!s->parent_result.is_some() || s->parent_result.is_api_result() || s->parent_result.parent_is_proxy()) {
       DebugTxn("http_trans", "request not cacheable, so bypass parent");
       s->parent_result.result = PARENT_DIRECT;
     }
@@ -291,11 +290,11 @@ find_server_and_update_current_info(HttpTransact::State *s)
     case PARENT_FAIL:
       // Check to see if should bypass the parent and go direct
       //   We can only do this if
-      //   1) the parent was not set from API
+      //   1) the config permitted us to dns the origin server
       //   2) the config permits us
-      //   3) the config permitted us to dns the origin server
-      if (!s->parent_params->apiParentExists(&s->request_data) && s->parent_result.rec->bypass_ok() &&
-          s->http_config_param->no_dns_forward_to_parent == 0 && s->parent_result.rec->parent_is_proxy) {
+      //   3) the parent was not set from API
+      if (s->http_config_param->no_dns_forward_to_parent == 0 && s->parent_result.bypass_ok() &&
+          s->parent_result.parent_is_proxy() && !s->parent_params->apiParentExists(&s->request_data)) {
         s->parent_result.result = PARENT_DIRECT;
       }
       break;
@@ -3545,9 +3544,9 @@ HttpTransact::handle_response_from_parent(State *s)
 
   // response is from a parent origin server.
   if (is_response_valid(s, &s->hdr_info.server_response) && s->current.request_to == HttpTransact::PARENT_PROXY &&
-      !s->parent_result.rec->parent_is_proxy) {
+      !s->parent_result.parent_is_proxy()) {
     // check for a retryable response if simple or unavailable server retry are enabled.
-    if (s->parent_result.rec->parent_retry & (PARENT_ORIGIN_SIMPLE_RETRY | PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY)) {
+    if (s->parent_result.retry_type() & (PARENT_ORIGIN_SIMPLE_RETRY | PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY)) {
       simple_or_unavailable_server_retry(s);
     }
   }
@@ -3587,7 +3586,7 @@ HttpTransact::handle_response_from_parent(State *s)
     // try a simple retry if we received a simple retryable response from the parent.
     if (s->current.retry_type == PARENT_ORIGIN_SIMPLE_RETRY || s->current.retry_type == PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY) {
       if (s->current.retry_type == PARENT_ORIGIN_SIMPLE_RETRY) {
-        if (s->current.simple_retry_attempts >= s->parent_result.rec->max_simple_retries) {
+        if (s->current.simple_retry_attempts >= s->parent_result.max_retries(PARENT_RETRY_SIMPLE)) {
           DebugTxn("http_trans", "PARENT_ORIGIN_SIMPLE_RETRY: retried all parents, send error to client.\n");
           s->current.retry_type = PARENT_ORIGIN_UNDEFINED_RETRY;
         } else {
@@ -3597,7 +3596,7 @@ HttpTransact::handle_response_from_parent(State *s)
           next_lookup = find_server_and_update_current_info(s);
         }
       } else { // try unavailable server retry if we have a unavailable server retry response from the parent.
-        if (s->current.unavailable_server_retry_attempts >= s->parent_result.rec->max_unavailable_server_retries) {
+        if (s->current.unavailable_server_retry_attempts >= s->parent_result.max_retries(PARENT_RETRY_UNAVAILABLE_SERVER)) {
           DebugTxn("http_trans", "PARENT_ORIGIN_UNAVAILABLE_SERVER_RETRY: retried all parents, send error to client.\n");
           s->current.retry_type = PARENT_ORIGIN_UNDEFINED_RETRY;
         } else {
@@ -3690,7 +3689,7 @@ HttpTransact::handle_response_from_server(State *s)
 {
   DebugTxn("http_trans", "[handle_response_from_server] (hrfs)");
   HTTP_RELEASE_ASSERT(s->current.server == &s->server_info);
-  int max_connect_retries = 0;
+  unsigned max_connect_retries = 0;
 
   // plugin call
   s->server_info.state = s->current.state;
@@ -3834,7 +3833,7 @@ HttpTransact::delete_server_rr_entry(State *s, int max_retries)
 //
 ///////////////////////////////////////////////////////////////////////////////
 void
-HttpTransact::retry_server_connection_not_open(State *s, ServerState_t conn_state, int max_retries)
+HttpTransact::retry_server_connection_not_open(State *s, ServerState_t conn_state, unsigned max_retries)
 {
   ink_assert(s->current.state != CONNECTION_ALIVE);
   ink_assert(s->current.state != ACTIVE_TIMEOUT);
@@ -7839,13 +7838,13 @@ HttpTransact::build_request(State *s, HTTPHdr *base_request, HTTPHdr *outgoing_r
   // If we're going to a parent proxy, make sure we pass host and port
   // in the URL even if we didn't get them (e.g. transparent proxy)
   if (s->current.request_to == PARENT_PROXY) {
-    if (!outgoing_request->is_target_in_url() && s->parent_result.rec->parent_is_proxy) {
+    if (!outgoing_request->is_target_in_url() && s->parent_result.parent_is_proxy()) {
       DebugTxn("http_trans", "[build_request] adding target to URL for parent proxy");
 
       // No worry about HTTP/0.9 because we reject forward proxy requests that
       // don't have a host anywhere.
       outgoing_request->set_url_target_from_host_field();
-    } else if (s->current.request_to == PARENT_PROXY && !s->parent_result.rec->parent_is_proxy &&
+    } else if (s->current.request_to == PARENT_PROXY && !s->parent_result.parent_is_proxy() &&
                outgoing_request->is_target_in_url()) {
       // If the parent is an origin server remove the hostname from the url.
       DebugTxn("http_trans", "[build_request] removing target from URL for a parent origin.");
diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h
index dab0edd..b5b1b27 100644
--- a/proxy/http/HttpTransact.h
+++ b/proxy/http/HttpTransact.h
@@ -716,9 +716,9 @@ public:
     ConnectionAttributes *server;
     ink_time_t now;
     ServerState_t state;
-    int attempts;
-    int simple_retry_attempts;
-    int unavailable_server_retry_attempts;
+    unsigned attempts;
+    unsigned simple_retry_attempts;
+    unsigned unavailable_server_retry_attempts;
     ParentOriginRetry_t retry_type;
 
     _CurrentInfo()
@@ -1234,7 +1234,7 @@ public:
   static void handle_response_from_parent(State *s);
   static void handle_response_from_server(State *s);
   static void delete_server_rr_entry(State *s, int max_retries);
-  static void retry_server_connection_not_open(State *s, ServerState_t conn_state, int max_retries);
+  static void retry_server_connection_not_open(State *s, ServerState_t conn_state, unsigned max_retries);
   static void handle_server_connection_not_open(State *s);
   static void handle_forward_server_connection_open(State *s);
   static void handle_cache_operation_on_forward_server_response(State *s);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 14/15: TS-4075: add a state check for sslHandshakeHookState after PreAcceptHookState checking. This closes #374.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 7fedb23bdf897781f832b2fc8faff43e082c8bdf
Author: Oknet <xu...@gmail.com>
AuthorDate: Mon Dec 14 20:00:45 2015 +0800

    TS-4075: add a state check for sslHandshakeHookState after PreAcceptHookState checking.  This closes #374.
    
    (cherry picked from commit 19cc051bb9e803855d2fb424ccf8a4b9546dc49d)
---
 iocore/net/SSLNetVConnection.cc | 52 ++++++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 24 deletions(-)

diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 1a819a7..a8388ad 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -1058,6 +1058,11 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
     }
   }
 
+  // handle SNI Hooks after PreAccept Hooks
+  if (HANDSHAKE_HOOKS_DONE != sslHandshakeHookState && HANDSHAKE_HOOKS_PRE != sslHandshakeHookState) {
+    return SSL_WAIT_FOR_HOOK;
+  }
+
   // If a blind tunnel was requested in the pre-accept calls, convert.
   // Again no data has been exchanged, so we can go directly
   // without data replay.
@@ -1403,10 +1408,9 @@ SSLNetVConnection::select_next_protocol(SSL *ssl, const unsigned char **out, uns
 void
 SSLNetVConnection::reenable(NetHandler *nh)
 {
-  if (this->sslPreAcceptHookState != SSL_HOOKS_DONE) {
-    this->sslPreAcceptHookState = SSL_HOOKS_INVOKE;
-    this->readReschedule(nh);
-  } else {
+  if (sslPreAcceptHookState != SSL_HOOKS_DONE) {
+    sslPreAcceptHookState = SSL_HOOKS_INVOKE;
+  } else if (sslHandshakeHookState == HANDSHAKE_HOOKS_INVOKE) {
     // Reenabling from the handshake callback
     //
     // Originally, we would wait for the callback to go again to execute additinonal
@@ -1416,16 +1420,17 @@ SSLNetVConnection::reenable(NetHandler *nh)
     // here in the reenable.
     if (curHook != NULL) {
       curHook = curHook->next();
-      if (curHook != NULL) {
-        // Invoke the hook
-        curHook->invoke(TS_SSL_CERT_HOOK, this);
-      }
     }
-    if (curHook == NULL) {
+    if (curHook != NULL) {
+      // Invoke the hook and return, wait for next reenable
+      curHook->invoke(TS_SSL_CERT_HOOK, this);
+      return;
+    } else { // curHook == NULL
+      // empty, set state to HOOKS_DONE
       this->sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
-      this->readReschedule(nh);
     }
   }
+  this->readReschedule(nh);
 }
 
 bool
@@ -1449,34 +1454,33 @@ SSLNetVConnection::callHooks(TSHttpHookID eventId)
   // Only dealing with the SNI/CERT hook so far.
   // TS_SSL_SNI_HOOK and TS_SSL_CERT_HOOK are the same value
   ink_assert(eventId == TS_SSL_CERT_HOOK);
+  Debug("ssl", "callHooks sslHandshakeHookState=%d", this->sslHandshakeHookState);
 
-  // First time through, set the type of the hook that is currently
-  // being invoked
-  if (this->sslHandshakeHookState == HANDSHAKE_HOOKS_PRE) {
+  // First time through, set the type of the hook that is currently being invoked
+  if (HANDSHAKE_HOOKS_PRE == sslHandshakeHookState) {
+    // the previous hook should be DONE and set curHook to NULL before trigger the sni hook.
+    ink_assert(curHook == NULL);
+    // set to HOOKS_CERT means CERT/SNI hooks has called by SSL_accept()
     this->sslHandshakeHookState = HANDSHAKE_HOOKS_CERT;
-  }
-
-  if (this->sslHandshakeHookState == HANDSHAKE_HOOKS_CERT && eventId == TS_SSL_CERT_HOOK) {
-    if (curHook != NULL) {
-      curHook = curHook->next();
-    } else {
-      curHook = ssl_hooks->get(TS_SSL_CERT_INTERNAL_HOOK);
-    }
+    // get Hooks
+    curHook = ssl_hooks->get(TS_SSL_CERT_INTERNAL_HOOK);
   } else {
-    // Not in the right state, or no plugins registered for this hook
+    // Not in the right state
     // reenable and continue
     return true;
   }
 
   bool reenabled = true;
-  SSLHandshakeHookState holdState = this->sslHandshakeHookState;
   if (curHook != NULL) {
     // Otherwise, we have plugin hooks to run
     this->sslHandshakeHookState = HANDSHAKE_HOOKS_INVOKE;
     curHook->invoke(eventId, this);
     reenabled = (this->sslHandshakeHookState != HANDSHAKE_HOOKS_INVOKE);
+  } else {
+    // no SNI-Hooks set, set state to HOOKS_DONE
+    // no plugins registered for this hook, return (reenabled == true)
+    sslHandshakeHookState = HANDSHAKE_HOOKS_DONE;
   }
-  this->sslHandshakeHookState = holdState;
   return reenabled;
 }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 13/15: TS-3485: Support ip_allow config for HTTP2. This closes #614.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 2a000a764ae0ab2e011f9f6679500b7c23399e05
Author: Susan Hinrichs <sh...@ieee.org>
AuthorDate: Wed May 4 01:49:30 2016 +0000

    TS-3485: Support ip_allow config for HTTP2.  This closes #614.
    
    (cherry picked from commit 5ce103e889ef2eec9216ec06ae681916cb6e2298)
---
 iocore/net/I_SessionAccept.h                       |  6 +++++
 iocore/net/Makefile.am                             |  1 +
 iocore/net/{I_SessionAccept.h => SessionAccept.cc} | 27 +++++++++++-----------
 proxy/http/HttpSessionAccept.cc                    | 19 +++++++--------
 proxy/http2/Http2ClientSession.cc                  | 12 ----------
 proxy/http2/Http2SessionAccept.cc                  | 13 ++++++++---
 6 files changed, 40 insertions(+), 38 deletions(-)

diff --git a/iocore/net/I_SessionAccept.h b/iocore/net/I_SessionAccept.h
index 3d25b3d..1a8d6a2 100644
--- a/iocore/net/I_SessionAccept.h
+++ b/iocore/net/I_SessionAccept.h
@@ -27,6 +27,8 @@
 #include "I_Net.h"
 #include "I_VConnection.h"
 
+class AclRecord;
+
 class SessionAccept : public Continuation
 {
 public:
@@ -34,6 +36,10 @@ public:
   ~SessionAccept() {}
   virtual void accept(NetVConnection *, MIOBuffer *, IOBufferReader *) = 0;
 
+  /* Returns NULL if the specified client_ip is not allowed by ip_allow
+   * Returns a pointer to the relevant IP policy for later processing otherwise */
+  static const AclRecord *testIpAllowPolicy(sockaddr const *client_ip);
+
 private:
   virtual int mainEvent(int event, void *netvc) = 0;
 };
diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am
index 888d3c2..45d3ee9 100644
--- a/iocore/net/Makefile.am
+++ b/iocore/net/Makefile.am
@@ -60,6 +60,7 @@ libinknet_a_SOURCES = \
   I_UDPPacket.h \
   Inline.cc \
   I_SessionAccept.h \
+  SessionAccept.cc \
   Net.cc \
   NetVConnection.cc \
   P_CompletionUtil.h \
diff --git a/iocore/net/I_SessionAccept.h b/iocore/net/SessionAccept.cc
similarity index 68%
copy from iocore/net/I_SessionAccept.h
copy to iocore/net/SessionAccept.cc
index 3d25b3d..9d0ff03 100644
--- a/iocore/net/I_SessionAccept.h
+++ b/iocore/net/SessionAccept.cc
@@ -21,21 +21,20 @@
   limitations under the License.
  */
 
-#ifndef I_SessionAccept_H_
-#define I_SessionAccept_H_
-
 #include "I_Net.h"
 #include "I_VConnection.h"
+#include "../../proxy/IPAllow.h"
 
-class SessionAccept : public Continuation
+const AclRecord *
+SessionAccept::testIpAllowPolicy(sockaddr const *client_ip)
 {
-public:
-  SessionAccept(ProxyMutex *amutex) : Continuation(amutex) { SET_HANDLER(&SessionAccept::mainEvent); }
-  ~SessionAccept() {}
-  virtual void accept(NetVConnection *, MIOBuffer *, IOBufferReader *) = 0;
-
-private:
-  virtual int mainEvent(int event, void *netvc) = 0;
-};
-
-#endif /* I_SessionAccept_H_ */
+  IpAllow::scoped_config ipallow;
+  const AclRecord *acl_record = NULL;
+  if (ipallow) {
+    acl_record = ipallow->match(client_ip);
+    if (acl_record && acl_record->isEmpty()) {
+      acl_record = NULL;
+    }
+  }
+  return acl_record;
+}
diff --git a/proxy/http/HttpSessionAccept.cc b/proxy/http/HttpSessionAccept.cc
index 394bbf7..ba5a500 100644
--- a/proxy/http/HttpSessionAccept.cc
+++ b/proxy/http/HttpSessionAccept.cc
@@ -33,20 +33,21 @@ HttpSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReade
   sockaddr const *client_ip = netvc->get_remote_addr();
   const AclRecord *acl_record = NULL;
   ip_port_text_buffer ipb;
-  IpAllow::scoped_config ipallow;
 
   // The backdoor port is now only bound to "localhost", so no
   // reason to check for if it's incoming from "localhost" or not.
   if (backdoor) {
     acl_record = IpAllow::AllMethodAcl();
-  } else if (ipallow && (((acl_record = ipallow->match(client_ip)) == NULL) || (acl_record->isEmpty()))) {
-    ////////////////////////////////////////////////////
-    // if client address forbidden, close immediately //
-    ////////////////////////////////////////////////////
-    Warning("client '%s' prohibited by ip-allow policy", ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
-    netvc->do_io_close();
-
-    return;
+  } else {
+    acl_record = testIpAllowPolicy(client_ip);
+    if (!acl_record) {
+      ////////////////////////////////////////////////////
+      // if client address forbidden, close immediately //
+      ////////////////////////////////////////////////////
+      Warning("client '%s' prohibited by ip-allow policy", ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
+      netvc->do_io_close();
+      return;
+    }
   }
 
   // Set the transport type if not already set
diff --git a/proxy/http2/Http2ClientSession.cc b/proxy/http2/Http2ClientSession.cc
index 71fe2f2..5bbcab4 100644
--- a/proxy/http2/Http2ClientSession.cc
+++ b/proxy/http2/Http2ClientSession.cc
@@ -24,7 +24,6 @@
 #include "Http2ClientSession.h"
 #include "HttpDebugNames.h"
 #include "ts/ink_base64.h"
-#include "../IPAllow.h"
 
 #define STATE_ENTER(state_name, event)                                                       \
   do {                                                                                       \
@@ -138,17 +137,6 @@ Http2ClientSession::start()
 void
 Http2ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor)
 {
-  acl_record = NULL;
-  sockaddr const *client_ip = new_vc->get_remote_addr();
-  IpAllow::scoped_config ipallow;
-  if (ipallow && (((acl_record = ipallow->match(client_ip)) == NULL) || (acl_record->isEmpty()))) {
-    ip_port_text_buffer ipb;
-    Warning("http2 client '%s' prohibited by ip-allow policy", ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
-  } else if (!acl_record) {
-    ip_port_text_buffer ipb;
-    Warning("http2 client '%s' no ip-allow policy specified", ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
-  }
-
   ink_assert(new_vc->mutex->thread_holding == this_ethread());
   HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT, new_vc->mutex->thread_holding);
   HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_TOTAL_CLIENT_CONNECTION_COUNT, new_vc->mutex->thread_holding);
diff --git a/proxy/http2/Http2SessionAccept.cc b/proxy/http2/Http2SessionAccept.cc
index 7aeefc7..3699d4c 100644
--- a/proxy/http2/Http2SessionAccept.cc
+++ b/proxy/http2/Http2SessionAccept.cc
@@ -25,6 +25,7 @@
 #include "Http2ClientSession.h"
 #include "I_Machine.h"
 #include "Error.h"
+#include "../IPAllow.h"
 
 Http2SessionAccept::Http2SessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(NULL), options(_o)
 {
@@ -38,9 +39,16 @@ Http2SessionAccept::~Http2SessionAccept()
 void
 Http2SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader)
 {
+  sockaddr const *client_ip = netvc->get_remote_addr();
+  const AclRecord *session_acl_record = testIpAllowPolicy(client_ip);
+  if (!session_acl_record) {
+    ip_port_text_buffer ipb;
+    Warning("HTTP/2 client '%s' prohibited by ip-allow policy", ats_ip_ntop(client_ip, ipb, sizeof(ipb)));
+    netvc->do_io_close();
+    return;
+  }
   netvc->attributes = this->options.transport_type;
 
-  const sockaddr *client_ip = netvc->get_remote_addr();
   if (is_debug_tag_set("http2_seq")) {
     ip_port_text_buffer ipb;
 
@@ -48,9 +56,8 @@ Http2SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead
           ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes);
   }
 
-  // XXX Allocate a Http2ClientSession
   Http2ClientSession *new_session = THREAD_ALLOC_INIT(http2ClientSessionAllocator, this_ethread());
-
+  new_session->acl_record = session_acl_record;
   new_session->new_connection(netvc, iobuf, reader, false /* backdoor */);
 }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 07/15: TS-4388: Refactor ParentResult initialization.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 584a5eb28008d7a1c08c3d800c853d5ed594be50
Author: James Peach <jp...@apache.org>
AuthorDate: Fri Apr 29 20:34:56 2016 -0700

    TS-4388: Refactor ParentResult initialization.
    
    There are a couple of placed where ParentResult objects are
    reinitialized. Refactor this into ParentResult::reset() so avoid
    duplicated code.
    
    (cherry picked from commit 2bf1a31cc95a2ffb1404d0a53e37190243c0aa1d)
    
     Conflicts:
    	proxy/ParentSelection.cc
    	proxy/ParentSelection.h
---
 proxy/ParentSelection.cc |  7 +------
 proxy/ParentSelection.h  | 24 +++++++++---------------
 proxy/http/HttpSM.cc     |  2 +-
 3 files changed, 11 insertions(+), 22 deletions(-)

diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc
index e3bce11..b7e197c 100644
--- a/proxy/ParentSelection.cc
+++ b/proxy/ParentSelection.cc
@@ -123,12 +123,7 @@ ParentConfigParams::findParent(HttpRequestData *rdata, ParentResult *result)
     return;
   }
   // Initialize the result structure
-  result->rec = NULL;
-  result->epoch = tablePtr;
-  result->line_number = 0xffffffff;
-  result->wrap_around = false;
-  result->start_parent = 0;
-  result->last_parent = 0;
+  result->reset();
 
   // Check to see if the parent was set through the
   //   api
diff --git a/proxy/ParentSelection.h b/proxy/ParentSelection.h
index 68f41c7..bbc9182 100644
--- a/proxy/ParentSelection.h
+++ b/proxy/ParentSelection.h
@@ -168,27 +168,21 @@ public:
 ParentRecord *const extApiRecord = (ParentRecord *)0xeeeeffff;
 
 struct ParentResult {
-  ParentResult()
-    : result(PARENT_UNDEFINED),
-      hostname(NULL),
-      port(0),
-      retry(false),
-      line_number(0),
-      epoch(NULL),
-      rec(NULL),
-      last_parent(0),
-      start_parent(0),
-      wrap_around(false),
-      last_lookup(0)
-  {
-  }
-
+  ParentResult() { reset(); }
   // For outside consumption
   ParentResultType result;
   const char *hostname;
   int port;
   bool retry;
 
+  void
+  reset()
+  {
+    ink_zero(*this);
+    line_number = -1;
+    result = PARENT_UNDEFINED;
+  }
+
   // Internal use only
   //   Not to be modified by HTTP
   int line_number;
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index 3fb056d..e9eb3cb 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -7694,7 +7694,7 @@ HttpSM::redirect_request(const char *redirect_url, const int redirect_len)
   // we want to close the server session
   // will do that in handle_api_return under the
   // HttpTransact::SM_ACTION_REDIRECT_READ state
-  t_state.parent_result.result = PARENT_UNDEFINED;
+  t_state.parent_result.reset();
   t_state.request_sent_time = 0;
   t_state.response_received_time = 0;
   t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_INIT;

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 01/15: TS-4359 Deprecate the SPDY feature

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 0d2214f022e3a27a28fde6f7e6f50370fa828d8e
Author: Leif Hedstrom <zw...@apache.org>
AuthorDate: Mon Apr 18 19:28:01 2016 -0600

    TS-4359 Deprecate the SPDY feature
    
    This marks the configuration options for SPDY as deprecated, as well
    as the help text for the SPDY option in configure.ac.
    
    (cherry picked from commit 9ebed0b37afe377151ac9e99adb24d8f158bdace)
---
 configure.ac                                          |  2 +-
 doc/admin-guide/configuration/session-protocol.en.rst | 13 +++----------
 doc/admin-guide/files/records.config.en.rst           | 11 ++++++++---
 doc/admin-guide/installation/index.en.rst             |  4 +++-
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/configure.ac b/configure.ac
index 3d38e7d..bee20f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -355,7 +355,7 @@ AC_MSG_RESULT([$enable_tproxy])
 #
 AC_MSG_CHECKING([whether to enable spdy])
 AC_ARG_ENABLE([spdy],
-        [AS_HELP_STRING([--enable-spdy], [turn on spdy protocol])],
+        [AS_HELP_STRING([--enable-spdy], [turn on spdy protocol [DEPRECATED!]])],
         [],
         [enable_spdy="no"])
 AC_MSG_RESULT([$enable_spdy])
diff --git a/doc/admin-guide/configuration/session-protocol.en.rst b/doc/admin-guide/configuration/session-protocol.en.rst
index bbaf33e..de14cae 100644
--- a/doc/admin-guide/configuration/session-protocol.en.rst
+++ b/doc/admin-guide/configuration/session-protocol.en.rst
@@ -24,13 +24,10 @@ Session Protocol
 
 |TS| supports some session level protocols in place of or on top of HTTP. These
 can be provided by a plugin (see :ref:`developer-plugins-new-protocol-plugins`)
-or be one that is supported directly by |TS|. The
-`SPDY <http://www.chromium.org/spdy>`_ protocol is the only one currently
-supported, but it is planned to support HTTP 2 when that is finalized.
+or be one that is supported directly by |TS|. Note that the SPDY protocol is
+deprecated as of v6.2.0, and will be removed in v7.0.0.
 
-Session protocols are specified by explicit names, based on the
-`NPN <https://technotes.googlecode.com/git/nextprotoneg.html>`_ names. The
-core supported names are:
+Session protocols are specified by explicit names:
 
 *  ``http/0.9``
 *  ``http/1.0``
@@ -41,10 +38,6 @@ core supported names are:
 *  ``spdy/3``
 *  ``spdy/3.1``
 
-The ``http/2`` value is not currently functional, but is included for future
-use. Both ``spdy/1`` and ``spdy/2`` are obsolete, but are include for
-completeness.
-
 The session protocols supported on a proxy port are a subset of these values.
 For convenience some pseudo-values are defined in terms of these fundamental
 protocols:
diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index d356cb1..da23cb6 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -610,7 +610,7 @@ proto
    Specify the :ref:`session level protocols <session-protocol>` supported. These should be
    separated by semi-colons. For TLS proxy ports the default value is
    all available protocols. For non-TLS proxy ports the default is HTTP
-   only. SPDY can be enabled on non-TLS proxy ports but that must be done explicitly.
+   only.
 
 tr-full
    Fully transparent. This is a convenience option and is identical to specifying both ``tr-in`` and ``tr-out``.
@@ -669,9 +669,9 @@ ip-resolve
 
 .. topic:: Example
 
-   Listen on port 9090 for TSL enabled SPDY or HTTP connections, accept no other session protocols.::
+   Listen on port 9090 for TSL enabled HTTP/2 or HTTP connections, accept no other session protocols.::
 
-      9090:proto=spdy;http:ssl
+      9090:proto=http2;http:ssl
 
 .. ts:cv:: CONFIG proxy.config.http.connect_ports STRING 443 563
 
@@ -3000,23 +3000,28 @@ HTTP/2 Configuration
 SPDY Configuration
 ==================
 
+
 .. ts:cv:: CONFIG proxy.config.spdy.accept_no_activity_timeout INT 120
    :reloadable:
+   :deprecated:
 
    How long a SPDY connection will be kept open after an accept without any streams created.
 
 .. ts:cv:: CONFIG proxy.config.spdy.no_activity_timeout_in INT 115
    :reloadable:
+   :deprecated:
 
    How long a stream is kept open without activity.
 
 .. ts:cv:: CONFIG proxy.config.spdy.initial_window_size_in INT 1048576
    :reloadable:
+   :deprecated:
 
    The initial window size for inbound connections.
 
 .. ts:cv:: CONFIG proxy.config.spdy.max_concurrent_streams_in INT 100
    :reloadable:
+   :deprecated:
 
    The maximum number of concurrent streams per inbound connection.
 
diff --git a/doc/admin-guide/installation/index.en.rst b/doc/admin-guide/installation/index.en.rst
index 2c933f9..2255c80 100644
--- a/doc/admin-guide/installation/index.en.rst
+++ b/doc/admin-guide/installation/index.en.rst
@@ -196,7 +196,9 @@ Adding SPDY Support
 -------------------
 
 Traffic Server v5.0.x and above are capable of supporting SPDY, but it is
-optional and must be explicitly configured during the build process.
+optional and must be explicitly configured during the build process. The
+support of SPDY is deprecated as of ATS v6.2.0, and will be removed in
+v7.0.0.
 
 #. Clone the spdylay Git repository from tatsuhiro. ::
 

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 15/15: TS-4431: ATSCPPAPI needs a mutex for intercept plugins

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 8750db6e9cc67d3989f4588075a16a4218a0f8d7
Author: Brian Geffon <br...@apache.org>
AuthorDate: Mon May 9 01:56:54 2016 -0700

    TS-4431: ATSCPPAPI needs a mutex for intercept plugins
    
    (cherry picked from commit d363b83410e2a2790af03201b0cd6ab8a507769c)
---
 lib/atscppapi/src/InterceptPlugin.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/atscppapi/src/InterceptPlugin.cc b/lib/atscppapi/src/InterceptPlugin.cc
index d51164a..a55e2ef 100644
--- a/lib/atscppapi/src/InterceptPlugin.cc
+++ b/lib/atscppapi/src/InterceptPlugin.cc
@@ -121,7 +121,7 @@ void destroyCont(InterceptPlugin::State *state);
 
 InterceptPlugin::InterceptPlugin(Transaction &transaction, InterceptPlugin::Type type) : TransactionPlugin(transaction)
 {
-  TSCont cont = TSContCreate(handleEvents, NULL);
+  TSCont cont = TSContCreate(handleEvents, TSMutexCreate());
   state_ = new State(cont, this);
   TSContDataSet(cont, state_);
   TSHttpTxn txn = static_cast<TSHttpTxn>(transaction.getAtsHandle());

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 03/15: TS-4388: Add an API test for TSHttpTxnParentProxySet.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit 071853a28c5186e915ae28bce9e41ab440cbe749
Author: James Peach <jp...@apache.org>
AuthorDate: Wed Apr 27 12:19:57 2016 -0700

    TS-4388: Add an API test for TSHttpTxnParentProxySet.
    
    Add an API test for TSHttpTxnParentProxySet. This test sends a
    request to the API test synserver, and expects a response. The quirk
    is that it can't get the right response unless TSHttpTxnParentProxySet()
    is called to parent proxy to the syn server.
    
    This test currently crashes, so it is only enabled at REGRESSION_TEST_FATAL
    (level 4).
    
    This closes #605.
    
    TSHttpTxnParentProxySet should take const arguments.
    
    (cherry picked from commit 600f4bc4d0754f7e028836f597a4a34f180be0c4)
    (cherry picked from commit 4c05b1cba0332347affa4596364d8e153bef32b7)
---
 .../api/functions/TSHttpTxnParentProxySet.en.rst   |   2 +-
 proxy/InkAPI.cc                                    |   4 +-
 proxy/InkAPITest.cc                                | 135 ++++++++++++++++++++-
 proxy/InkAPITestTool.cc                            |  40 ++++--
 proxy/api/ts/ts.h                                  |   4 +-
 5 files changed, 172 insertions(+), 13 deletions(-)

diff --git a/doc/developer-guide/api/functions/TSHttpTxnParentProxySet.en.rst b/doc/developer-guide/api/functions/TSHttpTxnParentProxySet.en.rst
index daae59a..8da767d 100644
--- a/doc/developer-guide/api/functions/TSHttpTxnParentProxySet.en.rst
+++ b/doc/developer-guide/api/functions/TSHttpTxnParentProxySet.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
 `#include <ts/ts.h>`
 
-.. function:: void TSHttpTxnParentProxySet(TSHttpTxn txnp, char * hostname, int port)
+.. function:: void TSHttpTxnParentProxySet(TSHttpTxn txnp, const char * hostname, int port)
 
 Description
 ===========
diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc
index f4ec204..5ec1466 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -5557,7 +5557,7 @@ TSHttpTxnServerRequestBodySet(TSHttpTxn txnp, char *buf, int64_t buflength)
 }
 
 TSReturnCode
-TSHttpTxnParentProxyGet(TSHttpTxn txnp, char **hostname, int *port)
+TSHttpTxnParentProxyGet(TSHttpTxn txnp, const char **hostname, int *port)
 {
   sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);
 
@@ -5570,7 +5570,7 @@ TSHttpTxnParentProxyGet(TSHttpTxn txnp, char **hostname, int *port)
 }
 
 void
-TSHttpTxnParentProxySet(TSHttpTxn txnp, char *hostname, int port)
+TSHttpTxnParentProxySet(TSHttpTxn txnp, const char *hostname, int port)
 {
   sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);
   sdk_assert(sdk_sanity_check_null_ptr((void *)hostname) == TS_SUCCESS);
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index 17d0140..d7d64dd 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -5668,7 +5668,7 @@ checkHttpTxnParentProxy(ContData *data, TSHttpTxn txnp)
 {
   const char *hostname = "txnpp.example.com";
   int port = 10180;
-  char *hostnameget = NULL;
+  const char *hostnameget = NULL;
   int portget = 0;
 
   TSHttpTxnParentProxySet(txnp, (char *)hostname, port);
@@ -5858,6 +5858,139 @@ EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpSsn)(RegressionTest *test, int /* atype AT
   return;
 }
 
+struct ParentTest {
+  RegressionTest *regtest;
+  int *pstatus;
+  SocketServer *os;
+  ClientTxn *browser;
+
+  RecBool parent_proxy_routing_enable;
+  unsigned int magic;
+};
+
+static int
+parent_proxy_handler(TSCont contp, TSEvent event, void *edata)
+{
+  ParentTest *ptest = (ParentTest *)TSContDataGet(contp);
+  TSHttpTxn txnp = (TSHttpTxn)edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+    rprintf(ptest->regtest, "setting synserver parent proxy to %s:%d\n", "127.0.0.1", SYNSERVER_LISTEN_PORT);
+
+    // Since we chose a request format with a hostname of trafficserver.apache.org, it won't get
+    // sent to the synserver unless we set a parent proxy.
+    TSHttpTxnParentProxySet(txnp, "127.0.0.1", SYNSERVER_LISTEN_PORT);
+
+    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
+    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, contp);
+
+    TSSkipRemappingSet(txnp, 1);
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+
+  case TS_EVENT_HTTP_SEND_RESPONSE_HDR: {
+    int expected = get_request_id(txnp);
+    int received = get_response_id(txnp);
+
+    if (expected != received) {
+      *(ptest->pstatus) = REGRESSION_TEST_FAILED;
+      SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_FAIL, "Expected response ID %d, received %d", expected,
+                 received);
+    } else {
+      *(ptest->pstatus) = REGRESSION_TEST_PASSED;
+      SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_PASS, "Received expected response ID %d", expected);
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+  }
+
+  case TS_EVENT_TIMEOUT:
+    if (*(ptest->pstatus) == REGRESSION_TEST_INPROGRESS) {
+      // If we are still in progress, reschedule.
+      rprintf(ptest->regtest, "waiting for response\n");
+      TSContSchedule(contp, 100, TS_THREAD_POOL_DEFAULT);
+    } else {
+      // Otherwise the test completed so clean up.
+      RecSetRecordInt("proxy.config.http.parent_proxy_routing_enable", ptest->parent_proxy_routing_enable, REC_SOURCE_EXPLICIT);
+
+      ptest->magic = MAGIC_DEAD;
+      synclient_txn_delete(ptest->browser);
+      synserver_delete(ptest->os);
+      TSfree(ptest);
+      TSContDataSet(contp, NULL);
+    }
+    break;
+
+  case TS_EVENT_HTTP_TXN_CLOSE:
+    // We expected to pass or fail reading the response header. At this point we must have failed.
+    if (*(ptest->pstatus) == REGRESSION_TEST_INPROGRESS) {
+      *(ptest->pstatus) = REGRESSION_TEST_FAILED;
+      SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_FAIL, "Failed on txn close");
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+
+  default:
+    *(ptest->pstatus) = REGRESSION_TEST_FAILED;
+    SDK_RPRINT(ptest->regtest, "TSHttpTxnParentProxySet", "TestCase", TC_FAIL, "Unexpected event %d", event);
+    break;
+  }
+
+  return 0;
+}
+
+EXCLUSIVE_REGRESSION_TEST(SDK_API_HttpParentProxySet)(RegressionTest *test, int level, int *pstatus)
+{
+  // Don't enable this test by default until it passes.
+  if (level < REGRESSION_TEST_FATAL) {
+    *pstatus = REGRESSION_TEST_NOT_RUN;
+    return;
+  }
+
+  *pstatus = REGRESSION_TEST_INPROGRESS;
+
+  TSCont cont = TSContCreate(parent_proxy_handler, TSMutexCreate());
+  if (cont == NULL) {
+    SDK_RPRINT(test, "TSHttpTxnParentProxySet", "TestCase", TC_FAIL, "Unable to create continuation");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  }
+
+  ParentTest *ptest = (ParentTest *)TSmalloc(sizeof(SocketTest));
+  ink_zero(*ptest);
+
+  ptest->regtest = test;
+  ptest->pstatus = pstatus;
+  ptest->magic = MAGIC_ALIVE;
+  TSContDataSet(cont, ptest);
+
+  /* If parent proxy routing is not enabled, enable it for the life of the test. */
+  RecGetRecordBool("proxy.config.http.parent_proxy_routing_enable", &ptest->parent_proxy_routing_enable);
+  if (!ptest->parent_proxy_routing_enable) {
+    rprintf(test, "enabling proxy.config.http.parent_proxy_routing_enable");
+    RecSetRecordInt("proxy.config.http.parent_proxy_routing_enable", 1, REC_SOURCE_EXPLICIT);
+  }
+
+  RecSetRecordInt("proxy.config.http.parent_proxy_routing_enable", 1, REC_SOURCE_EXPLICIT);
+  /* Hook read request headers, since that is the earliest reasonable place to set the parent proxy. */
+  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont);
+
+  /* Create a new synthetic server */
+  ptest->os = synserver_create(SYNSERVER_LISTEN_PORT);
+  synserver_start(ptest->os);
+
+  /* Create a client transaction */
+  ptest->browser = synclient_txn_create();
+
+  // HTTP_REQUEST_FORMAT10 is a hostname, so we will need to set the parent to the synserver to get a response.
+  char *request = generate_request(10);
+  synclient_txn_send_request(ptest->browser, request);
+  TSfree(request);
+
+  TSContSchedule(cont, 25, TS_THREAD_POOL_DEFAULT);
+}
+
 /////////////////////////////////////////////////////
 //       SDK_API_TSHttpTxnCache
 //
diff --git a/proxy/InkAPITestTool.cc b/proxy/InkAPITestTool.cc
index fa6d542..eb399fd 100644
--- a/proxy/InkAPITestTool.cc
+++ b/proxy/InkAPITestTool.cc
@@ -404,6 +404,21 @@ generate_response(const char *request)
   return response;
 }
 
+static int
+get_request_id_value(const char *name, TSMBuffer buf, TSMLoc hdr)
+{
+  int id = -1;
+  TSMLoc field;
+
+  field = TSMimeHdrFieldFind(buf, hdr, name, -1);
+  if (field != TS_NULL_MLOC) {
+    id = TSMimeHdrFieldValueIntGet(buf, hdr, field, 0);
+  }
+
+  TSHandleMLocRelease(buf, hdr, field);
+  return id;
+}
+
 // This routine can be called by tests, from the READ_REQUEST_HDR_HOOK
 // to figure out the id of a test message
 // Returns id/-1 in case of error
@@ -411,22 +426,33 @@ static int
 get_request_id(TSHttpTxn txnp)
 {
   TSMBuffer bufp;
-  TSMLoc hdr_loc, id_loc;
+  TSMLoc hdr_loc;
   int id = -1;
 
   if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
     return -1;
   }
 
-  id_loc = TSMimeHdrFieldFind(bufp, hdr_loc, X_REQUEST_ID, -1);
-  if (id_loc == TS_NULL_MLOC) {
-    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+  id = get_request_id_value(X_REQUEST_ID, bufp, hdr_loc);
+  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+  return id;
+}
+
+// This routine can be called by tests, from the READ_RESPONSE_HDR_HOOK
+// to figure out the id of a test message
+// Returns id/-1 in case of error
+static int
+get_response_id(TSHttpTxn txnp)
+{
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  int id = -1;
+
+  if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
     return -1;
   }
 
-  id = TSMimeHdrFieldValueIntGet(bufp, hdr_loc, id_loc, 0);
-
-  TSHandleMLocRelease(bufp, hdr_loc, id_loc);
+  id = get_request_id_value(X_RESPONSE_ID, bufp, hdr_loc);
   TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
   return id;
 }
diff --git a/proxy/api/ts/ts.h b/proxy/api/ts/ts.h
index 1593784..a55408a 100644
--- a/proxy/api/ts/ts.h
+++ b/proxy/api/ts/ts.h
@@ -1455,7 +1455,7 @@ tsapi void TSHttpTxnErrorBodySet(TSHttpTxn txnp, char *buf, size_t buflength, ch
     @param port parent proxy's port.
 
  */
-tsapi TSReturnCode TSHttpTxnParentProxyGet(TSHttpTxn txnp, char **hostname, int *port);
+tsapi TSReturnCode TSHttpTxnParentProxyGet(TSHttpTxn txnp, const char **hostname, int *port);
 
 /**
     Sets the parent proxy name and port. The string hostname is copied
@@ -1467,7 +1467,7 @@ tsapi TSReturnCode TSHttpTxnParentProxyGet(TSHttpTxn txnp, char **hostname, int
     @param port parent proxy port to set.
 
  */
-tsapi void TSHttpTxnParentProxySet(TSHttpTxn txnp, char *hostname, int port);
+tsapi void TSHttpTxnParentProxySet(TSHttpTxn txnp, const char *hostname, int port);
 
 tsapi void TSHttpTxnUntransformedRespCache(TSHttpTxn txnp, int on);
 tsapi void TSHttpTxnTransformedRespCache(TSHttpTxn txnp, int on);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 06/15: TS-4388: Rename ParentResult:r.

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sorber pushed a commit to branch 6.2.x
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

commit b0378ee621672a72111471f6828433f49cd8787c
Author: James Peach <jp...@apache.org>
AuthorDate: Fri Apr 29 20:04:20 2016 -0700

    TS-4388: Rename ParentResult:r.
    
    A single-letter state variable name is hard to read and hard to
    search for. Rename this to result since it is the result of a parent
    proxy lookup.
    
    (cherry picked from commit 41e013db839c0ece543ddc854805fa59a731b0db)
    
     Conflicts:
    	proxy/ParentSelection.cc
    	proxy/ParentSelection.h
---
 iocore/net/Socks.cc           |  6 +++---
 proxy/ParentConsistentHash.cc | 20 ++++++++++----------
 proxy/ParentRoundRobin.cc     | 22 +++++++++++-----------
 proxy/ParentSelection.cc      | 42 +++++++++++++++++++++---------------------
 proxy/ParentSelection.h       |  4 ++--
 proxy/http/HttpSM.cc          |  6 +++---
 proxy/http/HttpTransact.cc    | 28 ++++++++++++++--------------
 7 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/iocore/net/Socks.cc b/iocore/net/Socks.cc
index a4b0330..792c949 100644
--- a/iocore/net/Socks.cc
+++ b/iocore/net/Socks.cc
@@ -87,7 +87,7 @@ SocksEntry::findServer()
 
 #ifdef SOCKS_WITH_TS
   if (nattempts == 1) {
-    ink_assert(server_result.r == PARENT_UNDEFINED);
+    ink_assert(server_result.result == PARENT_UNDEFINED);
     server_params->findParent(&req_data, &server_result);
   } else {
     socks_conf_struct *conf = netProcessor.socks_conf_stuff;
@@ -97,12 +97,12 @@ SocksEntry::findServer()
     server_params->markParentDown(&server_result);
 
     if (nattempts > conf->connection_attempts)
-      server_result.r = PARENT_FAIL;
+      server_result.result = PARENT_FAIL;
     else
       server_params->nextParent(&req_data, &server_result);
   }
 
-  switch (server_result.r) {
+  switch (server_result.result) {
   case PARENT_SPECIFIED:
     // Original was inet_addr, but should hostnames work?
     // ats_ip_pton only supports numeric (because other clients
diff --git a/proxy/ParentConsistentHash.cc b/proxy/ParentConsistentHash.cc
index 6c19e9a..1b5e396 100644
--- a/proxy/ParentConsistentHash.cc
+++ b/proxy/ParentConsistentHash.cc
@@ -105,9 +105,9 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
   // Should only get into this state if we are supposed to go direct.
   if (parents[PRIMARY] == NULL && parents[SECONDARY] == NULL) {
     if (result->rec->go_direct == true && result->rec->parent_is_proxy == true) {
-      result->r = PARENT_DIRECT;
+      result->result = PARENT_DIRECT;
     } else {
-      result->r = PARENT_FAIL;
+      result->result = PARENT_FAIL;
     }
     result->hostname = NULL;
     result->port = 0;
@@ -156,7 +156,7 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
           result->last_parent = pRec->idx;
           result->last_lookup = last_lookup;
           result->retry = parentRetry;
-          result->r = PARENT_SPECIFIED;
+          result->result = PARENT_SPECIFIED;
           Debug("parent_select", "Down parent %s is now retryable, marked it available.", pRec->hostname);
           break;
         }
@@ -196,7 +196,7 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
 
   // use the available or marked for retry parent.
   if (pRec && (pRec->available || result->retry)) {
-    result->r = PARENT_SPECIFIED;
+    result->result = PARENT_SPECIFIED;
     result->hostname = pRec->hostname;
     result->port = pRec->port;
     result->last_parent = pRec->idx;
@@ -207,9 +207,9 @@ ParentConsistentHash::selectParent(const ParentSelectionPolicy *policy, bool fir
     Debug("parent_select", "Chosen parent: %s.%d", result->hostname, result->port);
   } else {
     if (result->rec->go_direct == true && result->rec->parent_is_proxy == true) {
-      result->r = PARENT_DIRECT;
+      result->result = PARENT_DIRECT;
     } else {
-      result->r = PARENT_FAIL;
+      result->result = PARENT_FAIL;
     }
     result->hostname = NULL;
     result->port = 0;
@@ -230,8 +230,8 @@ ParentConsistentHash::markParentDown(const ParentSelectionPolicy *policy, Parent
 
   //  Make sure that we are being called back with with a
   //   result structure with a parent
-  ink_assert(result->r == PARENT_SPECIFIED);
-  if (result->r != PARENT_SPECIFIED) {
+  ink_assert(result->result == PARENT_SPECIFIED);
+  if (result->result != PARENT_SPECIFIED) {
     return;
   }
   // If we were set through the API we currently have not failover
@@ -306,8 +306,8 @@ ParentConsistentHash::markParentUp(ParentResult *result)
   //  Make sure that we are being called back with with a
   //   result structure with a parent that is being retried
   ink_release_assert(result->retry == true);
-  ink_assert(result->r == PARENT_SPECIFIED);
-  if (result->r != PARENT_SPECIFIED) {
+  ink_assert(result->result == PARENT_SPECIFIED);
+  if (result->result != PARENT_SPECIFIED) {
     return;
   }
   // If we were set through the API we currently have not failover
diff --git a/proxy/ParentRoundRobin.cc b/proxy/ParentRoundRobin.cc
index ac453d3..0716d78 100644
--- a/proxy/ParentRoundRobin.cc
+++ b/proxy/ParentRoundRobin.cc
@@ -69,9 +69,9 @@ ParentRoundRobin::selectParent(const ParentSelectionPolicy *policy, bool first_c
       ink_assert(result->rec->go_direct == true);
       // Could not find a parent
       if (result->rec->go_direct == true && result->rec->parent_is_proxy == true) {
-        result->r = PARENT_DIRECT;
+        result->result = PARENT_DIRECT;
       } else {
-        result->r = PARENT_FAIL;
+        result->result = PARENT_FAIL;
       }
 
       result->hostname = NULL;
@@ -112,9 +112,9 @@ ParentRoundRobin::selectParent(const ParentSelectionPolicy *policy, bool first_c
       if (bypass_ok == true) {
         // Could not find a parent
         if (result->rec->go_direct == true && result->rec->parent_is_proxy == true) {
-          result->r = PARENT_DIRECT;
+          result->result = PARENT_DIRECT;
         } else {
-          result->r = PARENT_FAIL;
+          result->result = PARENT_FAIL;
         }
         result->hostname = NULL;
         result->port = 0;
@@ -153,7 +153,7 @@ ParentRoundRobin::selectParent(const ParentSelectionPolicy *policy, bool first_c
     }
 
     if (parentUp == true) {
-      result->r = PARENT_SPECIFIED;
+      result->result = PARENT_SPECIFIED;
       result->hostname = result->rec->parents[cur_index].hostname;
       result->port = result->rec->parents[cur_index].port;
       result->last_parent = cur_index;
@@ -167,9 +167,9 @@ ParentRoundRobin::selectParent(const ParentSelectionPolicy *policy, bool first_c
   } while ((unsigned int)cur_index != result->start_parent);
 
   if (result->rec->go_direct == true && result->rec->parent_is_proxy == true) {
-    result->r = PARENT_DIRECT;
+    result->result = PARENT_DIRECT;
   } else {
-    result->r = PARENT_FAIL;
+    result->result = PARENT_FAIL;
   }
 
   result->hostname = NULL;
@@ -192,8 +192,8 @@ ParentRoundRobin::markParentDown(const ParentSelectionPolicy *policy, ParentResu
   Debug("parent_select", "Starting ParentRoundRobin::markParentDown()");
   //  Make sure that we are being called back with with a
   //   result structure with a parent
-  ink_assert(result->r == PARENT_SPECIFIED);
-  if (result->r != PARENT_SPECIFIED) {
+  ink_assert(result->result == PARENT_SPECIFIED);
+  if (result->result != PARENT_SPECIFIED) {
     return;
   }
   // If we were set through the API we currently have not failover
@@ -251,8 +251,8 @@ ParentRoundRobin::markParentUp(ParentResult *result)
   //  Make sure that we are being called back with with a
   //   result structure with a parent that is being retried
   ink_release_assert(result->retry == true);
-  ink_assert(result->r == PARENT_SPECIFIED);
-  if (result->r != PARENT_SPECIFIED) {
+  ink_assert(result->result == PARENT_SPECIFIED);
+  if (result->result != PARENT_SPECIFIED) {
     return;
   }
   // If we were set through the API we currently have not failover
diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc
index 8f5b227..e3bce11 100644
--- a/proxy/ParentSelection.cc
+++ b/proxy/ParentSelection.cc
@@ -114,12 +114,12 @@ ParentConfigParams::findParent(HttpRequestData *rdata, ParentResult *result)
   ParentRecord *rec;
 
   Debug("parent_select", "In ParentConfigParams::findParent(): parent_table: %p.", parent_table);
-  ink_assert(result->r == PARENT_UNDEFINED);
+  ink_assert(result->result == PARENT_UNDEFINED);
 
   // Check to see if we are enabled
   Debug("parent_select", "policy.ParentEnable: %d", policy.ParentEnable);
   if (policy.ParentEnable == 0) {
-    result->r = PARENT_DIRECT;
+    result->result = PARENT_DIRECT;
     return;
   }
   // Initialize the result structure
@@ -133,7 +133,7 @@ ParentConfigParams::findParent(HttpRequestData *rdata, ParentResult *result)
   // Check to see if the parent was set through the
   //   api
   if (apiParentExists(rdata)) {
-    result->r = PARENT_SPECIFIED;
+    result->result = PARENT_SPECIFIED;
     result->hostname = rdata->api_info->parent_proxy_name;
     result->port = rdata->api_info->parent_proxy_port;
     result->rec = extApiRecord;
@@ -154,7 +154,7 @@ ParentConfigParams::findParent(HttpRequestData *rdata, ParentResult *result)
     if (defaultPtr != NULL) {
       rec = result->rec = defaultPtr;
     } else {
-      result->r = PARENT_DIRECT;
+      result->result = PARENT_DIRECT;
       Debug("parent_select", "Returning PARENT_DIRECT (no parents were found)");
       return;
     }
@@ -166,17 +166,17 @@ ParentConfigParams::findParent(HttpRequestData *rdata, ParentResult *result)
 
   const char *host = rdata->get_host();
 
-  switch (result->r) {
+  switch (result->result) {
   case PARENT_UNDEFINED:
     Debug("parent_select", "PARENT_UNDEFINED");
-    Debug("parent_select", "Result for %s was %s", host, ParentResultStr[result->r]);
+    Debug("parent_select", "Result for %s was %s", host, ParentResultStr[result->result]);
     break;
   case PARENT_FAIL:
     Debug("parent_select", "PARENT_FAIL");
     break;
   case PARENT_DIRECT:
     Debug("parent_select", "PARENT_DIRECT");
-    Debug("parent_select", "Result for %s was %s", host, ParentResultStr[result->r]);
+    Debug("parent_select", "Result for %s was %s", host, ParentResultStr[result->result]);
     break;
   case PARENT_SPECIFIED:
     Debug("parent_select", "PARENT_SPECIFIED");
@@ -199,20 +199,20 @@ ParentConfigParams::nextParent(HttpRequestData *rdata, ParentResult *result)
 
   //  Make sure that we are being called back with a
   //   result structure with a parent
-  ink_assert(result->r == PARENT_SPECIFIED);
-  if (result->r != PARENT_SPECIFIED) {
-    result->r = PARENT_FAIL;
+  ink_assert(result->result == PARENT_SPECIFIED);
+  if (result->result != PARENT_SPECIFIED) {
+    result->result = PARENT_FAIL;
     return;
   }
   // If we were set through the API we currently have not failover
   //   so just return fail
   if (result->rec == extApiRecord) {
-    Debug("parent_select", "Retry result for %s was %s", rdata->get_host(), ParentResultStr[result->r]);
-    result->r = PARENT_FAIL;
+    Debug("parent_select", "Retry result for %s was %s", rdata->get_host(), ParentResultStr[result->result]);
+    result->result = PARENT_FAIL;
     return;
   }
-  Debug("parent_select", "ParentConfigParams::nextParent(): result->r: %d, tablePtr: %p, result->epoch: %p", result->r, tablePtr,
-        result->epoch);
+  Debug("parent_select", "ParentConfigParams::nextParent(): result->result: %d, tablePtr: %p, result->epoch: %p", result->result,
+        tablePtr, result->epoch);
   ink_release_assert(tablePtr == result->epoch);
 
   // Find the next parent in the array
@@ -221,18 +221,18 @@ ParentConfigParams::nextParent(HttpRequestData *rdata, ParentResult *result)
 
   const char *host = rdata->get_host();
 
-  switch (result->r) {
+  switch (result->result) {
   case PARENT_UNDEFINED:
     Debug("parent_select", "PARENT_UNDEFINED");
-    Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->r]);
+    Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->result]);
     break;
   case PARENT_FAIL:
     Debug("parent_select", "PARENT_FAIL");
-    Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->r]);
+    Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->result]);
     break;
   case PARENT_DIRECT:
     Debug("parent_select", "PARENT_DIRECT");
-    Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->r]);
+    Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->result]);
     break;
   case PARENT_SPECIFIED:
     Debug("parent_select", "Retry result for %s was parent %s:%d", host, result->hostname, result->port);
@@ -251,7 +251,7 @@ ParentConfigParams::parentExists(HttpRequestData *rdata)
 
   findParent(rdata, &result);
 
-  if (result.r == PARENT_SPECIFIED) {
+  if (result.result == PARENT_SPECIFIED) {
     return true;
   } else {
     return false;
@@ -1317,7 +1317,7 @@ verify(ParentResult *r, ParentResultType e, const char *h, int p)
 {
   if (is_debug_tag_set("parent_select"))
     show_result(r);
-  return (r->r != e) ? 0 : ((e != PARENT_SPECIFIED) ? 1 : (strcmp(r->hostname, h) ? 0 : ((r->port == p) ? 1 : 0)));
+  return (r->result != e) ? 0 : ((e != PARENT_SPECIFIED) ? 1 : (strcmp(r->hostname, h) ? 0 : ((r->port == p) ? 1 : 0)));
 }
 
 // br creates an HttpRequestData object
@@ -1339,7 +1339,7 @@ br(HttpRequestData *h, const char *os_hostname, sockaddr const *dest_ip)
 void
 show_result(ParentResult *p)
 {
-  switch (p->r) {
+  switch (p->result) {
   case PARENT_UNDEFINED:
     printf("result is PARENT_UNDEFINED\n");
     break;
diff --git a/proxy/ParentSelection.h b/proxy/ParentSelection.h
index 0aebb55..68f41c7 100644
--- a/proxy/ParentSelection.h
+++ b/proxy/ParentSelection.h
@@ -169,7 +169,7 @@ ParentRecord *const extApiRecord = (ParentRecord *)0xeeeeffff;
 
 struct ParentResult {
   ParentResult()
-    : r(PARENT_UNDEFINED),
+    : result(PARENT_UNDEFINED),
       hostname(NULL),
       port(0),
       retry(false),
@@ -184,7 +184,7 @@ struct ParentResult {
   }
 
   // For outside consumption
-  ParentResultType r;
+  ParentResultType result;
   const char *hostname;
   int port;
   bool retry;
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index a0e6ec3..3fb056d 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -7154,7 +7154,7 @@ HttpSM::set_next_state()
       call_transact_and_set_next_state(HttpTransact::HandleFiltering);
       break;
     } else if (t_state.http_config_param->use_client_target_addr == 2 && !t_state.url_remap_success &&
-               t_state.parent_result.r != PARENT_SPECIFIED && t_state.client_info.is_transparent &&
+               t_state.parent_result.result != PARENT_SPECIFIED && t_state.client_info.is_transparent &&
                t_state.dns_info.os_addr_style == HttpTransact::DNSLookupInfo::OS_ADDR_TRY_DEFAULT &&
                ats_is_ip(addr = t_state.state_machine->ua_session->get_netvc()->get_local_addr())) {
       /* If the connection is client side transparent and the URL
@@ -7182,7 +7182,7 @@ HttpSM::set_next_state()
       t_state.dns_info.os_addr_style = HttpTransact::DNSLookupInfo::OS_ADDR_TRY_CLIENT;
       call_transact_and_set_next_state(NULL);
       break;
-    } else if (t_state.parent_result.r == PARENT_UNDEFINED && t_state.dns_info.lookup_success) {
+    } else if (t_state.parent_result.result == PARENT_UNDEFINED && t_state.dns_info.lookup_success) {
       // Already set, and we don't have a parent proxy to lookup
       ink_assert(ats_is_ip(t_state.host_db_info.ip()));
       DebugSM("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup, provided by plugin");
@@ -7694,7 +7694,7 @@ HttpSM::redirect_request(const char *redirect_url, const int redirect_len)
   // we want to close the server session
   // will do that in handle_api_return under the
   // HttpTransact::SM_ACTION_REDIRECT_READ state
-  t_state.parent_result.r = PARENT_UNDEFINED;
+  t_state.parent_result.result = PARENT_UNDEFINED;
   t_state.request_sent_time = 0;
   t_state.response_received_time = 0;
   t_state.cache_info.write_lock_state = HttpTransact::CACHE_WL_INIT;
diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index 1d24e43..d111737 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -251,12 +251,12 @@ find_server_and_update_current_info(HttpTransact::State *s)
     // Do not forward requests to local_host onto a parent.
     // I just wanted to do this for cop heartbeats, someone else
     // wanted it for all requests to local_host.
-    s->parent_result.r = PARENT_DIRECT;
+    s->parent_result.result = PARENT_DIRECT;
   } else if (s->method == HTTP_WKSIDX_CONNECT && s->http_config_param->disable_ssl_parenting) {
     s->parent_params->findParent(&s->request_data, &s->parent_result);
     if (s->parent_result.rec == NULL || s->parent_result.rec->parent_is_proxy) {
       DebugTxn("http_trans", "request not cacheable, so bypass parent");
-      s->parent_result.r = PARENT_DIRECT;
+      s->parent_result.result = PARENT_DIRECT;
     }
   } else if (s->http_config_param->uncacheable_requests_bypass_parent && s->http_config_param->no_dns_forward_to_parent == 0 &&
              !HttpTransact::is_request_cache_lookupable(s)) {
@@ -269,10 +269,10 @@ find_server_and_update_current_info(HttpTransact::State *s)
     s->parent_params->findParent(&s->request_data, &s->parent_result);
     if (s->parent_result.rec == NULL || s->parent_result.rec->parent_is_proxy) {
       DebugTxn("http_trans", "request not cacheable, so bypass parent");
-      s->parent_result.r = PARENT_DIRECT;
+      s->parent_result.result = PARENT_DIRECT;
     }
   } else {
-    switch (s->parent_result.r) {
+    switch (s->parent_result.result) {
     case PARENT_UNDEFINED:
       s->parent_params->findParent(&s->request_data, &s->parent_result);
       break;
@@ -283,9 +283,9 @@ find_server_and_update_current_info(HttpTransact::State *s)
       // We already have a parent that failed, if we are now told
       //  to go the origin server, we can only obey this if we
       //  dns'ed the origin server
-      if (s->parent_result.r == PARENT_DIRECT && s->http_config_param->no_dns_forward_to_parent != 0) {
+      if (s->parent_result.result == PARENT_DIRECT && s->http_config_param->no_dns_forward_to_parent != 0) {
         ink_assert(!s->server_info.dst_addr.isValid());
-        s->parent_result.r = PARENT_FAIL;
+        s->parent_result.result = PARENT_FAIL;
       }
       break;
     case PARENT_FAIL:
@@ -296,7 +296,7 @@ find_server_and_update_current_info(HttpTransact::State *s)
       //   3) the config permitted us to dns the origin server
       if (!s->parent_params->apiParentExists(&s->request_data) && s->parent_result.rec->bypass_ok() &&
           s->http_config_param->no_dns_forward_to_parent == 0 && s->parent_result.rec->parent_is_proxy) {
-        s->parent_result.r = PARENT_DIRECT;
+        s->parent_result.result = PARENT_DIRECT;
       }
       break;
     default:
@@ -310,7 +310,7 @@ find_server_and_update_current_info(HttpTransact::State *s)
     }
   }
 
-  switch (s->parent_result.r) {
+  switch (s->parent_result.result) {
   case PARENT_SPECIFIED:
     s->parent_info.name = s->arena.str_store(s->parent_result.hostname, strlen(s->parent_result.hostname));
     update_current_info(&s->current, &s->parent_info, HttpTransact::PARENT_PROXY, (s->current.attempts)++);
@@ -457,7 +457,7 @@ how_to_open_connection(HttpTransact::State *s)
     break;
   }
 
-  if (s->method == HTTP_WKSIDX_CONNECT && s->parent_result.r != PARENT_SPECIFIED) {
+  if (s->method == HTTP_WKSIDX_CONNECT && s->parent_result.result != PARENT_SPECIFIED) {
     s->cdn_saved_next_action = HttpTransact::SM_ACTION_ORIGIN_SERVER_RAW_OPEN;
   } else {
     s->cdn_saved_next_action = HttpTransact::SM_ACTION_ORIGIN_SERVER_OPEN;
@@ -2702,7 +2702,7 @@ HttpTransact::HandleCacheOpenReadHit(State *s)
       }
       // a parent lookup could come back as PARENT_FAIL if in parent.config, go_direct == false and
       // there are no available parents (all down).
-      else if (s->current.request_to == HOST_NONE && s->parent_result.r == PARENT_FAIL) {
+      else if (s->current.request_to == HOST_NONE && s->parent_result.result == PARENT_FAIL) {
         if (is_server_negative_cached(s) && response_returnable == true && is_stale_cache_response_returnable(s) == true) {
           server_up = false;
           update_current_info(&s->current, NULL, UNDEFINED_LOOKUP, 0);
@@ -3149,7 +3149,7 @@ HttpTransact::HandleCacheOpenReadMiss(State *s)
     find_server_and_update_current_info(s);
     // a parent lookup could come back as PARENT_FAIL if in parent.config go_direct == false and
     // there are no available parents (all down).
-    if (s->parent_result.r == PARENT_FAIL) {
+    if (s->parent_result.result == PARENT_FAIL) {
       handle_parent_died(s);
       return;
     }
@@ -3579,7 +3579,7 @@ HttpTransact::handle_response_from_parent(State *s)
     // If the request is not retryable, just give up!
     if (!is_request_retryable(s)) {
       s->parent_params->markParentDown(&s->parent_result);
-      s->parent_result.r = PARENT_FAIL;
+      s->parent_result.result = PARENT_FAIL;
       handle_parent_died(s);
       return;
     }
@@ -3635,7 +3635,7 @@ HttpTransact::handle_response_from_parent(State *s)
       //   appropriate
       DebugTxn("http_trans", "[handle_response_from_parent] Error. No more retries.");
       s->parent_params->markParentDown(&s->parent_result);
-      s->parent_result.r = PARENT_FAIL;
+      s->parent_result.result = PARENT_FAIL;
       next_lookup = find_server_and_update_current_info(s);
     }
 
@@ -7600,7 +7600,7 @@ HttpTransact::AuthenticationNeeded(const OverridableHttpConfigParams *p, HTTPHdr
 void
 HttpTransact::handle_parent_died(State *s)
 {
-  ink_assert(s->parent_result.r == PARENT_FAIL);
+  ink_assert(s->parent_result.result == PARENT_FAIL);
 
   build_error_response(s, HTTP_STATUS_BAD_GATEWAY, "Next Hop Connection Failed", "connect#failed_connect", NULL);
   TRANSACT_RETURN(SM_ACTION_SEND_ERROR_CACHE_NOOP, NULL);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.