diff --git a/plugins/experimental/cacheurl/README b/plugins/experimental/cacheurl/README deleted file mode 100644 index 6c09a402140..00000000000 --- a/plugins/experimental/cacheurl/README +++ /dev/null @@ -1,25 +0,0 @@ -This plugin allows you to change the key that is used for caching a request. -It is designed so that multiple requests that have different URLs but the same -content (for example, site mirrors) need be cached only once. - -Installation: - - make - sudo make install - -If you don't have the traffic server binaries in your path, then you will need -to specify the path to tsxs manually: - - make TSXS=/opt/ts/bin/tsxs - sudo make TSXS=/opt/ts/bin/tsxs install - -Configuration: - - Create a cacheurl.config file in the plugin directory with the url - patterns to match. See the cacheurl.config.example file for what to put in - this file. - - Add the plugin to your plugins.conf file: cacheurl.so - -Start traffic server. Any rewritten URLs will be written to cacheurl.log in -the log directory by default. diff --git a/plugins/experimental/cacheurl/README.rst b/plugins/experimental/cacheurl/README.rst new file mode 100644 index 00000000000..51b4110f6e7 --- /dev/null +++ b/plugins/experimental/cacheurl/README.rst @@ -0,0 +1,86 @@ +:title: CacheURL Plugin + +.. 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. + +This plugin allows you to change the key that is used for caching a request. +It is designed so that multiple requests that have different URLs but the same +content (for example, site mirrors) need be cached only once. + +Installation # {#Installation} +============================== + +:: + make + sudo make install + +If you don't have the traffic server binaries in your path, then you will need +to specify the path to tsxs manually: + +:: + make TSXS=/opt/ts/bin/tsxs + sudo make TSXS=/opt/ts/bin/tsxs install + +# Configuration # {#Configuration} +================================== + +Add the plugin to your plugins.conf file: `cacheurl.so` + +If you wish, you can specify a location for the cacheurl configuration file +by adding it as a parameter in plugins.conf. For example: + +:: + cacheurl.so /etc/trafficserver/cacheurl.config + +The default location for the config file is `cacheurl.config` in the plugins +directory. + +Cacheurl can also be called as a remap plugin in `remap.config`. For example: + +:: + map http://www.example.com/ http://origin.example.com/ @plugin=cacheurl.so @pparam=/path/to/cacheurl.config + +Next, create the configuration file with the url patterns to match. + +The configration file format is: `url_pattern cache_key_replacement` + +The url_pattern is a regular expression (pcre). The replacement can contain +$1, $2 and so on, which will be replaced with the appropriate matching group +from the pattern. + +Examples: + +:: + # Make files from s1.example.com, s2.example.com and s3.example.com all + # be cached with the same key. + # Adding a unique suffix (TSINTERNAL in this example) to the cache key + # guarantees that it won't clash with a real URL should s.example.com + # exist. + http://s[123].example.com/(.*) http://s.example.com.TSINTERNAL/$1 + + # Cache based on only some parts of a query string (e.g. ignore session + # information). This plucks out the id and format query string variables and + # only considers those when making the cache key. + http://www.example.com/video\?.*?\&?(id=[0-9a-f]*).*?\&(format=[a-z]*) http://video-srv.example.com.ATSINTERNAL/$1&$2 + + # Completely ignore a query string for a specific page + http://www.example.com/some/page.html(?:\?|$) http://www.example.com/some/page.html + +Start traffic server. Any rewritten URLs will be written to cacheurl.log in +the log directory by default. + +.. vim: ft=rst diff --git a/plugins/experimental/cacheurl/cacheurl.c b/plugins/experimental/cacheurl/cacheurl.c index c2f568016b2..549dc6f223a 100644 --- a/plugins/experimental/cacheurl/cacheurl.c +++ b/plugins/experimental/cacheurl/cacheurl.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -41,10 +42,13 @@ typedef struct { int *tokenoffset; /* Array of $x token offsets */ } regex_info; -static regex_info *pr_list[PATTERNCOUNT]; /* Pattern/replacement list */ -static int patterncount; +typedef struct { + regex_info *pr[PATTERNCOUNT]; /* Pattern/replacement list */ + int patterncount; /* Number of patterns */ + //pr_list *next; /* Link to next set of patterns, if any */ +} pr_list; -static TSTextLogObject log; +static TSTextLogObject log = NULL; static int regex_substitute(char **buf, char *str, regex_info *info) { int matchcount; @@ -181,10 +185,12 @@ static int regex_compile(regex_info **buf, char *pattern, char *replacement) { return status; } -static void load_config_file() { +static pr_list* load_config_file(const char *config_file) { char buffer[1024]; - char config_file[1024]; + char default_config_file[1024]; TSFile fh; + pr_list *prl = TSmalloc(sizeof(pr_list)); + prl->patterncount = 0; /* locations in a config file line, end of line, split start, split end */ char *eol, *spstart, *spend; @@ -192,16 +198,18 @@ static void load_config_file() { int retval; regex_info *info = 0; - /* TODO - should this file be located in etc/ rather than the plugin dir? - * */ - sprintf(config_file, "%s/cacheurl.config", TSPluginDirGet()); + if (!config_file) { + /* Default config file of plugins/cacheurl.config */ + sprintf(default_config_file, "%s/cacheurl.config", TSPluginDirGet()); + config_file = (const char *)default_config_file; + } TSDebug(PLUGIN_NAME, "Opening config file: %s", config_file); fh = TSfopen(config_file, "r"); if (!fh) { TSError("[%s] Unable to open %s. No patterns will be loaded\n", PLUGIN_NAME, config_file); - return; + return prl; } while (TSfgets(fh, buffer, sizeof(buffer) - 1)) { @@ -256,67 +264,83 @@ static void load_config_file() { TSError("[%s] Error precompiling regex/replacement. Skipping.\n", PLUGIN_NAME); } - if (patterncount > PATTERNCOUNT) { + // TODO - remove patterncount and make pr_list infinite (linked list) + if (prl->patterncount >= PATTERNCOUNT) { TSError("[%s] Warning, too many patterns - skipping the rest" "(max: %d)\n", PLUGIN_NAME, PATTERNCOUNT); TSfree(info); break; } - pr_list[patterncount] = info; - patterncount++; + prl->pr[prl->patterncount] = info; + prl->patterncount++; } TSfclose(fh); + // Make sure the last element is null + if (prl->patterncount < PATTERNCOUNT) { + prl->pr[prl->patterncount] = NULL; + } + return prl; } -static int handle_hook(TSCont *contp, TSEvent event, void *edata) { - TSHttpTxn txnp = (TSHttpTxn) edata; +static int rewrite_cacheurl(pr_list *prl, TSHttpTxn txnp) { + int ok = 1; char *newurl = 0; int retval; char *url; int url_length; int i; + if (ok) { + url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_length); + if (!url) { + TSError("[%s] couldn't retrieve request url\n", + PLUGIN_NAME); + ok = 0; + } + } + + if (ok) { + i=0; + while (i < PATTERNCOUNT && prl->pr[i]) { + retval = regex_substitute(&newurl, url, prl->pr[i]); + if (retval) { + /* Successful match/substitution */ + break; + } + i++; + } + if (newurl) { + if (log) { + TSTextLogObjectWrite(log, + "Rewriting cache URL for %s to %s", url, + newurl); + } + TSDebug(PLUGIN_NAME, "Rewriting cache URL for %s to %s\n", + url, newurl); + if (TSCacheUrlSet(txnp, newurl, strlen(newurl)) + != TS_SUCCESS) { + TSError("[%s] Unable to modify cache url from " + "%s to %s\n", PLUGIN_NAME, url, newurl); + ok = 0; + } + } + } + /* Clean up */ + if (url) TSfree(url); + if (newurl) TSfree(newurl); + return ok; +} +static int handle_hook(TSCont contp, TSEvent event, void *edata) { + TSHttpTxn txnp = (TSHttpTxn) edata; + pr_list *prl; int ok = 1; + prl = (pr_list *)TSContDataGet(contp); + switch (event) { case TS_EVENT_HTTP_READ_REQUEST_HDR: - if (ok) { - url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_length); - if (!url) { - TSError("[%s] couldn't retrieve request url\n", - PLUGIN_NAME); - ok = 0; - } - } - - if (ok) { - for (i=0; isize < sizeof(TSRemapInterface)) { + strncpy(errbuf, + "[tsremap_init] Incorrect size of TSRemapInterface structure", + errbuf_size - 1); + return TS_ERROR; + } + + if (api_info->tsremap_version < TSREMAP_VERSION) { + snprintf(errbuf, errbuf_size - 1, + "[tsremap_init] Incorrect API version %ld.%ld", + api_info->tsremap_version >> 16, + (api_info->tsremap_version & 0xffff)); + return TS_ERROR; + } + + if (!log) { + error = TSTextLogObjectCreate("cacheurl", TS_LOG_MODE_ADD_TIMESTAMP, + &log); + if (!log || error == TS_ERROR) { + snprintf(errbuf, errbuf_size - 1, + "[%s] Error creating log file\n", PLUGIN_NAME); + return TS_ERROR; + } + } + + TSDebug(PLUGIN_NAME, "remap plugin is successfully initialized"); + return TS_SUCCESS; +} + +TSReturnCode TSRemapNewInstance(int argc, char* argv[], void** ih, char* errbuf, + int errbuf_size) { + + *ih = load_config_file(argc > 2 ? argv[2] : NULL); + return TS_SUCCESS; +} + + +void TSRemapDeleteInstance(void *ih) { + // Clean up + TSDebug(PLUGIN_NAME, "Deleting remap instance"); + pr_list *prl = (pr_list *)ih; + int i=0; + while (prl->pr[i]) { + if (prl->pr[i]->tokens) TSfree(prl->pr[i]->tokens); + if (prl->pr[i]->tokenoffset) TSfree(prl->pr[i]->tokenoffset); + if (prl->pr[i]->re) pcre_free(prl->pr[i]->re); + TSfree(prl->pr[i]); + i++; + } + TSfree(prl); +} + +TSRemapStatus TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo *rri) { + int ok; + ok = rewrite_cacheurl((pr_list *)ih, rh); + if (ok) { + return TSREMAP_NO_REMAP; + } else { + return TSREMAP_ERROR; + } +} + void TSPluginInit(int argc, const char *argv[]) { TSPluginRegistrationInfo info; TSReturnCode error; + TSCont contp; + pr_list *prl; info.plugin_name = PLUGIN_NAME; info.vendor_name = "OmniTI"; @@ -378,14 +475,18 @@ void TSPluginInit(int argc, const char *argv[]) { return; } - error = TSTextLogObjectCreate("cacheurl", TS_LOG_MODE_ADD_TIMESTAMP, - &log); - if (!log || error == TS_ERROR) { - TSError("[%s] Error creating log file\n", PLUGIN_NAME); + if (!log) { + error = TSTextLogObjectCreate("cacheurl", TS_LOG_MODE_ADD_TIMESTAMP, + &log); + if (!log || error == TS_ERROR) { + TSError("[%s] Error creating log file\n", PLUGIN_NAME); + } } - load_config_file(); + prl = load_config_file(argc > 1 ? argv[1] : NULL); - TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, - TSContCreate((TSEventFunc)handle_hook, NULL)); + contp = TSContCreate((TSEventFunc)handle_hook, NULL); + /* Store the pattern replacement list in the continuation */ + TSContDataSet(contp, prl); + TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, contp); }