You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2017/07/07 17:03:30 UTC

[trafficserver] branch master updated: Add experimental plugin to initiate H2 Server push for preload links.

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 8d2712b  Add experimental plugin to initiate H2 Server push for preload links.
8d2712b is described below

commit 8d2712b5395c0c44640378b1b38cb752dffb996d
Author: David Calavera <da...@gmail.com>
AuthorDate: Fri May 19 17:59:36 2017 -0700

    Add experimental plugin to initiate H2 Server push for preload links.
    
    This plugin parses the response Link header to extract assets to preload.
    Then an H2 Server Push is initiated for those assets.
    
    Signed-off-by: David Calavera <da...@gmail.com>
---
 plugins/Makefile.am                                |   1 +
 .../experimental/server_push_preload/Makefile.inc  |  20 +++
 plugins/experimental/server_push_preload/README.md |   3 +
 .../server_push_preload/server_push_preload.cc     | 140 +++++++++++++++++++++
 4 files changed, 164 insertions(+)

diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 32e14db..5e0db4d 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -68,6 +68,7 @@ include experimental/money_trace/Makefile.inc
 include experimental/mp4/Makefile.inc
 include experimental/multiplexer/Makefile.inc
 include experimental/remap_purge/Makefile.inc
+include experimental/server_push_preload/Makefile.inc
 include experimental/ssl_cert_loader/Makefile.inc
 include experimental/sslheaders/Makefile.inc
 include experimental/stale_while_revalidate/Makefile.inc
diff --git a/plugins/experimental/server_push_preload/Makefile.inc b/plugins/experimental/server_push_preload/Makefile.inc
new file mode 100644
index 0000000..4d8fd47
--- /dev/null
+++ b/plugins/experimental/server_push_preload/Makefile.inc
@@ -0,0 +1,20 @@
+#  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.
+
+pkglib_LTLIBRARIES += experimental/server_push_preload/server_push_preload.la
+
+experimental_server_push_preload_server_push_preload_la_SOURCES = \
+  experimental/server_push_preload/server_push_preload.cc
diff --git a/plugins/experimental/server_push_preload/README.md b/plugins/experimental/server_push_preload/README.md
new file mode 100644
index 0000000..296794c
--- /dev/null
+++ b/plugins/experimental/server_push_preload/README.md
@@ -0,0 +1,3 @@
+Parse origin response Link headers and use H2 Server Push to initiate push requests of assets that have the preload keyword.
+
+https://www.w3.org/TR/preload/
diff --git a/plugins/experimental/server_push_preload/server_push_preload.cc b/plugins/experimental/server_push_preload/server_push_preload.cc
new file mode 100644
index 0000000..49d2f4b
--- /dev/null
+++ b/plugins/experimental/server_push_preload/server_push_preload.cc
@@ -0,0 +1,140 @@
+/** @file
+
+  A plugin to parse Link headers from an origin server's response and initiate H2 Server Push for preload links.
+
+  @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 <regex>
+#include <set>
+#include <sstream>
+#include <ts/ts.h>
+#include <ts/experimental.h>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/utils.h>
+
+#define PLUGIN_NAME "server_push_preload"
+#define PRELOAD_PARAM "rel=preload"
+#define NOPUSH_OPTION "nopush"
+
+using namespace std;
+using namespace atscppapi;
+
+static regex linkRegexp("<([^>]+)>;(.+)");
+
+namespace
+{
+GlobalPlugin *plugin;
+}
+
+class LinkServerPushPlugin : public GlobalPlugin
+{
+public:
+  LinkServerPushPlugin()
+  {
+    TSDebug(PLUGIN_NAME, "registering transaction hooks");
+    LinkServerPushPlugin::registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  virtual void
+  handleSendResponseHeaders(Transaction &transaction)
+  {
+    serverPush(transaction);
+    transaction.resume();
+  }
+
+  void
+  serverPush(Transaction &transaction)
+  {
+    TSHttpTxn txnp = static_cast<TSHttpTxn>(transaction.getAtsHandle());
+    if (TSHttpTxnClientProtocolStackContains(txnp, "h2") == nullptr) {
+      return;
+    }
+
+    ClientRequest &request = transaction.getClientRequest();
+    Response &response     = transaction.getClientResponse();
+    Headers &headers       = response.getHeaders();
+
+    const Url &clientUrl = request.getPristineUrl();
+
+    for (header_field_iterator it = headers.find("Link"); it != headers.end(); it.nextDup()) {
+      HeaderField field = *it;
+
+      for (header_field_value_iterator hit = field.begin(); hit != field.end(); ++hit) {
+        const string &link = *hit;
+
+        TSDebug(PLUGIN_NAME, "Parsing link header: %s", link.c_str());
+        smatch matches;
+
+        if (regex_search(link, matches, linkRegexp)) {
+          string url = matches[1].str();
+          TSDebug(PLUGIN_NAME, "Found link header match: %s", url.c_str());
+
+          set<string> params = split(matches[2].str(), ';');
+          auto preload       = params.find(PRELOAD_PARAM);
+          if (preload == params.end()) {
+            continue;
+          }
+
+          auto noPush = params.find(NOPUSH_OPTION);
+          if (noPush != params.end()) {
+            TSDebug(PLUGIN_NAME, "Skipping nopush link: %s", link.c_str());
+            continue;
+          }
+
+          Request request(url);
+          Url &linkUrl = request.getUrl();
+
+          if (linkUrl.getHost().empty()) {
+            linkUrl.setHost(clientUrl.getHost());
+            linkUrl.setScheme(clientUrl.getScheme());
+          }
+          string lu = linkUrl.getUrlString();
+          TSDebug(PLUGIN_NAME, "Push preloaded content: %s", lu.c_str());
+          TSHttpTxnServerPush(txnp, lu.c_str(), lu.length());
+        } else {
+          TSDebug(PLUGIN_NAME, "No match found for link header: %s", link.c_str());
+        }
+      }
+    }
+  }
+
+  set<string>
+  split(const string &params, char delim)
+  {
+    stringstream ss(params);
+    string s;
+    set<string> tokens;
+    while (getline(ss, s, delim)) {
+      s.erase(find_if(s.rbegin(), s.rend(), not1(std::ptr_fun<int, int>(isspace))).base(), s.end()); // trim left
+      s.erase(s.begin(), find_if(s.begin(), s.end(), not1(std::ptr_fun<int, int>(isspace))));        // trim right
+      tokens.insert(s);
+    }
+    return tokens;
+  }
+};
+
+void
+TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED)
+{
+  TSDebug(PLUGIN_NAME, "Init");
+  RegisterGlobalPlugin("ServerPushPreloadPlugin", PLUGIN_NAME, "dev@trafficserver.apache.org");
+  plugin = new LinkServerPushPlugin();
+}

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