• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

RemapConfig.cc

Go to the documentation of this file.
00001 /** @file
00002  *
00003  *  Remap configuration file parsing.
00004  *
00005  *  @section license License
00006  *
00007  *  Licensed to the Apache Software Foundation (ASF) under one
00008  *  or more contributor license agreements.  See the NOTICE file
00009  *  distributed with this work for additional information
00010  *  regarding copyright ownership.  The ASF licenses this file
00011  *  to you under the Apache License, Version 2.0 (the
00012  *  "License"); you may not use this file except in compliance
00013  *  with the License.  You may obtain a copy of the License at
00014  *
00015  *      http://www.apache.org/licenses/LICENSE-2.0
00016  *
00017  *  Unless required by applicable law or agreed to in writing, software
00018  *  distributed under the License is distributed on an "AS IS" BASIS,
00019  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020  *  See the License for the specific language governing permissions and
00021  *  limitations under the License.
00022  */
00023 
00024 #include "RemapConfig.h"
00025 #include "UrlRewrite.h"
00026 #include "ReverseProxy.h"
00027 #include "I_Layout.h"
00028 #include "HTTP.h"
00029 #include "libts.h"
00030 #include "ink_cap.h"
00031 
00032 #define modulePrefix "[ReverseProxy]"
00033 
00034 static bool remap_parse_config_bti(const char * path, BUILD_TABLE_INFO * bti);
00035 
00036 /**
00037   Returns the length of the URL.
00038 
00039   Will replace the terminator with a '/' if this is a full URL and
00040   there are no '/' in it after the the host.  This ensures that class
00041   URL parses the URL correctly.
00042 
00043 */
00044 static int
00045 UrlWhack(char *toWhack, int *origLength)
00046 {
00047   int length = strlen(toWhack);
00048   char *tmp;
00049   *origLength = length;
00050 
00051   // Check to see if this a full URL
00052   tmp = strstr(toWhack, "://");
00053   if (tmp != NULL) {
00054     if (strchr(tmp + 3, '/') == NULL) {
00055       toWhack[length] = '/';
00056       length++;
00057     }
00058   }
00059   return length;
00060 }
00061 
00062 /**
00063   Cleanup *char[] array - each item in array must be allocated via
00064   ats_malloc or similar "x..." function.
00065 
00066 */
00067 static void
00068 clear_xstr_array(char *v[], size_t vsize)
00069 {
00070   for (unsigned i = 0; i < vsize; i++) {
00071     v[i] = (char *)ats_free_null(v[i]);
00072   }
00073 }
00074 
00075 BUILD_TABLE_INFO::BUILD_TABLE_INFO()
00076   : remap_optflg(0), paramc(0), argc(0), rules_list(NULL), rewrite(NULL)
00077 {
00078   memset(this->paramv, 0, sizeof(this->paramv));
00079   memset(this->argv, 0, sizeof(this->argv));
00080 }
00081 
00082 BUILD_TABLE_INFO::~BUILD_TABLE_INFO()
00083 {
00084   this->reset();
00085 }
00086 
00087 void
00088 BUILD_TABLE_INFO::reset()
00089 {
00090   this->paramc = this->argc = 0;
00091   clear_xstr_array(this->paramv, sizeof(this->paramv) / sizeof(char *));
00092   clear_xstr_array(this->argv, sizeof(this->argv) / sizeof(char *));
00093 }
00094 
00095 static const char *
00096 process_filter_opt(url_mapping * mp, const BUILD_TABLE_INFO * bti, char * errStrBuf, int errStrBufSize)
00097 {
00098   acl_filter_rule *rp, **rpp;
00099   const char *errStr = NULL;
00100 
00101   if (unlikely(!mp || !bti || !errStrBuf || errStrBufSize <= 0)) {
00102     Debug("url_rewrite", "[process_filter_opt] Invalid argument(s)");
00103     return (const char *) "[process_filter_opt] Invalid argument(s)";
00104   }
00105   for (rp = bti->rules_list; rp; rp = rp->next) {
00106     if (rp->active_queue_flag) {
00107       Debug("url_rewrite", "[process_filter_opt] Add active main filter \"%s\" (argc=%d)",
00108             rp->filter_name ? rp->filter_name : "<NULL>", rp->argc);
00109       for (rpp = &mp->filter; *rpp; rpp = &((*rpp)->next));
00110       if ((errStr = remap_validate_filter_args(rpp, (const char **)rp->argv, rp->argc, errStrBuf, errStrBufSize)) != NULL)
00111         break;
00112     }
00113   }
00114   if (!errStr && (bti->remap_optflg & REMAP_OPTFLG_ALL_FILTERS) != 0) {
00115     Debug("url_rewrite", "[process_filter_opt] Add per remap filter");
00116     for (rpp = &mp->filter; *rpp; rpp = &((*rpp)->next));
00117     errStr = remap_validate_filter_args(rpp, (const char **)bti->argv, bti->argc, errStrBuf, errStrBufSize);
00118   }
00119   return errStr;
00120 }
00121 
00122 static bool
00123 is_inkeylist(const char * key, ...)
00124 {
00125   va_list ap;
00126 
00127   if (unlikely(key == NULL || key[0] == '\0')) {
00128     return false;
00129   }
00130 
00131   va_start(ap, key);
00132 
00133   const char *str = va_arg(ap, const char *);
00134   for (unsigned idx = 1; str; idx++) {
00135     if (!strcasecmp(key, str)) {
00136       va_end(ap);
00137       return true;
00138     }
00139 
00140     str = va_arg(ap, const char *);
00141   }
00142 
00143   va_end(ap);
00144   return false;
00145 }
00146 
00147 static const char *
00148 parse_define_directive(const char * directive, BUILD_TABLE_INFO * bti, char * errbuf, size_t errbufsize)
00149 {
00150   bool flg;
00151   acl_filter_rule * rp;
00152   acl_filter_rule ** rpp;
00153   const char * cstr = NULL;
00154 
00155   if (bti->paramc < 2) {
00156     snprintf(errbuf, errbufsize, "Directive \"%s\" must have name argument", directive);
00157     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00158     return (const char *) errbuf;
00159   }
00160   if (bti->argc < 1) {
00161     snprintf(errbuf, errbufsize, "Directive \"%s\" must have filter parameter(s)", directive);
00162     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00163     return (const char *) errbuf;
00164   }
00165 
00166   flg = ((rp = acl_filter_rule::find_byname(bti->rules_list, (const char *) bti->paramv[1])) == NULL) ? true : false;
00167   // coverity[alloc_arg]
00168   if ((cstr = remap_validate_filter_args(&rp, (const char **)bti->argv, bti->argc, errbuf, errbufsize)) == NULL && rp) {
00169     if (flg) {                  // new filter - add to list
00170       Debug("url_rewrite", "[parse_directive] new rule \"%s\" was created", bti->paramv[1]);
00171       for (rpp = &bti->rules_list; *rpp; rpp = &((*rpp)->next));
00172       (*rpp = rp)->name(bti->paramv[1]);
00173     }
00174     Debug("url_rewrite", "[parse_directive] %d argument(s) were added to rule \"%s\"", bti->argc, bti->paramv[1]);
00175     rp->add_argv(bti->argc, bti->argv);       // store string arguments for future processing
00176   }
00177 
00178   return cstr;
00179 }
00180 
00181 static const char *
00182 parse_delete_directive(const char * directive, BUILD_TABLE_INFO * bti, char * errbuf, size_t errbufsize)
00183 {
00184   if (bti->paramc < 2) {
00185     snprintf(errbuf, errbufsize, "Directive \"%s\" must have name argument", directive);
00186     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00187     return (const char *) errbuf;
00188   }
00189 
00190   acl_filter_rule::delete_byname(&bti->rules_list, (const char *) bti->paramv[1]);
00191   return NULL;
00192 }
00193 
00194 static const char *
00195 parse_activate_directive(const char * directive, BUILD_TABLE_INFO * bti, char * errbuf, size_t errbufsize)
00196 {
00197   acl_filter_rule * rp;
00198 
00199   if (bti->paramc < 2) {
00200     snprintf(errbuf, errbufsize, "Directive \"%s\" must have name argument", directive);
00201     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00202     return (const char *) errbuf;
00203   }
00204 
00205   if ((rp = acl_filter_rule::find_byname(bti->rules_list, (const char *) bti->paramv[1])) == NULL) {
00206     snprintf(errbuf, errbufsize, "Undefined filter \"%s\" in directive \"%s\"", bti->paramv[1], directive);
00207     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00208     return (const char *) errbuf;
00209   }
00210 
00211   acl_filter_rule::requeue_in_active_list(&bti->rules_list, rp);
00212   return NULL;
00213 }
00214 
00215 static const char *
00216 parse_deactivate_directive(const char * directive, BUILD_TABLE_INFO * bti, char * errbuf, size_t errbufsize)
00217 {
00218   acl_filter_rule * rp;
00219 
00220   if (bti->paramc < 2) {
00221     snprintf(errbuf, errbufsize, "Directive \"%s\" must have name argument", directive);
00222     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00223     return (const char *) errbuf;
00224   }
00225 
00226   if ((rp = acl_filter_rule::find_byname(bti->rules_list, (const char *) bti->paramv[1])) == NULL) {
00227     snprintf(errbuf, errbufsize, "Undefined filter \"%s\" in directive \"%s\"", bti->paramv[1], directive);
00228     Debug("url_rewrite", "[parse_directive] %s", errbuf);
00229     return (const char *) errbuf;
00230   }
00231 
00232   acl_filter_rule::requeue_in_passive_list(&bti->rules_list, rp);
00233   return NULL;
00234 }
00235 
00236 static const char *
00237 parse_include_directive(const char * directive, BUILD_TABLE_INFO * bti, char * errbuf, size_t errbufsize)
00238 {
00239 
00240   if (bti->paramc < 2) {
00241     snprintf(errbuf, errbufsize, "Directive \"%s\" must have a path argument", directive);
00242     Debug("url_rewrite", "[%s] %s", __func__, errbuf);
00243     return (const char *) errbuf;
00244   }
00245 
00246   for (unsigned i = 1; i < (unsigned) bti->paramc; ++i) {
00247     // We need to create a new bti so that we don't clobber any state in the parent parse, but we want
00248     // to keep the ACL rules from the parent because ACLs must be global across the full set of config
00249     // files.
00250     BUILD_TABLE_INFO  nbti;
00251     ats_scoped_str        path;
00252     bool              success;
00253 
00254     // The included path is relative to SYSCONFDIR, just like remap.config is.
00255     path = Layout::relative_to(Layout::get()->sysconfdir, bti->paramv[i]);
00256 
00257     // XXX including directories is not supported (yet!).
00258     if (ink_file_is_directory(path)) {
00259       snprintf(errbuf, errbufsize, "included path %s is a directory", bti->paramv[i]);
00260       return (const char *)errbuf;
00261     }
00262 
00263     nbti.rules_list = bti->rules_list;
00264     nbti.rewrite = bti->rewrite;
00265 
00266     // XXX at this point, we need to register the included file(s) with the management subsystem
00267     // so that we can correctly reload them when they change. Otherwise, the operator will have to
00268     // touch remap.config before reloading the configuration.
00269 
00270     Debug("url_rewrite", "[%s] including remap configuration from %s", __func__, (const char *)path);
00271     success = remap_parse_config_bti(path, &nbti);
00272 
00273     // The sub-parse might have updated the rules list, so push it up to the parent parse.
00274     bti->rules_list = nbti.rules_list;
00275 
00276     if (!success) {
00277       snprintf(errbuf, errbufsize, "failed to parse included file %s", bti->paramv[i]);
00278       return (const char *)errbuf;
00279     }
00280   }
00281 
00282   return NULL;
00283 }
00284 
00285 struct remap_directive
00286 {
00287   const char * name;
00288   const char * (*parser)(const char *, BUILD_TABLE_INFO *, char *, size_t);
00289 };
00290 
00291 static const remap_directive directives[] = {
00292 
00293   { ".definefilter", parse_define_directive},
00294   { ".deffilter", parse_define_directive},
00295   { ".defflt", parse_define_directive},
00296 
00297   { ".deletefilter", parse_delete_directive},
00298   { ".delfilter", parse_delete_directive},
00299   { ".delflt", parse_delete_directive},
00300 
00301   { ".usefilter", parse_activate_directive},
00302   { ".activefilter", parse_activate_directive},
00303   { ".activatefilter", parse_activate_directive},
00304   { ".useflt", parse_activate_directive},
00305 
00306   { ".unusefilter", parse_deactivate_directive},
00307   { ".deactivatefilter", parse_deactivate_directive},
00308   { ".unactivefilter", parse_deactivate_directive},
00309   { ".deuseflt", parse_deactivate_directive},
00310   { ".unuseflt", parse_deactivate_directive},
00311 
00312   { ".include", parse_include_directive },
00313 };
00314 
00315 const char *
00316 remap_parse_directive(BUILD_TABLE_INFO *bti, char * errbuf, size_t errbufsize)
00317 {
00318   const char * directive = NULL;
00319 
00320   // Check arguments
00321   if (unlikely(!bti || !errbuf || errbufsize <= 0 || !bti->paramc || (directive = bti->paramv[0]) == NULL)) {
00322     Debug("url_rewrite", "[parse_directive] Invalid argument(s)");
00323     return "Invalid argument(s)";
00324   }
00325 
00326   for (unsigned i = 0; i < countof(directives); ++i) {
00327     if (strcmp(directive, directives[i].name) == 0) {
00328       return directives[i].parser(directive, bti, errbuf, errbufsize);
00329     }
00330   }
00331 
00332   snprintf(errbuf, errbufsize, "Unknown directive \"%s\"", directive);
00333   Debug("url_rewrite", "[parse_directive] %s", errbuf);
00334   return (const char *) errbuf;
00335 }
00336 
00337 const char *
00338 remap_validate_filter_args(acl_filter_rule ** rule_pp, const char ** argv, int argc, char * errStrBuf, size_t errStrBufSize)
00339 {
00340   acl_filter_rule *rule;
00341   unsigned long ul;
00342   const char *argptr;
00343   char tmpbuf[1024];
00344   src_ip_info_t *ipi;
00345   int i, j, m;
00346   bool new_rule_flg = false;
00347 
00348   if (!rule_pp) {
00349     Debug("url_rewrite", "[validate_filter_args] Invalid argument(s)");
00350     return (const char *) "Invalid argument(s)";
00351   }
00352 
00353   if (is_debug_tag_set("url_rewrite")) {
00354     printf("validate_filter_args: ");
00355     for (i = 0; i < argc; i++)
00356       printf("\"%s\" ", argv[i]);
00357     printf("\n");
00358   }
00359 
00360   if ((rule = *rule_pp) == NULL) {
00361     rule = new acl_filter_rule();
00362     if (unlikely((*rule_pp = rule) == NULL)) {
00363       Debug("url_rewrite", "[validate_filter_args] Memory allocation error");
00364       return (const char *) "Memory allocation Error";
00365     }
00366     new_rule_flg = true;
00367     Debug("url_rewrite", "[validate_filter_args] new acl_filter_rule class was created during remap rule processing");
00368   }
00369 
00370   for (i = 0; i < argc; i++) {
00371     if ((ul = remap_check_option((const char **)&argv[i], 1, 0, NULL, &argptr)) == 0) {
00372       Debug("url_rewrite", "[validate_filter_args] Unknow remap option - %s", argv[i]);
00373       snprintf(errStrBuf, errStrBufSize, "Unknown option - \"%s\"", argv[i]);
00374       errStrBuf[errStrBufSize - 1] = 0;
00375       if (new_rule_flg) {
00376         delete rule;
00377         *rule_pp = NULL;
00378       }
00379       return (const char *) errStrBuf;
00380     }
00381     if (!argptr || !argptr[0]) {
00382       Debug("url_rewrite", "[validate_filter_args] Empty argument in %s", argv[i]);
00383       snprintf(errStrBuf, errStrBufSize, "Empty argument in \"%s\"", argv[i]);
00384       errStrBuf[errStrBufSize - 1] = 0;
00385       if (new_rule_flg) {
00386         delete rule;
00387         *rule_pp = NULL;
00388       }
00389       return (const char *) errStrBuf;
00390     }
00391 
00392     if (ul & REMAP_OPTFLG_METHOD) {     /* "method=" option */
00393       // Please remember that the order of hash idx creation is very important and it is defined
00394       // in HTTP.cc file
00395       m = -1;
00396       if (!strcasecmp(argptr, "CONNECT"))
00397         m = HTTP_WKSIDX_CONNECT;
00398       else if (!strcasecmp(argptr, "DELETE"))
00399         m = HTTP_WKSIDX_DELETE;
00400       else if (!strcasecmp(argptr, "GET"))
00401         m = HTTP_WKSIDX_GET;
00402       else if (!strcasecmp(argptr, "HEAD"))
00403         m = HTTP_WKSIDX_HEAD;
00404       else if (!strcasecmp(argptr, "ICP_QUERY"))
00405         m = HTTP_WKSIDX_ICP_QUERY;
00406       else if (!strcasecmp(argptr, "OPTIONS"))
00407         m = HTTP_WKSIDX_OPTIONS;
00408       else if (!strcasecmp(argptr, "POST"))
00409         m = HTTP_WKSIDX_POST;
00410       else if (!strcasecmp(argptr, "PURGE"))
00411         m = HTTP_WKSIDX_PURGE;
00412       else if (!strcasecmp(argptr, "PUT"))
00413         m = HTTP_WKSIDX_PUT;
00414       else if (!strcasecmp(argptr, "TRACE"))
00415         m = HTTP_WKSIDX_TRACE;
00416       else if (!strcasecmp(argptr, "PUSH"))
00417         m = HTTP_WKSIDX_PUSH;
00418       if (m != -1) {
00419         m = m - HTTP_WKSIDX_CONNECT;    // get method index
00420         rule->standard_method_lookup[m] = true;
00421       } else {
00422         Debug("url_rewrite", "[validate_filter_args] Using nonstandard method [%s]", argptr);
00423         rule->nonstandard_methods.insert(argptr);
00424       }
00425       rule->method_restriction_enabled = true;
00426     } else if (ul & REMAP_OPTFLG_SRC_IP) {      /* "src_ip=" option */
00427       if (rule->src_ip_cnt >= ACL_FILTER_MAX_SRC_IP) {
00428         Debug("url_rewrite", "[validate_filter_args] Too many \"src_ip=\" filters");
00429         snprintf(errStrBuf, errStrBufSize, "Defined more than %d \"src_ip=\" filters!", ACL_FILTER_MAX_SRC_IP);
00430         errStrBuf[errStrBufSize - 1] = 0;
00431         if (new_rule_flg) {
00432           delete rule;
00433           *rule_pp = NULL;
00434         }
00435         return (const char *) errStrBuf;
00436       }
00437       ipi = &rule->src_ip_array[rule->src_ip_cnt];
00438       if (ul & REMAP_OPTFLG_INVERT)
00439         ipi->invert = true;
00440       ink_strlcpy(tmpbuf, argptr, sizeof(tmpbuf));
00441       // important! use copy of argument
00442       if (ExtractIpRange(tmpbuf, &ipi->start.sa, &ipi->end.sa) != NULL) {
00443         Debug("url_rewrite", "[validate_filter_args] Unable to parse IP value in %s", argv[i]);
00444         snprintf(errStrBuf, errStrBufSize, "Unable to parse IP value in %s", argv[i]);
00445         errStrBuf[errStrBufSize - 1] = 0;
00446         if (new_rule_flg) {
00447           delete rule;
00448           *rule_pp = NULL;
00449         }
00450         return (const char*) errStrBuf;
00451       }
00452       for (j = 0; j < rule->src_ip_cnt; j++) {
00453         if (rule->src_ip_array[j].start == ipi->start && rule->src_ip_array[j].end == ipi->end) {
00454           ipi->reset();
00455           ipi = NULL;
00456           break;                /* we have the same src_ip in the list */
00457         }
00458       }
00459       if (ipi) {
00460         rule->src_ip_cnt++;
00461         rule->src_ip_valid = 1;
00462       }
00463     } else if (ul & REMAP_OPTFLG_ACTION) {      /* "action=" option */
00464       if (is_inkeylist(argptr, "0", "off", "deny", "disable", NULL)) {
00465         rule->allow_flag = 0;
00466       } else if (is_inkeylist(argptr, "1", "on", "allow", "enable", NULL)) {
00467         rule->allow_flag = 1;
00468       } else {
00469         Debug("url_rewrite", "[validate_filter_args] Unknown argument \"%s\"", argv[i]);
00470         snprintf(errStrBuf, errStrBufSize, "Unknown argument \"%s\"", argv[i]);
00471         errStrBuf[errStrBufSize - 1] = 0;
00472         if (new_rule_flg) {
00473           delete rule;
00474           *rule_pp = NULL;
00475         }
00476         return (const char *) errStrBuf;
00477       }
00478     }
00479   }
00480 
00481   if (is_debug_tag_set("url_rewrite"))
00482     rule->print();
00483 
00484   return NULL;                  /* success */
00485 }
00486 
00487 unsigned long
00488 remap_check_option(const char ** argv, int argc, unsigned long findmode, int *_ret_idx, const char **argptr)
00489 {
00490   unsigned long ret_flags = 0;
00491   int idx = 0;
00492 
00493   if (argptr)
00494     *argptr = NULL;
00495   if (argv && argc > 0) {
00496     for (int i = 0; i < argc; i++) {
00497       if (!strcasecmp(argv[i], "map_with_referer")) {
00498         if ((findmode & REMAP_OPTFLG_MAP_WITH_REFERER) != 0)
00499           idx = i;
00500         ret_flags |= REMAP_OPTFLG_MAP_WITH_REFERER;
00501       } else if (!strncasecmp(argv[i], "plugin=", 7)) {
00502         if ((findmode & REMAP_OPTFLG_PLUGIN) != 0)
00503           idx = i;
00504         if (argptr)
00505           *argptr = &argv[i][7];
00506         ret_flags |= REMAP_OPTFLG_PLUGIN;
00507       } else if (!strncasecmp(argv[i], "pparam=", 7)) {
00508         if ((findmode & REMAP_OPTFLG_PPARAM) != 0)
00509           idx = i;
00510         if (argptr)
00511           *argptr = &argv[i][7];
00512         ret_flags |= REMAP_OPTFLG_PPARAM;
00513       } else if (!strncasecmp(argv[i], "method=", 7)) {
00514         if ((findmode & REMAP_OPTFLG_METHOD) != 0)
00515           idx = i;
00516         if (argptr)
00517           *argptr = &argv[i][7];
00518         ret_flags |= REMAP_OPTFLG_METHOD;
00519       } else if (!strncasecmp(argv[i], "src_ip=~", 8)) {
00520         if ((findmode & REMAP_OPTFLG_SRC_IP) != 0)
00521           idx = i;
00522         if (argptr)
00523           *argptr = &argv[i][8];
00524         ret_flags |= (REMAP_OPTFLG_SRC_IP | REMAP_OPTFLG_INVERT);
00525       } else if (!strncasecmp(argv[i], "src_ip=", 7)) {
00526         if ((findmode & REMAP_OPTFLG_SRC_IP) != 0)
00527           idx = i;
00528         if (argptr)
00529           *argptr = &argv[i][7];
00530         ret_flags |= REMAP_OPTFLG_SRC_IP;
00531       } else if (!strncasecmp(argv[i], "action=", 7)) {
00532         if ((findmode & REMAP_OPTFLG_ACTION) != 0)
00533           idx = i;
00534         if (argptr)
00535           *argptr = &argv[i][7];
00536         ret_flags |= REMAP_OPTFLG_ACTION;
00537       } else if (!strncasecmp(argv[i], "mapid=", 6)) {
00538         if ((findmode & REMAP_OPTFLG_MAP_ID) != 0)
00539           idx = i;
00540         if (argptr)
00541           *argptr = &argv[i][6];
00542         ret_flags |= REMAP_OPTFLG_MAP_ID;
00543       }
00544 
00545       if ((findmode & ret_flags) && !argptr) {
00546         if (_ret_idx)
00547           *_ret_idx = idx;
00548         return ret_flags;
00549       }
00550 
00551     }
00552   }
00553   if (_ret_idx)
00554     *_ret_idx = idx;
00555   return ret_flags;
00556 }
00557 
00558 int
00559 remap_load_plugin(const char ** argv, int argc, url_mapping *mp, char *errbuf, int errbufsize,
00560     int jump_to_argc, int *plugin_found_at)
00561 {
00562   TSRemapInterface ri;
00563   struct stat stat_buf;
00564   remap_plugin_info *pi;
00565   char *c, *err, tmpbuf[2048], default_path[PATH_NAME_MAX];
00566   const char *new_argv[1024];
00567   char * parv[1024];
00568   int idx = 0, retcode = 0;
00569   int parc = 0;
00570 
00571   *plugin_found_at = 0;
00572 
00573   memset(parv, 0, sizeof(parv));
00574   memset(new_argv, 0, sizeof(new_argv));
00575   tmpbuf[0] = 0;
00576 
00577   ink_assert((unsigned) argc < countof(new_argv));
00578 
00579   if (jump_to_argc != 0) {
00580     argc -= jump_to_argc;
00581     int i = 0;
00582     while (argv[i + jump_to_argc]) {
00583       new_argv[i] = argv[i + jump_to_argc];
00584       i++;
00585     }
00586     argv = &new_argv[0];
00587     if (!remap_check_option(argv, argc, REMAP_OPTFLG_PLUGIN, &idx)) {
00588       return -1;
00589     }
00590   } else {
00591     if (unlikely(!mp || (remap_check_option(argv, argc, REMAP_OPTFLG_PLUGIN, &idx) & REMAP_OPTFLG_PLUGIN) == 0)) {
00592       snprintf(errbuf, errbufsize, "Can't find remap plugin keyword or \"url_mapping\" is NULL");
00593       return -1;                /* incorrect input data - almost impossible case */
00594     }
00595   }
00596 
00597   if (unlikely((c = (char *) strchr(argv[idx], (int) '=')) == NULL || !(*(++c)))) {
00598     snprintf(errbuf, errbufsize, "Can't find remap plugin file name in \"@%s\"", argv[idx]);
00599     return -2;                  /* incorrect input data */
00600   }
00601 
00602   if (stat(c, &stat_buf) != 0) {
00603     const char *plugin_default_path = TSPluginDirGet();
00604 
00605     // Try with the plugin path instead
00606     if (strlen(c) + strlen(plugin_default_path) > (PATH_NAME_MAX - 1)) {
00607       Debug("remap_plugin", "way too large a path specified for remap plugin");
00608       return -3;
00609     }
00610 
00611     snprintf(default_path, PATH_NAME_MAX, "%s/%s", plugin_default_path, c);
00612     Debug("remap_plugin", "attempting to stat default plugin path: %s", default_path);
00613 
00614     if (stat(default_path, &stat_buf) == 0) {
00615       Debug("remap_plugin", "stat successful on %s using that", default_path);
00616       c = &default_path[0];
00617     } else {
00618       snprintf(errbuf, errbufsize, "Can't find remap plugin file \"%s\"", c);
00619       return -3;
00620     }
00621   }
00622 
00623   Debug("remap_plugin", "using path %s for plugin", c);
00624 
00625   if (!remap_pi_list || (pi = remap_pi_list->find_by_path(c)) == 0) {
00626     pi = new remap_plugin_info(c);
00627     if (!remap_pi_list) {
00628       remap_pi_list = pi;
00629     } else {
00630       remap_pi_list->add_to_list(pi);
00631     }
00632     Debug("remap_plugin", "New remap plugin info created for \"%s\"", c);
00633 
00634     // elevate the access to read files as root if compiled with capabilities, if not
00635     // change the effective user to root
00636     {
00637       uint32_t elevate_access = 0;
00638       REC_ReadConfigInteger(elevate_access, "proxy.config.plugin.load_elevated");
00639       ElevateAccess access(elevate_access != 0);
00640 
00641       if ((pi->dlh = dlopen(c, RTLD_NOW)) == NULL) {
00642 #if defined(freebsd) || defined(openbsd)
00643         err = (char *)dlerror();
00644 #else
00645         err = dlerror();
00646 #endif
00647         snprintf(errbuf, errbufsize, "Can't load plugin \"%s\" - %s", c, err ? err : "Unknown dlopen() error");
00648         return -4;
00649       }
00650       pi->fp_tsremap_init = (remap_plugin_info::_tsremap_init *) dlsym(pi->dlh, TSREMAP_FUNCNAME_INIT);
00651       pi->fp_tsremap_done = (remap_plugin_info::_tsremap_done *) dlsym(pi->dlh, TSREMAP_FUNCNAME_DONE);
00652       pi->fp_tsremap_new_instance = (remap_plugin_info::_tsremap_new_instance *) dlsym(pi->dlh, TSREMAP_FUNCNAME_NEW_INSTANCE);
00653       pi->fp_tsremap_delete_instance = (remap_plugin_info::_tsremap_delete_instance *) dlsym(pi->dlh, TSREMAP_FUNCNAME_DELETE_INSTANCE);
00654       pi->fp_tsremap_do_remap = (remap_plugin_info::_tsremap_do_remap *) dlsym(pi->dlh, TSREMAP_FUNCNAME_DO_REMAP);
00655       pi->fp_tsremap_os_response = (remap_plugin_info::_tsremap_os_response *) dlsym(pi->dlh, TSREMAP_FUNCNAME_OS_RESPONSE);
00656 
00657       if (!pi->fp_tsremap_init) {
00658         snprintf(errbuf, errbufsize, "Can't find \"%s\" function in remap plugin \"%s\"", TSREMAP_FUNCNAME_INIT, c);
00659         retcode = -10;
00660       } else if (!pi->fp_tsremap_new_instance) {
00661         snprintf(errbuf, errbufsize, "Can't find \"%s\" function in remap plugin \"%s\"",
00662             TSREMAP_FUNCNAME_NEW_INSTANCE, c);
00663         retcode = -11;
00664       } else if (!pi->fp_tsremap_do_remap) {
00665         snprintf(errbuf, errbufsize, "Can't find \"%s\" function in remap plugin \"%s\"", TSREMAP_FUNCNAME_DO_REMAP, c);
00666         retcode = -12;
00667       }
00668       if (retcode) {
00669         if (errbuf && errbufsize > 0)
00670           Debug("remap_plugin", "%s", errbuf);
00671         dlclose(pi->dlh);
00672         pi->dlh = NULL;
00673         return retcode;
00674       }
00675       memset(&ri, 0, sizeof(ri));
00676       ri.size = sizeof(ri);
00677       ri.tsremap_version = TSREMAP_VERSION;
00678 
00679       if (pi->fp_tsremap_init(&ri, tmpbuf, sizeof(tmpbuf) - 1) != TS_SUCCESS) {
00680         Warning("Failed to initialize plugin %s (non-zero retval) ... bailing out", pi->path);
00681         return -5;
00682       }
00683     } // done elevating access
00684     Debug("remap_plugin", "Remap plugin \"%s\" - initialization completed", c);
00685   }
00686 
00687   if (!pi->dlh) {
00688     snprintf(errbuf, errbufsize, "Can't load plugin \"%s\"", c);
00689     return -6;
00690   }
00691 
00692   if ((err = mp->fromURL.string_get(NULL)) == NULL) {
00693     snprintf(errbuf, errbufsize, "Can't load fromURL from URL class");
00694     return -7;
00695   }
00696   parv[parc++] = ats_strdup(err);
00697   ats_free(err);
00698 
00699   if ((err = mp->toUrl.string_get(NULL)) == NULL) {
00700     snprintf(errbuf, errbufsize, "Can't load toURL from URL class");
00701     return -7;
00702   }
00703   parv[parc++] = ats_strdup(err);
00704   ats_free(err);
00705 
00706   bool plugin_encountered = false;
00707   // how many plugin parameters we have for this remapping
00708   for (idx = 0; idx < argc && parc < (int) (countof(parv) - 1); idx++) {
00709 
00710     if (plugin_encountered && !strncasecmp("plugin=", argv[idx], 7) && argv[idx][7]) {
00711       *plugin_found_at = idx;
00712       break;                    //if there is another plugin, lets deal with that later
00713     }
00714 
00715     if (!strncasecmp("plugin=", argv[idx], 7)) {
00716       plugin_encountered = true;
00717     }
00718 
00719     if (!strncasecmp("pparam=", argv[idx], 7) && argv[idx][7]) {
00720       parv[parc++] = const_cast<char *>(&(argv[idx][7]));
00721     }
00722   }
00723 
00724   Debug("url_rewrite", "Viewing all parameters for config line");
00725   for (int k = 0; k < argc; k++) {
00726     Debug("url_rewrite", "Argument %d: %s", k, argv[k]);
00727   }
00728 
00729   Debug("url_rewrite", "Viewing parsed plugin parameters for %s: [%d]", pi->path, *plugin_found_at);
00730   for (int k = 0; k < parc; k++) {
00731     Debug("url_rewrite", "Argument %d: %s", k, parv[k]);
00732   }
00733 
00734   void* ih;
00735 
00736   Debug("remap_plugin", "creating new plugin instance");
00737 
00738   TSReturnCode res = TS_ERROR;
00739   res = pi->fp_tsremap_new_instance(parc, parv, &ih, tmpbuf, sizeof(tmpbuf) - 1);
00740 
00741   Debug("remap_plugin", "done creating new plugin instance");
00742 
00743   ats_free(parv[0]);               // fromURL
00744   ats_free(parv[1]);               // toURL
00745 
00746   if (res != TS_SUCCESS) {
00747     snprintf(errbuf, errbufsize, "Can't create new remap instance for plugin \"%s\" - %s", c,
00748                  tmpbuf[0] ? tmpbuf : "Unknown plugin error");
00749     Warning("Failed to create new instance for plugin %s (not a TS_SUCCESS return)", pi->path);
00750     return -8;
00751   }
00752 
00753   mp->add_plugin(pi, ih);
00754 
00755   return 0;
00756 }
00757 /** will process the regex mapping configuration and create objects in
00758     output argument reg_map. It assumes existing data in reg_map is
00759     inconsequential and will be perfunctorily null-ed;
00760 */
00761 static bool
00762 process_regex_mapping_config(const char *from_host_lower, url_mapping *new_mapping, UrlRewrite::RegexMapping *reg_map)
00763 {
00764   const char *str;
00765   int str_index;
00766   const char *to_host;
00767   int to_host_len;
00768   int substitution_id;
00769   int substitution_count = 0;
00770 
00771   reg_map->re = NULL;
00772   reg_map->re_extra = NULL;
00773   reg_map->to_url_host_template = NULL;
00774   reg_map->to_url_host_template_len = 0;
00775   reg_map->n_substitutions = 0;
00776 
00777   reg_map->url_map = new_mapping;
00778 
00779   // using from_host_lower (and not new_mapping->fromURL.host_get())
00780   // as this one will be NULL-terminated (required by pcre_compile)
00781   reg_map->re = pcre_compile(from_host_lower, 0, &str, &str_index, NULL);
00782   if (reg_map->re == NULL) {
00783     Warning("pcre_compile failed! Regex has error starting at %s", from_host_lower + str_index);
00784     goto lFail;
00785   }
00786 
00787   reg_map->re_extra = pcre_study(reg_map->re, 0, &str);
00788   if ((reg_map->re_extra == NULL) && (str != NULL)) {
00789     Warning("pcre_study failed with message [%s]", str);
00790     goto lFail;
00791   }
00792 
00793   int n_captures;
00794   if (pcre_fullinfo(reg_map->re, reg_map->re_extra, PCRE_INFO_CAPTURECOUNT, &n_captures) != 0) {
00795     Warning("pcre_fullinfo failed!");
00796     goto lFail;
00797   }
00798   if (n_captures >= UrlRewrite::MAX_REGEX_SUBS) { // off by one for $0 (implicit capture)
00799     Warning("Regex has %d capturing subpatterns (including entire regex); Max allowed: %d",
00800             n_captures + 1, UrlRewrite::MAX_REGEX_SUBS);
00801     goto lFail;
00802   }
00803 
00804   to_host = new_mapping->toUrl.host_get(&to_host_len);
00805   for (int i = 0; i < (to_host_len - 1); ++i) {
00806     if (to_host[i] == '$') {
00807       if (substitution_count > UrlRewrite::MAX_REGEX_SUBS) {
00808         Warning("Cannot have more than %d substitutions in mapping with host [%s]",
00809                 UrlRewrite::MAX_REGEX_SUBS, from_host_lower);
00810         goto lFail;
00811       }
00812       substitution_id = to_host[i + 1] - '0';
00813       if ((substitution_id < 0) || (substitution_id > n_captures)) {
00814         Warning("Substitution id [%c] has no corresponding capture pattern in regex [%s]",
00815               to_host[i + 1], from_host_lower);
00816         goto lFail;
00817       }
00818       reg_map->substitution_markers[reg_map->n_substitutions] = i;
00819       reg_map->substitution_ids[reg_map->n_substitutions] = substitution_id;
00820       ++reg_map->n_substitutions;
00821     }
00822   }
00823 
00824   // so the regex itself is stored in fromURL.host; string to match
00825   // will be in the request; string to use for substitutions will be
00826   // in this buffer
00827   str = new_mapping->toUrl.host_get(&str_index); // reusing str and str_index
00828   reg_map->to_url_host_template_len = str_index;
00829   reg_map->to_url_host_template = static_cast<char *>(ats_malloc(str_index));
00830   memcpy(reg_map->to_url_host_template, str, str_index);
00831 
00832   return true;
00833 
00834  lFail:
00835   if (reg_map->re) {
00836     pcre_free(reg_map->re);
00837     reg_map->re = NULL;
00838   }
00839   if (reg_map->re_extra) {
00840     pcre_free(reg_map->re_extra);
00841     reg_map->re_extra = NULL;
00842   }
00843   if (reg_map->to_url_host_template) {
00844     ats_free(reg_map->to_url_host_template);
00845     reg_map->to_url_host_template = NULL;
00846     reg_map->to_url_host_template_len = 0;
00847   }
00848   return false;
00849 }
00850 
00851 static bool
00852 remap_parse_config_bti(const char * path, BUILD_TABLE_INFO * bti)
00853 {
00854 
00855   char errBuf[1024], errStrBuf[1024];
00856   Tokenizer whiteTok(" \t");
00857   bool alarm_already = false;
00858   const char *errStr;
00859 
00860   // Vars to parse line in file
00861   char *tok_state, *cur_line, *cur_line_tmp;
00862   int rparse, cur_line_size, cln = 0;        // Our current line number
00863 
00864   // Vars to build the mapping
00865   const char *fromScheme, *toScheme;
00866   int fromSchemeLen, toSchemeLen;
00867   const char *fromHost, *toHost;
00868   int fromHostLen, toHostLen;
00869   char *map_from, *map_from_start;
00870   char *map_to, *map_to_start;
00871   const char *tmp;              // Appease the DEC compiler
00872   char *fromHost_lower = NULL;
00873   char *fromHost_lower_ptr = NULL;
00874   char fromHost_lower_buf[1024];
00875   url_mapping *new_mapping = NULL;
00876   mapping_type maptype;
00877   referer_info *ri;
00878   int origLength;
00879   int length;
00880   int tok_count;
00881 
00882   UrlRewrite::RegexMapping* reg_map;
00883   bool is_cur_mapping_regex;
00884   const char *type_id_str;
00885 
00886   ats_scoped_str file_buf(readIntoBuffer(path, modulePrefix, NULL));
00887   if (!file_buf) {
00888     Warning("can't load remapping configuration file %s", path);
00889     return false;
00890   }
00891 
00892   Debug("url_rewrite", "[BuildTable] UrlRewrite::BuildTable()");
00893 
00894   for (cur_line = tokLine(file_buf, &tok_state, '\\'); cur_line != NULL;) {
00895     reg_map = NULL;
00896     new_mapping = NULL;
00897     errStrBuf[0] = 0;
00898     bti->reset();
00899 
00900     // Strip leading whitespace
00901     while (*cur_line && isascii(*cur_line) && isspace(*cur_line))
00902       ++cur_line;
00903 
00904     if ((cur_line_size = strlen((char *) cur_line)) <= 0) {
00905       cur_line = tokLine(NULL, &tok_state, '\\');
00906       ++cln;
00907       continue;
00908     }
00909 
00910     // Strip trailing whitespace
00911     cur_line_tmp = cur_line + cur_line_size - 1;
00912     while (cur_line_tmp != cur_line && isascii(*cur_line_tmp) && isspace(*cur_line_tmp)) {
00913       *cur_line_tmp = '\0';
00914       --cur_line_tmp;
00915     }
00916 
00917     if ((cur_line_size = strlen((char *) cur_line)) <= 0 || *cur_line == '#' || *cur_line == '\0') {
00918       cur_line = tokLine(NULL, &tok_state, '\\');
00919       ++cln;
00920       continue;
00921     }
00922 
00923     Debug("url_rewrite", "[BuildTable] Parsing: \"%s\"", cur_line);
00924 
00925     tok_count = whiteTok.Initialize(cur_line, SHARE_TOKS);
00926 
00927     for (int j = 0; j < tok_count; j++) {
00928       if (((char *) whiteTok[j])[0] == '@') {
00929         if (((char *) whiteTok[j])[1])
00930           bti->argv[bti->argc++] = ats_strdup(&(((char *) whiteTok[j])[1]));
00931       } else {
00932         bti->paramv[bti->paramc++] = ats_strdup((char *) whiteTok[j]);
00933       }
00934     }
00935 
00936     // Initial verification for number of arguments
00937     if (bti->paramc<1 || (bti->paramc < 3 && bti->paramv[0][0] != '.') || bti->paramc> BUILD_TABLE_MAX_ARGS) {
00938       snprintf(errBuf, sizeof(errBuf), "%s Malformed line %d in file %s", modulePrefix, cln + 1, path);
00939       errStr = errStrBuf;
00940       goto MAP_ERROR;
00941     }
00942     // just check all major flags/optional arguments
00943     bti->remap_optflg = remap_check_option((const char **)bti->argv, bti->argc);
00944 
00945     // Check directive keywords (starting from '.')
00946     if (bti->paramv[0][0] == '.') {
00947       if ((errStr = remap_parse_directive(bti, errStrBuf, sizeof(errStrBuf))) != NULL) {
00948         snprintf(errBuf, sizeof(errBuf) - 1, "%s Error on line %d - %s", modulePrefix, cln + 1, errStr);
00949         errStr = errStrBuf;
00950         goto MAP_ERROR;
00951       }
00952       // We skip the rest of the parsing here.
00953       cur_line = tokLine(NULL, &tok_state, '\\');
00954       ++cln;
00955       continue;
00956     }
00957 
00958     is_cur_mapping_regex = (strncasecmp("regex_", bti->paramv[0], 6) == 0);
00959     type_id_str = is_cur_mapping_regex ? (bti->paramv[0] + 6) : bti->paramv[0];
00960 
00961     // Check to see whether is a reverse or forward mapping
00962     if (!strcasecmp("reverse_map", type_id_str)) {
00963       Debug("url_rewrite", "[BuildTable] - REVERSE_MAP");
00964       maptype = REVERSE_MAP;
00965     } else if (!strcasecmp("map", type_id_str)) {
00966       Debug("url_rewrite", "[BuildTable] - %s",
00967             ((bti->remap_optflg & REMAP_OPTFLG_MAP_WITH_REFERER) == 0) ? "FORWARD_MAP" : "FORWARD_MAP_REFERER");
00968       maptype = ((bti->remap_optflg & REMAP_OPTFLG_MAP_WITH_REFERER) == 0) ? FORWARD_MAP : FORWARD_MAP_REFERER;
00969     } else if (!strcasecmp("redirect", type_id_str)) {
00970       Debug("url_rewrite", "[BuildTable] - PERMANENT_REDIRECT");
00971       maptype = PERMANENT_REDIRECT;
00972     } else if (!strcasecmp("redirect_temporary", type_id_str)) {
00973       Debug("url_rewrite", "[BuildTable] - TEMPORARY_REDIRECT");
00974       maptype = TEMPORARY_REDIRECT;
00975     } else if (!strcasecmp("map_with_referer", type_id_str)) {
00976       Debug("url_rewrite", "[BuildTable] - FORWARD_MAP_REFERER");
00977       maptype = FORWARD_MAP_REFERER;
00978     } else if (!strcasecmp("map_with_recv_port", type_id_str)) {
00979       Debug("url_rewrite", "[BuildTable] - FORWARD_MAP_WITH_RECV_PORT");
00980       maptype = FORWARD_MAP_WITH_RECV_PORT;
00981     } else {
00982       snprintf(errBuf, sizeof(errBuf) - 1, "%s Unknown mapping type at line %d", modulePrefix, cln + 1);
00983       errStr = errStrBuf;
00984       goto MAP_ERROR;
00985     }
00986 
00987     new_mapping = new url_mapping(cln);  // use line # for rank for now
00988 
00989     // apply filter rules if we have to
00990     if ((errStr = process_filter_opt(new_mapping, bti, errStrBuf, sizeof(errStrBuf))) != NULL) {
00991       goto MAP_ERROR;
00992     }
00993 
00994     new_mapping->map_id = 0;
00995     if ((bti->remap_optflg & REMAP_OPTFLG_MAP_ID) != 0) {
00996       int idx = 0;
00997       char *c;
00998       int ret = remap_check_option((const char **)bti->argv, bti->argc, REMAP_OPTFLG_MAP_ID, &idx);
00999       if (ret & REMAP_OPTFLG_MAP_ID) {
01000         c = strchr(bti->argv[idx], (int) '=');
01001         new_mapping->map_id = (unsigned int) atoi(++c);
01002       }
01003     }
01004 
01005     map_from = bti->paramv[1];
01006     length = UrlWhack(map_from, &origLength);
01007 
01008     // FIX --- what does this comment mean?
01009     //
01010     // URL::create modified map_from so keep a point to
01011     //   the beginning of the string
01012     if ((tmp = (map_from_start = map_from)) != NULL && length > 2 && tmp[length - 1] == '/' && tmp[length - 2] == '/') {
01013       new_mapping->unique = true;
01014       length -= 2;
01015     }
01016 
01017     new_mapping->fromURL.create(NULL);
01018     rparse = new_mapping->fromURL.parse_no_path_component_breakdown(tmp, length);
01019 
01020     map_from_start[origLength] = '\0';  // Unwhack
01021 
01022     if (rparse != PARSE_DONE) {
01023       errStr = "Malformed From URL";
01024       goto MAP_ERROR;
01025     }
01026 
01027     map_to = bti->paramv[2];
01028     length = UrlWhack(map_to, &origLength);
01029     map_to_start = map_to;
01030     tmp = map_to;
01031 
01032     new_mapping->toUrl.create(NULL);
01033     rparse = new_mapping->toUrl.parse_no_path_component_breakdown(tmp, length);
01034     map_to_start[origLength] = '\0';    // Unwhack
01035 
01036     if (rparse != PARSE_DONE) {
01037       errStr = "Malformed To URL";
01038       goto MAP_ERROR;
01039     }
01040 
01041     fromScheme = new_mapping->fromURL.scheme_get(&fromSchemeLen);
01042     // If the rule is "/" or just some other relative path
01043     //   we need to default the scheme to http
01044     if (fromScheme == NULL || fromSchemeLen == 0) {
01045       new_mapping->fromURL.scheme_set(URL_SCHEME_HTTP, URL_LEN_HTTP);
01046       fromScheme = new_mapping->fromURL.scheme_get(&fromSchemeLen);
01047       new_mapping->wildcard_from_scheme = true;
01048     }
01049     toScheme = new_mapping->toUrl.scheme_get(&toSchemeLen);
01050 
01051     // Include support for HTTPS scheme
01052     // includes support for FILE scheme
01053     if ((fromScheme != URL_SCHEME_HTTP && fromScheme != URL_SCHEME_HTTPS &&
01054          fromScheme != URL_SCHEME_FILE &&
01055          fromScheme != URL_SCHEME_TUNNEL &&
01056          fromScheme != URL_SCHEME_WS &&
01057          fromScheme != URL_SCHEME_WSS) ||
01058         (toScheme != URL_SCHEME_HTTP && toScheme != URL_SCHEME_HTTPS &&
01059          toScheme != URL_SCHEME_TUNNEL && toScheme != URL_SCHEME_WS &&
01060          toScheme != URL_SCHEME_WSS)) {
01061       errStr = "Only http, https, ws, wss, and tunnel remappings are supported";
01062       goto MAP_ERROR;
01063     }
01064 
01065     // If mapping from WS or WSS we must map out to WS or WSS
01066     if ( (fromScheme == URL_SCHEME_WSS || fromScheme == URL_SCHEME_WS) &&
01067          (toScheme != URL_SCHEME_WSS && toScheme != URL_SCHEME_WS)) {
01068       errStr = "WS or WSS can only be mapped out to WS or WSS.";
01069       goto MAP_ERROR;
01070     }
01071 
01072     // Check if a tag is specified.
01073     if (bti->paramv[3] != NULL) {
01074       if (maptype == FORWARD_MAP_REFERER) {
01075         new_mapping->filter_redirect_url = ats_strdup(bti->paramv[3]);
01076         if (!strcasecmp(bti->paramv[3], "<default>") || !strcasecmp(bti->paramv[3], "default") ||
01077             !strcasecmp(bti->paramv[3], "<default_redirect_url>") || !strcasecmp(bti->paramv[3], "default_redirect_url"))
01078           new_mapping->default_redirect_url = true;
01079         new_mapping->redir_chunk_list = redirect_tag_str::parse_format_redirect_url(bti->paramv[3]);
01080         for (int j = bti->paramc; j > 4; j--) {
01081           if (bti->paramv[j - 1] != NULL) {
01082             char refinfo_error_buf[1024];
01083             bool refinfo_error = false;
01084 
01085             ri = new referer_info((char *)bti->paramv[j - 1], &refinfo_error, refinfo_error_buf,
01086                                       sizeof(refinfo_error_buf));
01087             if (refinfo_error) {
01088               snprintf(errBuf, sizeof(errBuf), "%s Incorrect Referer regular expression \"%s\" at line %d - %s",
01089                            modulePrefix, bti->paramv[j - 1], cln + 1, refinfo_error_buf);
01090               SignalError(errBuf, alarm_already);
01091               delete ri;
01092               ri = 0;
01093             }
01094 
01095             if (ri && ri->negative) {
01096               if (ri->any) {
01097                 new_mapping->optional_referer = true;   /* referer header is optional */
01098                 delete ri;
01099                 ri = 0;
01100               } else {
01101                 new_mapping->negative_referer = true;   /* we have negative referer in list */
01102               }
01103             }
01104             if (ri) {
01105               ri->next = new_mapping->referer_list;
01106               new_mapping->referer_list = ri;
01107             }
01108           }
01109         }
01110       } else {
01111         new_mapping->tag = ats_strdup(&(bti->paramv[3][0]));
01112       }
01113     }
01114     // Check to see the fromHost remapping is a relative one
01115     fromHost = new_mapping->fromURL.host_get(&fromHostLen);
01116     if (fromHost == NULL || fromHostLen <= 0) {
01117       if (maptype == FORWARD_MAP || maptype == FORWARD_MAP_REFERER || maptype == FORWARD_MAP_WITH_RECV_PORT) {
01118         if (*map_from_start != '/') {
01119           errStr = "Relative remappings must begin with a /";
01120           goto MAP_ERROR;
01121         } else {
01122           fromHost = "";
01123           fromHostLen = 0;
01124         }
01125       } else {
01126         errStr = "Remap source in reverse mappings requires a hostname";
01127         goto MAP_ERROR;
01128       }
01129     }
01130 
01131     toHost = new_mapping->toUrl.host_get(&toHostLen);
01132     if (toHost == NULL || toHostLen <= 0) {
01133       errStr = "The remap destinations require a hostname";
01134       goto MAP_ERROR;
01135     }
01136     // Get rid of trailing slashes since they interfere
01137     //  with our ability to send redirects
01138 
01139     // You might be tempted to remove these lines but the new
01140     // optimized header system will introduce problems.  You
01141     // might get two slashes occasionally instead of one because
01142     // the rest of the system assumes that trailing slashes have
01143     // been removed.
01144 
01145     if (unlikely(fromHostLen >= (int) sizeof(fromHost_lower_buf))) {
01146       fromHost_lower = (fromHost_lower_ptr = (char *)ats_malloc(fromHostLen + 1));
01147     } else {
01148       fromHost_lower = &fromHost_lower_buf[0];
01149     }
01150     // Canonicalize the hostname by making it lower case
01151     memcpy(fromHost_lower, fromHost, fromHostLen);
01152     fromHost_lower[fromHostLen] = 0;
01153     LowerCaseStr(fromHost_lower);
01154 
01155     // set the normalized string so nobody else has to normalize this
01156     new_mapping->fromURL.host_set(fromHost_lower, fromHostLen);
01157 
01158     reg_map = NULL;
01159     if (is_cur_mapping_regex) {
01160       reg_map = new UrlRewrite::RegexMapping();
01161       if (!process_regex_mapping_config(fromHost_lower, new_mapping, reg_map)) {
01162         errStr = "Could not process regex mapping config line";
01163         goto MAP_ERROR;
01164       }
01165       Debug("url_rewrite_regex", "Configured regex rule for host [%s]", fromHost_lower);
01166     }
01167 
01168     // If a TS receives a request on a port which is set to tunnel mode
01169     // (ie, blind forwarding) and a client connects directly to the TS,
01170     // then the TS will use its IPv4 address and remap rules given
01171     // to send the request to its proper destination.
01172     // See HttpTransact::HandleBlindTunnel().
01173     // Therefore, for a remap rule like "map tunnel://hostname..."
01174     // in remap.config, we also needs to convert hostname to its IPv4 addr
01175     // and gives a new remap rule with the IPv4 addr.
01176     if ((maptype == FORWARD_MAP || maptype == FORWARD_MAP_REFERER || maptype == FORWARD_MAP_WITH_RECV_PORT) &&
01177         fromScheme == URL_SCHEME_TUNNEL && (fromHost_lower[0]<'0' || fromHost_lower[0]> '9')) {
01178       addrinfo* ai_records; // returned records.
01179       ip_text_buffer ipb; // buffer for address string conversion.
01180       if (0 == getaddrinfo(fromHost_lower, 0, 0, &ai_records)) {
01181         for ( addrinfo* ai_spot = ai_records ; ai_spot ; ai_spot = ai_spot->ai_next) {
01182           if (ats_is_ip(ai_spot->ai_addr) && !ats_is_ip_any(ai_spot->ai_addr)) {
01183             url_mapping *u_mapping;
01184 
01185             ats_ip_ntop(ai_spot->ai_addr, ipb, sizeof ipb);
01186             u_mapping = new url_mapping;
01187             u_mapping->fromURL.create(NULL);
01188             u_mapping->fromURL.copy(&new_mapping->fromURL);
01189             u_mapping->fromURL.host_set(ipb, strlen(ipb));
01190             u_mapping->toUrl.create(NULL);
01191             u_mapping->toUrl.copy(&new_mapping->toUrl);
01192 
01193             if (bti->paramv[3] != NULL) {
01194               u_mapping->tag = ats_strdup(&(bti->paramv[3][0]));
01195             }
01196 
01197             if (!bti->rewrite->InsertForwardMapping(maptype, u_mapping, ipb)) {
01198               errStr = "Unable to add mapping rule to lookup table";
01199               freeaddrinfo(ai_records);
01200               goto MAP_ERROR;
01201             }
01202           }
01203         }
01204 
01205         freeaddrinfo(ai_records);
01206       }
01207     }
01208 
01209     // Check "remap" plugin options and load .so object
01210     if ((bti->remap_optflg & REMAP_OPTFLG_PLUGIN) != 0 && (maptype == FORWARD_MAP || maptype == FORWARD_MAP_REFERER ||
01211                                                           maptype == FORWARD_MAP_WITH_RECV_PORT)) {
01212       if ((remap_check_option((const char **)bti->argv, bti->argc, REMAP_OPTFLG_PLUGIN, &tok_count) & REMAP_OPTFLG_PLUGIN) != 0) {
01213         int plugin_found_at = 0;
01214         int jump_to_argc = 0;
01215 
01216         // this loads the first plugin
01217         if (remap_load_plugin((const char **)bti->argv, bti->argc, new_mapping, errStrBuf, sizeof(errStrBuf), 0, &plugin_found_at)) {
01218           Debug("remap_plugin", "Remap plugin load error - %s", errStrBuf[0] ? errStrBuf : "Unknown error");
01219           errStr = errStrBuf;
01220           goto MAP_ERROR;
01221         }
01222         //this loads any subsequent plugins (if present)
01223         while (plugin_found_at) {
01224           jump_to_argc += plugin_found_at;
01225           if (remap_load_plugin((const char **)bti->argv, bti->argc, new_mapping, errStrBuf, sizeof(errStrBuf), jump_to_argc, &plugin_found_at)) {
01226             Debug("remap_plugin", "Remap plugin load error - %s", errStrBuf[0] ? errStrBuf : "Unknown error");
01227             errStr = errStrBuf;
01228             goto MAP_ERROR;
01229           }
01230         }
01231       }
01232     }
01233 
01234     // Now add the mapping to appropriate container
01235     if (!bti->rewrite->InsertMapping(maptype, new_mapping, reg_map, fromHost_lower, is_cur_mapping_regex)) {
01236       errStr = "Unable to add mapping rule to lookup table";
01237       goto MAP_ERROR;
01238     }
01239 
01240     fromHost_lower_ptr = (char *)ats_free_null(fromHost_lower_ptr);
01241 
01242     cur_line = tokLine(NULL, &tok_state, '\\');
01243     ++cln;
01244     continue;
01245 
01246     // Deal with error / warning scenarios
01247   MAP_ERROR:
01248     Warning("Could not add rule at line #%d; Aborting!", cln + 1);
01249     snprintf(errBuf, sizeof(errBuf), "%s %s at line %d", modulePrefix, errStr, cln + 1);
01250     SignalError(errBuf, alarm_already);
01251     delete reg_map;
01252     delete new_mapping;
01253     return false;
01254   }                             /* end of while(cur_line != NULL) */
01255 
01256   return true;
01257 }
01258 
01259 bool
01260 remap_parse_config(const char * path, UrlRewrite * rewrite)
01261 {
01262     BUILD_TABLE_INFO bti;
01263 
01264     bti.rewrite = rewrite;
01265     return remap_parse_config_bti(path, &bti);
01266 }

Generated by  doxygen 1.7.1