00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "UrlRewrite.h"
00025 #include "ProxyConfig.h"
00026 #include "ReverseProxy.h"
00027 #include "UrlMappingPathIndex.h"
00028 #include "RemapConfig.h"
00029 #include "I_Layout.h"
00030 
00031 #define modulePrefix "[ReverseProxy]"
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 static void
00043 SetHomePageRedirectFlag(url_mapping *new_mapping, URL &new_to_url)
00044 {
00045   int fromLen, toLen;
00046   const char *from_path = new_mapping->fromURL.path_get(&fromLen);
00047   const char *to_path = new_to_url.path_get(&toLen);
00048 
00049   new_mapping->homePageRedirect = (from_path && !to_path) ? true : false;
00050 }
00051 
00052 
00053 
00054 
00055 UrlRewrite::UrlRewrite()
00056  : nohost_rules(0), reverse_proxy(0), backdoor_enabled(0),
00057    mgmt_autoconf_port(0), default_to_pac(0), default_to_pac_port(0), ts_name(NULL),
00058    http_default_redirect_url(NULL), num_rules_forward(0), num_rules_reverse(0), num_rules_redirect_permanent(0),
00059    num_rules_redirect_temporary(0), num_rules_forward_with_recv_port(0), _valid(false)
00060 {
00061 
00062   forward_mappings.hash_lookup = reverse_mappings.hash_lookup =
00063     permanent_redirects.hash_lookup = temporary_redirects.hash_lookup =
00064     forward_mappings_with_recv_port.hash_lookup = NULL;
00065 
00066   char * config_file = NULL;
00067   char * config_file_path = NULL;
00068 
00069   REC_ReadConfigStringAlloc(config_file, "proxy.config.url_remap.filename");
00070   if (config_file == NULL) {
00071     pmgmt->signalManager(MGMT_SIGNAL_CONFIG_ERROR, "Unable to find proxy.config.url_remap.filename");
00072     Warning("%s Unable to locate remap.config.  No remappings in effect", modulePrefix);
00073     return;
00074   }
00075 
00076   this->ts_name = NULL;
00077   REC_ReadConfigStringAlloc(this->ts_name, "proxy.config.proxy_name");
00078   if (this->ts_name == NULL) {
00079     pmgmt->signalManager(MGMT_SIGNAL_CONFIG_ERROR, "Unable to read proxy.config.proxy_name");
00080     Warning("%s Unable to determine proxy name.  Incorrect redirects could be generated", modulePrefix);
00081     this->ts_name = ats_strdup("");
00082   }
00083 
00084   this->http_default_redirect_url = NULL;
00085   REC_ReadConfigStringAlloc(this->http_default_redirect_url, "proxy.config.http.referer_default_redirect");
00086   if (this->http_default_redirect_url == NULL) {
00087     pmgmt->signalManager(MGMT_SIGNAL_CONFIG_ERROR, "Unable to read proxy.config.http.referer_default_redirect");
00088     Warning("%s Unable to determine default redirect url for \"referer\" filter.", modulePrefix);
00089     this->http_default_redirect_url = ats_strdup("http://www.apache.org");
00090   }
00091 
00092   REC_ReadConfigInteger(reverse_proxy, "proxy.config.reverse_proxy.enabled");
00093   REC_ReadConfigInteger(mgmt_autoconf_port, "proxy.config.admin.autoconf_port");
00094   REC_ReadConfigInteger(default_to_pac, "proxy.config.url_remap.default_to_server_pac");
00095   REC_ReadConfigInteger(default_to_pac_port, "proxy.config.url_remap.default_to_server_pac_port");
00096   REC_ReadConfigInteger(url_remap_mode, "proxy.config.url_remap.url_remap_mode");
00097   REC_ReadConfigInteger(backdoor_enabled, "proxy.config.url_remap.handle_backdoor_urls");
00098 
00099   config_file_path = Layout::relative_to(Layout::get()->sysconfdir, config_file);
00100 
00101   if (0 == this->BuildTable(config_file_path)) {
00102     _valid = true;
00103     if (is_debug_tag_set("url_rewrite")) {
00104       Print();
00105     }
00106   } else {
00107     Warning("something failed during BuildTable() -- check your remap plugins!");
00108   }
00109 
00110   ats_free(config_file_path);
00111   ats_free(config_file);
00112 }
00113 
00114 UrlRewrite::~UrlRewrite()
00115 {
00116   ats_free(this->ts_name);
00117   ats_free(this->http_default_redirect_url);
00118 
00119   DestroyStore(forward_mappings);
00120   DestroyStore(reverse_mappings);
00121   DestroyStore(permanent_redirects);
00122   DestroyStore(temporary_redirects);
00123   DestroyStore(forward_mappings_with_recv_port);
00124   _valid = false;
00125 }
00126 
00127 
00128 void
00129 UrlRewrite::SetReverseFlag(int flag)
00130 {
00131   reverse_proxy = flag;
00132   if (is_debug_tag_set("url_rewrite"))
00133     Print();
00134 }
00135 
00136 
00137 
00138 
00139 
00140 
00141 url_mapping *
00142 UrlRewrite::SetupPacMapping()
00143 {
00144   const char *from_url = "http:///";
00145   const char *local_url = "http://127.0.0.1/";
00146 
00147   url_mapping *mapping;
00148   int pac_generator_port;
00149 
00150   mapping = new url_mapping;
00151 
00152   mapping->fromURL.create(NULL);
00153   mapping->fromURL.parse(from_url, strlen(from_url));
00154 
00155   mapping->toUrl.create(NULL);
00156   mapping->toUrl.parse(local_url, strlen(local_url));
00157 
00158   pac_generator_port = (default_to_pac_port < 0) ? mgmt_autoconf_port : default_to_pac_port;
00159 
00160   mapping->toUrl.port_set(pac_generator_port);
00161 
00162   return mapping;
00163 }
00164 
00165 
00166 
00167 
00168 
00169 
00170 
00171 
00172 
00173 url_mapping *
00174 UrlRewrite::SetupBackdoorMapping()
00175 {
00176   const char from_url[] = "/ink/rh";
00177   const char to_url[] = "http://{backdoor}/ink/rh";
00178 
00179   url_mapping *mapping = new url_mapping;
00180 
00181   mapping->fromURL.create(NULL);
00182   mapping->fromURL.parse(from_url, sizeof(from_url) - 1);
00183   mapping->fromURL.scheme_set(URL_SCHEME_HTTP, URL_LEN_HTTP);
00184 
00185   mapping->toUrl.create(NULL);
00186   mapping->toUrl.parse(to_url, sizeof(to_url) - 1);
00187 
00188   return mapping;
00189 }
00190 
00191 
00192 void
00193 UrlRewrite::_destroyTable(InkHashTable *h_table)
00194 {
00195   InkHashTableEntry *ht_entry;
00196   InkHashTableIteratorState ht_iter;
00197   UrlMappingPathIndex *item;
00198 
00199   if (h_table != NULL) {        
00200     
00201     for (ht_entry = ink_hash_table_iterator_first(h_table, &ht_iter); ht_entry != NULL;) {
00202       item = (UrlMappingPathIndex *)ink_hash_table_entry_value(h_table, ht_entry);
00203       delete item;
00204       ht_entry = ink_hash_table_iterator_next(h_table, &ht_iter);
00205     }
00206     ink_hash_table_destroy(h_table);
00207   }
00208 }
00209 
00210 
00211 void
00212 UrlRewrite::Print()
00213 {
00214   printf("URL Rewrite table with %d entries\n", num_rules_forward + num_rules_reverse +
00215          num_rules_redirect_temporary + num_rules_redirect_permanent + num_rules_forward_with_recv_port);
00216   printf("  Reverse Proxy is %s\n", (reverse_proxy == 0) ? "Off" : "On");
00217 
00218   printf("  Forward Mapping Table with %d entries\n", num_rules_forward);
00219   PrintStore(forward_mappings);
00220 
00221   printf("  Reverse Mapping Table with %d entries\n", num_rules_reverse);
00222   PrintStore(reverse_mappings);
00223 
00224   printf("  Permanent Redirect Mapping Table with %d entries\n", num_rules_redirect_permanent);
00225   PrintStore(permanent_redirects);
00226 
00227   printf("  Temporary Redirect Mapping Table with %d entries\n", num_rules_redirect_temporary);
00228   PrintStore(temporary_redirects);
00229 
00230   printf("  Forward Mapping With Recv Port Table with %d entries\n", num_rules_forward_with_recv_port);
00231   PrintStore(forward_mappings_with_recv_port);
00232 
00233   if (http_default_redirect_url != NULL) {
00234     printf("  Referer filter default redirect URL: \"%s\"\n", http_default_redirect_url);
00235   }
00236 }
00237 
00238 
00239 void
00240 UrlRewrite::PrintStore(MappingsStore &store)
00241 {
00242   if (store.hash_lookup != NULL) {
00243     InkHashTableEntry *ht_entry;
00244     InkHashTableIteratorState ht_iter;
00245     UrlMappingPathIndex *value;
00246 
00247     for (ht_entry = ink_hash_table_iterator_first(store.hash_lookup, &ht_iter); ht_entry != NULL;) {
00248       value = (UrlMappingPathIndex *) ink_hash_table_entry_value(store.hash_lookup, ht_entry);
00249       value->Print();
00250       ht_entry = ink_hash_table_iterator_next(store.hash_lookup, &ht_iter);
00251     }
00252   }
00253 
00254   if (!store.regex_list.empty()) {
00255     printf("    Regex mappings:\n");
00256     forl_LL(RegexMapping, list_iter, store.regex_list) {
00257       list_iter->url_map->Print();
00258     }
00259   }
00260 }
00261 
00262 
00263 
00264 
00265 
00266 
00267 url_mapping *
00268 UrlRewrite::_tableLookup(InkHashTable *h_table, URL *request_url,
00269                         int request_port, char *request_host, int request_host_len)
00270 {
00271   UrlMappingPathIndex *ht_entry;
00272   url_mapping *um = NULL;
00273   int ht_result;
00274 
00275   ht_result = ink_hash_table_lookup(h_table, request_host, (void **) &ht_entry);
00276 
00277   if (likely(ht_result && ht_entry)) {
00278     
00279     um = ht_entry->Search(request_url, request_port, request_host_len ? true : false);
00280   }
00281   return um;
00282 }
00283 
00284 
00285 
00286 void
00287 url_rewrite_remap_request(const UrlMappingContainer& mapping_container, URL *request_url)
00288 {
00289   const char *requestPath;
00290   int requestPathLen = 0;
00291   int fromPathLen = 0;
00292 
00293   URL *map_to = mapping_container.getToURL();
00294   URL *map_from = mapping_container.getFromURL();
00295   const char *toHost;
00296   const char *toPath;
00297   const char *toScheme;
00298   int toPathLen;
00299   int toHostLen;
00300   int toSchemeLen;
00301 
00302   map_from->path_get(&fromPathLen);
00303 
00304   toHost = map_to->host_get(&toHostLen);
00305   toPath = map_to->path_get(&toPathLen);
00306   toScheme = map_to->scheme_get(&toSchemeLen);
00307 
00308   Debug("url_rewrite", "%s: Remapping rule id: %d matched", __func__, mapping_container.getMapping()->map_id);
00309 
00310   request_url->host_set(toHost, toHostLen);
00311   request_url->port_set(map_to->port_get_raw());
00312   request_url->scheme_set(toScheme, toSchemeLen);
00313 
00314   requestPath = request_url->path_get(&requestPathLen);
00315 
00316   
00317   
00318   
00319   char *newPath = static_cast<char*>(alloca(sizeof(char*)*((requestPathLen - fromPathLen) + toPathLen + 8)));
00320   int newPathLen = 0;
00321 
00322   *newPath = 0;
00323   if (toPath) {
00324     memcpy(newPath, toPath, toPathLen);
00325     newPathLen += toPathLen;
00326   }
00327 
00328   
00329   
00330   if (!fromPathLen && requestPathLen && newPathLen && toPathLen && *(newPath + newPathLen - 1) != '/') {
00331     *(newPath + newPathLen) = '/';
00332     newPathLen++;
00333   }
00334 
00335   if (requestPath) {
00336     
00337     if (requestPathLen < fromPathLen) {
00338       if (toPathLen && requestPath[requestPathLen - 1] == '/' && toPath[toPathLen - 1] == '/') {
00339         fromPathLen++;
00340       }
00341     } else {
00342       if (toPathLen && requestPath[fromPathLen] == '/' && toPath[toPathLen - 1] == '/') {
00343         fromPathLen++;
00344       }
00345     }
00346 
00347     
00348     if ((requestPathLen - fromPathLen) > 0) {
00349       memcpy(newPath + newPathLen, requestPath + fromPathLen, requestPathLen - fromPathLen);
00350       newPathLen += (requestPathLen - fromPathLen);
00351     }
00352   }
00353 
00354   
00355   if (*newPath == '/') {
00356     request_url->path_set(newPath + 1, newPathLen - 1);
00357   } else {
00358     request_url->path_set(newPath, newPathLen);
00359   }
00360 }
00361 
00362 
00363 #define N_URL_HEADERS 4
00364 bool
00365 UrlRewrite::ReverseMap(HTTPHdr *response_header)
00366 {
00367   const char *location_hdr;
00368   URL location_url;
00369   int loc_length;
00370   bool remap_found = false;
00371   const char *host;
00372   int host_len;
00373   char *new_loc_hdr;
00374   int new_loc_length;
00375   int i;
00376   const struct {
00377     const char *const field;
00378     const int len;
00379   } url_headers[N_URL_HEADERS] = {
00380     { MIME_FIELD_LOCATION, MIME_LEN_LOCATION } ,
00381     { MIME_FIELD_CONTENT_LOCATION, MIME_LEN_CONTENT_LOCATION } ,
00382     { "URI", 3 } ,
00383     { "Destination", 11 }
00384   };
00385 
00386   if (unlikely(num_rules_reverse == 0)) {
00387     ink_assert(reverse_mappings.empty());
00388     return false;
00389   }
00390 
00391   for (i = 0; i < N_URL_HEADERS; ++i) {
00392     location_hdr = response_header->value_get(url_headers[i].field, url_headers[i].len, &loc_length);
00393 
00394     if (location_hdr == NULL) {
00395       continue;
00396     }
00397 
00398     location_url.create(NULL);
00399     location_url.parse(location_hdr, loc_length);
00400 
00401     host = location_url.host_get(&host_len);
00402 
00403     UrlMappingContainer reverse_mapping(response_header->m_heap);
00404 
00405     if (reverseMappingLookup(&location_url, location_url.port_get(), host, host_len, reverse_mapping)) {
00406       if (i == 0)
00407         remap_found = true;
00408       url_rewrite_remap_request(reverse_mapping, &location_url);
00409       new_loc_hdr = location_url.string_get_ref(&new_loc_length);
00410       response_header->value_set(url_headers[i].field, url_headers[i].len, new_loc_hdr, new_loc_length);
00411     }
00412 
00413     location_url.destroy();
00414   }
00415   return remap_found;
00416 }
00417 
00418 
00419 void
00420 UrlRewrite::PerformACLFiltering(HttpTransact::State *s, url_mapping *map)
00421 {
00422   if (unlikely(!s || s->acl_filtering_performed || !s->client_connection_enabled))
00423     return;
00424 
00425   s->acl_filtering_performed = true;    
00426 
00427   if (map->filter) {
00428     int res;
00429     int method = s->hdr_info.client_request.method_get_wksidx();
00430     int method_wksidx = (method != -1) ? (method - HTTP_WKSIDX_CONNECT) : -1;
00431     bool client_enabled_flag = true;
00432     ink_release_assert(ats_is_ip(&s->client_info.addr));
00433     for (acl_filter_rule * rp = map->filter; rp; rp = rp->next) {
00434       bool match = true;
00435       if (rp->method_restriction_enabled) {
00436         if (method_wksidx != -1) {
00437           match = rp->standard_method_lookup[method_wksidx];
00438         }
00439         else if (!rp->nonstandard_methods.empty()) {
00440           int method_str_len;
00441           const char *method_str = s->hdr_info.client_request.method_get(&method_str_len);
00442           match = rp->nonstandard_methods.count(std::string(method_str, method_str_len));
00443         }
00444       }
00445       if (match && rp->src_ip_valid) {
00446         match = false;
00447         for (int j = 0; j < rp->src_ip_cnt && !match; j++) {
00448           res = rp->src_ip_array[j].contains(s->client_info.addr) ? 1 : 0;
00449           if (rp->src_ip_array[j].invert) {
00450             if (res != 1)
00451               match = true;
00452           } else {
00453             if (res == 1)
00454               match = true;
00455           }
00456         }
00457       }
00458       if (match && client_enabled_flag) {     
00459         Debug("url_rewrite", "matched ACL filter rule, %s request", rp->allow_flag ? "allowing" : "denying");
00460         client_enabled_flag = rp->allow_flag ? true : false;
00461       } else {
00462         if (!client_enabled_flag) {
00463           Debug("url_rewrite", "Previous ACL filter rule denied request, continuing to deny it");
00464         } else {
00465           Debug("url_rewrite", "did NOT match ACL filter rule, %s request", rp->allow_flag ? "denying" : "allowing");
00466           client_enabled_flag = rp->allow_flag ? false : true;
00467         }
00468       }
00469       
00470     }                         
00471     s->client_connection_enabled = client_enabled_flag;
00472   }
00473 }
00474 
00475 
00476 
00477 
00478 
00479 
00480 mapping_type
00481 UrlRewrite::Remap_redirect(HTTPHdr *request_header, URL *redirect_url)
00482 {
00483   URL *request_url;
00484   mapping_type mappingType;
00485   const char *host = NULL;
00486   int host_len = 0, request_port = 0;
00487   bool prt, trt;                        
00488 
00489   prt = (num_rules_redirect_permanent != 0);
00490   trt = (num_rules_redirect_temporary != 0);
00491 
00492   if (prt + trt == 0)
00493     return NONE;
00494 
00495   
00496   
00497   
00498   
00499   if (request_header == NULL) {
00500     Debug("url_rewrite", "request_header was invalid.  UrlRewrite::Remap_redirect bailing out.");
00501     return NONE;
00502   }
00503   request_url = request_header->url_get();
00504   if (!request_url->valid()) {
00505     Debug("url_rewrite", "request_url was invalid.  UrlRewrite::Remap_redirect bailing out.");
00506     return NONE;
00507   }
00508 
00509   host = request_url->host_get(&host_len);
00510   request_port = request_url->port_get();
00511 
00512   if (host_len == 0 && reverse_proxy != 0) {    
00513                                                 
00514     int host_hdr_len;
00515     const char *host_hdr = request_header->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &host_hdr_len);
00516 
00517     if (!host_hdr) {
00518       host_hdr = "";
00519       host_hdr_len = 0;
00520     }
00521 
00522     const char *tmp = (const char *) memchr(host_hdr, ':', host_hdr_len);
00523 
00524     if (tmp == NULL) {
00525       host_len = host_hdr_len;
00526     } else {
00527       host_len = tmp - host_hdr;
00528       request_port = ink_atoi(tmp + 1, host_hdr_len - host_len);
00529 
00530       
00531       
00532       if (request_port == 0) {
00533         request_port = request_url->port_get();
00534       }
00535     }
00536 
00537     host = host_hdr;
00538   }
00539   
00540   
00541   
00542   
00543   mappingType = NONE;
00544 
00545   UrlMappingContainer redirect_mapping(request_header->m_heap);
00546 
00547   if (trt) {
00548     if (temporaryRedirectLookup(request_url, request_port, host, host_len, redirect_mapping)) {
00549       mappingType = TEMPORARY_REDIRECT;
00550     }
00551   }
00552   if ((mappingType == NONE) && prt) {
00553     if (permanentRedirectLookup(request_url, request_port, host, host_len, redirect_mapping)) {
00554       mappingType = PERMANENT_REDIRECT;
00555     }
00556   }
00557 
00558   if (mappingType != NONE) {
00559     ink_assert((mappingType == PERMANENT_REDIRECT) || (mappingType == TEMPORARY_REDIRECT));
00560 
00561     
00562     
00563     redirect_url->create(NULL);
00564     redirect_url->copy(request_url);
00565 
00566     
00567     url_rewrite_remap_request(redirect_mapping, redirect_url);
00568 
00569     return mappingType;
00570   }
00571   ink_assert(mappingType == NONE);
00572 
00573   return NONE;
00574 }
00575 
00576 bool
00577 UrlRewrite::_addToStore(MappingsStore &store, url_mapping *new_mapping, RegexMapping *reg_map,
00578                         const char * src_host, bool is_cur_mapping_regex, int &count)
00579 {
00580   bool retval;
00581   if (is_cur_mapping_regex) {
00582     store.regex_list.enqueue(reg_map);
00583     retval = true;
00584   } else {
00585     retval = TableInsert(store.hash_lookup, new_mapping, src_host);
00586   }
00587   if (retval) {
00588     ++count;
00589   }
00590   return retval;
00591 }
00592 
00593 bool
00594 UrlRewrite::InsertMapping(mapping_type maptype, url_mapping *new_mapping, RegexMapping *reg_map,
00595                         const char * src_host, bool is_cur_mapping_regex)
00596 {
00597   bool success = false;
00598 
00599   
00600   switch (maptype) {
00601   case FORWARD_MAP:
00602   case FORWARD_MAP_REFERER:
00603     success = _addToStore(forward_mappings, new_mapping, reg_map, src_host,
00604                                   is_cur_mapping_regex, num_rules_forward);
00605     if (success) {
00606       
00607       SetHomePageRedirectFlag(new_mapping, new_mapping->toUrl);
00608     }
00609     break;
00610   case REVERSE_MAP:
00611     success = _addToStore(reverse_mappings, new_mapping, reg_map, src_host,
00612                              is_cur_mapping_regex, num_rules_reverse);
00613     new_mapping->homePageRedirect = false;
00614     break;
00615   case PERMANENT_REDIRECT:
00616     success = _addToStore(permanent_redirects, new_mapping, reg_map, src_host,
00617                              is_cur_mapping_regex, num_rules_redirect_permanent);
00618     break;
00619   case TEMPORARY_REDIRECT:
00620     success = _addToStore(temporary_redirects, new_mapping, reg_map, src_host,
00621                              is_cur_mapping_regex, num_rules_redirect_temporary);
00622     break;
00623   case FORWARD_MAP_WITH_RECV_PORT:
00624     success = _addToStore(forward_mappings_with_recv_port, new_mapping, reg_map, src_host,
00625                              is_cur_mapping_regex, num_rules_forward_with_recv_port);
00626     break;
00627   default:
00628     
00629     
00630     return false;
00631   }
00632 
00633   return success;
00634 }
00635 
00636 bool
00637 UrlRewrite::InsertForwardMapping(mapping_type maptype, url_mapping * mapping, const char * src_host)
00638 {
00639   bool success;
00640 
00641   if (maptype == FORWARD_MAP_WITH_RECV_PORT) {
00642     success = TableInsert(forward_mappings_with_recv_port.hash_lookup, mapping, src_host);
00643   } else {
00644     success = TableInsert(forward_mappings.hash_lookup, mapping, src_host);
00645   }
00646 
00647   if (success) {
00648     switch (maptype) {
00649       case FORWARD_MAP:
00650       case FORWARD_MAP_REFERER:
00651       case FORWARD_MAP_WITH_RECV_PORT:
00652         SetHomePageRedirectFlag(mapping, mapping->toUrl);
00653         break;
00654       default:
00655         break;
00656     }
00657 
00658     (maptype != FORWARD_MAP_WITH_RECV_PORT) ? ++num_rules_forward
00659                                             : ++num_rules_forward_with_recv_port;
00660   }
00661 
00662   return success;
00663 }
00664 
00665 
00666 
00667 
00668 
00669 
00670 
00671 int
00672 UrlRewrite::BuildTable(const char * path)
00673 {
00674   BUILD_TABLE_INFO bti;
00675   url_mapping * new_mapping = NULL;
00676 
00677   ink_assert(forward_mappings.empty());
00678   ink_assert(reverse_mappings.empty());
00679   ink_assert(permanent_redirects.empty());
00680   ink_assert(temporary_redirects.empty());
00681   ink_assert(forward_mappings_with_recv_port.empty());
00682   ink_assert(num_rules_forward == 0);
00683   ink_assert(num_rules_reverse == 0);
00684   ink_assert(num_rules_redirect_permanent == 0);
00685   ink_assert(num_rules_redirect_temporary == 0);
00686   ink_assert(num_rules_forward_with_recv_port == 0);
00687 
00688 
00689   forward_mappings.hash_lookup = ink_hash_table_create(InkHashTableKeyType_String);
00690   reverse_mappings.hash_lookup = ink_hash_table_create(InkHashTableKeyType_String);
00691   permanent_redirects.hash_lookup = ink_hash_table_create(InkHashTableKeyType_String);
00692   temporary_redirects.hash_lookup = ink_hash_table_create(InkHashTableKeyType_String);
00693   forward_mappings_with_recv_port.hash_lookup = ink_hash_table_create(InkHashTableKeyType_String);
00694 
00695   if (!remap_parse_config(path, this)) {
00696     
00697     return 3;
00698   }
00699 
00700   
00701   
00702   
00703   if (unlikely(backdoor_enabled)) {
00704     new_mapping = SetupBackdoorMapping();
00705     if (TableInsert(forward_mappings.hash_lookup, new_mapping, "")) {
00706       num_rules_forward++;
00707     } else {
00708       Warning("Could not insert backdoor mapping into store");
00709       delete new_mapping;
00710       return 3;
00711     }
00712   }
00713   
00714   
00715   if (default_to_pac) {
00716     new_mapping = SetupPacMapping();
00717     if (TableInsert(forward_mappings.hash_lookup, new_mapping, "")) {
00718       num_rules_forward++;
00719     } else {
00720       Warning("Could not insert pac mapping into store");
00721       delete new_mapping;
00722       return 3;
00723     }
00724   }
00725   
00726   if (num_rules_forward == 0) {
00727     forward_mappings.hash_lookup = ink_hash_table_destroy(forward_mappings.hash_lookup);
00728   } else {
00729     if (ink_hash_table_isbound(forward_mappings.hash_lookup, "")) {
00730       nohost_rules = 1;
00731     }
00732   }
00733 
00734   if (num_rules_reverse == 0) {
00735     reverse_mappings.hash_lookup = ink_hash_table_destroy(reverse_mappings.hash_lookup);
00736   }
00737 
00738   if (num_rules_redirect_permanent == 0) {
00739     permanent_redirects.hash_lookup = ink_hash_table_destroy(permanent_redirects.hash_lookup);
00740   }
00741 
00742   if (num_rules_redirect_temporary == 0) {
00743     temporary_redirects.hash_lookup = ink_hash_table_destroy(temporary_redirects.hash_lookup);
00744   }
00745 
00746   if (num_rules_forward_with_recv_port == 0) {
00747     forward_mappings_with_recv_port.hash_lookup = ink_hash_table_destroy(
00748       forward_mappings_with_recv_port.hash_lookup);
00749   }
00750 
00751   return 0;
00752 }
00753 
00754 
00755 
00756 
00757 
00758 
00759 bool
00760 UrlRewrite::TableInsert(InkHashTable *h_table, url_mapping *mapping, const char *src_host)
00761 {
00762   char src_host_tmp_buf[1];
00763   UrlMappingPathIndex *ht_contents;
00764 
00765   if (!src_host) {
00766     src_host = &src_host_tmp_buf[0];
00767     src_host_tmp_buf[0] = 0;
00768   }
00769   
00770   if (ink_hash_table_lookup(h_table, src_host, (void**) &ht_contents)) {
00771     
00772     if (ht_contents == NULL) {
00773       
00774       Warning("Found entry cannot be null!");
00775       return false;
00776     }
00777   } else {
00778     ht_contents = new UrlMappingPathIndex();
00779     ink_hash_table_insert(h_table, src_host, ht_contents);
00780   }
00781   if (!ht_contents->Insert(mapping)) {
00782     Warning("Could not insert new mapping");
00783     return false;
00784   }
00785   return true;
00786 }
00787 
00788 
00789 
00790 
00791 
00792 
00793 
00794 bool
00795 UrlRewrite::_mappingLookup(MappingsStore &mappings, URL *request_url,
00796                            int request_port, const char *request_host, int request_host_len,
00797                            UrlMappingContainer &mapping_container)
00798 {
00799   char request_host_lower[TS_MAX_HOST_NAME_LEN];
00800 
00801   if (!request_host || !request_url ||
00802       (request_host_len < 0) || (request_host_len >= TS_MAX_HOST_NAME_LEN)) {
00803     Debug("url_rewrite", "Invalid arguments!");
00804     return false;
00805   }
00806 
00807   
00808   for (int i = 0; i < request_host_len; ++i) {
00809     request_host_lower[i] = tolower(request_host[i]);
00810   }
00811   request_host_lower[request_host_len] = 0;
00812 
00813   bool retval = false;
00814   int rank_ceiling = -1;
00815   url_mapping *mapping = _tableLookup(mappings.hash_lookup, request_url, request_port, request_host_lower,
00816                                       request_host_len);
00817   if (mapping != NULL) {
00818     rank_ceiling = mapping->getRank();
00819     Debug("url_rewrite", "Found 'simple' mapping with rank %d", rank_ceiling);
00820     mapping_container.set(mapping);
00821     retval = true;
00822   }
00823   if (_regexMappingLookup(mappings.regex_list, request_url, request_port, request_host_lower, request_host_len,
00824                           rank_ceiling, mapping_container)) {
00825     Debug("url_rewrite", "Using regex mapping with rank %d", (mapping_container.getMapping())->getRank());
00826     retval = true;
00827   }
00828   return retval;
00829 }
00830 
00831 
00832 int
00833 UrlRewrite::_expandSubstitutions(int *matches_info, const RegexMapping *reg_map,
00834                                  const char *matched_string,
00835                                  char *dest_buf, int dest_buf_size)
00836 {
00837   int cur_buf_size = 0;
00838   int token_start = 0;
00839   int n_bytes_needed;
00840   int match_index;
00841   for (int i = 0; i < reg_map->n_substitutions; ++i) {
00842     
00843     n_bytes_needed = reg_map->substitution_markers[i] - token_start;
00844     if ((cur_buf_size + n_bytes_needed) > dest_buf_size) {
00845       goto lOverFlow;
00846     }
00847     memcpy(dest_buf + cur_buf_size, reg_map->to_url_host_template + token_start, n_bytes_needed);
00848     cur_buf_size += n_bytes_needed;
00849 
00850     
00851     match_index = reg_map->substitution_ids[i] * 2;
00852     n_bytes_needed = matches_info[match_index + 1] - matches_info[match_index];
00853     if ((cur_buf_size + n_bytes_needed) > dest_buf_size) {
00854       goto lOverFlow;
00855     }
00856     memcpy(dest_buf + cur_buf_size, matched_string + matches_info[match_index], n_bytes_needed);
00857     cur_buf_size += n_bytes_needed;
00858 
00859     token_start = reg_map->substitution_markers[i] + 2; 
00860   }
00861 
00862   
00863   if (token_start < reg_map->to_url_host_template_len) {
00864     n_bytes_needed = reg_map->to_url_host_template_len - token_start;
00865     if ((cur_buf_size + n_bytes_needed) > dest_buf_size) {
00866       goto lOverFlow;
00867     }
00868     memcpy(dest_buf + cur_buf_size, reg_map->to_url_host_template + token_start, n_bytes_needed);
00869     cur_buf_size += n_bytes_needed;
00870   }
00871   Debug("url_rewrite_regex", "Expanded substitutions and returning string [%.*s] with length %d",
00872         cur_buf_size, dest_buf, cur_buf_size);
00873   return cur_buf_size;
00874 
00875  lOverFlow:
00876   Warning("Overflow while expanding substitutions");
00877   return 0;
00878 }
00879 
00880 bool
00881 UrlRewrite::_regexMappingLookup(RegexMappingList ®ex_mappings, URL *request_url, int request_port,
00882                                 const char *request_host, int request_host_len, int rank_ceiling,
00883                                 UrlMappingContainer &mapping_container)
00884 {
00885   bool retval = false;
00886 
00887   if (rank_ceiling == -1) { 
00888     rank_ceiling = INT_MAX;
00889     Debug("url_rewrite_regex", "Going to match all regexes");
00890   }
00891   else {
00892     Debug("url_rewrite_regex", "Going to match regexes with rank <= %d", rank_ceiling);
00893   }
00894 
00895   int request_scheme_len, reg_map_scheme_len;
00896   const char *request_scheme = request_url->scheme_get(&request_scheme_len), *reg_map_scheme;
00897 
00898   int request_path_len, reg_map_path_len;
00899   const char *request_path = request_url->path_get(&request_path_len), *reg_map_path;
00900 
00901   
00902   forl_LL(RegexMapping, list_iter, regex_mappings) {
00903     int reg_map_rank = list_iter->url_map->getRank();
00904 
00905     if (reg_map_rank > rank_ceiling) {
00906       break;
00907     }
00908 
00909     reg_map_scheme = list_iter->url_map->fromURL.scheme_get(®_map_scheme_len);
00910     if ((request_scheme_len != reg_map_scheme_len) ||
00911         strncmp(request_scheme, reg_map_scheme, request_scheme_len)) {
00912       Debug("url_rewrite_regex", "Skipping regex with rank %d as scheme does not match request scheme",
00913             reg_map_rank);
00914       continue;
00915     }
00916 
00917     if (list_iter->url_map->fromURL.port_get() != request_port) {
00918       Debug("url_rewrite_regex", "Skipping regex with rank %d as regex map port does not match request port. "
00919             "regex map port: %d, request port %d",
00920             reg_map_rank, list_iter->url_map->fromURL.port_get(), request_port);
00921       continue;
00922     }
00923 
00924     reg_map_path = list_iter->url_map->fromURL.path_get(®_map_path_len);
00925     if ((request_path_len < reg_map_path_len) ||
00926         strncmp(reg_map_path, request_path, reg_map_path_len)) { 
00927       Debug("url_rewrite_regex", "Skipping regex with rank %d as path does not cover request path",
00928             reg_map_rank);
00929       continue;
00930     }
00931 
00932     int matches_info[MAX_REGEX_SUBS * 3];
00933     int match_result = pcre_exec(list_iter->re, list_iter->re_extra, request_host, request_host_len,
00934                                  0, 0, matches_info, (sizeof(matches_info) / sizeof(int)));
00935     if (match_result > 0) {
00936       Debug("url_rewrite_regex", "Request URL host [%.*s] matched regex in mapping of rank %d "
00937             "with %d possible substitutions", request_host_len, request_host, reg_map_rank, match_result);
00938 
00939       mapping_container.set(list_iter->url_map);
00940 
00941       char buf[4096];
00942       int buf_len;
00943 
00944       
00945       buf_len = _expandSubstitutions(matches_info, list_iter, request_host, buf, sizeof(buf));
00946       URL *expanded_url = mapping_container.createNewToURL();
00947       expanded_url->copy(&((list_iter->url_map)->toUrl));
00948       expanded_url->host_set(buf, buf_len);
00949 
00950       Debug("url_rewrite_regex", "Expanded toURL to [%.*s]",
00951             expanded_url->length_get(), expanded_url->string_get_ref());
00952       retval = true;
00953       break;
00954     } else if (match_result == PCRE_ERROR_NOMATCH) {
00955       Debug("url_rewrite_regex", "Request URL host [%.*s] did NOT match regex in mapping of rank %d",
00956             request_host_len, request_host, reg_map_rank);
00957     } else {
00958       Warning("pcre_exec() failed with error code %d", match_result);
00959       break;
00960     }
00961   }
00962 
00963   return retval;
00964 }
00965 
00966 void
00967 UrlRewrite::_destroyList(RegexMappingList &mappings)
00968 {
00969   RegexMapping *list_iter;
00970   while ((list_iter=mappings.pop()) != NULL) {
00971     delete list_iter->url_map;
00972     if (list_iter->re) {
00973       pcre_free(list_iter->re);
00974     }
00975     if (list_iter->re_extra) {
00976       pcre_free(list_iter->re_extra);
00977     }
00978     if (list_iter->to_url_host_template) {
00979       ats_free(list_iter->to_url_host_template);
00980     }
00981     delete list_iter;
00982   }
00983   mappings.clear();
00984 }