SBinetValidator.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:25k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #ifndef _SB_USE_STD_NAMESPACE
  23. #define _SB_USE_STD_NAMESPACE
  24. #endif
  25. #include <wchar.h>
  26. #include <stdio.h>
  27. #include "SBinetValidator.h"     // For this class
  28. #include "SBinetLog.h"           // For logging definitions
  29. #include "HttpUtils.hpp"
  30. #include "SBinetUtils.hpp"
  31. #include "SBinetChannel.h"
  32. #ifdef DEBUG_VALIDATOR
  33. #include <iostream>
  34. #endif
  35. using namespace std;
  36. /*****************************************************************************
  37.  *****************************************************************************
  38.  * SBinetValidator Implementation
  39.  *****************************************************************************
  40.  *****************************************************************************
  41.  */
  42. #if defined(_decunix_) || defined(_solaris_)
  43. // On solaris,
  44. // wsncasecmp is defined in widec.h but we don't have the right comp. flags to get the prototype.
  45. // I'm not sure about decunix though.
  46. //
  47. extern "C" int wsncasecmp(const wchar_t *, const wchar_t *, size_t);
  48. #define wcsncasecmp(s1,s2,n) wsncasecmp(s1,s2,n)
  49. #if 0
  50. static int my_wcsncasecmp(const wchar_t *s1, const wchar_t *s2,
  51.   register size_t n)
  52. {
  53.   register unsigned int u1, u2;
  54.   for (; n != 0; --n) {
  55.     u1 = (unsigned int) *s1++;
  56.     u2 = (unsigned int) *s2++;
  57.     if (HttpUtils::toUpper(u1) != HttpUtils::toUpper(u2)) {
  58.       return HttpUtils::toUpper(u1) - HttpUtils::toUpper(u2);
  59.     }
  60.     if (u1 == '') {
  61.       return 0;
  62.     }
  63.   }
  64.   return 0;
  65. }
  66. #endif
  67. #endif
  68. SBinetValidator::SBinetValidator(VXIlogInterface *log, VXIunsigned diagTagBase)
  69.   : SWIutilLogger(MODULE_SBINET, log, diagTagBase), _freshnessLifetime((time_t) -1),
  70.     _refTime((time_t) -1), _sizeBytes(0), _eTag(NULL), _mustRevalidateF(false),
  71.     _url(NULL), _lastModified((time_t) -1), _expiresTime((time_t) -1),
  72.     _pragmaDirective(NULL), _cacheControlDirective(NULL), _dateTime((time_t) -1)
  73. {}
  74. SBinetValidator::~SBinetValidator()
  75. {
  76.   delete [] _eTag;
  77.   delete [] _url;
  78.   delete [] _cacheControlDirective;
  79.   delete [] _pragmaDirective;
  80. }
  81. VXIinetResult SBinetValidator::Create(const VXIchar *filename, VXIulong sizeBytes,
  82.                                       time_t refTime)
  83. {
  84.   _lastModified = refTime;
  85.   _refTime = refTime;
  86.   return Create(filename, sizeBytes, (time_t) -1, (VXIMap *) NULL);
  87. }
  88. VXIinetResult SBinetValidator::Create(const VXIchar *url,
  89.                                       time_t requestTime,
  90.                                       const VXIMap *streamInfo)
  91. {
  92.   if (url == NULL || !*url || streamInfo == NULL)
  93.   {
  94.     return VXIinet_RESULT_INVALID_ARGUMENT;
  95.   }
  96.   VXIint32 sizeBytes = 0;
  97.   SBinetUtils::getInteger(streamInfo, INET_INFO_SIZE_BYTES, sizeBytes);
  98.   return Create(url, (VXIulong) sizeBytes, requestTime, streamInfo);
  99. }
  100. static time_t computeRefTime(time_t requestTime,
  101.                              const VXIMap* streamInfo,
  102.                              time_t& dateTime)
  103. {
  104.   // The algorithm is based on the RFC section 13.2.3 but instead of computing
  105.   // an initial age, it computes a reference time that can later be used to
  106.   // retrieve the age.
  107.   // The algo in the RFC to compute current-age is as follows.
  108.   //  response_delay = response_time - request_time;
  109.   //  corrected_initial_age = corrected_received_age + response_delay;
  110.   //  resident_time = now - response_time;
  111.   //  current_age   = corrected_initial_age + resident_time;
  112.   // Which can be rewritten as follows:
  113.   //  current_age = (corrected_received_age + response_delay) + (now - response_time)
  114.   //              = (corrected_received_age + response_time - request_time) + (now - response_time)
  115.   //              = corrected_received_age + now - request_time
  116.   //              = now - (request_time - corrected_received_age)
  117.   // This algorithm computes the ref. time to be equal to request_time - corrected_received_age.
  118.   // Using this algorithm has two advantages:
  119.   //
  120.   // 1) More efficient: less computation required to compute the ref. time
  121.   // than to compute the corrected initial age. When computing the current
  122.   //
  123.   // 2) Only requires to store the ref. time in the validator rather than the
  124.   // response time and the corrected initial age.
  125.   VXIint32 tmp;
  126.   time_t responseTime = time(NULL);
  127.   time_t computed_age = (time_t) 0;
  128.   if (SBinetUtils::getInteger(streamInfo, L"Date", tmp))
  129.   {
  130.     dateTime = (time_t) tmp;
  131.     computed_age = responseTime - dateTime;
  132.     if (computed_age < (time_t) 0) computed_age = (time_t) 0;
  133.   }
  134.   else
  135.   {
  136.     dateTime = responseTime;
  137.   }
  138.   if (SBinetUtils::getInteger(streamInfo, L"Age", tmp))
  139.   {
  140.     time_t age = (time_t) tmp;
  141.     if (age > computed_age) computed_age = age;
  142.   }
  143.   return requestTime - computed_age;
  144. }
  145. VXIinetResult SBinetValidator::Create(const VXIchar *url, VXIulong sizeBytes,
  146.                                       time_t requestTime,
  147.                                       const VXIMap *streamInfo)
  148. {
  149.   if (url == NULL || !*url)
  150.   {
  151.     return VXIinet_RESULT_INVALID_ARGUMENT;
  152.   }
  153.   if (_url)
  154.     delete [] _url;
  155.   _url = ::wcscpy(new VXIchar[::wcslen(url) + 1], url);
  156.   _sizeBytes = sizeBytes;
  157.   _freshnessLifetime = (time_t) -1;
  158.   const VXIchar *eTag = NULL;
  159.   delete [] _eTag;
  160.   //   // Sanity check
  161.   //   if (_expiresTime >= 0 && _lastModifiedTime >= _expiresTime)
  162.   //     _expiresTime = 0;
  163.   //   time_t now = time(NULL);
  164.   //   if (_lastModifiedTime > now)
  165.   //     _lastModifiedTime = now;
  166.   if (streamInfo != NULL)
  167.   {
  168.     // Reference time
  169.     _refTime = computeRefTime(requestTime, streamInfo, _dateTime);
  170.     // Last-modified
  171.     VXIint32 lastModified = -1;
  172.     SBinetUtils::getInteger(streamInfo, L"Last-Modified", lastModified);
  173.     _lastModified = (time_t) lastModified;
  174.     // Expires
  175.     VXIint32 expiresTime = -1;
  176.     SBinetUtils::getInteger(streamInfo, L"Expires", expiresTime);
  177.     _expiresTime = (time_t) expiresTime;
  178.     // ETag
  179.     eTag = SBinetUtils::getString(streamInfo, L"ETag");
  180.     // Pragma
  181.     const VXIchar* pragmaDirective = SBinetUtils::getString(streamInfo, L"Pragma");
  182.     if (pragmaDirective)
  183.     {
  184.       _pragmaDirective = new VXIchar [::wcslen(pragmaDirective) + 1];
  185.       ::wcscpy(_pragmaDirective, pragmaDirective);
  186.     }
  187.     // Cache-control
  188.     const VXIchar* cacheControlDirective = SBinetUtils::getString(streamInfo, L"Cache-Control");
  189.     if (cacheControlDirective)
  190.     {
  191.       _cacheControlDirective = new VXIchar [::wcslen(cacheControlDirective) + 1];
  192.       ::wcscpy(_cacheControlDirective, cacheControlDirective);
  193.     }
  194.     computeFreshnessLifetime();
  195.   }
  196.   if (eTag == NULL || !*eTag)
  197.   {
  198.     _eTag = NULL;
  199.   }
  200.   else
  201.   {
  202.     _eTag = ::wcscpy(new VXIchar[::wcslen(eTag) + 1], eTag);
  203.   }
  204.   Log(L"SBinetValidator::Create");
  205.   return VXIinet_RESULT_SUCCESS;
  206. }
  207. void SBinetValidator::computeFreshnessLifetime()
  208. {
  209.   // Inspect the headers for other relevant directives ('no-cache' etc.)
  210.   _freshnessLifetime = checkPragma();
  211.   if (_freshnessLifetime == (time_t) -1)
  212.   {
  213.     _freshnessLifetime = checkCacheControl();
  214.   }
  215.   if (_freshnessLifetime == (time_t) -1)
  216.   {
  217.     if (_expiresTime != (time_t) -1)
  218.       _freshnessLifetime = ((time_t) _expiresTime) - _dateTime;
  219.     else
  220.       _freshnessLifetime = (time_t) 0;
  221.   }
  222.   if (_freshnessLifetime < (time_t) 0)
  223.     _freshnessLifetime = (time_t) 0;
  224. }
  225. VXIinetResult SBinetValidator::Create(const VXIValue *content)
  226. {
  227.   if (VXIValueGetType(content) != VALUE_CONTENT)
  228.   {
  229.     Error(214, L"Type: %d", VXIValueGetType(content));
  230.     return VXIinet_RESULT_INVALID_ARGUMENT;
  231.   }
  232.   // Get the content
  233.   const VXIchar *contentType;
  234.   const VXIbyte *contentData;
  235.   VXIulong contentSizeBytes;
  236.   if ( VXIContentValue((const VXIContent*) content,
  237.                        &contentType, &contentData,
  238.        &contentSizeBytes) != VXIvalue_RESULT_SUCCESS )
  239.   {
  240.     Error(215, NULL);
  241.     return VXIinet_RESULT_INVALID_ARGUMENT;
  242.   }
  243.   else if ( ::wcscmp(contentType, VALIDATOR_MIME_TYPE) != 0 )
  244.   {
  245.     Error(216, L"mimeType: %s", contentType);
  246.     return VXIinet_RESULT_INVALID_ARGUMENT;
  247.   }
  248.   return Create(contentData, contentSizeBytes);
  249. }
  250. VXIinetResult SBinetValidator::Create(const VXIbyte *data, VXIulong contentSizeBytes)
  251. {
  252.   // Unpack the data
  253.   const VXIbyte *ptr = data;
  254.   ::memcpy(&_dateTime, ptr, sizeof _dateTime);
  255.   ptr += sizeof _dateTime;
  256.   ::memcpy(&_expiresTime, ptr, sizeof _expiresTime);
  257.   ptr += sizeof _expiresTime;
  258.   ::memcpy(&_refTime, ptr, sizeof _refTime);
  259.   ptr += sizeof _refTime;
  260.   ::memcpy(&_freshnessLifetime, ptr, sizeof _freshnessLifetime);
  261.   ptr += sizeof _freshnessLifetime;
  262.   ::memcpy(&_lastModified, ptr, sizeof _lastModified);
  263.   ptr += sizeof _lastModified;
  264.   ::memcpy(&_mustRevalidateF, ptr, sizeof _mustRevalidateF);
  265.   ptr += sizeof _mustRevalidateF;
  266.   ::memcpy(&_sizeBytes, ptr, sizeof _sizeBytes);
  267.   ptr += sizeof _sizeBytes;
  268.   int len;
  269.   ::memcpy(&len, ptr, sizeof len);
  270.   ptr += sizeof len;
  271.   delete [] _eTag;
  272.   if (len > 0)
  273.   {
  274.     int size = len * sizeof(VXIchar);
  275.     _eTag = new VXIchar[len + 1];
  276.     ::memcpy(_eTag, ptr, size);
  277.     ptr += size;
  278.     _eTag[len] = L'';
  279.   }
  280.   else
  281.   {
  282.     _eTag = NULL;
  283.   }
  284.   ::memcpy(&len, ptr, sizeof len);
  285.   ptr += sizeof len;
  286.   delete [] _url;
  287.   if (len > 0)
  288.   {
  289.     int size = len * sizeof(VXIchar);
  290.     _url = new VXIchar[len + 1];
  291.     ::memcpy(_url, ptr, size);
  292.     ptr += size;
  293.     _url[len] = L'';
  294.   }
  295.   else
  296.   {
  297.     _url = NULL;
  298.   }
  299.   ::memcpy(&len, ptr, sizeof len);
  300.   ptr += sizeof len;
  301.   delete [] _pragmaDirective;
  302.   if (len > 0)
  303.   {
  304.     int size = len * sizeof(VXIchar);
  305.     _pragmaDirective = new VXIchar[len + 1];
  306.     ::memcpy(_pragmaDirective, ptr, size);
  307.     ptr += size;
  308.     _pragmaDirective[len] = L'';
  309.   }
  310.   else
  311.   {
  312.     _pragmaDirective = NULL;
  313.   }
  314.   delete [] _cacheControlDirective;
  315.   if (len > 0)
  316.   {
  317.     int size = len * sizeof(VXIchar);
  318.     _cacheControlDirective = new VXIchar[len + 1];
  319.     ::memcpy(_cacheControlDirective, ptr, size);
  320.     ptr += size;
  321.     _cacheControlDirective[len] = L'';
  322.   }
  323.   else
  324.   {
  325.     _cacheControlDirective = NULL;
  326.   }
  327.   Log(L"SBinetValidator::Deserialize");
  328.   return VXIinet_RESULT_SUCCESS;
  329. }
  330. VXIContent *SBinetValidator::serialize() const
  331. {
  332.   VXIbyte *data = NULL;
  333.   VXIulong dataSize;
  334.   VXIContent *content;
  335.   if (serialize(data, dataSize))
  336.   {
  337.     // Create the content
  338.     content = VXIContentCreate(VALIDATOR_MIME_TYPE, data, dataSize,
  339.                                ContentDestroy, NULL);
  340.     if (content == NULL)
  341.       delete [] data;
  342.   }
  343.   return content;
  344. }
  345. bool SBinetValidator::serialize(VXIbyte*& content, VXIulong& contentSize) const
  346. {
  347.   // Pack the data
  348.   int eTagLen = 0;
  349.   int urlLen = 0;
  350.   int pragmaDirectiveLen = 0;
  351.   int cacheControlDirectiveLen = 0;
  352.   contentSize = ((sizeof _dateTime) +
  353.                  (sizeof _expiresTime) +
  354.                  (sizeof _refTime) +
  355.                  (sizeof _freshnessLifetime) +
  356.                  (sizeof _lastModified) +
  357.                  (sizeof _mustRevalidateF) +
  358.                  (sizeof _sizeBytes) +
  359.                  (sizeof eTagLen) +
  360.                  (sizeof urlLen) +
  361.                  (sizeof pragmaDirectiveLen) +
  362.                  (sizeof cacheControlDirectiveLen));
  363.   if (_eTag != NULL)
  364.   {
  365.     eTagLen = ::wcslen(_eTag);
  366.     contentSize += eTagLen * sizeof(VXIchar);
  367.   }
  368.   if (_url != NULL)
  369.   {
  370.     urlLen = ::wcslen(_url);
  371.     contentSize += urlLen * sizeof(VXIchar);
  372.   }
  373.   if (_pragmaDirective != NULL)
  374.   {
  375.     pragmaDirectiveLen = ::wcslen(_pragmaDirective);
  376.     contentSize += pragmaDirectiveLen * sizeof(VXIchar);
  377.   }
  378.   if (_cacheControlDirective != NULL)
  379.   {
  380.     cacheControlDirectiveLen = ::wcslen(_cacheControlDirective);
  381.     contentSize += cacheControlDirectiveLen * sizeof(VXIchar);
  382.   }
  383.   content = new VXIbyte[contentSize];
  384.   VXIbyte *ptr = content;
  385.   ::memcpy(ptr, &_dateTime, sizeof _refTime);
  386.   ptr += sizeof _dateTime;
  387.   ::memcpy(ptr, &_expiresTime, sizeof _expiresTime);
  388.   ptr += sizeof _expiresTime;
  389.   ::memcpy(ptr, &_refTime, sizeof _refTime);
  390.   ptr += sizeof _refTime;
  391.   ::memcpy(ptr, &_freshnessLifetime, sizeof _freshnessLifetime);
  392.   ptr += sizeof _freshnessLifetime;
  393.   ::memcpy(ptr, &_lastModified, sizeof _lastModified);
  394.   ptr += sizeof _lastModified;
  395.   ::memcpy(ptr, &_mustRevalidateF, sizeof _mustRevalidateF);
  396.   ptr += sizeof _mustRevalidateF;
  397.   ::memcpy(ptr, &_sizeBytes, sizeof _sizeBytes);
  398.   ptr += sizeof _sizeBytes;
  399.   ::memcpy(ptr, &eTagLen, sizeof eTagLen);
  400.   ptr += sizeof eTagLen;
  401.   if (eTagLen > 0)
  402.   {
  403.     ::memcpy(ptr, _eTag, eTagLen * sizeof(VXIchar));
  404.     ptr += eTagLen * sizeof(VXIchar);
  405.   }
  406.   ::memcpy(ptr, &urlLen, sizeof urlLen);
  407.   ptr += sizeof urlLen;
  408.   if (urlLen > 0)
  409.   {
  410.     ::memcpy(ptr, _url, urlLen * sizeof(VXIchar));
  411.     ptr += urlLen * sizeof(VXIchar);
  412.   }
  413.   ::memcpy(ptr, &pragmaDirectiveLen, sizeof pragmaDirectiveLen);
  414.   ptr += sizeof pragmaDirectiveLen;
  415.   if (pragmaDirectiveLen > 0)
  416.   {
  417.     ::memcpy(ptr, _pragmaDirective, pragmaDirectiveLen * sizeof(VXIchar));
  418.     ptr += pragmaDirectiveLen * sizeof(VXIchar);
  419.   }
  420.   ::memcpy(ptr, &cacheControlDirectiveLen, sizeof cacheControlDirectiveLen);
  421.   ptr += sizeof cacheControlDirectiveLen;
  422.   if (pragmaDirectiveLen > 0)
  423.   {
  424.     ::memcpy(ptr, _cacheControlDirective, cacheControlDirectiveLen * sizeof(VXIchar));
  425.     ptr += cacheControlDirectiveLen * sizeof(VXIchar);
  426.   }
  427.   return true;
  428. }
  429. time_t SBinetValidator::getExpiresTime() const
  430. {
  431.   if (_freshnessLifetime <= (time_t) 0)
  432.     return (time_t) 0;
  433.   return _refTime + _freshnessLifetime;
  434. }
  435. bool SBinetValidator::isExpired() const
  436. {
  437.   return _freshnessLifetime == (time_t) 0 ||
  438.     _freshnessLifetime < time(NULL) - _refTime;
  439. }
  440. bool SBinetValidator::isExpired(const VXIint maxAge,
  441.                                 const VXIint maxStale) const
  442. {
  443. #ifdef DEBUG_VALIDATOR
  444.   cout << "maxAge:t" << maxAge << endl;
  445.   cout << "maxStale:t" << maxStale << endl;
  446. #endif
  447.   if (maxAge == 0) return true;
  448.   time_t now = time(NULL);
  449.   time_t currentAge = now - _refTime;
  450. #ifdef DEBUG_VALIDATOR
  451.   cout << "now:t" << now << endl;
  452.   cout << "_refTime:t" << _refTime << endl;
  453. #endif
  454.   if (maxAge > 0 && currentAge > maxAge) return true;
  455.   time_t staleness = currentAge - _freshnessLifetime;
  456. #ifdef DEBUG_VALIDATOR
  457.   cout << "_freshnessLifetime:t" << _freshnessLifetime << endl;
  458.   cout << "staleness: " << staleness << endl;
  459.   cout << "_mustRevalidateF: " << _mustRevalidateF << endl;
  460.   cout << "_expiresTime: " << _expiresTime << endl;
  461. #endif
  462.   if (staleness < 0) return false;
  463.   if (_mustRevalidateF) return true;
  464.   if (staleness > maxStale) return true;
  465.   if (_freshnessLifetime == (time_t) 0) return true;
  466.   return false;
  467. }
  468. bool SBinetValidator::isStrong() const
  469. {
  470.   return (_eTag != NULL) && (wcsncasecmp(_eTag, L"w/", 2) != 0);
  471. }
  472. void SBinetValidator::Log(const VXIchar *name) const
  473. {
  474.   if (DiagIsEnabled(MODULE_SBINET_VALIDATOR_TAGID))
  475.   {
  476.     char refTimeStr[64], expireStr[64], lastModifiedStr[64];
  477.     if (_refTime == (time_t) -1)
  478.       ::strcpy(refTimeStr, "-1");
  479.     else
  480.       SBinetUtils::getTimeStampStr(_refTime, refTimeStr);
  481.     SBinetUtils::getTimeStampStr(getExpiresTime(), expireStr);
  482.     if (_lastModified == (time_t) -1)
  483.       ::strcpy(lastModifiedStr, "-1");
  484.     else
  485.       SBinetUtils::getTimeStampStr(_lastModified, lastModifiedStr);
  486.     Diag(MODULE_SBINET_VALIDATOR_TAGID, name,
  487.          L"URL: '%s', refTime %S, last modified %S, expires %S, must revalidate %s, size %lu, etag '%s'",
  488.          _url, refTimeStr, lastModifiedStr, expireStr,
  489.          _mustRevalidateF ? L"true" : L"false",
  490.          _sizeBytes, _eTag ? _eTag : L"");
  491.   }
  492. }
  493. void SBinetValidator::ContentDestroy(VXIbyte **content, void *userData)
  494. {
  495.   if (content)
  496.   {
  497.     delete [] *content;
  498.     *content = NULL;
  499.   }
  500. }
  501. time_t SBinetValidator::checkPragma()
  502. {
  503.   if (_pragmaDirective == NULL)
  504.   {
  505.     Diag(MODULE_SBINET_VALIDATOR_TAGID, L"SBinetValidator::checkPragma",
  506.          L"No Pragma directive.");
  507.     return (time_t) -1;
  508.   }
  509.   Diag(MODULE_SBINET_VALIDATOR_TAGID, L"SBinetValidator::checkPragma",
  510.        L"Pragma directive: '%s'", _pragmaDirective);
  511.   const VXIchar *p = _pragmaDirective;
  512.   while (*p && SBinetHttpUtils::isSpace(*p)) p++;
  513.   if (wcsncasecmp(p, L"no-cache", 8) == 0)
  514.   {
  515.     Diag(MODULE_SBINET_VALIDATOR_TAGID, L"SBinetValidator::checkPragma",
  516.          L"Got Pragma: no-cache directive.");
  517.     return (time_t) 0;
  518.   }
  519.   return (time_t) -1;
  520. }
  521. time_t SBinetValidator::checkCacheControl()
  522. {
  523.   time_t maxAge = (time_t) -1;
  524.   if (_cacheControlDirective == NULL)
  525.   {
  526.     Diag(MODULE_SBINET_VALIDATOR_TAGID, L"SBinetValidator::checkCacheControl",
  527.          L"No Cache-Control directive.");
  528.     return maxAge;
  529.   }
  530.   // We need to convert to narrow string in order to take advantage of the
  531.   // HttpUtils function that are written in terms of narrow character.
  532.   SBinetNString tmp = _cacheControlDirective;
  533.   const char *content = tmp.c_str();
  534.   Diag(MODULE_SBINET_VALIDATOR_TAGID, L"SBinetValidator::checkCacheControl",
  535.        L"Cache-Control directive: '%S'", content);
  536.   int priority = 0;
  537.   static const int maxAgePriority = 0;
  538.   static const int sMaxAgePriority = 1;
  539.   static const int cacheControlPriority = 2;
  540.   SBinetNString attrib;
  541.   SBinetNString val;
  542.   for (;;)
  543.   {
  544.     content = SBinetHttpUtils::getValue(content, attrib);
  545.     if (content == NULL)
  546.     {
  547.       Diag(MODULE_SBINET_VALIDATOR_TAGID,
  548.            L"SBinetValidator::checkCacheControl",
  549.            L"Could not get value.");
  550.       break;
  551.     }
  552.     content = SBinetHttpUtils::expectChar(content, "=,");
  553.     if (content == NULL)
  554.     {
  555.       Diag(MODULE_SBINET_VALIDATOR_TAGID,
  556.            L"SBinetValidator::checkCacheControl",
  557.            L"Expecting '=' or ','.");
  558.       break;
  559.     }
  560.     const char *attribute = attrib.c_str();
  561.     const char *value = NULL;
  562.     if (*content == '=')
  563.     {
  564.       content = SBinetHttpUtils::getValue(++content, val);
  565.       if (content == NULL)
  566.       {
  567.         Diag(MODULE_SBINET_VALIDATOR_TAGID,
  568.              L"SBinetValidator::checkCacheControl",
  569.              L"Could not extract value for attribute",
  570.              attribute);
  571.         break;
  572.       }
  573.       value = val.c_str();
  574.     }
  575.     Diag(MODULE_SBINET_VALIDATOR_TAGID, L"SBinetValidator::checkCacheControl",
  576.          L"attribute = '%S', value = '%S'", attribute, value);
  577.     if (strcasecmp(attribute, "no-cache") == 0)
  578.     {
  579.       // Ignore no-cache="something" as we have one cookie jar per channel.
  580.       // So they are not shared.
  581.       if (value == NULL && priority <= cacheControlPriority)
  582.       {
  583.         maxAge = (time_t) 0;
  584.         priority = cacheControlPriority;
  585.       }
  586.     }
  587.     else if ((strcasecmp(attribute, "no-store") == 0 ||
  588.               strcasecmp(attribute, "private") == 0)
  589.              && priority <= cacheControlPriority)
  590.     {
  591.       maxAge = (time_t) 0;
  592.       priority = cacheControlPriority;
  593.     }
  594.     else if (strcasecmp(attribute, "must-revalidate") == 0)
  595.     {
  596.       // This directive does not affect priority nor does it depend on a
  597.       // priority as it does not modify the maxAge value.
  598.       _mustRevalidateF = true;
  599.     }
  600.     else if (strcasecmp(attribute, "max-age") == 0)
  601.     {
  602.       if (value != NULL &&  priority <= maxAgePriority)
  603.       {
  604.         maxAge = (time_t) atoi(value);
  605.         priority = maxAgePriority;
  606.       }
  607.     }
  608.     else if (strcasecmp(attribute, "s-maxage") == 0)
  609.     {
  610.       if (value != NULL && priority <= sMaxAgePriority)
  611.       {
  612.         maxAge = atoi(value);
  613.         priority = sMaxAgePriority;
  614.       }
  615.     }
  616.     content = SBinetHttpUtils::expectChar(content, ",");
  617.     if (content == NULL)
  618.     {
  619.       Diag(MODULE_SBINET_VALIDATOR_TAGID,
  620.            L"SBinetValidator::checkCacheControl",
  621.            L"Expecting ','.");
  622.       break;
  623.     }
  624.     if (!*content)
  625.     {
  626.       // end of string. No error.
  627.       break;
  628.     }
  629.     content++;
  630.   }
  631.   return maxAge;
  632. }
  633. // Propagates data from an old validator to a new validator.
  634. // For example, if an HTTP fetch returns 304 (Not-Modified), the
  635. // validator constructed from the data returned may not contain
  636. // all the validation data necessary.  Some of this data may need
  637. // to be propagated from the old validator that was stored in the
  638. // cache.
  639. bool SBinetValidator::propagateDataFrom(const SBinetValidator& validator)
  640. {
  641.   bool changed = false;
  642.   // Document Size in Bytes
  643.   // When a 304 response is received from an HTTP server, we don't know what
  644.   // the actual size of the resource/document is.  So, we set it to -1 knowing
  645.   // that when we propagate values from the cached validator, this value gets
  646.   // updated properly.  I don't like this, but the original coupled design
  647.   // of INET leaves us no choice for now.
  648.   if (_sizeBytes == -1)
  649.   {
  650.     _sizeBytes = validator._sizeBytes;
  651.     changed = true;
  652.   }
  653.   // Pragma
  654.   if ((_pragmaDirective == NULL) && (validator._pragmaDirective != NULL))
  655.   {
  656.     delete [] _pragmaDirective;
  657.     _pragmaDirective = new VXIchar [::wcslen(validator._pragmaDirective) + 1];
  658.     ::wcscpy(_pragmaDirective, validator._pragmaDirective);
  659.     // Pragma directive overrides other directives, we can just return.
  660.     computeFreshnessLifetime();
  661.     return true;
  662.   }
  663.   // Cache-Control
  664.   if ((_cacheControlDirective == NULL) && (validator._cacheControlDirective != NULL))
  665.   {
  666.     delete [] _cacheControlDirective;
  667.     _cacheControlDirective = new VXIchar [::wcslen(validator._cacheControlDirective) + 1];
  668.     ::wcscpy(_cacheControlDirective, validator._cacheControlDirective);
  669.     changed = true;
  670.   }
  671.   // Expires
  672.   if ((_expiresTime == (time_t) -1) && (validator._expiresTime != (time_t) -1))
  673.   {
  674.     _expiresTime = validator._expiresTime;
  675.     // If a new expiration time is not set, and there was an old expiration time,
  676.     // our new date time should be the same as the old date time.
  677.     _dateTime = validator._dateTime;
  678.     changed = true;
  679.   }
  680.   // Last-Modified
  681.   if ((_lastModified == (time_t) -1) && (validator._lastModified != (time_t) -1))
  682.   {
  683.     _lastModified = validator._lastModified;
  684.     changed = true;
  685.   }
  686.   // ETag
  687.   if ((_eTag == NULL) && (validator._eTag != NULL))
  688.   {
  689.     delete [] _eTag;
  690.     _eTag = new VXIchar [::wcslen(validator._eTag) + 1];
  691.     ::wcscpy(_eTag, validator._eTag);
  692.     changed = true;
  693.   }
  694.   // If some data was propagated from the other validator,
  695.   // compute the new freshness lifetime based on the new data.
  696.   if (changed)
  697.   {
  698.     computeFreshnessLifetime();
  699.     return true;
  700.   }
  701.   return false;
  702. }
  703. // Checks whether the current validator's validator info matches that of
  704. // the specified validator.  This is used when an external validator is used
  705. // to verify whether that external validator matches the cached validator in
  706. // cases where a conditional fetch on an HTTP server returns NOT_MODIFIED.
  707. // In such cases, the cached validator says the current cached version of the
  708. // document is up-to-date.  When the external validator does not match the
  709. // cached validator, it means that the externally cached version of the
  710. // document does not match the currently cached version.
  711. bool SBinetValidator::operator==(const SBinetValidator& validator)
  712. {
  713.   if (_sizeBytes != validator._sizeBytes)
  714.     return false;
  715.   if (_lastModified != validator._lastModified)
  716.     return false;
  717.   if (!_eTag && validator._eTag)
  718.     return false;
  719.   if (_eTag && !validator._eTag)
  720.     return false;
  721.   if (_eTag && validator._eTag && wcscmp(_eTag, validator._eTag))
  722.     return false;
  723.   return true;
  724. }
  725. void SBinetValidator::Clear()
  726. {
  727.   if (_url)
  728.   {
  729.     delete [] _url;
  730.     _url = NULL;
  731.   }
  732.   if (_eTag)
  733.   {
  734.     delete [] _eTag;
  735.     _eTag = NULL;
  736.   }
  737.   if (_pragmaDirective)
  738.   {
  739.     delete [] _pragmaDirective;
  740.     _pragmaDirective = NULL;
  741.   }
  742.   if (_cacheControlDirective)
  743.   {
  744.     delete [] _cacheControlDirective;
  745.     _cacheControlDirective = NULL;
  746.   }
  747.   _sizeBytes = 0;
  748.   _dateTime = _expiresTime = _lastModified = _refTime = _freshnessLifetime = (time_t)-1;
  749.   _mustRevalidateF = false;
  750. }