diff --git a/NOTICE b/NOTICE index 453af9b4419..adb427a534b 100644 --- a/NOTICE +++ b/NOTICE @@ -9,6 +9,7 @@ This product includes software developed at - Comcast - LinkedIn - Mike Pall + - GoDaddy ~~~ @@ -44,8 +45,8 @@ Copyright (C) 2012 Oregon Health & Science University ~~~ -healthcheck Plugin developed by GoDaddy. -Copyright (C) 2012 GoDaddy. +cache-key-genid Plugin developed by GoDaddy +Copyright (C) 2013 GoDaddy Operating Company, LLC ~~~ @@ -78,7 +79,7 @@ Copyright (C) 2014 Yahoo! Inc. All rights reserved. ~~~ healthchecks: Plugin for ATS healthchecks. -Copyright (C) 2012 Go Daddy Operating Company, LLC +Copyright (C) 2012 GoDaddy Operating Company, LLC ~~~ diff --git a/configure.ac b/configure.ac index b39e56eeac1..308b71ebe49 100644 --- a/configure.ac +++ b/configure.ac @@ -1891,6 +1891,19 @@ AC_CHECK_LIB([mysqlclient],[mysql_info],[AC_SUBST([LIB_MYSQLCLIENT],["-lmysqlcli AC_SUBST(has_mysql) AM_CONDITIONAL([HAS_MYSQL], [ test "x${has_mysql}" = "x1" ]) +AC_CHECK_HEADERS([kclangc.h], [ + AC_CHECK_LIB([kyotocabinet], [kcdbopen], [ + AC_SUBST([LIB_KYOTOCABINET], ["-lkyotocabinet"]) + has_kyotocabinet=1 + ], [ + has_kyotocabinet=0 + ]) +], +[has_kyotocabinet=0] +) +AC_SUBST(has_kyotocabinet) +AM_CONDITIONAL([HAS_KYOTOCABINET], [ test "x${has_kyotocabinet}" = "x1" ]) + AS_IF([test "x$enable_experimental_plugins" = "xyes"], [ AC_CONFIG_FILES([ plugins/experimental/Makefile @@ -1898,6 +1911,7 @@ AS_IF([test "x$enable_experimental_plugins" = "xyes"], [ plugins/experimental/background_fetch/Makefile plugins/experimental/balancer/Makefile plugins/experimental/buffer_upload/Makefile + plugins/experimental/cache_key_genid/Makefile plugins/experimental/cache_range_requests/Makefile plugins/experimental/channel_stats/Makefile plugins/experimental/cache_promote/Makefile diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am index 98f82939231..fb554528998 100644 --- a/plugins/experimental/Makefile.am +++ b/plugins/experimental/Makefile.am @@ -51,3 +51,7 @@ endif if BUILD_LUAJIT SUBDIRS += ts_lua endif + +if HAS_KYOTOCABINET + SUBDIRS += cache_key_genid +endif diff --git a/plugins/experimental/cache_key_genid/Makefile.am b/plugins/experimental/cache_key_genid/Makefile.am new file mode 100644 index 00000000000..41db1387ad3 --- /dev/null +++ b/plugins/experimental/cache_key_genid/Makefile.am @@ -0,0 +1,22 @@ +# 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 $(top_srcdir)/build/plugins.mk + +pkglib_LTLIBRARIES = cache_key_genid.la +cache_key_genid_la_SOURCES = cache_key_genid.c +cache_key_genid_la_LDFLAGS = $(TS_PLUGIN_LDFLAGS) $(LIB_KYOTOCABINET) + diff --git a/plugins/experimental/cache_key_genid/cache_key_genid.c b/plugins/experimental/cache_key_genid/cache_key_genid.c new file mode 100644 index 00000000000..96cb11ef5d0 --- /dev/null +++ b/plugins/experimental/cache_key_genid/cache_key_genid.c @@ -0,0 +1,175 @@ +/* + * Licensed 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. + */ + +/* cache-key-genid.c - Plugin to modify the URL used as a cache key for + * requests, without modifying the URL used for actually fetching data from + * the origin server. + */ + +#include +#include +#include +#include "kclangc.h" + +#define PLUGIN_NAME "cache-key-genid" + +static char genid_kyoto_db[PATH_MAX + 1]; + +// Find the host in url and set host to it +static void +get_genid_host(char **host, char *url) +{ + char *pt1; + char *pt2; + size_t host_len; + unsigned num = 1; + + pt1 = strstr(url, "//"); + + if (pt1) { + pt1 = pt1 + 2; + pt2 = strstr(pt1, "/"); + } + + if (pt1 && pt2 && pt2 > pt1) { + host_len = pt2 - pt1; + *host = calloc(num, host_len + 1); + strncpy(*host, pt1, host_len); + } +} + +/* get_genid + * Looks up the host's genid in the host->genid database + */ +static int +get_genid (char *host) +{ + KCDB* db; + char *vbuf; + size_t vsiz; + int answer = 0; + int host_size; + + /* create the database object */ + db = kcdbnew(); + + /* open the database */ + if (!kcdbopen(db, genid_kyoto_db, KCOREADER | KCONOLOCK)) { + TSDebug(PLUGIN_NAME, "could not open the genid database %s", genid_kyoto_db); + TSError("[%s] could not open the genid database %s: %s", + PLUGIN_NAME, genid_kyoto_db, strerror(errno)); + return 0; + } + + vbuf = kcdbget(db, host, strlen(host), &vsiz); + + if (vbuf) { + TSDebug(PLUGIN_NAME, "kcdbget(%s) = %s", host, vbuf); + answer = (int) strtol(vbuf, NULL, 10); + kcfree(vbuf); + } else { + host_size = strlen(host); + TSDebug(PLUGIN_NAME, "kcdbget(%s) - no record found, len(%d)", host, host_size); + answer = 0; + } + + kcdbclose(db); + return answer; +} + +/* handle_hook + * Fires on TS_EVENT_HTTP_READ_REQUEST_HDR events, gets the effectiveUrl + * finds the host, gets the generation ID, gen_id, for the host + * and runs TSCacheUrlSet to change the cache key for the read + */ +static int +handle_hook(TSCont *contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = (TSHttpTxn) edata; + char *url = NULL, *host = NULL; + int url_length; + int gen_id; + int ok = 1; + + switch (event) { + case TS_EVENT_HTTP_READ_REQUEST_HDR: + TSDebug(PLUGIN_NAME, "handling TS_EVENT_HTTP_READ_REQUEST_HDR"); + + if (ok) { + url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_length); + if (!url) { + TSError("[%s] could not retrieve request url", PLUGIN_NAME); + ok = 0; + } + } + + if (ok) { + get_genid_host(&host, url); + if (!host) { + TSError("[%s] could not retrieve request host", PLUGIN_NAME); + ok = 0; + } + } + + if (ok) { + TSDebug(PLUGIN_NAME, "From url (%s) discovered host (%s)", url, host); + if ((gen_id = get_genid(host)) != 0) { + if (TSHttpTxnConfigIntSet(txnp, TS_CONFIG_HTTP_CACHE_GENERATION, gen_id) != TS_SUCCESS) { + TSDebug(PLUGIN_NAME, "Error, unable to modify cache url"); + TSError("[%s] Unable to set cache generation for %s to %d", PLUGIN_NAME, url, gen_id); + ok = 0; + } + } + } + + /* Clean up */ + if (url) + TSfree(url); + if (host) + TSfree(host); + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); + break; + + default: + TSAssert(!"Unexpected event"); + ok = 0; + break; + } + + return ok; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + TSPluginRegistrationInfo info; + + info.plugin_name = (char *)PLUGIN_NAME; + info.vendor_name = (char *)"Apache Software Foundation"; + info.support_email = (char *)"dev@trafficserver.apache.org"; + + if (argc > 1) { + TSstrlcpy(genid_kyoto_db, argv[1], sizeof(genid_kyoto_db)); + } else { + TSError("[%s] plugin registration failed. check argv[1] for db path", PLUGIN_NAME); + return; + } + + if (TSPluginRegister(&info) != TS_SUCCESS) { + TSError("[%s] plugin registration failed. check version.", PLUGIN_NAME); + return; + } + + TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate((TSEventFunc)handle_hook, NULL)); +}