Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions plugins/experimental/esi/README.combo
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ The arguments in the plugin.config line in order represent
"admin/v1/combo")

2) The name of the key used for signature verification (disabled
by default)
by default) [verification not implemented yet]

A "-" can be supplied as a value for any of these arguments to request
default value be applied.
default value be applied.

Also, just like the original combohandler, this plugin generates URLs
of the form 'http://localhost/<dir>/<file-path>'. <dir> here defaults
to 'l' unless specified by the file path in the query parameter using
to "Host" header unless specified by the file path in the query parameter using
a colon. For example:

http://combo.com/admin/v1/combo?filepath1&dir1:filepath2&filepath3

Will result in these three pages being fetched:

http://localhost/l/filepath1
http://localhost/combo.com/filepath1
http://localhost/dir1/filepath2
http://localhost/l/filepath3
http://localhost/combo.com/filepath3

Remap rules have to be specified to map the above URLs to desired
content servers.
Expand All @@ -49,6 +49,25 @@ results in these file paths being "reconstructed":
/dir:path2/file5
/dir:path2/file6

Config sample
------
[plugin.config]
combo_handler.so admin/v1/combo

[remap.config]
map http://combo.com http://os.combo.com @plugin=combo_handler.so
map http://localhost/combo.com http://os.combo.com
map http://localhost/dir1 http://os1.combo.com

(note that if pristine_host_hdr is enabled in records.config, the Host header
of request to your combo origin server is 'localhost')

Version 1.2.0
- ported to ATS-3.3.3
- per-map enabled (disabled for all map by default)
- use full Host header as default bucket
- limit sub-file's max count(30) and querystring's max length(3000)

Version 1.1.2
- Use the Bucket visited(instead of 'l' as the default) as the nickname if nickname is not passed.

Expand Down
127 changes: 121 additions & 6 deletions plugins/experimental/esi/combo_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "ts/ts.h"
#include "ts/experimental.h"
#include "ts/remap.h"
#include "ink_defs.h"

#include "HttpDataFetcherImpl.h"
Expand All @@ -39,6 +40,10 @@ using namespace EsiLib;

#define DEBUG_TAG "combo_handler"

#define MAX_FILE_COUNT 30
#define MAX_QUERY_LENGTH 3000

int arg_idx;
static string SIG_KEY_NAME;

#define DEFAULT_COMBO_HANDLER_PATH "admin/v1/combo"
Expand All @@ -61,7 +66,7 @@ struct ClientRequest {
const sockaddr *client_addr;
StringList file_urls;
bool gzip_accepted;
string defaultBucket; //default Bucket is set to l
string defaultBucket; // default Bucket will be set to HOST header
ClientRequest()
: status(TS_HTTP_STATUS_OK), client_addr(NULL), gzip_accepted(false), defaultBucket("l") { };
};
Expand Down Expand Up @@ -217,19 +222,54 @@ TSPluginInit(int argc, const char *argv[])
LOG_ERROR("Could not create read request header continuation");
return;
}
TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, rrh_contp);

TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, rrh_contp);

if (TSHttpArgIndexReserve(DEBUG_TAG, "will save plugin-enable flag here",
&arg_idx) != TS_SUCCESS) {
LOG_ERROR("failed to reserve private data slot");
return;
} else {
LOG_DEBUG("arg_idx: %d", arg_idx);
}

Utils::init(&TSDebug, &TSError);
LOG_DEBUG("Plugin started");
}

/*
Handle TS_EVENT_HTTP_OS_DNS event after TS_EVENT_HTTP_POST_REMAP and
TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE in order to make this plugin
"per-remap configurable", that is, we enable combo for specific channels,
and disable for other channels.

In yahoo's original code, this function handle TS_EVENT_HTTP_READ_REQUEST_HDR.
Because TS_EVENT_HTTP_READ_REQUEST_HDR is before TSRemapDoRemap, we can not
read "plugin_enable" flag in the READ_REQUEST_HDR event.
*/
static int
handleReadRequestHeader(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata)
{
TSAssert(event == TS_EVENT_HTTP_READ_REQUEST_HDR);

LOG_DEBUG("handling read request header event...");
TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);

if (event != TS_EVENT_HTTP_OS_DNS) {
LOG_ERROR("unknown event for this plugin %d", event);
return 0;
}

