1 /** @file
2
3 Class to execute one (or more) remap plugin(s).
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 */
24
25 #include "RemapPlugins.h"
26
27 ClassAllocator<RemapPlugins> pluginAllocator("RemapPluginsAlloc");
28
29 TSRemapStatus
run_plugin(RemapPluginInst * plugin)30 RemapPlugins::run_plugin(RemapPluginInst *plugin)
31 {
32 ink_assert(_s);
33
34 TSRemapStatus plugin_retcode;
35 TSRemapRequestInfo rri;
36 URL *map_from = _s->url_map.getFromURL();
37 URL *map_to = _s->url_map.getToURL();
38
39 // This is the equivalent of TSHttpTxnClientReqGet(), which every remap plugin would
40 // have to call.
41 rri.requestBufp = reinterpret_cast<TSMBuffer>(_request_header);
42 rri.requestHdrp = reinterpret_cast<TSMLoc>(_request_header->m_http);
43
44 // Read-only URL's (TSMLoc's to the SDK)
45 rri.mapFromUrl = reinterpret_cast<TSMLoc>(map_from->m_url_impl);
46 rri.mapToUrl = reinterpret_cast<TSMLoc>(map_to->m_url_impl);
47 rri.requestUrl = reinterpret_cast<TSMLoc>(_request_url->m_url_impl);
48
49 rri.redirect = 0;
50
51 // Prepare State for the future
52 if (_cur == 0) {
53 _s->os_response_plugin_inst = plugin;
54 }
55
56 plugin_retcode = plugin->doRemap(reinterpret_cast<TSHttpTxn>(_s->state_machine), &rri);
57 // TODO: Deal with negative return codes here
58 if (plugin_retcode < 0) {
59 plugin_retcode = TSREMAP_NO_REMAP;
60 }
61
62 // First step after plugin remap must be "redirect url" check
63 if ((TSREMAP_DID_REMAP == plugin_retcode || TSREMAP_DID_REMAP_STOP == plugin_retcode) && rri.redirect) {
64 _s->remap_redirect = _request_url->string_get(nullptr);
65 }
66
67 return plugin_retcode;
68 }
69
70 /**
71 This is the equivalent of the old DoRemap().
72
73 @return 1 when you are done doing crap (otherwise, you get re-called
74 with schedule_imm and i hope you have something more to do), else
75 0 if you have something more do do (this isn't strict and we check
76 there actually *is* something to do).
77
78 */
79 bool
run_single_remap()80 RemapPlugins::run_single_remap()
81 {
82 url_mapping *map = _s->url_map.getMapping();
83 RemapPluginInst *plugin = map->get_plugin_instance(_cur); // get the nth plugin in our list of plugins
84 TSRemapStatus plugin_retcode = TSREMAP_NO_REMAP;
85 bool zret = true; // default - last iteration.
86 Debug("url_rewrite", "running single remap rule id %d for the %d%s time", map->map_id, _cur,
87 _cur == 1 ? "st" : _cur == 2 ? "nd" : _cur == 3 ? "rd" : "th");
88
89 if (0 == _cur) {
90 Debug("url_rewrite", "setting the remapped url by copying from mapping rule");
91 url_rewrite_remap_request(_s->url_map, _request_url, _s->hdr_info.client_request.method_get_wksidx());
92 }
93
94 // There might not be a plugin if we are a regular non-plugin map rule. In that case, we will fall through
95 // and do the default mapping and then stop.
96 if (plugin) {
97 plugin_retcode = run_plugin(plugin);
98 }
99
100 ++_cur;
101
102 // If the plugin redirected, we need to end the remap chain now. Otherwise see what's next.
103 if (!_s->remap_redirect) {
104 if (TSREMAP_DID_REMAP_STOP == plugin_retcode || TSREMAP_DID_REMAP == plugin_retcode) {
105 ++_rewritten;
106 }
107
108 if (TSREMAP_NO_REMAP_STOP == plugin_retcode || TSREMAP_DID_REMAP_STOP == plugin_retcode) {
109 Debug("url_rewrite", "breaking remap plugin chain since last plugin said we should stop after %d rewrites", _rewritten);
110 } else if (_cur >= map->plugin_instance_count()) {
111 Debug("url_rewrite", "completed all remap plugins for rule id %d, changed by %d plugins", map->map_id, _rewritten);
112 } else {
113 Debug("url_rewrite", "completed single remap, attempting another via immediate callback");
114 zret = false; // not done yet.
115 }
116 }
117 return zret;
118 }
119
120 int
run_remap(int event,Event * e)121 RemapPlugins::run_remap(int event, Event *e)
122 {
123 Debug("url_rewrite", "Inside RemapPlugins::run_remap with cur = %d", _cur);
124
125 ink_assert(action.continuation);
126 ink_assert(action.continuation);
127
128 /* make sure we weren't cancelled */
129 if (action.cancelled) {
130 mutex.clear();
131 pluginAllocator.free(this); // ugly
132 return EVENT_DONE;
133 }
134
135 switch (event) {
136 case EVENT_IMMEDIATE:
137 Debug("url_rewrite", "handling immediate event inside RemapPlugins::run_remap");
138 /**
139 * If @c run_single_remap returns @c true then we are done with this processor and we call back
140 * into the SM; otherwise, we call this function again immediately (which really isn't
141 * immediate) thru the eventProcessor, thus forcing another run of run_single_remap() which will
142 * then operate on _request_url, etc performing additional remaps (mainly another plugin run)
143 *
144 **/
145 if (run_single_remap()) {
146 action.continuation->handleEvent(EVENT_REMAP_COMPLETE, nullptr);
147 mutex.clear();
148 action.mutex.clear();
149 mutex = nullptr;
150 action.mutex = nullptr;
151 // THREAD_FREE(this, pluginAllocator, t);
152 pluginAllocator.free(this); // ugly
153 return EVENT_DONE;
154 } else {
155 e->schedule_imm(event);
156 return EVENT_CONT;
157 }
158
159 break;
160 default:
161 ink_assert(!"unknown event type");
162 break;
163 };
164 return EVENT_DONE;
165 }
166