| /** @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(RemapPluginInst *plugin) |
| { |
| ink_assert(_s); |
| |
| TSRemapStatus plugin_retcode; |
| TSRemapRequestInfo rri; |
| 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; |
| |
| // Prepare State for the future |
| if (_cur == 0) { |
| _s->os_response_plugin_inst = plugin; |
| } |
| |
| plugin_retcode = plugin->doRemap(reinterpret_cast<TSHttpTxn>(_s->state_machine), &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(nullptr); |
| } |
| |
| 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). |
| |
| */ |
| bool |
| RemapPlugins::run_single_remap() |
| { |
| url_mapping *map = _s->url_map.getMapping(); |
| RemapPluginInst *plugin = map->get_plugin_instance(_cur); // get the nth plugin in our list of plugins |
| TSRemapStatus plugin_retcode = TSREMAP_NO_REMAP; |
| bool zret = true; // default - last iteration. |
| 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"); |
| |
| if (0 == _cur) { |
| Debug("url_rewrite", "setting the remapped url by copying from mapping rule"); |
| url_rewrite_remap_request(_s->url_map, _request_url, _s->hdr_info.client_request.method_get_wksidx()); |
| } |
| |
| // 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. Otherwise see what's next. |
| if (!_s->remap_redirect) { |
| if (TSREMAP_DID_REMAP_STOP == plugin_retcode || TSREMAP_DID_REMAP == plugin_retcode) { |
| ++_rewritten; |
| } |
| |
| 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 after %d rewrites", _rewritten); |
| } else if (_cur >= map->plugin_instance_count()) { |
| Debug("url_rewrite", "completed all remap plugins for rule id %d, changed by %d plugins", map->map_id, _rewritten); |
| } else { |
| Debug("url_rewrite", "completed single remap, attempting another via immediate callback"); |
| zret = false; // not done yet. |
| } |
| } |
| return zret; |
| } |
| |
| 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); |
| |
| /* 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"); |
| /** |
| * If @c run_single_remap returns @c true 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 (run_single_remap()) { |
| action.continuation->handleEvent(EVENT_REMAP_COMPLETE, nullptr); |
| mutex.clear(); |
| action.mutex.clear(); |
| mutex = nullptr; |
| action.mutex = nullptr; |
| // 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; |
| } |