int *plugin_enable;
plugin_enable = (int *)TSHttpTxnArgGet(txnp, arg_idx);
if (plugin_enable && *plugin_enable == 1) {
LOG_DEBUG("combo is enabled for this channel");
} else {
LOG_DEBUG("combo is disabled for this channel");
TSfree(plugin_enable);
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
return 0;
}
TSfree(plugin_enable);

LOG_DEBUG("handling TS_EVENT_HTTP_OS_DNS event...");
TSEvent reenable_to_event = TS_EVENT_HTTP_CONTINUE;
TSMBuffer bufp;
TSMLoc hdr_loc;
Expand Down Expand Up @@ -321,6 +361,10 @@ getDefaultBucket(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer bufp, TSMLoc hdr_obj
}

LOG_DEBUG("host: %.*s", host_len, host);
creq.defaultBucket = string(host, host_len);
defaultBucketFound = true;

/*
for(int i = 0 ; i < host_len; i++)
{
if (host[i] == '.')
Expand All @@ -330,6 +374,7 @@ getDefaultBucket(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer bufp, TSMLoc hdr_obj
break;
}
}
*/

TSHandleMLocRelease (bufp, hdr_obj, field_loc);

Expand All @@ -345,12 +390,19 @@ getClientRequest(TSHttpTxn txnp, TSMBuffer bufp, TSMLoc hdr_loc, TSMLoc url_loc,

if (!query) {
LOG_ERROR("Could not get query from request URL");
creq.status = TS_HTTP_STATUS_BAD_REQUEST;
return;
} else {
if (!getDefaultBucket(txnp, bufp, hdr_loc, creq))
{
LOG_ERROR("failed getting Default Bucket for the request");
return;
}
if (query_len > MAX_QUERY_LENGTH) {
creq.status = TS_HTTP_STATUS_BAD_REQUEST;
LOG_ERROR("querystring too long");
return;
}
parseQueryParameters(query, query_len, creq);
creq.client_addr = TSHttpTxnClientAddrGet(txnp);
checkGzipAcceptance(bufp, hdr_loc, creq);
Expand All @@ -372,7 +424,7 @@ parseQueryParameters(const char *query, int query_len, ClientRequest &creq)
int common_prefix_path_size = 0;

for (int i = 0; i <= query_len; ++i) {
if ((i == query_len) || (query[i] == '&') || (query[i] == '?')) {
if ((i == query_len) || (query[i] == '&')) {
int param_len = i - param_start_pos;
if (param_len) {
const char *param = query + param_start_pos;
Expand Down Expand Up @@ -463,6 +515,13 @@ if (!creq.file_urls.size()) {
creq.status = TS_HTTP_STATUS_FORBIDDEN;
creq.file_urls.clear();
}

if (creq.file_urls.size() > MAX_FILE_COUNT) {
creq.status = TS_HTTP_STATUS_BAD_REQUEST;
LOG_ERROR("too many files in url");
creq.file_urls.clear();
}

}

static void
Expand Down Expand Up @@ -844,3 +903,59 @@ writeErrorResponse(InterceptData &int_data, int &n_bytes_written)
n_bytes_written += response->size();
return true;
}

TSRemapStatus
TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo* rri)
{
int *plugin_enable;

plugin_enable = static_cast<int *>(TSmalloc(sizeof(int)));
*plugin_enable = 1;

TSHttpTxnArgSet(rh, arg_idx, plugin_enable); /* Save for later hooks */

return TSREMAP_NO_REMAP; /* Continue with next remap plugin in chain */
}

/*
Initialize the plugin as a remap plugin.
*/
TSReturnCode
TSRemapInit(TSRemapInterface* api_info, char *errbuf, int errbuf_size)
{
if (!api_info) {
strncpy(errbuf, "[TSRemapInit] - Invalid TSRemapInterface argument",
errbuf_size - 1);
return TS_ERROR;
}

if (api_info->size < sizeof(TSRemapInterface)) {
strncpy(errbuf,
"[TSRemapInit] - Incorrect size of TSRemapInterface structure",
errbuf_size - 1);
return TS_ERROR;
}

TSDebug(DEBUG_TAG, "%s plugin's remap part is initialized", DEBUG_TAG);

return TS_SUCCESS;
}

TSReturnCode
TSRemapNewInstance(int argc, char* argv[], void** ih, char* errbuf,
int errbuf_size)
{
*ih = NULL;

TSDebug(DEBUG_TAG, "%s Remap Instance for '%s' created",
DEBUG_TAG, argv[0]);

return TS_SUCCESS;
}


void
TSRemapDeleteInstance(void* ih)
{
return;
}