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

RemapProcessor.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
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 "RemapProcessor.h"
00025 
00026 RemapProcessor remapProcessor;
00027 extern ClassAllocator<RemapPlugins> pluginAllocator;
00028 
00029 int
00030 RemapProcessor::start(int num_threads, size_t stacksize)
00031 {
00032   if (_use_separate_remap_thread)
00033     ET_REMAP = eventProcessor.spawn_event_threads(num_threads, "ET_REMAP", stacksize);  // ET_REMAP is a class member
00034 
00035   return 0;
00036 }
00037 
00038 /**
00039   Most of this comes from UrlRewrite::Remap(). Generally, all this does
00040   is set "map" to the appropriate entry from the global rewrite_table
00041   such that we will then have access to the correct url_mapping inside
00042   perform_remap.
00043 
00044 */
00045 bool
00046 RemapProcessor::setup_for_remap(HttpTransact::State *s)
00047 {
00048   Debug("url_rewrite", "setting up for remap: %p", s);
00049   URL *request_url = NULL;
00050   bool mapping_found = false;
00051   HTTPHdr *request_header = &s->hdr_info.client_request;
00052   char **redirect_url = &s->remap_redirect;
00053   const char *request_host;
00054   int request_host_len;
00055   int request_port;
00056   bool proxy_request = false;
00057 
00058   s->reverse_proxy = rewrite_table->reverse_proxy;
00059   s->url_map.set(s->hdr_info.client_request.m_heap);
00060 
00061   ink_assert(redirect_url != NULL);
00062 
00063   if (unlikely((rewrite_table->num_rules_forward == 0) &&
00064                (rewrite_table->num_rules_forward_with_recv_port == 0))) {
00065     ink_assert(rewrite_table->forward_mappings.empty() &&
00066                rewrite_table->forward_mappings_with_recv_port.empty());
00067     Debug("url_rewrite", "[lookup] No forward mappings found; Skipping...");
00068     return false;
00069   }
00070 
00071   // Since we are called before request validity checking
00072   // occurs, make sure that we have both a valid request
00073   // header and a valid URL
00074   if (unlikely(!request_header || (request_url = request_header->url_get()) == NULL || !request_url->valid())) {
00075     Error("NULL or invalid request data");
00076     return false;
00077   }
00078 
00079   request_host = request_header->host_get(&request_host_len);
00080   request_port = request_header->port_get();
00081   proxy_request = request_header->is_target_in_url() || ! s->reverse_proxy;
00082 
00083   // Default to empty host.
00084   if (!request_host) {
00085     request_host = "";
00086     request_host_len = 0;
00087   }
00088 
00089   Debug("url_rewrite", "[lookup] attempting %s lookup", proxy_request ? "proxy" : "normal");
00090 
00091   if (rewrite_table->num_rules_forward_with_recv_port) {
00092     Debug("url_rewrite", "[lookup] forward mappings with recv port found; Using recv port %d",
00093           s->client_info.port);
00094     if (rewrite_table->forwardMappingWithRecvPortLookup(request_url, s->client_info.port,
00095                                                          request_host, request_host_len, s->url_map)) {
00096       Debug("url_rewrite", "Found forward mapping with recv port");
00097       mapping_found = true;
00098     } else if (rewrite_table->num_rules_forward == 0) {
00099       ink_assert(rewrite_table->forward_mappings.empty());
00100       Debug("url_rewrite", "No forward mappings left");
00101       return false;
00102     }
00103   }
00104 
00105   if (!mapping_found) {
00106     mapping_found = rewrite_table->forwardMappingLookup(request_url, request_port, request_host, request_host_len, s->url_map);
00107   }
00108 
00109   // If no rules match and we have a host, check empty host rules since
00110   // they function as default rules for server requests.
00111   // If there's no host, we've already done this.
00112   if (!mapping_found && rewrite_table->nohost_rules && request_host_len) {
00113     Debug("url_rewrite", "[lookup] nothing matched");
00114     mapping_found = rewrite_table->forwardMappingLookup(request_url, 0, "", 0, s->url_map);
00115   }
00116 
00117   if (!proxy_request) { // do extra checks on a server request
00118 
00119     // Save this information for later
00120     // @amc: why is this done only for requests without a host in the URL?
00121     s->hh_info.host_len = request_host_len;
00122     s->hh_info.request_host = request_host;
00123     s->hh_info.request_port = request_port;
00124 
00125     if (mapping_found) {
00126       // Downstream mapping logic (e.g., self::finish_remap())
00127       // apparently assumes the presence of the target in the URL, so
00128       // we need to copy it. Perhaps it's because it's simpler to just
00129       // do the remap on the URL and then fix the field at the end.
00130       request_header->set_url_target_from_host_field();
00131     }
00132   }
00133 
00134   if (mapping_found) {
00135     request_header->mark_target_dirty();
00136   } else {
00137     Debug("url_rewrite", "RemapProcessor::setup_for_remap did not find a mapping");
00138   }
00139 
00140   return mapping_found;
00141 }
00142 
00143 bool
00144 RemapProcessor::finish_remap(HttpTransact::State *s)
00145 {
00146   url_mapping *map = NULL;
00147   HTTPHdr *request_header = &s->hdr_info.client_request;
00148   URL *request_url = request_header->url_get();
00149   char **redirect_url = &s->remap_redirect;
00150   char host_hdr_buf[TS_MAX_HOST_NAME_LEN], tmp_referer_buf[4096], tmp_redirect_buf[4096], tmp_buf[2048], *c;
00151   const char *remapped_host;
00152   int remapped_host_len, remapped_port, tmp;
00153   int from_len;
00154   bool remap_found = false;
00155   referer_info *ri;
00156 
00157   map = s->url_map.getMapping();
00158   if (!map) {
00159     return false;
00160   }
00161   // Do fast ACL filtering (it is safe to check map here)
00162   rewrite_table->PerformACLFiltering(s, map);
00163 
00164   // Check referer filtering rules
00165   if ((s->filter_mask & URL_REMAP_FILTER_REFERER) != 0 && (ri = map->referer_list) != 0) {
00166     const char *referer_hdr = 0;
00167     int referer_len = 0;
00168     bool enabled_flag = map->optional_referer ? true : false;
00169 
00170     if (request_header->presence(MIME_PRESENCE_REFERER) &&
00171         (referer_hdr = request_header->value_get(MIME_FIELD_REFERER, MIME_LEN_REFERER, &referer_len)) != NULL) {
00172       if (referer_len >= (int) sizeof(tmp_referer_buf))
00173         referer_len = (int) (sizeof(tmp_referer_buf) - 1);
00174       memcpy(tmp_referer_buf, referer_hdr, referer_len);
00175       tmp_referer_buf[referer_len] = 0;
00176       for (enabled_flag = false; ri; ri = ri->next) {
00177         if (ri->any) {
00178           enabled_flag = true;
00179           if (!map->negative_referer)
00180             break;
00181         } else if (ri->regx_valid && (pcre_exec(ri->regx, NULL, tmp_referer_buf, referer_len, 0, 0, NULL, 0) != -1)) {
00182           enabled_flag = ri->negative ? false : true;
00183           break;
00184         }
00185       }
00186     }
00187 
00188     if (!enabled_flag) {
00189       if (!map->default_redirect_url) {
00190         if ((s->filter_mask & URL_REMAP_FILTER_REDIRECT_FMT) != 0 && map->redir_chunk_list) {
00191           redirect_tag_str *rc;
00192           tmp_redirect_buf[(tmp = 0)] = 0;
00193           for (rc = map->redir_chunk_list; rc; rc = rc->next) {
00194             c = 0;
00195             switch (rc->type) {
00196             case 's':
00197               c = rc->chunk_str;
00198               break;
00199             case 'r':
00200               c = (referer_len && referer_hdr) ? &tmp_referer_buf[0] : 0;
00201               break;
00202             case 'f':
00203             case 't':
00204               remapped_host = (rc->type == 'f') ?
00205                 map->fromURL.string_get_buf(tmp_buf, (int) sizeof(tmp_buf), &from_len) :
00206                 ((s->url_map).getToURL())->string_get_buf(tmp_buf, (int)sizeof(tmp_buf), &from_len);
00207               if (remapped_host && from_len > 0) {
00208                 c = &tmp_buf[0];
00209               }
00210               break;
00211             case 'o':
00212               c = s->pristine_url.string_get_ref(NULL);
00213               break;
00214             };
00215 
00216             if (c && tmp < (int) (sizeof(tmp_redirect_buf) - 1)) {
00217               tmp += snprintf(&tmp_redirect_buf[tmp], sizeof(tmp_redirect_buf) - tmp, "%s", c);
00218             }
00219           }
00220           tmp_redirect_buf[sizeof(tmp_redirect_buf) - 1] = 0;
00221           *redirect_url = ats_strdup(tmp_redirect_buf);
00222         }
00223       } else {
00224         *redirect_url = ats_strdup(rewrite_table->http_default_redirect_url);
00225       }
00226 
00227       if (*redirect_url == NULL) {
00228         *redirect_url = ats_strdup(map->filter_redirect_url ? map->filter_redirect_url :
00229                                    rewrite_table->http_default_redirect_url);
00230       }
00231 
00232       return false;
00233     }
00234   }
00235 
00236   remap_found = true;
00237 
00238   // We also need to rewrite the "Host:" header if it exists and
00239   //   pristine host hdr is not enabled
00240   int host_len;
00241   const char *host_hdr = request_header->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &host_len);
00242 
00243   if (request_url && host_hdr != NULL && s->txn_conf->maintain_pristine_host_hdr == 0) {
00244     // Debug code to print out old host header.  This was easier before
00245     //  the header conversion.  Now we have to copy to gain null
00246     //  termination for the Debug() call
00247     if (is_debug_tag_set("url_rewrite")) {
00248       int old_host_hdr_len;
00249       char *old_host_hdr = (char *) request_header->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &old_host_hdr_len);
00250 
00251       if (old_host_hdr) {
00252         old_host_hdr = ats_strndup(old_host_hdr, old_host_hdr_len);
00253         Debug("url_rewrite", "Host: Header before rewrite %.*s", old_host_hdr_len, old_host_hdr);
00254         ats_free(old_host_hdr);
00255       }
00256     }
00257     //
00258     // Create the new host header field being careful that our
00259     //   temporary buffer has adequate length
00260     //
00261     remapped_host = request_url->host_get(&remapped_host_len);
00262     remapped_port = request_url->port_get_raw();
00263 
00264     if (TS_MAX_HOST_NAME_LEN > remapped_host_len) {
00265       tmp = remapped_host_len;
00266       memcpy(host_hdr_buf, remapped_host, remapped_host_len);
00267       if (remapped_port) {
00268         tmp += snprintf(host_hdr_buf + remapped_host_len, TS_MAX_HOST_NAME_LEN - remapped_host_len - 1,
00269                         ":%d", remapped_port);
00270     }
00271     } else {
00272       tmp = TS_MAX_HOST_NAME_LEN;
00273     }
00274 
00275     // It is possible that the hostname is too long.  If it is punt,
00276     //   and remove the host header.  If it is too long the HostDB
00277     //   won't be able to resolve it and the request will not go
00278     //   through
00279     if (tmp >= TS_MAX_HOST_NAME_LEN) {
00280       request_header->field_delete(MIME_FIELD_HOST, MIME_LEN_HOST);
00281       Debug("url_rewrite", "Host: Header too long after rewrite");
00282     } else {
00283       Debug("url_rewrite", "Host: Header after rewrite %.*s", tmp, host_hdr_buf);
00284       request_header->value_set(MIME_FIELD_HOST, MIME_LEN_HOST, host_hdr_buf, tmp);
00285     }
00286   }
00287 
00288   request_header->mark_target_dirty();
00289 
00290   return remap_found;
00291 }
00292 
00293 Action *
00294 RemapProcessor::perform_remap(Continuation *cont, HttpTransact::State *s)
00295 {
00296   Debug("url_rewrite", "Beginning RemapProcessor::perform_remap");
00297   HTTPHdr *request_header = &s->hdr_info.client_request;
00298   URL *request_url = request_header->url_get();
00299   url_mapping *map = s->url_map.getMapping();
00300   host_hdr_info *hh_info = &(s->hh_info);
00301 
00302   if (!map) {
00303     Error("Could not find corresponding url_mapping for this transaction %p", s);
00304     Debug("url_rewrite", "Could not find corresponding url_mapping for this transaction");
00305     ink_assert(!"this should never happen -- call setup_for_remap first");
00306     cont->handleEvent(EVENT_REMAP_ERROR, NULL);
00307     return ACTION_RESULT_DONE;
00308   }
00309 
00310   if (_use_separate_remap_thread) {
00311     RemapPlugins *plugins = pluginAllocator.alloc();
00312 
00313     plugins->setState(s);
00314     plugins->setRequestUrl(request_url);
00315     plugins->setRequestHeader(request_header);
00316     plugins->setHostHeaderInfo(hh_info);
00317 
00318     // Execute "inline" if not using separate remap threads.
00319     ink_assert(cont->mutex->thread_holding == this_ethread());
00320     plugins->mutex = cont->mutex;
00321     plugins->action = cont;
00322     SET_CONTINUATION_HANDLER(plugins, &RemapPlugins::run_remap);
00323     eventProcessor.schedule_imm(plugins, ET_REMAP);
00324 
00325     return &plugins->action;
00326   } else {
00327     RemapPlugins plugins(s, request_url, request_header, hh_info);
00328     int ret = 0;
00329 
00330     do {
00331       ret = plugins.run_single_remap();
00332     } while (ret == 0);
00333 
00334     return ACTION_RESULT_DONE;
00335   }
00336 }

Generated by  doxygen 1.7.1