blob: 626ed1f961e34495dd6321a4af2c184f12279f21 [file] [log] [blame]
/** @file
Class to execute one (or more) remap plugin(s).
@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 "RemapPlugins.h"
ClassAllocator<RemapPlugins> pluginAllocator("RemapPluginsAlloc");
TSRemapStatus
RemapPlugins::run_plugin(remap_plugin_info* plugin)
{
TSRemapStatus plugin_retcode;
TSRemapRequestInfo rri;
url_mapping *map = _s->url_map.getMapping();
URL * map_from = _s->url_map.getFromURL();
URL * map_to = _s->url_map.getToURL();
// This is the equivalent of TSHttpTxnClientReqGet(), which every remap plugin would
// have to call.
rri.requestBufp = reinterpret_cast<TSMBuffer>(_request_header);
rri.requestHdrp = reinterpret_cast<TSMLoc>(_request_header->m_http);
// Read-only URL's (TSMLoc's to the SDK)
rri.mapFromUrl = reinterpret_cast<TSMLoc>(map_from->m_url_impl);
rri.mapToUrl = reinterpret_cast<TSMLoc>(map_to->m_url_impl);
rri.requestUrl = reinterpret_cast<TSMLoc>(_request_url->m_url_impl);
rri.redirect = 0;
// These are made to reflect the "defaults" that will be used in
// the case where the plugins don't modify them. It's semi-weird
// that the "from" and "to" URLs changes when chaining happens, but
// it is necessary to get predictable behavior.
#if 0
if (_cur == 0) {
rri.remap_from_host = map_from->host_get(&rri.remap_from_host_size);
rri.remap_from_port = map_from->port_get();
rri.remap_from_path = map_from->path_get(&rri.remap_from_path_size);
rri.from_scheme = map_from->scheme_get(&rri.from_scheme_len);
} else {
rri.remap_from_host = _request_url->host_get(&rri.remap_from_host_size);
rri.remap_from_port = _request_url->port_get();
rri.remap_from_path = _request_url->path_get(&rri.remap_from_path_size);
rri.from_scheme = _request_url->scheme_get(&rri.from_scheme_len);
}
#endif
void* ih = map->get_instance(_cur);
// Prepare State for the future
if (_s && _cur == 0) {
_s->fp_tsremap_os_response = plugin->fp_tsremap_os_response;
_s->remap_plugin_instance = ih;
}
plugin_retcode = plugin->fp_tsremap_do_remap(ih, _s ? reinterpret_cast<TSHttpTxn>(_s->state_machine) : NULL, &rri);
// TODO: Deal with negative return codes here
if (plugin_retcode < 0)
plugin_retcode = TSREMAP_NO_REMAP;
// First step after plugin remap must be "redirect url" check
if ((TSREMAP_DID_REMAP == plugin_retcode || TSREMAP_DID_REMAP_STOP == plugin_retcode) && rri.redirect)
_s->remap_redirect = _request_url->string_get(NULL);
return plugin_retcode;
}
/**
This is the equivalent of the old DoRemap().
@return 1 when you are done doing crap (otherwise, you get re-called
with schedule_imm and i hope you have something more to do), else
0 if you have something more do do (this isnt strict and we check
there actually *is* something to do).
*/
int
RemapPlugins::run_single_remap()
{
url_mapping * map = _s->url_map.getMapping();
remap_plugin_info * plugin = map->get_plugin(_cur); //get the nth plugin in our list of plugins
TSRemapStatus plugin_retcode = TSREMAP_NO_REMAP;
Debug("url_rewrite", "running single remap rule id %d for the %d%s time",
map->map_id, _cur, _cur == 1 ? "st" : _cur == 2 ? "nd" : _cur == 3 ? "rd" : "th");
// There might not be a plugin if we are a regular non-plugin map rule. In that case, we will fall through
// and do the default mapping and then stop.
if (plugin) {
plugin_retcode = run_plugin(plugin);
}
_cur++;
// If the plugin redirected, we need to end the remap chain now.
if (_s->remap_redirect) {
return 1;
}
if (TSREMAP_NO_REMAP == plugin_retcode || TSREMAP_NO_REMAP_STOP == plugin_retcode) {
// After running the first plugin, rewrite the request URL. This is doing the default rewrite rule
// to handle the case where no plugin ever rewrites.
//
// XXX we could probably optimize this a bit more by keeping a flag and only rewriting the request URL
// if no plugin has rewritten it already.
if (_cur == 1) {
Debug("url_rewrite", "plugin did not change host, port or path, copying from mapping rule");
url_rewrite_remap_request(_s->url_map, _request_url, _s->hdr_info.client_request.method_get_wksidx());
}
}
if (TSREMAP_NO_REMAP_STOP == plugin_retcode || TSREMAP_DID_REMAP_STOP == plugin_retcode) {
Debug("url_rewrite", "breaking remap plugin chain since last plugin said we should stop");
return 1;
}
if (_cur > MAX_REMAP_PLUGIN_CHAIN) {
Error("called %s more than %u times; stopping this remap insanity now", __func__, MAX_REMAP_PLUGIN_CHAIN);
return 1;
}
if (_cur >= map->_plugin_count) {
// Normally, we would callback into this function but we dont have anything more to do!
Debug("url_rewrite", "completed all remap plugins for rule id %d", map->map_id);
return 1;
}
Debug("url_rewrite", "completed single remap, attempting another via immediate callback");
return 0;
}
int
RemapPlugins::run_remap(int event, Event* e)
{
Debug("url_rewrite", "Inside RemapPlugins::run_remap with cur = %d", _cur);
ink_assert(action.continuation);
ink_assert(action.continuation);
int ret = 0;
/* make sure we weren't cancelled */
if (action.cancelled) {
mutex.clear();
pluginAllocator.free(this); //ugly
return EVENT_DONE;
}
switch (event) {
case EVENT_IMMEDIATE:
Debug("url_rewrite", "handling immediate event inside RemapPlugins::run_remap");
ret = run_single_remap();
/**
* If ret !=0 then we are done with this processor and we call back into the SM;
* otherwise, we call this function again immediately (which really isn't immediate)
* thru the eventProcessor, thus forcing another run of run_single_remap() which will
* then operate on _request_url, etc performing additional remaps (mainly another plugin run)
**/
if (ret) {
action.continuation->handleEvent(EVENT_REMAP_COMPLETE, NULL);
mutex.clear();
action.mutex.clear();
mutex = NULL;
action.mutex = NULL;
//THREAD_FREE(this, pluginAllocator, t);
pluginAllocator.free(this); //ugly
return EVENT_DONE;
} else {
e->schedule_imm(event);
return EVENT_CONT;
}
break;
default:
ink_assert(!"unknown event type");
break;
};
return EVENT_DONE;
}