| /** @file |
| |
| A brief file description |
| |
| @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. |
| */ |
| |
| /***************************************************************************** |
| * |
| * ControlMatcher.cc - Implementation of general purpose matcher |
| * |
| * |
| ****************************************************************************/ |
| |
| #include <sys/types.h> |
| |
| #include "tscore/ink_config.h" |
| #include "tscore/MatcherUtils.h" |
| #include "tscore/Tokenizer.h" |
| #include "tscore/ts_file.h" |
| #include "ProxyConfig.h" |
| #include "ControlMatcher.h" |
| #include "CacheControl.h" |
| #include "ParentSelection.h" |
| #include "tscore/HostLookup.h" |
| #include "HTTP.h" |
| #include "URL.h" |
| #include "P_EventSystem.h" |
| #include "P_Net.h" |
| #include "P_Cache.h" |
| #include "P_SplitDNS.h" |
| |
| /**************************************************************** |
| * Place all template instantiations at the bottom of the file |
| ****************************************************************/ |
| |
| // HttpRequestData accessors |
| // Can not be inlined due being virtual functions |
| // |
| char * |
| HttpRequestData::get_string() |
| { |
| char *str = hdr->url_string_get(nullptr); |
| |
| if (str) { |
| unescapifyStr(str); |
| } |
| return str; |
| } |
| |
| const char * |
| HttpRequestData::get_host() |
| { |
| return hostname_str; |
| } |
| |
| sockaddr const * |
| HttpRequestData::get_ip() |
| { |
| return &dest_ip.sa; |
| } |
| |
| sockaddr const * |
| HttpRequestData::get_client_ip() |
| { |
| return &src_ip.sa; |
| } |
| |
| /************************************************************* |
| * Begin class HostMatcher |
| *************************************************************/ |
| |
| template <class Data, class MatchResult> |
| HostMatcher<Data, MatchResult>::HostMatcher(const char *name, const char *filename) : BaseMatcher<Data>(name, filename) |
| { |
| host_lookup = new HostLookup(name); |
| } |
| |
| template <class Data, class MatchResult> HostMatcher<Data, MatchResult>::~HostMatcher() |
| { |
| delete host_lookup; |
| } |
| |
| // |
| // template <class Data,class MatchResult> |
| // void HostMatcher<Data,MatchResult>::Print() |
| // |
| // Debugging Method |
| // |
| template <class Data, class MatchResult> |
| void |
| HostMatcher<Data, MatchResult>::Print() const |
| { |
| printf("\tHost/Domain Matcher with %d elements\n", num_el); |
| host_lookup->Print(PrintFunc); |
| } |
| |
| // |
| // template <class Data,class MatchResult> |
| // void HostMatcher<Data,MatchResult>::PrintFunc(void* opaque_data) |
| // |
| // Debugging Method |
| // |
| template <class Data, class MatchResult> |
| void |
| HostMatcher<Data, MatchResult>::PrintFunc(void *opaque_data) |
| { |
| Data *d = (Data *)opaque_data; |
| d->Print(); |
| } |
| |
| // void HostMatcher<Data,MatchResult>::AllocateSpace(int num_entries) |
| // |
| // Allocates the the HostLeaf and Data arrays |
| // |
| template <class Data, class MatchResult> |
| void |
| HostMatcher<Data, MatchResult>::AllocateSpace(int num_entries) |
| { |
| // Should not have been allocated before |
| ink_assert(array_len == -1); |
| |
| host_lookup->AllocateSpace(num_entries); |
| |
| data_array = new Data[num_entries]; |
| array_len = num_entries; |
| num_el = 0; |
| } |
| |
| // void HostMatcher<Data,MatchResult>::Match(RequestData* rdata, MatchResult* result) |
| // |
| // Searches our tree and updates argresult for each element matching |
| // arg hostname |
| // |
| template <class Data, class MatchResult> |
| void |
| HostMatcher<Data, MatchResult>::Match(RequestData *rdata, MatchResult *result) const |
| { |
| void *opaque_ptr; |
| Data *data_ptr; |
| bool r; |
| |
| // Check to see if there is any work to do before making |
| // the string copy |
| if (num_el <= 0) { |
| return; |
| } |
| |
| HostLookupState s; |
| |
| r = host_lookup->MatchFirst(rdata->get_host(), &s, &opaque_ptr); |
| |
| while (r == true) { |
| ink_assert(opaque_ptr != nullptr); |
| data_ptr = (Data *)opaque_ptr; |
| data_ptr->UpdateMatch(result, rdata); |
| |
| r = host_lookup->MatchNext(&s, &opaque_ptr); |
| } |
| } |
| |
| // |
| // Result HostMatcher<Data,MatchResult>::NewEntry(bool domain_record, |
| // char* match_data, char* match_info, int line_num) |
| // |
| // Creates a new host/domain record |
| // |
| // If successful, returns NULL |
| // If not, returns a pointer to malloc allocated error string |
| // that the caller MUST DEALLOCATE |
| // |
| template <class Data, class MatchResult> |
| Result |
| HostMatcher<Data, MatchResult>::NewEntry(matcher_line *line_info) |
| { |
| Data *cur_d; |
| Result error = Result::ok(); |
| char *match_data; |
| |
| // Make sure space has been allocated |
| ink_assert(num_el >= 0); |
| ink_assert(array_len >= 0); |
| |
| // Make sure we do not overrun the array; |
| ink_assert(num_el < array_len); |
| |
| match_data = line_info->line[1][line_info->dest_entry]; |
| |
| // Make sure that the line_info is not bogus |
| ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS); |
| ink_assert(match_data != nullptr); |
| |
| // Remove our consumed label from the parsed line |
| line_info->line[0][line_info->dest_entry] = nullptr; |
| line_info->num_el--; |
| |
| // Fill in the parameter info |
| cur_d = data_array + num_el; |
| error = cur_d->Init(line_info); |
| if (error.failed()) { |
| // There was a problem so undo the effects this function |
| new (cur_d) Data(); // reconstruct |
| } else { |
| // Fill in the matching info |
| host_lookup->NewEntry(match_data, (line_info->type == MATCH_DOMAIN) ? true : false, cur_d); |
| num_el++; |
| } |
| |
| return error; |
| } |
| |
| /************************************************************* |
| * End class HostMatcher |
| *************************************************************/ |
| |
| // |
| // UrlMatcher<Data,MatchResult>::UrlMatcher() |
| // |
| template <class Data, class MatchResult> |
| UrlMatcher<Data, MatchResult>::UrlMatcher(const char *name, const char *filename) : BaseMatcher<Data>(name, filename) |
| { |
| } |
| |
| // |
| // UrlMatcher<Data,MatchResult>::~UrlMatcher() |
| // |
| template <class Data, class MatchResult> UrlMatcher<Data, MatchResult>::~UrlMatcher() |
| { |
| for (int i = 0; i < num_el; i++) { |
| ats_free(url_str[i]); |
| } |
| delete[] url_str; |
| delete[] url_value; |
| } |
| |
| // |
| // void UrlMatcher<Data,MatchResult>::Print() |
| // |
| // Debugging function |
| // |
| template <class Data, class MatchResult> |
| void |
| UrlMatcher<Data, MatchResult>::Print() const |
| { |
| printf("\tUrl Matcher with %d elements\n", num_el); |
| for (int i = 0; i < num_el; i++) { |
| printf("\t\tUrl: %s\n", url_str[i]); |
| data_array[i].Print(); |
| } |
| } |
| |
| // |
| // void UrlMatcher<Data,MatchResult>::AllocateSpace(int num_entries) |
| // |
| template <class Data, class MatchResult> |
| void |
| UrlMatcher<Data, MatchResult>::AllocateSpace(int num_entries) |
| { |
| // Should not have been allocated before |
| ink_assert(array_len == -1); |
| |
| data_array = new Data[num_entries]; |
| url_value = new int[num_entries]; |
| url_str = new char *[num_entries]; |
| memset(url_str, 0, sizeof(char *) * num_entries); |
| array_len = num_entries; |
| num_el = 0; |
| } |
| |
| // |
| // Result UrlMatcher<Data,MatchResult>::NewEntry(matcher_line* line_info) |
| // |
| template <class Data, class MatchResult> |
| Result |
| UrlMatcher<Data, MatchResult>::NewEntry(matcher_line *line_info) |
| { |
| Data *cur_d; |
| char *pattern; |
| Result error = Result::ok(); |
| |
| // Make sure space has been allocated |
| ink_assert(num_el >= 0); |
| ink_assert(array_len >= 0); |
| |
| // Make sure we do not overrun the array; |
| ink_assert(num_el < array_len); |
| |
| pattern = line_info->line[1][line_info->dest_entry]; |
| // Make sure that the line_info is not bogus |
| ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS); |
| ink_assert(pattern != nullptr); |
| |
| if (url_ht.find(pattern) != url_ht.end()) { |
| return Result::failure("%s url expression error (have exist) at line %d position", matcher_name, line_info->line_num); |
| } |
| |
| // Remove our consumed label from the parsed line |
| line_info->line[0][line_info->dest_entry] = nullptr; |
| line_info->num_el--; |
| |
| // Fill in the parameter info |
| cur_d = data_array + num_el; |
| error = cur_d->Init(line_info); |
| if (error.failed()) { |
| url_str[num_el] = ats_strdup(pattern); |
| url_value[num_el] = num_el; |
| url_ht.emplace(url_str[num_el], url_value[num_el]); |
| num_el++; |
| } |
| |
| return error; |
| } |
| |
| // |
| // void UrlMatcher<Data,MatchResult>::Match(RD* rdata, MatchResult* result) |
| // |
| // Coduncts a linear search through the regex array and |
| // updates arg result for each regex that matches arg URL |
| // |
| template <class Data, class MatchResult> |
| void |
| UrlMatcher<Data, MatchResult>::Match(RequestData *rdata, MatchResult *result) const |
| { |
| char *url_str; |
| |
| // Check to see there is any work to before we copy the |
| // URL |
| if (num_el <= 0) { |
| return; |
| } |
| |
| url_str = rdata->get_string(); |
| |
| // Can't do a regex match with a NULL string so |
| // use an empty one instead |
| if (url_str == nullptr) { |
| url_str = ats_strdup(""); |
| } |
| |
| if (auto it = url_ht.find(url_str); it != url_ht.end()) { |
| Debug("matcher", "%s Matched %s with url at line %d", matcher_name, url_str, data_array[it->second].line_num); |
| data_array[it->second].UpdateMatch(result, rdata); |
| } |
| |
| ats_free(url_str); |
| } |
| |
| // |
| // RegexMatcher<Data,MatchResult>::RegexMatcher() |
| // |
| template <class Data, class MatchResult> |
| RegexMatcher<Data, MatchResult>::RegexMatcher(const char *name, const char *filename) : BaseMatcher<Data>(name, filename) |
| { |
| } |
| |
| // |
| // RegexMatcher<Data,MatchResult>::~RegexMatcher() |
| // |
| template <class Data, class MatchResult> RegexMatcher<Data, MatchResult>::~RegexMatcher() |
| { |
| for (int i = 0; i < num_el; i++) { |
| pcre_free(re_array[i]); |
| ats_free(re_str[i]); |
| } |
| delete[] re_str; |
| ats_free(re_array); |
| } |
| |
| // |
| // void RegexMatcher<Data,MatchResult>::Print() const |
| // |
| // Debugging function |
| // |
| template <class Data, class MatchResult> |
| void |
| RegexMatcher<Data, MatchResult>::Print() const |
| { |
| printf("\tRegex Matcher with %d elements\n", num_el); |
| for (int i = 0; i < num_el; i++) { |
| printf("\t\tRegex: %s\n", re_str[i]); |
| data_array[i].Print(); |
| } |
| } |
| |
| // |
| // void RegexMatcher<Data,MatchResult>::AllocateSpace(int num_entries) |
| // |
| template <class Data, class MatchResult> |
| void |
| RegexMatcher<Data, MatchResult>::AllocateSpace(int num_entries) |
| { |
| // Should not have been allocated before |
| ink_assert(array_len == -1); |
| |
| re_array = static_cast<pcre **>(ats_malloc(sizeof(pcre *) * num_entries)); |
| memset(re_array, 0, sizeof(pcre *) * num_entries); |
| |
| data_array = new Data[num_entries]; |
| |
| re_str = new char *[num_entries]; |
| memset(re_str, 0, sizeof(char *) * num_entries); |
| |
| array_len = num_entries; |
| num_el = 0; |
| } |
| |
| // |
| // Result RegexMatcher<Data,MatchResult>::NewEntry(matcher_line* line_info) |
| // |
| template <class Data, class MatchResult> |
| Result |
| RegexMatcher<Data, MatchResult>::NewEntry(matcher_line *line_info) |
| { |
| Data *cur_d; |
| char *pattern; |
| const char *errptr; |
| int erroffset; |
| Result error = Result::ok(); |
| |
| // Make sure space has been allocated |
| ink_assert(num_el >= 0); |
| ink_assert(array_len >= 0); |
| |
| // Make sure we do not overrun the array; |
| ink_assert(num_el < array_len); |
| |
| pattern = line_info->line[1][line_info->dest_entry]; |
| // Make sure that the line_info is not bogus |
| ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS); |
| ink_assert(pattern != nullptr); |
| |
| // Create the compiled regular expression |
| re_array[num_el] = pcre_compile(pattern, 0, &errptr, &erroffset, nullptr); |
| if (!re_array[num_el]) { |
| return Result::failure("%s regular expression error at line %d position %d : %s", matcher_name, line_info->line_num, erroffset, |
| errptr); |
| } |
| re_str[num_el] = ats_strdup(pattern); |
| |
| // Remove our consumed label from the parsed line |
| line_info->line[0][line_info->dest_entry] = nullptr; |
| line_info->num_el--; |
| |
| // Fill in the parameter info |
| cur_d = data_array + num_el; |
| error = cur_d->Init(line_info); |
| |
| if (error.failed()) { |
| // There was a problem so undo the effects this function |
| ats_free(re_str[num_el]); |
| re_str[num_el] = nullptr; |
| pcre_free(re_array[num_el]); |
| re_array[num_el] = nullptr; |
| } else { |
| num_el++; |
| } |
| |
| return error; |
| } |
| |
| // |
| // void RegexMatcher<Data,MatchResult>::Match(RequestData* rdata, MatchResult* result) |
| // |
| // Coduncts a linear search through the regex array and |
| // updates arg result for each regex that matches arg URL |
| // |
| template <class Data, class MatchResult> |
| void |
| RegexMatcher<Data, MatchResult>::Match(RequestData *rdata, MatchResult *result) const |
| { |
| char *url_str; |
| int r; |
| |
| // Check to see there is any work to before we copy the |
| // URL |
| if (num_el <= 0) { |
| return; |
| } |
| |
| url_str = rdata->get_string(); |
| |
| // Can't do a regex match with a NULL string so |
| // use an empty one instead |
| if (url_str == nullptr) { |
| url_str = ats_strdup(""); |
| } |
| |
| // INKqa12980 |
| // The function unescapifyStr() is already called in |
| // HttpRequestData::get_string(); therefore, no need to call again here. |
| |
| for (int i = 0; i < num_el; i++) { |
| r = pcre_exec(re_array[i], nullptr, url_str, strlen(url_str), 0, 0, nullptr, 0); |
| if (r > -1) { |
| Debug("matcher", "%s Matched %s with regex at line %d", matcher_name, url_str, data_array[i].line_num); |
| data_array[i].UpdateMatch(result, rdata); |
| } else if (r < -1) { |
| // An error has occurred |
| Warning("Error [%d] matching regex at line %d.", r, data_array[i].line_num); |
| } // else it's -1 which means no match was found. |
| } |
| ats_free(url_str); |
| } |
| |
| // |
| // HostRegexMatcher<Data,MatchResult>::HostRegexMatcher() |
| // |
| template <class Data, class MatchResult> |
| HostRegexMatcher<Data, MatchResult>::HostRegexMatcher(const char *name, const char *filename) |
| : RegexMatcher<Data, MatchResult>(name, filename) |
| { |
| } |
| |
| // |
| // void HostRegexMatcher<Data,MatchResult>::Match(RequestData* rdata, MatchResult* result) |
| // |
| // Conducts a linear search through the regex array and |
| // updates arg result for each regex that matches arg host_regex |
| // |
| template <class Data, class MatchResult> |
| void |
| HostRegexMatcher<Data, MatchResult>::Match(RequestData *rdata, MatchResult *result) const |
| { |
| const char *url_str; |
| int r; |
| |
| // Check to see there is any work to before we copy the |
| // URL |
| if (this->num_el <= 0) { |
| return; |
| } |
| |
| url_str = rdata->get_host(); |
| |
| // Can't do a regex match with a NULL string so |
| // use an empty one instead |
| if (url_str == nullptr) { |
| url_str = ""; |
| } |
| for (int i = 0; i < this->num_el; i++) { |
| r = pcre_exec(this->re_array[i], nullptr, url_str, strlen(url_str), 0, 0, nullptr, 0); |
| if (r != -1) { |
| Debug("matcher", "%s Matched %s with regex at line %d", const_cast<char *>(this->matcher_name), url_str, |
| this->data_array[i].line_num); |
| this->data_array[i].UpdateMatch(result, rdata); |
| } else { |
| // An error has occurred |
| Warning("error matching regex at line %d", this->data_array[i].line_num); |
| } |
| } |
| } |
| |
| // |
| // IpMatcher<Data,MatchResult>::IpMatcher() |
| // |
| template <class Data, class MatchResult> |
| IpMatcher<Data, MatchResult>::IpMatcher(const char *name, const char *filename) : BaseMatcher<Data>(name, filename) |
| { |
| } |
| |
| // |
| // void IpMatcher<Data,MatchResult>::AllocateSpace(int num_entries) |
| // |
| template <class Data, class MatchResult> |
| void |
| IpMatcher<Data, MatchResult>::AllocateSpace(int num_entries) |
| { |
| // Should not have been allocated before |
| ink_assert(array_len == -1); |
| |
| data_array = new Data[num_entries]; |
| |
| array_len = num_entries; |
| num_el = 0; |
| } |
| |
| // |
| // Result IpMatcher<Data,MatchResult>::NewEntry(matcher_line* line_info) |
| // |
| // Inserts a range the ip lookup table. |
| // Creates new table levels as needed |
| // |
| // Returns NULL is all was OK. On error returns, a malloc |
| // allocated error string which the CALLEE is responsible |
| // for deallocating |
| // |
| template <class Data, class MatchResult> |
| Result |
| IpMatcher<Data, MatchResult>::NewEntry(matcher_line *line_info) |
| { |
| Data *cur_d; |
| const char *errptr; |
| char *match_data; |
| IpEndpoint addr1, addr2; |
| Result error = Result::ok(); |
| |
| // Make sure space has been allocated |
| ink_assert(num_el >= 0); |
| ink_assert(array_len >= 0); |
| |
| // Make sure we do not overrun the array; |
| ink_assert(num_el < array_len); |
| |
| match_data = line_info->line[1][line_info->dest_entry]; |
| |
| // Make sure that the line_info is not bogus |
| ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS); |
| ink_assert(match_data != nullptr); |
| |
| // Extract the IP range |
| errptr = ExtractIpRange(match_data, &addr1.sa, &addr2.sa); |
| if (errptr != nullptr) { |
| return Result::failure("%s %s at %s line %d", matcher_name, errptr, file_name, line_info->line_num); |
| } |
| |
| // Remove our consumed label from the parsed line |
| line_info->line[0][line_info->dest_entry] = nullptr; |
| line_info->num_el--; |
| |
| // Fill in the parameter info |
| cur_d = data_array + num_el; |
| error = cur_d->Init(line_info); |
| if (!error.failed()) { |
| ip_map.mark(&addr1.sa, &addr2.sa, cur_d); |
| ++num_el; |
| } |
| |
| return error; |
| } |
| |
| // |
| // void IpMatcherData,MatchResult>::Match(in_addr_t addr, RequestData* rdata, MatchResult* result) |
| // |
| template <class Data, class MatchResult> |
| void |
| IpMatcher<Data, MatchResult>::Match(sockaddr const *addr, RequestData *rdata, MatchResult *result) const |
| { |
| void *raw; |
| if (ip_map.contains(addr, &raw)) { |
| Data *cur = static_cast<Data *>(raw); |
| ink_assert(cur != nullptr); |
| cur->UpdateMatch(result, rdata); |
| } |
| } |
| |
| template <class Data, class MatchResult> |
| void |
| IpMatcher<Data, MatchResult>::Print() const |
| { |
| printf("\tIp Matcher with %d elements, %zu ranges.\n", num_el, ip_map.count()); |
| for (auto &spot : ip_map) { |
| char b1[INET6_ADDRSTRLEN], b2[INET6_ADDRSTRLEN]; |
| printf("\tRange %s - %s ", ats_ip_ntop(spot.min(), b1, sizeof b1), ats_ip_ntop(spot.max(), b2, sizeof b2)); |
| static_cast<Data *>(spot.data())->Print(); |
| } |
| } |
| |
| template <class Data, class MatchResult> |
| ControlMatcher<Data, MatchResult>::ControlMatcher(const char *file_var, const char *name, const matcher_tags *tags, int flags_in) |
| { |
| flags = flags_in; |
| ink_assert(flags & (ALLOW_HOST_TABLE | ALLOW_REGEX_TABLE | ALLOW_URL_TABLE | ALLOW_IP_TABLE)); |
| |
| config_tags = tags; |
| ink_assert(config_tags != nullptr); |
| |
| matcher_name = name; |
| config_file_path[0] = '\0'; |
| |
| if (!(flags & DONT_BUILD_TABLE)) { |
| ats_scoped_str config_path(RecConfigReadConfigPath(file_var)); |
| |
| ink_release_assert(config_path); |
| ink_strlcpy(config_file_path, config_path, sizeof(config_file_path)); |
| } |
| |
| reMatch = nullptr; |
| urlMatch = nullptr; |
| hostMatch = nullptr; |
| ipMatch = nullptr; |
| hrMatch = nullptr; |
| |
| if (!(flags & DONT_BUILD_TABLE)) { |
| m_numEntries = this->BuildTable(); |
| } else { |
| m_numEntries = 0; |
| } |
| } |
| |
| template <class Data, class MatchResult> ControlMatcher<Data, MatchResult>::~ControlMatcher() |
| { |
| delete reMatch; |
| delete urlMatch; |
| delete hostMatch; |
| delete ipMatch; |
| delete hrMatch; |
| } |
| |
| // void ControlMatcher<Data, MatchResult>::Print() |
| // |
| // Debugging method |
| // |
| template <class Data, class MatchResult> |
| void |
| ControlMatcher<Data, MatchResult>::Print() const |
| { |
| printf("Control Matcher Table: %s\n", matcher_name); |
| if (hostMatch != nullptr) { |
| hostMatch->Print(); |
| } |
| if (reMatch != nullptr) { |
| reMatch->Print(); |
| } |
| if (urlMatch != nullptr) { |
| urlMatch->Print(); |
| } |
| if (ipMatch != nullptr) { |
| ipMatch->Print(); |
| } |
| if (hrMatch != nullptr) { |
| hrMatch->Print(); |
| } |
| } |
| |
| // void ControlMatcher<Data, MatchResult>::Match(RequestData* rdata |
| // MatchResult* result) const |
| // |
| // Queries each table for the MatchResult* |
| // |
| template <class Data, class MatchResult> |
| void |
| ControlMatcher<Data, MatchResult>::Match(RequestData *rdata, MatchResult *result) const |
| { |
| if (hostMatch != nullptr) { |
| hostMatch->Match(rdata, result); |
| } |
| if (reMatch != nullptr) { |
| reMatch->Match(rdata, result); |
| } |
| if (urlMatch != nullptr) { |
| urlMatch->Match(rdata, result); |
| } |
| if (ipMatch != nullptr) { |
| ipMatch->Match(rdata->get_ip(), rdata, result); |
| } |
| if (hrMatch != nullptr) { |
| hrMatch->Match(rdata, result); |
| } |
| } |
| |
| // int ControlMatcher::BuildTable() |
| // |
| // Reads the cache.config file and build the records array |
| // from it |
| // |
| template <class Data, class MatchResult> |
| int |
| ControlMatcher<Data, MatchResult>::BuildTableFromString(char *file_buf) |
| { |
| // Table build locals |
| Tokenizer bufTok("\n"); |
| tok_iter_state i_state; |
| const char *tmp; |
| matcher_line *first = nullptr; |
| matcher_line *current; |
| matcher_line *last = nullptr; |
| int line_num = 0; |
| int second_pass = 0; |
| int numEntries = 0; |
| bool alarmAlready = false; |
| |
| // type counts |
| int hostDomain = 0; |
| int regex = 0; |
| int url = 0; |
| int ip = 0; |
| int hostregex = 0; |
| |
| if (bufTok.Initialize(file_buf, SHARE_TOKS | ALLOW_EMPTY_TOKS) == 0) { |
| // We have an empty file |
| return 0; |
| } |
| |
| // First get the number of entries |
| tmp = bufTok.iterFirst(&i_state); |
| while (tmp != nullptr) { |
| line_num++; |
| |
| // skip all blank spaces at beginning of line |
| while (*tmp && isspace(*tmp)) { |
| tmp++; |
| } |
| |
| if (*tmp != '#' && *tmp != '\0') { |
| const char *errptr; |
| |
| current = static_cast<matcher_line *>(ats_malloc(sizeof(matcher_line))); |
| errptr = parseConfigLine(const_cast<char *>(tmp), current, config_tags); |
| |
| if (errptr != nullptr) { |
| if (config_tags != &socks_server_tags) { |
| Result error = |
| Result::failure("%s discarding %s entry at line %d : %s", matcher_name, config_file_path, line_num, errptr); |
| SignalError(error.message(), alarmAlready); |
| } |
| ats_free(current); |
| } else { |
| // Line parsed ok. Figure out what the destination |
| // type is and link it into our list |
| numEntries++; |
| current->line_num = line_num; |
| |
| switch (current->type) { |
| case MATCH_HOST: |
| case MATCH_DOMAIN: |
| hostDomain++; |
| break; |
| case MATCH_IP: |
| ip++; |
| break; |
| case MATCH_REGEX: |
| regex++; |
| break; |
| case MATCH_URL: |
| url++; |
| break; |
| case MATCH_HOST_REGEX: |
| hostregex++; |
| break; |
| case MATCH_NONE: |
| default: |
| ink_assert(0); |
| } |
| |
| if (first == nullptr) { |
| ink_assert(last == nullptr); |
| first = last = current; |
| } else { |
| last->next = current; |
| last = current; |
| } |
| } |
| } |
| tmp = bufTok.iterNext(&i_state); |
| } |
| |
| // Make we have something to do before going on |
| if (numEntries == 0) { |
| ats_free(first); |
| return 0; |
| } |
| // Now allocate space for the record pointers |
| if ((flags & ALLOW_REGEX_TABLE) && regex > 0) { |
| reMatch = new RegexMatcher<Data, MatchResult>(matcher_name, config_file_path); |
| reMatch->AllocateSpace(regex); |
| } |
| |
| if ((flags & ALLOW_URL_TABLE) && url > 0) { |
| urlMatch = new UrlMatcher<Data, MatchResult>(matcher_name, config_file_path); |
| urlMatch->AllocateSpace(url); |
| } |
| |
| if ((flags & ALLOW_HOST_TABLE) && hostDomain > 0) { |
| hostMatch = new HostMatcher<Data, MatchResult>(matcher_name, config_file_path); |
| hostMatch->AllocateSpace(hostDomain); |
| } |
| |
| if ((flags & ALLOW_IP_TABLE) && ip > 0) { |
| ipMatch = new IpMatcher<Data, MatchResult>(matcher_name, config_file_path); |
| ipMatch->AllocateSpace(ip); |
| } |
| |
| if ((flags & ALLOW_HOST_REGEX_TABLE) && hostregex > 0) { |
| hrMatch = new HostRegexMatcher<Data, MatchResult>(matcher_name, config_file_path); |
| hrMatch->AllocateSpace(hostregex); |
| } |
| // Traverse the list and build the records table |
| current = first; |
| while (current != nullptr) { |
| Result error = Result::ok(); |
| |
| second_pass++; |
| if ((flags & ALLOW_HOST_TABLE) && current->type == MATCH_DOMAIN) { |
| error = hostMatch->NewEntry(current); |
| } else if ((flags & ALLOW_HOST_TABLE) && current->type == MATCH_HOST) { |
| error = hostMatch->NewEntry(current); |
| } else if ((flags & ALLOW_REGEX_TABLE) && current->type == MATCH_REGEX) { |
| error = reMatch->NewEntry(current); |
| } else if ((flags & ALLOW_URL_TABLE) && current->type == MATCH_URL) { |
| error = urlMatch->NewEntry(current); |
| } else if ((flags & ALLOW_IP_TABLE) && current->type == MATCH_IP) { |
| error = ipMatch->NewEntry(current); |
| } else if ((flags & ALLOW_HOST_REGEX_TABLE) && current->type == MATCH_HOST_REGEX) { |
| error = hrMatch->NewEntry(current); |
| } else { |
| error = |
| Result::failure("%s discarding %s entry with unknown type at line %d", matcher_name, config_file_path, current->line_num); |
| } |
| |
| // Check to see if there was an error in creating the NewEntry |
| if (error.failed()) { |
| SignalError(error.message(), alarmAlready); |
| } |
| |
| // Deallocate the parsing structure |
| last = current; |
| current = current->next; |
| ats_free(last); |
| } |
| |
| ink_assert(second_pass == numEntries); |
| |
| if (is_debug_tag_set("matcher")) { |
| Print(); |
| } |
| return numEntries; |
| } |
| |
| template <class Data, class MatchResult> |
| int |
| ControlMatcher<Data, MatchResult>::BuildTable() |
| { |
| std::error_code ec; |
| std::string content{ts::file::load(ts::file::path{config_file_path}, ec)}; |
| if (ec) { |
| switch (ec.value()) { |
| case ENOENT: |
| Warning("ControlMatcher - Cannot open config file: %s - %s", config_file_path, strerror(ec.value())); |
| break; |
| default: |
| Error("ControlMatcher - %s failed to load: %s", config_file_path, strerror(ec.value())); |
| return 1; |
| } |
| } |
| |
| return BuildTableFromString(content.data()); |
| } |
| |
| /**************************************************************** |
| * TEMPLATE INSTANTIATIONS GO HERE |
| * |
| ****************************************************************/ |
| |
| template class ControlMatcher<ParentRecord, ParentResult>; |
| template class HostMatcher<ParentRecord, ParentResult>; |
| template class RegexMatcher<ParentRecord, ParentResult>; |
| template class UrlMatcher<ParentRecord, ParentResult>; |
| template class IpMatcher<ParentRecord, ParentResult>; |
| template class HostRegexMatcher<ParentRecord, ParentResult>; |
| |
| template class ControlMatcher<SplitDNSRecord, SplitDNSResult>; |
| template class HostMatcher<SplitDNSRecord, SplitDNSResult>; |
| template class RegexMatcher<SplitDNSRecord, SplitDNSResult>; |
| template class UrlMatcher<SplitDNSRecord, SplitDNSResult>; |
| template class IpMatcher<SplitDNSRecord, SplitDNSResult>; |
| template class HostRegexMatcher<SplitDNSRecord, SplitDNSResult>; |
| |
| template class ControlMatcher<CacheControlRecord, CacheControlResult>; |
| template class HostMatcher<CacheControlRecord, CacheControlResult>; |
| template class RegexMatcher<CacheControlRecord, CacheControlResult>; |
| template class UrlMatcher<CacheControlRecord, CacheControlResult>; |
| template class IpMatcher<CacheControlRecord, CacheControlResult>; |