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 "tscore/ink_config.h"
28 #include "UrlMapping.h"
29 #include "UrlMappingPathIndex.h"
30 #include "HttpTransact.h"
31 #include "tscore/Regex.h"
32 #include "PluginFactory.h"
33 #include "NextHopStrategyFactory.h"
34 
35 #include <memory>
36 
37 #define URL_REMAP_FILTER_NONE 0x00000000
38 #define URL_REMAP_FILTER_REFERER 0x00000001      /* enable "referer" header validation */
39 #define URL_REMAP_FILTER_REDIRECT_FMT 0x00010000 /* enable redirect URL formatting */
40 
41 struct BUILD_TABLE_INFO;
42 
43 /**
44  * used for redirection, mapping, and reverse mapping
45  **/
46 enum mapping_type {
47   FORWARD_MAP,
48   REVERSE_MAP,
49   PERMANENT_REDIRECT,
50   TEMPORARY_REDIRECT,
51   FORWARD_MAP_REFERER,
52   FORWARD_MAP_WITH_RECV_PORT,
53   NONE
54 };
55 
56 /**
57  *
58  **/
59 class UrlRewrite : public RefCountObj
60 {
61 public:
62   using URLTable = std::unordered_map<std::string, UrlMappingPathIndex *>;
63   UrlRewrite()   = default;
64   ~UrlRewrite() override;
65 
66   /** Load the configuration.
67    *
68    * This access data in librecords to obtain the information needed for loading the configuration.
69    *
70    * @return @c true if the instance state is valid, @c false if not.
71    */
72   bool load();
73 
74   /** Build the internal url write tables.
75    *
76    * @param path Path to configuration file.
77    * @return 0 on success, non-zero error code on failure.
78    */
79   int BuildTable(const char *path);
80 
81   mapping_type Remap_redirect(HTTPHdr *request_header, URL *redirect_url);
82   bool ReverseMap(HTTPHdr *response_header);
83   void SetReverseFlag(int flag);
84   void Print() const;
85 
86   // The UrlRewrite object is-a RefCountObj, but this is a convenience to make it clear that we
87   // don't delete() these objects directly, but via the release() method only.
88   UrlRewrite *
acquire()89   acquire()
90   {
91     this->refcount_inc();
92     return this;
93   }
94 
95   void
release()96   release()
97   {
98     if (0 == this->refcount_dec()) {
99       // Delete this on an ET_TASK thread, which avoids doing potentially slow things on an ET_NET thread.
100       Debug("url_rewrite", "Deleting old configuration immediately");
101       new_Deleter(this, 0);
102     }
103   }
104 
105   bool
is_valid()106   is_valid() const
107   {
108     return _valid;
109   };
110 
111   static constexpr int MAX_REGEX_SUBS = 10;
112 
113   struct RegexMapping {
114     url_mapping *url_map;
115     Regex regular_expression;
116 
117     // we store the host-string-to-substitute here; if a match is found,
118     // the substitutions are made and the resulting url is stored
119     // directly in toURL's host field
120     char *to_url_host_template;
121     int to_url_host_template_len;
122 
123     // stores the number of substitutions
124     int n_substitutions;
125 
126     // these two together point to template string places where
127     // substitutions need to be made and the matching substring
128     // to use
129     int substitution_markers[MAX_REGEX_SUBS];
130     int substitution_ids[MAX_REGEX_SUBS];
131 
132     LINK(RegexMapping, link);
133   };
134 
135   typedef Queue<RegexMapping> RegexMappingList;
136 
137   struct MappingsStore {
138     std::unique_ptr<URLTable> hash_lookup;
139     RegexMappingList regex_list;
140     bool
emptyMappingsStore141     empty()
142     {
143       return ((hash_lookup == nullptr) && regex_list.empty());
144     }
145   };
146 
147   void PerformACLFiltering(HttpTransact::State *s, url_mapping *mapping);
148   void PrintStore(const MappingsStore &store) const;
149 
150   void
DestroyStore(MappingsStore & store)151   DestroyStore(MappingsStore &store)
152   {
153     _destroyTable(store.hash_lookup);
154     _destroyList(store.regex_list);
155   }
156 
157   bool InsertForwardMapping(mapping_type maptype, url_mapping *mapping, const char *src_host);
158   bool InsertMapping(mapping_type maptype, url_mapping *new_mapping, RegexMapping *reg_map, const char *src_host,
159                      bool is_cur_mapping_regex);
160 
161   bool TableInsert(std::unique_ptr<URLTable> &h_table, url_mapping *mapping, const char *src_host);
162 
163   MappingsStore forward_mappings;
164   MappingsStore reverse_mappings;
165   MappingsStore permanent_redirects;
166   MappingsStore temporary_redirects;
167   MappingsStore forward_mappings_with_recv_port;
168 
169   bool
forwardMappingLookup(URL * request_url,int request_port,const char * request_host,int request_host_len,UrlMappingContainer & mapping_container)170   forwardMappingLookup(URL *request_url, int request_port, const char *request_host, int request_host_len,
171                        UrlMappingContainer &mapping_container)
172   {
173     return _mappingLookup(forward_mappings, request_url, request_port, request_host, request_host_len, mapping_container);
174   }
175   bool
reverseMappingLookup(URL * request_url,int request_port,const char * request_host,int request_host_len,UrlMappingContainer & mapping_container)176   reverseMappingLookup(URL *request_url, int request_port, const char *request_host, int request_host_len,
177                        UrlMappingContainer &mapping_container)
178   {
179     return _mappingLookup(reverse_mappings, request_url, request_port, request_host, request_host_len, mapping_container);
180   }
181   bool
permanentRedirectLookup(URL * request_url,int request_port,const char * request_host,int request_host_len,UrlMappingContainer & mapping_container)182   permanentRedirectLookup(URL *request_url, int request_port, const char *request_host, int request_host_len,
183                           UrlMappingContainer &mapping_container)
184   {
185     return _mappingLookup(permanent_redirects, request_url, request_port, request_host, request_host_len, mapping_container);
186   }
187   bool
temporaryRedirectLookup(URL * request_url,int request_port,const char * request_host,int request_host_len,UrlMappingContainer & mapping_container)188   temporaryRedirectLookup(URL *request_url, int request_port, const char *request_host, int request_host_len,
189                           UrlMappingContainer &mapping_container)
190   {
191     return _mappingLookup(temporary_redirects, request_url, request_port, request_host, request_host_len, mapping_container);
192   }
193   bool
forwardMappingWithRecvPortLookup(URL * request_url,int recv_port,const char * request_host,int request_host_len,UrlMappingContainer & mapping_container)194   forwardMappingWithRecvPortLookup(URL *request_url, int recv_port, const char *request_host, int request_host_len,
195                                    UrlMappingContainer &mapping_container)
196   {
197     return _mappingLookup(forward_mappings_with_recv_port, request_url, recv_port, request_host, request_host_len,
198                           mapping_container);
199   }
200 
201   int nohost_rules  = 0;
202   int reverse_proxy = 0;
203 
204   char *ts_name = nullptr; // Used to send redirects when no host info
205 
206   char *http_default_redirect_url      = nullptr; // Used if redirect in "referer" filtering was not defined properly
207   int num_rules_forward                = 0;
208   int num_rules_reverse                = 0;
209   int num_rules_redirect_permanent     = 0;
210   int num_rules_redirect_temporary     = 0;
211   int num_rules_forward_with_recv_port = 0;
212 
213   PluginFactory pluginFactory;
214   NextHopStrategyFactory *strategyFactory = nullptr;
215 
216 private:
217   bool _valid = false;
218 
219   bool _mappingLookup(MappingsStore &mappings, URL *request_url, int request_port, const char *request_host, int request_host_len,
220                       UrlMappingContainer &mapping_container);
221   url_mapping *_tableLookup(std::unique_ptr<URLTable> &h_table, URL *request_url, int request_port, char *request_host,
222                             int request_host_len);
223   bool _regexMappingLookup(RegexMappingList &regex_mappings, URL *request_url, int request_port, const char *request_host,
224                            int request_host_len, int rank_ceiling, UrlMappingContainer &mapping_container);
225   int _expandSubstitutions(int *matches_info, const RegexMapping *reg_map, const char *matched_string, char *dest_buf,
226                            int dest_buf_size);
227   void _destroyTable(std::unique_ptr<URLTable> &h_table);
228   void _destroyList(RegexMappingList &regexes);
229   inline bool _addToStore(MappingsStore &store, url_mapping *new_mapping, RegexMapping *reg_map, const char *src_host,
230                           bool is_cur_mapping_regex, int &count);
231 };
232 
233 void url_rewrite_remap_request(const UrlMappingContainer &mapping_container, URL *request_url, int scheme = -1);
234