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

CacheControl.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 /*****************************************************************************
00025  *
00026  *  CacheControl.cc - Implementation to Cache Control systtem
00027  *
00028  *
00029  ****************************************************************************/
00030 
00031 #include "ink_config.h"
00032 
00033 #include <sys/types.h>
00034 
00035 #ifdef HAVE_PCRE_PCRE_H
00036 #include <pcre/pcre.h>
00037 #else
00038 #include <pcre.h>
00039 #endif
00040 
00041 #include "CacheControl.h"
00042 #include "ControlMatcher.h"
00043 #include "Main.h"
00044 #include "Error.h"
00045 #include "P_EventSystem.h"
00046 #include "ProxyConfig.h"
00047 #include "HTTP.h"
00048 #include "HttpConfig.h"
00049 #include "StatSystem.h"
00050 #include "P_Cache.h"
00051 
00052 static const char modulePrefix[] = "[CacheControl]";
00053 
00054 # define TWEAK_CACHE_RESPONSES_TO_COOKIES "cache-responses-to-cookies"
00055 
00056 static const char *CC_directive_str[CC_NUM_TYPES] = {
00057   "INVALID",
00058   "REVALIDATE_AFTER",
00059   "NEVER_CACHE",
00060   "STANDARD_CACHE",
00061   "IGNORE_NO_CACHE",
00062   "CLUSTER_CACHE_LOCAL",
00063   "IGNORE_CLIENT_NO_CACHE",
00064   "IGNORE_SERVER_NO_CACHE",
00065   "PIN_IN_CACHE",
00066   "TTL_IN_CACHE"
00067  // "CACHE_AUTH_CONTENT"
00068 };
00069 
00070 typedef ControlMatcher<CacheControlRecord, CacheControlResult> CC_table;
00071 
00072 // Global Ptrs
00073 static Ptr<ProxyMutex> reconfig_mutex;
00074 CC_table *CacheControlTable = NULL;
00075 
00076 void
00077 CC_delete_table()
00078 {
00079   delete CacheControlTable;
00080 }
00081 
00082 // struct CC_FreerContinuation
00083 // Continuation to free old cache control lists after
00084 //  a timeout
00085 //
00086 struct CC_FreerContinuation;
00087 typedef int (CC_FreerContinuation::*CC_FreerContHandler) (int, void *);
00088 struct CC_FreerContinuation: public Continuation
00089 {
00090   CC_table *p;
00091   int freeEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
00092   {
00093     Debug("cache_control", "Deleting old table");
00094     delete p;
00095     delete this;
00096     return EVENT_DONE;
00097   }
00098   CC_FreerContinuation(CC_table * ap):Continuation(NULL), p(ap)
00099   {
00100     SET_HANDLER((CC_FreerContHandler) & CC_FreerContinuation::freeEvent);
00101   }
00102 };
00103 
00104 
00105 // struct CC_UpdateContinuation
00106 //
00107 //   Used to read the cache.conf file after the manager signals
00108 //      a change
00109 //
00110 struct CC_UpdateContinuation: public Continuation
00111 {
00112   int file_update_handler(int /* etype ATS_UNUSED */, void * /* data ATS_UNUSED */)
00113   {
00114     reloadCacheControl();
00115     delete this;
00116     return EVENT_DONE;
00117   }
00118   CC_UpdateContinuation(ProxyMutex * m):Continuation(m)
00119   {
00120     SET_HANDLER(&CC_UpdateContinuation::file_update_handler);
00121   }
00122 };
00123 
00124 int
00125 cacheControlFile_CB(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
00126                     RecData /* data ATS_UNUSED */, void * /* cookie ATS_UNUSED */)
00127 {
00128   eventProcessor.schedule_imm(new CC_UpdateContinuation(reconfig_mutex), ET_CACHE);
00129   return 0;
00130 }
00131 
00132 //
00133 //   Begin API functions
00134 //
00135 bool
00136 host_rule_in_CacheControlTable()
00137 {
00138   return (CacheControlTable->hostMatch ? true : false);
00139 }
00140 
00141 bool
00142 ip_rule_in_CacheControlTable()
00143 {
00144   return (CacheControlTable->ipMatch ? true : false);
00145 }
00146 
00147 void
00148 initCacheControl()
00149 {
00150   ink_assert(CacheControlTable == NULL);
00151   reconfig_mutex = new_ProxyMutex();
00152   CacheControlTable = new CC_table("proxy.config.cache.control.filename", modulePrefix, &http_dest_tags);
00153   REC_RegisterConfigUpdateFunc("proxy.config.cache.control.filename", cacheControlFile_CB, NULL);
00154 }
00155 
00156 // void reloadCacheControl()
00157 //
00158 //  Called when the cache.conf file changes.  Since it called
00159 //   infrequently, we do the load of new file as blocking I/O and
00160 //   lock aquire is also blocking
00161 //
00162 void
00163 reloadCacheControl()
00164 {
00165   CC_table *newTable;
00166 
00167   Debug("cache_control", "cache.config updated, reloading");
00168   eventProcessor.schedule_in(new CC_FreerContinuation(CacheControlTable), CACHE_CONTROL_TIMEOUT, ET_CACHE);
00169   newTable = new CC_table("proxy.config.cache.control.filename", modulePrefix, &http_dest_tags);
00170   ink_atomic_swap(&CacheControlTable, newTable);
00171 }
00172 
00173 void
00174 getCacheControl(CacheControlResult *result, HttpRequestData *rdata, OverridableHttpConfigParams *h_txn_conf, char *tag)
00175 {
00176   rdata->tag = tag;
00177   CacheControlTable->Match(rdata, result);
00178 
00179   if (h_txn_conf->cache_cluster_cache_local) {
00180     result->cluster_cache_local = true;
00181   }
00182 
00183   if (h_txn_conf->cache_ignore_client_no_cache) {
00184     result->ignore_client_no_cache = true;
00185   }
00186 
00187   if (h_txn_conf->cache_ignore_server_no_cache) {
00188     result->ignore_server_no_cache = true;
00189   }
00190 
00191   if (!h_txn_conf->cache_ignore_client_cc_max_age) {
00192     result->ignore_client_cc_max_age = false;
00193   }
00194 }
00195 
00196 bool 
00197 getClusterCacheLocal(URL *url, char * /* hostname ATS_UNUSED */)
00198 {
00199   HttpRequestData rdata;
00200   CacheControlResult result;
00201   HTTPHdr req_hdr;  
00202 
00203   req_hdr.create(HTTP_TYPE_REQUEST, NULL);
00204   req_hdr.url_set(url);
00205   rdata.hdr = &req_hdr;
00206   CacheControlTable->Match(&rdata, &result);
00207   req_hdr.clear();
00208   return result.cluster_cache_local;
00209 }
00210 
00211 //
00212 //   End API functions
00213 //
00214 
00215 
00216 // void CacheControlResult::Print()
00217 //
00218 //  Debugging Method
00219 //
00220 void
00221 CacheControlResult::Print()
00222 {
00223   printf("\t reval: %d, never-cache: %d, pin: %d, cluster-cache-c: %d ignore-c: %d ignore-s: %d\n",
00224          revalidate_after, never_cache, pin_in_cache_for, cluster_cache_local, ignore_client_no_cache,
00225          ignore_server_no_cache);
00226 }
00227 
00228 // void CacheControlRecord::Print()
00229 //
00230 //  Debugging Method
00231 //
00232 void
00233 CacheControlRecord::Print()
00234 {
00235   switch (this->directive) {
00236   case CC_REVALIDATE_AFTER:
00237     printf("\t\tDirective: %s : %d\n", CC_directive_str[CC_REVALIDATE_AFTER], this->time_arg);
00238     break;
00239   case CC_PIN_IN_CACHE:
00240     printf("\t\tDirective: %s : %d\n", CC_directive_str[CC_PIN_IN_CACHE], this->time_arg);
00241     break;
00242   case CC_TTL_IN_CACHE:
00243     printf("\t\tDirective: %s : %d\n", CC_directive_str[CC_TTL_IN_CACHE], this->time_arg);
00244     break;
00245   case CC_CLUSTER_CACHE_LOCAL:
00246   case CC_IGNORE_CLIENT_NO_CACHE:
00247   case CC_IGNORE_SERVER_NO_CACHE:
00248   case CC_NEVER_CACHE:
00249   case CC_STANDARD_CACHE:
00250   case CC_IGNORE_NO_CACHE:
00251     printf("\t\tDirective: %s\n", CC_directive_str[this->directive]);
00252     break;
00253   case CC_INVALID:
00254   case CC_NUM_TYPES:
00255     printf("\t\tDirective: INVALID\n");
00256     break;
00257   }
00258   if (cache_responses_to_cookies >= 0)
00259     printf("\t\t  - " TWEAK_CACHE_RESPONSES_TO_COOKIES ":%d\n",
00260       cache_responses_to_cookies
00261     );
00262   ControlBase::Print();
00263 }
00264 
00265 // bool CacheControlRecord::Init(matcher_line* line_info)
00266 //
00267 //    matcher_line* line_info - contains parsed label/value
00268 //      pairs of the current cache.config line
00269 //
00270 //    Returns NULL if everything is OK
00271 //      Otherwise, returns an error string that the caller MUST
00272 //        DEALLOCATE with free()
00273 //
00274 char *
00275 CacheControlRecord::Init(matcher_line * line_info)
00276 {
00277   int time_in;
00278   char *errBuf;
00279   const int errBufLen = 1024;
00280   const char *tmp;
00281   char *label;
00282   char *val;
00283   bool d_found = false;
00284 
00285   this->line_num = line_info->line_num;
00286 
00287   // First pass for optional tweaks.
00288   for (int i = 0; i < MATCHER_MAX_TOKENS && line_info->num_el ; ++i) {
00289     bool used = false;
00290     label = line_info->line[0][i];
00291     val = line_info->line[1][i];
00292     if (!label) continue;
00293 
00294     if (strcasecmp(label, TWEAK_CACHE_RESPONSES_TO_COOKIES) == 0) {
00295       char* ptr = 0;
00296       int v = strtol(val, &ptr, 0);
00297       if (!ptr || v < 0 || v > 4) {
00298         errBuf = static_cast<char*>(ats_malloc(errBufLen * sizeof(char)));
00299         snprintf(errBuf, errBufLen, "Value for " TWEAK_CACHE_RESPONSES_TO_COOKIES
00300                  " must be an integer in the range 0..4");
00301         return errBuf;
00302       } else {
00303         cache_responses_to_cookies = v;
00304       }
00305       used = true;
00306     }
00307 
00308     // Clip pair if used.
00309     if (used) {
00310       line_info->line[0][i] = 0;
00311       --(line_info->num_el);
00312     }
00313   }
00314 
00315   // Now look for the directive.
00316   for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
00317     label = line_info->line[0][i];
00318     val = line_info->line[1][i];
00319 
00320     if (label == NULL) {
00321       continue;
00322     }
00323 
00324     if (strcasecmp(label, "action") == 0) {
00325       if (strcasecmp(val, "never-cache") == 0) {
00326         directive = CC_NEVER_CACHE;
00327         d_found = true;
00328       } else if (strcasecmp(val, "standard-cache") == 0) {
00329         directive = CC_STANDARD_CACHE;
00330         d_found = true;
00331       } else if (strcasecmp(val, "ignore-no-cache") == 0) {
00332         directive = CC_IGNORE_NO_CACHE;
00333         d_found = true;
00334       } else if (strcasecmp(val, "cluster-cache-local") == 0) {
00335         directive = CC_CLUSTER_CACHE_LOCAL;;
00336         d_found = true;
00337       } else if (strcasecmp(val, "ignore-client-no-cache") == 0) {
00338         directive = CC_IGNORE_CLIENT_NO_CACHE;
00339         d_found = true;
00340       } else if (strcasecmp(val, "ignore-server-no-cache") == 0) {
00341         directive = CC_IGNORE_SERVER_NO_CACHE;
00342         d_found = true;
00343       } else {
00344         errBuf = (char *)ats_malloc(errBufLen * sizeof(char));
00345         snprintf(errBuf, errBufLen, "%s Invalid action at line %d in cache.config", modulePrefix, line_num);
00346         return errBuf;
00347       }
00348     } else {
00349 
00350       if (strcasecmp(label, "revalidate") == 0) {
00351         directive = CC_REVALIDATE_AFTER;
00352         d_found = true;
00353       } else if (strcasecmp(label, "pin-in-cache") == 0) {
00354         directive = CC_PIN_IN_CACHE;
00355         d_found = true;
00356       } else if (strcasecmp(label, "ttl-in-cache") == 0) {
00357         directive = CC_TTL_IN_CACHE;
00358         d_found = true;
00359       }
00360       // Process the time argument for the remaining directives
00361       if (d_found == true) {
00362         tmp = processDurationString(val, &time_in);
00363         if (tmp == NULL) {
00364           this->time_arg = time_in;
00365 
00366         } else {
00367           errBuf = (char *)ats_malloc(errBufLen * sizeof(char));
00368           snprintf(errBuf, errBufLen, "%s %s at line %d in cache.config", modulePrefix, tmp, line_num);
00369           return errBuf;
00370         }
00371       }
00372     }
00373 
00374     if (d_found == true) {
00375       // Consume the label/value pair we used
00376       line_info->line[0][i] = NULL;
00377       line_info->num_el--;
00378       break;
00379     }
00380   }
00381 
00382   if (d_found == false) {
00383     errBuf = (char *)ats_malloc(errBufLen * sizeof(char));
00384     snprintf(errBuf, errBufLen, "%s No directive in cache.config at line %d", modulePrefix, line_num);
00385     return errBuf;
00386   }
00387   // Process any modifiers to the directive, if they exist
00388   if (line_info->num_el > 0) {
00389     tmp = ProcessModifiers(line_info);
00390 
00391     if (tmp != NULL) {
00392       errBuf = (char *)ats_malloc(errBufLen * sizeof(char));
00393       snprintf(errBuf, errBufLen, "%s %s at line %d in cache.config", modulePrefix, tmp, line_num);
00394       return errBuf;
00395     }
00396   }
00397 
00398   return NULL;
00399 }
00400 
00401 // void CacheControlRecord::UpdateMatch(CacheControlResult* result, RequestData* rdata)
00402 //
00403 //    Updates the parameters in result if the this element
00404 //     appears later in the file
00405 //
00406 void
00407 CacheControlRecord::UpdateMatch(CacheControlResult * result, RequestData * rdata)
00408 {
00409   bool match = false;
00410   HttpRequestData *h_rdata = (HttpRequestData *) rdata;
00411 
00412   switch (this->directive) {
00413   case CC_REVALIDATE_AFTER:
00414     if (this->CheckForMatch(h_rdata, result->reval_line) == true) {
00415       result->revalidate_after = time_arg;
00416       result->reval_line = this->line_num;
00417       match = true;
00418     }
00419     break;
00420   case CC_NEVER_CACHE:
00421     if (this->CheckForMatch(h_rdata, result->never_line) == true) {
00422       result->never_cache = true;
00423       result->never_line = this->line_num;
00424       match = true;
00425     }
00426     break;
00427   case CC_STANDARD_CACHE:
00428     // Standard cache just overrides never-cache
00429     if (this->CheckForMatch(h_rdata, result->never_line) == true) {
00430       result->never_cache = false;
00431       result->never_line = this->line_num;
00432       match = true;
00433     }
00434     break;
00435   case CC_IGNORE_NO_CACHE:
00436     // We cover both client & server cases for this directive
00437     //  FALLTHROUGH
00438   case CC_IGNORE_CLIENT_NO_CACHE:
00439     if (this->CheckForMatch(h_rdata, result->ignore_client_line) == true) {
00440       result->ignore_client_no_cache = true;
00441       result->ignore_client_line = this->line_num;
00442       match = true;
00443     }
00444     if (this->directive != CC_IGNORE_NO_CACHE) {
00445       break;
00446     }
00447     // FALLTHROUGH
00448   case CC_IGNORE_SERVER_NO_CACHE:
00449     if (this->CheckForMatch(h_rdata, result->ignore_server_line) == true) {
00450       result->ignore_server_no_cache = true;
00451       result->ignore_server_line = this->line_num;
00452       match = true;
00453     }
00454     break;
00455   case CC_CLUSTER_CACHE_LOCAL:
00456     if (this->CheckForMatch(h_rdata, result->cluster_cache_local_line) == true) {
00457       result->cluster_cache_local = true;
00458       result->cluster_cache_local_line = this->line_num;
00459       match = true;
00460     }
00461     break;
00462   case CC_PIN_IN_CACHE:
00463     if (this->CheckForMatch(h_rdata, result->pin_line) == true) {
00464       result->pin_in_cache_for = time_arg;
00465       result->pin_line = this->line_num;
00466       match = true;
00467     }
00468     break;
00469   case CC_TTL_IN_CACHE:
00470     if (this->CheckForMatch(h_rdata, result->ttl_line) == true) {
00471       result->ttl_in_cache = time_arg;
00472       result->ttl_line = this->line_num;
00473       // ttl-in-cache overrides never-cache
00474       result->never_cache = false;
00475       result->never_line = this->line_num;
00476       match = true;
00477     }
00478     break;
00479   case CC_INVALID:
00480   case CC_NUM_TYPES:
00481   default:
00482     // Should not get here
00483     Warning("Impossible directive in CacheControlRecord::UpdateMatch");
00484     ink_assert(0);
00485     break;
00486   }
00487 
00488   if (cache_responses_to_cookies >= 0)
00489     result->cache_responses_to_cookies = cache_responses_to_cookies;
00490 
00491   if (match == true) {
00492     char crtc_debug[80];
00493     if (result->cache_responses_to_cookies >= 0)
00494       snprintf(crtc_debug, sizeof(crtc_debug), " [" TWEAK_CACHE_RESPONSES_TO_COOKIES "=%d]",
00495                result->cache_responses_to_cookies);
00496     else
00497       crtc_debug[0] = 0;
00498       
00499     Debug("cache_control", "Matched with for %s at line %d%s", CC_directive_str[this->directive],
00500           this->line_num, crtc_debug);
00501   }
00502 }

Generated by  doxygen 1.7.1