/src/trafficserver/include/proxy/http/remap/UrlRewrite.h
Line | Count | Source |
1 | | /** @file |
2 | | |
3 | | URL rewriting. |
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 | | #pragma once |
26 | | |
27 | | #include "iocore/eventsystem/Freer.h" |
28 | | #include "mgmt/config/ConfigContext.h" |
29 | | #include "proxy/http/remap/UrlMapping.h" |
30 | | #include "proxy/http/remap/UrlMappingPathIndex.h" |
31 | | #include "proxy/http/HttpTransact.h" |
32 | | #include "tsutil/Regex.h" |
33 | | #include "proxy/http/remap/PluginFactory.h" |
34 | | #include "proxy/http/remap/NextHopStrategyFactory.h" |
35 | | #include "proxy/http/remap/RemapConfig.h" |
36 | | |
37 | | #include <memory> |
38 | | |
39 | | #define URL_REMAP_FILTER_NONE 0x00000000 |
40 | 0 | #define URL_REMAP_FILTER_REFERER 0x00000001 /* enable "referer" header validation */ |
41 | 0 | #define URL_REMAP_FILTER_REDIRECT_FMT 0x00010000 /* enable redirect URL formatting */ |
42 | | |
43 | | /** |
44 | | |
45 | | * used for redirection, mapping, and reverse mapping |
46 | | **/ |
47 | | enum class mapping_type { |
48 | | FORWARD_MAP, |
49 | | REVERSE_MAP, |
50 | | PERMANENT_REDIRECT, |
51 | | TEMPORARY_REDIRECT, |
52 | | FORWARD_MAP_REFERER, |
53 | | FORWARD_MAP_WITH_RECV_PORT, |
54 | | NONE |
55 | | }; |
56 | | |
57 | | /** |
58 | | * |
59 | | **/ |
60 | | class UrlRewrite |
61 | | { |
62 | | public: |
63 | | using URLTable = std::unordered_map<std::string, UrlMappingPathIndex *>; |
64 | 0 | UrlRewrite() = default; |
65 | | ~UrlRewrite(); |
66 | | |
67 | | /** Retrieve the configured ACL matching policy. |
68 | | * |
69 | | * @param[out] policy The configured ACL behavior policy. |
70 | | * @return @c true if the policy is configured to an appropriate value, @c |
71 | | * false if not. |
72 | | */ |
73 | | static bool get_acl_behavior_policy(ACLBehaviorPolicy &policy); |
74 | | |
75 | | /** Load the configuration. |
76 | | * |
77 | | * This access data in librecords to obtain the information needed for loading the configuration. |
78 | | * |
79 | | * @return @c true if the instance state is valid, @c false if not. |
80 | | */ |
81 | | bool load(ConfigContext ctx = {}); |
82 | | |
83 | | /** Build the tables from @a path, or from @a remap_node when it is set. |
84 | | * |
85 | | * @param path Configuration file to parse. Ignored when @a remap_node is set, so inline callers pass it empty. |
86 | | * @param remap_node Inline remap.yaml style rule sequence, or @c nullptr to parse @a path. |
87 | | * @param ctx ConfigContext for reload status tracking. |
88 | | */ |
89 | | bool load_table(const std::string &path, YAML::Node const *remap_node, ConfigContext ctx = {}); |
90 | | |
91 | | /** Build the internal url write tables. |
92 | | * |
93 | | * @param path Path to configuration file. |
94 | | * @param ctx ConfigContext for reload status tracking. |
95 | | * @return 0 on success, non-zero error code on failure. |
96 | | */ |
97 | | int BuildTable(const char *path, YAML::Node const *remap_node = nullptr, ConfigContext ctx = {}); |
98 | | |
99 | | mapping_type Remap_redirect(HTTPHdr *request_header, URL *redirect_url); |
100 | | bool ReverseMap(HTTPHdr *response_header); |
101 | | void SetReverseFlag(int flag); |
102 | | void Print() const; |
103 | | |
104 | | bool |
105 | | is_valid() const |
106 | 0 | { |
107 | 0 | return _valid; |
108 | 0 | }; |
109 | | |
110 | | bool |
111 | | is_remap_yaml() const |
112 | 0 | { |
113 | 0 | return _remap_yaml; |
114 | 0 | }; |
115 | | |
116 | | void |
117 | | set_remap_yaml(bool yaml) |
118 | 0 | { |
119 | 0 | _remap_yaml = yaml; |
120 | 0 | }; |
121 | | |
122 | | /// @return Number of rules defined. |
123 | | int |
124 | | rule_count() const |
125 | 0 | { |
126 | 0 | return num_rules_forward + num_rules_reverse + num_rules_redirect_permanent + num_rules_redirect_temporary + |
127 | 0 | num_rules_forward_with_recv_port; |
128 | 0 | } |
129 | | |
130 | | static constexpr int MAX_REGEX_SUBS = 10; |
131 | | |
132 | | struct RegexMapping { |
133 | | url_mapping *url_map; |
134 | | Regex regular_expression; |
135 | | |
136 | | // we store the host-string-to-substitute here; if a match is found, |
137 | | // the substitutions are made and the resulting url is stored |
138 | | // directly in toURL's host field |
139 | | char *to_url_host_template; |
140 | | int to_url_host_template_len; |
141 | | |
142 | | // stores the number of substitutions |
143 | | int n_substitutions; |
144 | | |
145 | | // these two together point to template string places where |
146 | | // substitutions need to be made and the matching substring |
147 | | // to use |
148 | | int substitution_markers[MAX_REGEX_SUBS]; |
149 | | int substitution_ids[MAX_REGEX_SUBS]; |
150 | | |
151 | | LINK(RegexMapping, link); |
152 | | }; |
153 | | |
154 | | using RegexMappingList = Queue<RegexMapping>; |
155 | | |
156 | | struct MappingsStore { |
157 | | std::unique_ptr<URLTable> hash_lookup; |
158 | | RegexMappingList regex_list; |
159 | | bool |
160 | | empty() |
161 | 0 | { |
162 | 0 | return ((hash_lookup == nullptr) && regex_list.empty()); |
163 | 0 | } |
164 | | }; |
165 | | |
166 | | void PerformACLFiltering(HttpTransact::State *s, const url_mapping *const mapping); |
167 | | void PrintStore(const MappingsStore &store) const; |
168 | | std::string PrintRemapHits(); |
169 | | std::string PrintRemapHitsStore(MappingsStore &store); |
170 | | |
171 | | void |
172 | | DestroyStore(MappingsStore &store) |
173 | 0 | { |
174 | 0 | _destroyTable(store.hash_lookup); |
175 | 0 | _destroyList(store.regex_list); |
176 | 0 | } |
177 | | |
178 | | bool InsertForwardMapping(mapping_type maptype, url_mapping *mapping, const char *src_host); |
179 | | bool InsertMapping(mapping_type maptype, url_mapping *new_mapping, RegexMapping *reg_map, const char *src_host, |
180 | | bool is_cur_mapping_regex); |
181 | | |
182 | | bool TableInsert(std::unique_ptr<URLTable> &h_table, url_mapping *mapping, const char *src_host); |
183 | | |
184 | | MappingsStore forward_mappings; |
185 | | MappingsStore reverse_mappings; |
186 | | MappingsStore permanent_redirects; |
187 | | MappingsStore temporary_redirects; |
188 | | MappingsStore forward_mappings_with_recv_port; |
189 | | |
190 | | bool |
191 | | forwardMappingLookup(URL *request_url, int request_port, const char *request_host, int request_host_len, |
192 | | UrlMappingContainer &mapping_container) |
193 | 0 | { |
194 | 0 | return _mappingLookup(forward_mappings, request_url, request_port, request_host, request_host_len, mapping_container); |
195 | 0 | } |
196 | | bool |
197 | | reverseMappingLookup(URL *request_url, int request_port, const char *request_host, int request_host_len, |
198 | | UrlMappingContainer &mapping_container) |
199 | 0 | { |
200 | 0 | return _mappingLookup(reverse_mappings, request_url, request_port, request_host, request_host_len, mapping_container); |
201 | 0 | } |
202 | | bool |
203 | | permanentRedirectLookup(URL *request_url, int request_port, const char *request_host, int request_host_len, |
204 | | UrlMappingContainer &mapping_container) |
205 | 0 | { |
206 | 0 | return _mappingLookup(permanent_redirects, request_url, request_port, request_host, request_host_len, mapping_container); |
207 | 0 | } |
208 | | bool |
209 | | temporaryRedirectLookup(URL *request_url, int request_port, const char *request_host, int request_host_len, |
210 | | UrlMappingContainer &mapping_container) |
211 | 0 | { |
212 | 0 | return _mappingLookup(temporary_redirects, request_url, request_port, request_host, request_host_len, mapping_container); |
213 | 0 | } |
214 | | bool |
215 | | forwardMappingWithRecvPortLookup(URL *request_url, int recv_port, const char *request_host, int request_host_len, |
216 | | UrlMappingContainer &mapping_container) |
217 | 0 | { |
218 | 0 | return _mappingLookup(forward_mappings_with_recv_port, request_url, recv_port, request_host, request_host_len, |
219 | 0 | mapping_container); |
220 | 0 | } |
221 | | |
222 | | int nohost_rules = 0; |
223 | | int reverse_proxy = 0; |
224 | | |
225 | | char *ts_name = nullptr; // Used to send redirects when no host info |
226 | | |
227 | | char *http_default_redirect_url = nullptr; // Used if redirect in "referer" filtering was not defined properly |
228 | | int num_rules_forward = 0; |
229 | | int num_rules_reverse = 0; |
230 | | int num_rules_redirect_permanent = 0; |
231 | | int num_rules_redirect_temporary = 0; |
232 | | int num_rules_forward_with_recv_port = 0; |
233 | | |
234 | | PluginFactory pluginFactory; |
235 | | NextHopStrategyFactory *strategyFactory = nullptr; |
236 | | |
237 | | private: |
238 | | bool _valid = false; |
239 | | bool _remap_yaml = false; |
240 | | ACLBehaviorPolicy _acl_behavior_policy = ACLBehaviorPolicy::ACL_BEHAVIOR_LEGACY; |
241 | | |
242 | | bool _mappingLookup(MappingsStore &mappings, URL *request_url, int request_port, const char *request_host, int request_host_len, |
243 | | UrlMappingContainer &mapping_container); |
244 | | url_mapping *_tableLookup(std::unique_ptr<URLTable> &h_table, URL *request_url, int request_port, char *request_host, |
245 | | int request_host_len); |
246 | | bool _regexMappingLookup(RegexMappingList ®ex_mappings, URL *request_url, int request_port, const char *request_host, |
247 | | int request_host_len, int rank_ceiling, UrlMappingContainer &mapping_container); |
248 | | int _expandSubstitutions(size_t *matches_info, const RegexMapping *reg_map, const char *matched_string, char *dest_buf, |
249 | | int dest_buf_size); |
250 | | void _destroyTable(std::unique_ptr<URLTable> &h_table); |
251 | | void _destroyList(RegexMappingList ®exes); |
252 | | inline bool _addToStore(MappingsStore &store, url_mapping *new_mapping, RegexMapping *reg_map, const char *src_host, |
253 | | bool is_cur_mapping_regex, int &count); |
254 | | }; |
255 | | |
256 | | void url_rewrite_remap_request(const UrlMappingContainer &mapping_container, URL *request_url, int scheme = -1); |
257 | | |
258 | | mapping_type get_mapping_type(const char *type_str, BUILD_TABLE_INFO *bti); |
259 | | |
260 | | bool process_regex_mapping_config(const char *from_host_lower, url_mapping *new_mapping, UrlRewrite::RegexMapping *reg_map); |