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

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. #if _MSC_VER >= 1100    // Visual C++ 5.x
  23. #pragma warning( disable : 4786 4503 )
  24. #endif
  25. #include "VXIinet.h"
  26. #include "SBinetHttpCacheStream.hpp"
  27. #include "SBinetURL.h"
  28. #include "SBinetValidator.h"
  29. #include "SBinetChannel.h"
  30. #include "SBinetUtils.hpp"
  31. #include "SBinetString.hpp"
  32. #include "HttpUtils.hpp"
  33. VXIinetResult
  34. SBinetHttpCacheStream::cache2inetRc(VXIcacheResult result)
  35. {
  36.   switch (result)
  37.   {
  38.    case VXIcache_RESULT_FATAL_ERROR:
  39.      return VXIinet_RESULT_FATAL_ERROR;
  40.    case VXIcache_RESULT_IO_ERROR:
  41.      return VXIinet_RESULT_IO_ERROR;
  42.    case VXIcache_RESULT_OUT_OF_MEMORY:
  43.      return VXIinet_RESULT_OUT_OF_MEMORY;
  44.    case VXIcache_RESULT_SYSTEM_ERROR:
  45.      return VXIinet_RESULT_SYSTEM_ERROR;
  46.    case VXIcache_RESULT_PLATFORM_ERROR:
  47.      return VXIinet_RESULT_PLATFORM_ERROR;
  48.    case VXIcache_RESULT_BUFFER_TOO_SMALL:
  49.      return VXIinet_RESULT_BUFFER_TOO_SMALL;
  50.    case VXIcache_RESULT_INVALID_PROP_NAME:
  51.      return VXIinet_RESULT_INVALID_PROP_NAME;
  52.    case VXIcache_RESULT_INVALID_PROP_VALUE:
  53.      return VXIinet_RESULT_INVALID_PROP_VALUE;
  54.    case VXIcache_RESULT_INVALID_ARGUMENT:
  55.      return VXIinet_RESULT_INVALID_ARGUMENT;
  56.    case VXIcache_RESULT_SUCCESS:
  57.      return VXIinet_RESULT_SUCCESS;
  58.    case VXIcache_RESULT_FAILURE:
  59.      return VXIinet_RESULT_FAILURE;
  60.    case VXIcache_RESULT_NON_FATAL_ERROR:
  61.      return VXIinet_RESULT_NON_FATAL_ERROR;
  62.    case VXIcache_RESULT_NOT_FOUND:
  63.      return VXIinet_RESULT_NOT_FOUND;
  64.    case VXIcache_RESULT_WOULD_BLOCK:
  65.      return VXIinet_RESULT_WOULD_BLOCK;
  66.    case VXIcache_RESULT_END_OF_STREAM:
  67.      return VXIinet_RESULT_END_OF_STREAM;
  68.    case VXIcache_RESULT_EXCEED_MAXSIZE:
  69.      return VXIinet_RESULT_OUT_OF_MEMORY;
  70.    case VXIcache_RESULT_ENTRY_LOCKED:
  71.      return VXIinet_RESULT_FETCH_TIMEOUT;
  72.    case VXIcache_RESULT_UNSUPPORTED:
  73.      return VXIinet_RESULT_UNSUPPORTED;
  74.    default: {
  75.      Error(299, L"%s%i", L"VXIcacheResult", result);
  76.      return VXIinet_RESULT_NON_FATAL_ERROR;
  77.     }
  78.   }
  79. }
  80. // Refer to SBinetHttpCacheStream.hpp for doc.
  81. SBinetHttpCacheStream::
  82. SBinetHttpCacheStream(SBinetURL* url,
  83.                       SBinetHttpStream::SubmitMethod method,
  84.                       SBinetChannel* ch,
  85.                       VXIcacheInterface *cache,
  86.                       VXIlogInterface *log,
  87.                       VXIunsigned diagLogBase):
  88.   SBinetStoppableStream(url, SBinetStream_CACHE, log, diagLogBase),
  89.   _httpStream(NULL),
  90.   _channel(ch),
  91.   _cache(cache),
  92.   _cacheStream(NULL),
  93.   _method(method),
  94.   _maxAge(-1),
  95.   _maxStale(-1),
  96.   _httpReadCompleted(false)
  97. {}
  98. // SBinetHttpCacheStream::~SBinetHttpCacheStream
  99. // Refer to SBinetHttpCacheStream.hpp for doc.
  100. SBinetHttpCacheStream::~SBinetHttpCacheStream()
  101. {
  102.   Close();
  103. }
  104. VXIinetResult SBinetHttpCacheStream::Open(VXIint flags,
  105.                                           const VXIMap* properties,
  106.                                           VXIMap* streamInfo)
  107. {
  108.   getCacheInfo(properties, _maxAge, _maxStale);
  109.   SBinetValidator cachedValidator(GetLog(), GetDiagBase());
  110.   bool cachedValidatorPresent = false;
  111.   std::basic_string<VXIchar> oldCachedUri;
  112.   
  113.   // Read the cached validator for this resource.
  114.   SBinetURL* ultimateURL = NULL;
  115.   bool isCacheExpired = false;
  116.   switch(readValidatorFromCache(ultimateURL, cachedValidator, isCacheExpired))
  117.   {
  118.     case VXIcache_RESULT_SUCCESS:
  119.       // All is well, we successfully read the validator.
  120.       cachedValidatorPresent = true;
  121.       break;
  122.     case VXIcache_RESULT_ENTRY_LOCKED:
  123.       Error(234, L"%s%s", L"URL", _url->getAbsolute());
  124.       delete ultimateURL;
  125.       return VXIinet_RESULT_FETCH_TIMEOUT;
  126.     default:
  127.       cachedValidatorPresent = isCacheExpired;
  128.       break;
  129.   }
  130.   // Determine if this is a conditional open with a validator,
  131.   // irrelevant if caching is disabled
  132.   bool externalValidatorPresent = false;
  133.   const VXIValue* validatorVal =
  134.     VXIMapGetProperty(properties, INET_OPEN_IF_MODIFIED);;
  135.   SBinetValidator externalValidator(GetLog(), GetDiagBase());
  136.   if (validatorVal != NULL)
  137.   {
  138.     externalValidatorPresent = true;
  139.     externalValidator.Create(validatorVal);
  140.     if (!externalValidator.isExpired(_maxAge, _maxStale))
  141.     {
  142.       delete ultimateURL;
  143.       // Update the external validator information with the latest cached
  144.       // validator for this document.  If there is no cached validator,
  145.       // just return the external validator that was passed in.
  146.       if (streamInfo)
  147.       {
  148.         SBinetValidator* pValidatorToReturn = &cachedValidator;
  149.         if (!pValidatorToReturn)
  150.           pValidatorToReturn = &externalValidator;
  151.         if (!SBinetUtils::setValidatorInfo(streamInfo, pValidatorToReturn))
  152.         {
  153.           Error(103, NULL);
  154.           return VXIinet_RESULT_OUT_OF_MEMORY;
  155.         }
  156.         // Set CACHE data source information   
  157.         VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, 
  158.                          (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_CACHE));
  159.       }
  160.       return VXIinet_RESULT_NOT_MODIFIED;
  161.     }
  162.   }
  163.   // Check whether we can read this document from the cache.
  164.   if (_maxAge != 0)
  165.   {
  166.     // Possible scenarios:
  167.     // 1) There was no cached validator -> continue with http fetch
  168.     // 2) Validator is expired -> continue with http fetch
  169.     // 3) Error reading document from cache -> continue with http fetch
  170.     // 4) Locked document cache entry -> return fetch timeout
  171.     // 5) Success -> return not modified
  172.     if (cachedValidatorPresent)
  173.     {
  174.       if (!cachedValidator.isExpired(_maxAge, _maxStale))
  175.       {
  176.         // The cache is available for retreiving.
  177.         switch (openCacheRead(ultimateURL->getAbsolute(), streamInfo))
  178.         {
  179.           case VXIcache_RESULT_SUCCESS:
  180.             delete ultimateURL;
  181.             if( streamInfo ) {
  182.               // Set CACHE data source information   
  183.               VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, 
  184.                         (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_CACHE));
  185.               
  186.             }
  187.             // Remove the HTTP status property (there was no HTTP status for this fetch).
  188.             VXIMapDeleteProperty(streamInfo, INET_INFO_HTTP_STATUS);
  189.             // Return the cached validator to the user.
  190.             SBinetUtils::setValidatorInfo(streamInfo, &cachedValidator);
  191.             // If an external validator was passed in and it matches the
  192.             // cached validator for this resource, return NOT_MODIFIED.
  193.             // Otherwise, return SUCCESS.
  194.             if (externalValidatorPresent && (externalValidator == cachedValidator))
  195.             {
  196.               Close();
  197.               return VXIinet_RESULT_NOT_MODIFIED;
  198.             }
  199.             else
  200.             {
  201.               // Document cache entry is not closed.
  202.               // Subsequent calls to Read() are possible.
  203.               return VXIinet_RESULT_SUCCESS;
  204.             }
  205.           case VXIcache_RESULT_ENTRY_LOCKED:
  206.             Error(234, L"%s%s", L"URL", _url->getAbsolute());
  207.             delete ultimateURL;
  208.             return VXIinet_RESULT_FETCH_TIMEOUT;
  209.           default:
  210.             // Unable to read the document from the cache.  Perhaps the cache
  211.             // entry no longer exists.  Continue with http fetch.
  212.             // Disregard the cached validator.
  213.             cachedValidator.Clear();
  214.             break;
  215.         }
  216.       }
  217.       else
  218.       {
  219.         Diag(MODULE_SBINET_CACHE_TAGID, L"SBinetHttpCacheStream::Open",
  220.              L"%s%s", L"Validator expired: ", ultimateURL->getAbsolute());     
  221.         oldCachedUri = ultimateURL->getAbsolute();
  222.         isCacheExpired = true;
  223.         // Continue on with the HTTP fetch.
  224.       }
  225.     }
  226.   }
  227.   delete ultimateURL;
  228.   SBinetURL *url = new SBinetURL(*_url);
  229.   if (!_cache && externalValidatorPresent)
  230.   {
  231.     _httpStream =
  232.       new SBinetHttpStream(url, _method, _channel, &externalValidator, GetLog(), GetDiagBase());
  233.   }
  234.   else
  235.   {
  236.     // If there is a cache, use the cached validator.  If there is no cached
  237.     // validator, use the default cached validator which is empty.
  238.     _httpStream =
  239.       new SBinetHttpStream(url, _method, _channel, &cachedValidator, GetLog(), GetDiagBase());
  240.   }
  241.   _httpReadCompleted = false;
  242.   SWITimeStamp timeout;
  243.   getTimeOut(&timeout);
  244.   _httpStream->setTimeOut(&timeout);
  245.   // Fetch the document using HTTP.
  246.   VXIinetResult rc = _httpStream->Open(flags, properties, streamInfo);
  247.   SBinetValidator *newValidator = (SBinetValidator*)_httpStream->getValidator();
  248.   switch (rc)
  249.   {
  250.    case VXIinet_RESULT_SUCCESS: {
  251.      VXIcacheResult crc;    
  252.      if( isCacheExpired && !oldCachedUri.empty() ) { 
  253.         // Remove the document cache entry associated with this validator.
  254.         // if the cache expired and changed from the webserver
  255.         VXIMap * dummy = VXIMapCreate();
  256.         crc = openCacheEntry(oldCachedUri.c_str(), CACHE_MODE_WRITE, dummy);
  257.         if (crc == VXIcache_RESULT_SUCCESS)
  258.         {
  259.           crc = _cache->CloseEx(_cache, FALSE, &_cacheStream);
  260.           if (crc != VXIcache_RESULT_SUCCESS)
  261.             Error(239, L"%s%s%s%i", L"URL", oldCachedUri.c_str(), L"rc", crc);
  262.           _cacheStream = NULL;
  263.         }
  264.         if( dummy ) VXIMapDestroy(&dummy);
  265.      }
  266.       
  267.      if (newValidator != NULL)
  268.      {
  269.        // Only write to cache if no other thread/channel is writting the
  270.        // same cache
  271.        crc = writeValidatorToCache(url, *newValidator);
  272.        if (crc != VXIcache_RESULT_SUCCESS) {
  273.          return cache2inetRc(crc);
  274.        } 
  275.        // Prepare the cache for writing (as the document is fetched during
  276.        // Read(), it is written to the cache).
  277.        rc = openCacheWrite(url->getAbsolute(), streamInfo);
  278.        // NOTE: In this case, the validator to return in the streamInfo map
  279.        // has already been set by the HTTP stream.
  280.      }
  281.    } break;
  282.    case VXIinet_RESULT_NOT_MODIFIED:
  283.      {
  284.        // Update the new validator return by the HTTP stream with any
  285.        // information it does not contain from the previously cached validator.
  286.        // This is an assumption we make to make sure validator data is
  287.        // properly progated when it is not returned by an HTTP server.
  288.        if (newValidator != NULL)
  289.        {
  290.          bool changed = newValidator->propagateDataFrom(cachedValidator);
  291.          if (changed)
  292.          {
  293.            // If the new validator has changed, update the validator in the
  294.            // streamInfo map.
  295.            if (!SBinetUtils::setValidatorInfo(streamInfo, newValidator))
  296.            {
  297.              Error(103, NULL);
  298.              rc = VXIinet_RESULT_OUT_OF_MEMORY;
  299.            }
  300.          }
  301.        }
  302.        if( streamInfo ) {
  303.          // Set VALIDATED CACHE data source information   
  304.          VXIMapSetProperty(streamInfo, INET_INFO_DATA_SOURCE, 
  305.                        (VXIValue*) VXIIntegerCreate(INET_DATA_SOURCE_VALIDATED));
  306.        }
  307.        // Write the updated validator to the cache.  This validator contains
  308.        // all original validator information (propagated from the original
  309.        // validator) and contains any new information returned by the server
  310.        // in the Not-Modified response.
  311.        if (newValidator != NULL)
  312.        {
  313.          // Make sure only ONE thread/channel write this info
  314.          VXIcacheResult crc = writeValidatorToCache(url, *newValidator);
  315.          // let other thread/channel to write validator info
  316.          if (crc != VXIcache_RESULT_SUCCESS) {
  317.            return cache2inetRc(crc);
  318.          }
  319.        }
  320.        // Cases for non-error return values when HTTP stream returns NOT_MODIFIED:
  321.        // 1) No external validator was passed to INET -> SUCCESS
  322.        // 2) An external validator was passed to INET and it did not match the
  323.        //    cached validator -> SUCCESS;
  324.        // 3) An external validator was passed to INET and it matched the cached
  325.        //    validator -> NOT_MODIFIED
  326.        // NOTE: The case where an external validator was passed to INET but
  327.        //       there is no cached validator results in SUCCESS since the HTTP
  328.        //       fetch will have occurred (no conditional fetch will be
  329.        //       performed).
  330.        if (externalValidatorPresent && (externalValidator == cachedValidator))
  331.        {
  332.          rc = Close();
  333.          if (rc != VXIinet_RESULT_SUCCESS)
  334.            return rc;
  335.          return VXIinet_RESULT_NOT_MODIFIED;
  336.        }
  337.        else
  338.        {
  339.          // Reset return code, if error occurs it will be set accordingly
  340.          rc = VXIinet_RESULT_SUCCESS;
  341.          
  342.          // We no longer need the http stream.  We must close and delete it.
  343.          // Otherwise, subsequent calls to Read() will attempt to read from
  344.          // it rather than the cache.
  345.          // It is important to do this after we are done using the stream's
  346.          // validator.
  347.          if (_httpStream != NULL)
  348.          {
  349.            VXIinetResult nrc = _httpStream->Close();
  350.            if (nrc != VXIinet_RESULT_SUCCESS)
  351.              return nrc;
  352.            delete _httpStream;
  353.            _httpStream = NULL;
  354.            newValidator = NULL;
  355.          }
  356.          // Prepare the document for reading so that subsequent calls to
  357.          // Read() will succeed.
  358.          if (_cache)
  359.          {
  360.            VXIcacheResult crc = openCacheRead(_url->getAbsolute(), streamInfo);
  361.            // The cache entry may have been deleted, fetch the content from webserver
  362.            // Do not cache this page
  363.            if (crc != VXIcache_RESULT_SUCCESS) {
  364.              // (1) Close all streams and clear validator
  365.              Close();
  366.              cachedValidator.Clear();
  367.              
  368.              // (2) Create new HTTP stream, no matter external or interal validator, the client
  369.              //     must read from the HTTP stream, and obtains new stream info!
  370.              SBinetURL *tmpUrl = new SBinetURL(*_url);
  371.              _httpStream =
  372.                new SBinetHttpStream(tmpUrl, _method, _channel, &cachedValidator, GetLog(), GetDiagBase());
  373.              // (3) Setup timeout
  374.              _httpReadCompleted = false;
  375.              getTimeOut(&timeout);
  376.              _httpStream->setTimeOut(&timeout);
  377.              
  378.              // (4) Connect to webserver for non-conditional fetch
  379.              rc = _httpStream->Open(flags, properties, streamInfo);
  380.              
  381.              // (5) Cleanup if fetch failed!
  382.              if( rc != VXIinet_RESULT_SUCCESS )
  383.                Close();                        
  384.            }              
  385.          }
  386.        }
  387.      }
  388.      break;
  389.    default:
  390.      Close();
  391.      break;
  392.   }
  393.   return rc;
  394. }
  395. // This method writes the message body to the cache.
  396. VXIinetResult SBinetHttpCacheStream::Read(/* [OUT] */ VXIbyte*         pBuffer,
  397.                                           /* [IN]  */ VXIulong         nBuflen,
  398.                                           /* [OUT] */ VXIulong*        pnRead )
  399. {
  400.   VXIinetResult rc = VXIinet_RESULT_NON_FATAL_ERROR;
  401.   bool cleanCache = false;
  402.   if (_httpStream != NULL)
  403.   {
  404.     VXIulong nbRead;
  405.     rc = _httpStream->Read(pBuffer, nBuflen, &nbRead);
  406.     if (pnRead != NULL) *pnRead = nbRead;
  407.     if (_cacheStream != NULL)
  408.     {
  409.       switch (rc)
  410.       {
  411.        case VXIinet_RESULT_END_OF_STREAM:
  412.          _httpReadCompleted = true;
  413.          // no break: intentional
  414.        case VXIinet_RESULT_SUCCESS:
  415.          if (nbRead > 0)
  416.          {
  417.            VXIulong nbWritten = 0;
  418.            // Now write the read data (message body) to the cache
  419.            VXIcacheResult rcc = _cache->Write(_cache, pBuffer, nbRead,
  420.                                               &nbWritten, _cacheStream);
  421.            if ((rcc != VXIcache_RESULT_SUCCESS) || (nbWritten != nbRead))
  422.            {
  423.              if (rcc == VXIcache_RESULT_EXCEED_MAXSIZE)
  424.              {
  425.                Error(305, L"%s%s", L"URL", _url->getAbsolute());
  426.                rc = VXIinet_RESULT_SUCCESS;
  427.              }
  428.              else
  429.              {
  430.                Error(232, L"%s%s%s%i%s%i%s%i", L"URL", _url->getAbsolute(),
  431.                      L"rc", rcc, L"written", nbWritten, L"expected", nbRead);
  432.                rc = VXIinet_RESULT_NON_FATAL_ERROR;
  433.              }
  434.              cleanCache = true;
  435.            }
  436.          }
  437.          break;
  438.        default:
  439.          cleanCache = true;
  440.          break;
  441.       }
  442.     }    
  443.   }
  444.   else if (_cacheStream != NULL)
  445.   {
  446.     if (hasTimedOut())
  447.     {
  448.       Error(251, L"%s%s", L"URL", _url->getAbsolute());
  449.       rc = VXIinet_RESULT_FETCH_TIMEOUT;
  450.       cleanCache = true;
  451.     }
  452.     else
  453.     {
  454.       VXIcacheResult rcc = _cache->Read(_cache, pBuffer, nBuflen, pnRead, _cacheStream);
  455.       if ((rcc != VXIcache_RESULT_SUCCESS) && (rcc != VXIcache_RESULT_END_OF_STREAM))
  456.       {
  457.          Error(231, L"%s%s%s%i%s%i%s%i", L"URL", _url->getAbsolute(),
  458.                L"rc", rcc, L"read", *pnRead, L"expected", nBuflen);
  459.          cleanCache = true;
  460.       }
  461.       rc = cache2inetRc(rcc);
  462.     }
  463.   }
  464.   else
  465.   {
  466.     Error(218, L"%s%s", L"URL", _url->getAbsolute());
  467.   }
  468.   if (cleanCache)
  469.   {
  470.     VXIcacheResult rcc = _cache->CloseEx(_cache, FALSE, &_cacheStream);
  471.     if (rcc != VXIcache_RESULT_SUCCESS)
  472.       Error(239, L"%s%s%s%i", L"URL", _url->getAbsolute(), L"rc", rcc);
  473.     _cacheStream = NULL;
  474.   }
  475.   return rc;
  476. }
  477. VXIinetResult SBinetHttpCacheStream::Write(/* [IN] */ const VXIbyte*   pBuffer,
  478.                                            /* [IN]  */ VXIulong         nBuflen,
  479.                                            /* [OUT] */ VXIulong*        pnWritten)
  480. {
  481.   if (_httpStream != NULL)
  482.   {
  483.     return _httpStream->Write(pBuffer, nBuflen, pnWritten);
  484.   }
  485.   return VXIinet_RESULT_PLATFORM_ERROR;
  486. }
  487. VXIinetResult SBinetHttpCacheStream::Close()
  488. {
  489.   VXIinetResult rc1 = VXIinet_RESULT_SUCCESS;
  490.   VXIinetResult rc2 = VXIinet_RESULT_SUCCESS;
  491.   VXIbool keepEntry = TRUE;
  492.   
  493.   if (_httpStream != NULL)
  494.   {
  495.     rc1 = _httpStream->Close();
  496.     delete _httpStream;
  497.     _httpStream = NULL;
  498.     keepEntry = _httpReadCompleted;
  499.   }
  500.   if (_cacheStream != NULL)
  501.   {
  502.     VXIcacheResult rcc = _cache->CloseEx(_cache, keepEntry, &_cacheStream);
  503.     if (rcc != VXIcache_RESULT_SUCCESS)
  504.     {
  505.       Error(239, L"%s%s%s%i", L"URL", _url->getAbsolute(), L"rc", rcc);
  506.       rc2 = VXIinet_RESULT_FAILURE;
  507.     }
  508.     _cacheStream = NULL;
  509.   }
  510.   // If any of the close fails, return that one.
  511.   return rc1 != VXIinet_RESULT_SUCCESS ? rc1 : rc2;
  512. }
  513. void SBinetHttpCacheStream::setTimeOut(const SWITimeStamp *timeOfDay)
  514. {
  515.   if (_httpStream != NULL)
  516.   {
  517.     _httpStream->setTimeOut(timeOfDay);
  518.   }
  519.   SBinetStoppableStream::setTimeOut(timeOfDay);
  520. }
  521. VXIcacheResult
  522. SBinetHttpCacheStream::openCacheEntry(const VXIchar *absoluteURL,
  523.                                       VXIcacheOpenMode mode,
  524.                                       VXIMap *cacheStreamInfo)
  525. {
  526.   VXIcacheResult rc;
  527.   long delay;
  528.   const long maxSleepTime = 20;
  529.   static const VXIchar *moduleName = L"swi:" MODULE_SBINET;
  530.   SBinetString cacheKey = moduleName;
  531.   cacheKey += L':';
  532.   cacheKey += absoluteURL;
  533.   VXIMapHolder cacheProp; // will destroy the map for us
  534.   VXIMapSetProperty(cacheProp.GetValue(), CACHE_CREATION_COST,
  535.     (VXIValue *) VXIIntegerCreate(CACHE_CREATION_COST_FETCH));
  536.   while ((rc = _cache->Open(_cache, MODULE_SBINET,
  537.                             cacheKey.c_str(),
  538.                             mode, CACHE_FLAG_NULL,
  539.                             cacheProp.GetValue(), cacheStreamInfo,
  540.     &_cacheStream))
  541.          == VXIcache_RESULT_ENTRY_LOCKED)
  542.   {
  543.     //VXItrdThreadYield();
  544.     delay = getDelay();
  545.     if (delay == 0)
  546.       break;
  547.     else if (delay < 0 || delay > maxSleepTime)
  548.       delay = maxSleepTime;
  549.     SBinetHttpUtils::usleep(delay * 1000);
  550.   }
  551.   if (rc != VXIcache_RESULT_SUCCESS)
  552.   {
  553.     if (rc == VXIcache_RESULT_NOT_FOUND)
  554.       Diag(MODULE_SBINET_CACHE_TAGID, L"SBinetHttpCacheStream",
  555.            L"Not found in cache: %s", absoluteURL);
  556.     else
  557.       Error(230, L"%s%s%s%i", L"URL", absoluteURL, L"rc", rc);
  558.   }
  559.   return rc;
  560. }
  561. // This method reads the document mime type from the cache.
  562. // Sets the INET_INFO_SIZE_BYTES and INET_INFO_MIME_TYPE info values
  563. // in this stream's streamInfo map.
  564. // The actual reading of the document is done inside Read().
  565. VXIcacheResult SBinetHttpCacheStream::openCacheRead(const VXIchar* absoluteURL, VXIMap *streamInfo)
  566. {
  567.   VXIMap *cacheStreamInfo = VXIMapCreate();
  568.   VXIcacheResult rc;
  569.   VXIint32 entrySizeBytes = 0;
  570.   VXIchar* mimeType = NULL;
  571.   VXIulong bytesRead = 0;
  572.   VXIulong dataSize = 0;
  573.   VXIulong dataSizeBytes = 0;
  574.   if (_cache == NULL)
  575.     return VXIcache_RESULT_FAILURE;
  576.   rc = openCacheEntry(absoluteURL, CACHE_MODE_READ, cacheStreamInfo);
  577.   if (rc != VXIcache_RESULT_SUCCESS)
  578.     goto failure;
  579.   // Retrieve the total size of the cache entry
  580.   if (!SBinetUtils::getInteger(cacheStreamInfo,
  581.                                CACHE_INFO_SIZE_BYTES, entrySizeBytes))
  582.   {
  583.     Error(233, L"%s%s%", L"URL", absoluteURL);
  584.     rc = VXIcache_RESULT_FAILURE;
  585.     goto failure;
  586.   }
  587.   // Read the MIME type size (number of VXIchar), followed by the actual MIME
  588.   // type
  589.   bytesRead = 0;
  590.   rc = _cache->Read(_cache, (VXIbyte *) &dataSize, sizeof(dataSize), &bytesRead, _cacheStream);
  591.   if ((rc != VXIcache_RESULT_SUCCESS) || (bytesRead != sizeof(dataSize)))
  592.   {
  593.     Error(231, L"%s%s%s%i%s%i%s%i", "URL", absoluteURL, L"rc", rc,
  594.           L"read", bytesRead, L"expected", sizeof(dataSize));
  595.     rc = VXIcache_RESULT_FAILURE;
  596.     goto failure;
  597.   }
  598.   // Adjust the actual size
  599.   entrySizeBytes -= bytesRead;
  600.   // Now read mime type.
  601.   mimeType = new VXIchar[dataSize + 1];
  602.   dataSizeBytes = dataSize * sizeof(VXIchar);
  603.   rc = _cache->Read(_cache, (VXIbyte *) mimeType, dataSizeBytes, &bytesRead, _cacheStream);
  604.   if ((rc != VXIcache_RESULT_SUCCESS) || (bytesRead != dataSizeBytes))
  605.   {
  606.     Error(231, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  607.           L"read", bytesRead, L"expected", dataSizeBytes);
  608.     rc = VXIcache_RESULT_FAILURE;
  609.     goto failure;
  610.   }
  611.   mimeType[dataSize] = L'';
  612.   // Adjust the actual size
  613.   entrySizeBytes -= bytesRead;
  614.   // Set the document size property
  615.   VXIMapSetProperty(streamInfo, INET_INFO_SIZE_BYTES,
  616.                     (VXIValue*)VXIIntegerCreate(entrySizeBytes));
  617.   // Set the MIME type property
  618.   VXIMapSetProperty(streamInfo, INET_INFO_MIME_TYPE,
  619.                     (VXIValue*)VXIStringCreate(mimeType));
  620.   // Set the absolute URL property
  621.   VXIMapSetProperty(streamInfo, INET_INFO_ABSOLUTE_NAME,
  622.                     (VXIValue*)VXIStringCreate(absoluteURL));
  623.   goto end;
  624.  failure:
  625.   if (_cacheStream)
  626.   {
  627.     VXIcacheResult rcc = _cache->CloseEx(_cache, TRUE, &_cacheStream);
  628.     if (rcc != VXIcache_RESULT_SUCCESS)
  629.       Error(239, L"%s%s%s%i", L"URL", absoluteURL, L"rc", rcc);
  630.   }
  631.   _cacheStream = NULL;
  632.  end:
  633.   if (mimeType)
  634.     delete [] mimeType;
  635.   if (cacheStreamInfo)
  636.     VXIMapDestroy(&cacheStreamInfo);
  637.   return rc;
  638. }
  639. // This method reads the validator from the validator cache entry.
  640. VXIcacheResult
  641. SBinetHttpCacheStream::readValidatorFromCache(SBinetURL *&ultimateURL,
  642.                                               SBinetValidator& validator,
  643.                                               bool &expired)
  644. {
  645.   if (_cache == NULL)
  646.     return VXIcache_RESULT_FAILURE;
  647.   VXIMap *cacheStreamInfo = VXIMapCreate();
  648.   VXIbyte *validatorData = NULL;
  649.   VXIcacheResult rc;
  650.   VXIulong maxDataSize = 0;
  651.   VXIulong bytesRead = 0;
  652.   VXIulong dataSize = 0;
  653.   SBinetURL *tmpURL = NULL;
  654.   const VXIchar *absoluteURL = NULL;
  655.   ultimateURL = new SBinetURL(*_url);
  656.   expired = false;
  657.   
  658.   for (;;)
  659.   {
  660.     absoluteURL = ultimateURL->getAbsolute();
  661.     VXIchar* urlKey = new VXIchar [wcslen(absoluteURL) + 12];
  662.     wcscpy(urlKey, absoluteURL);
  663.     wcscat(urlKey, L"_validator");
  664.     rc = openCacheEntry(urlKey, CACHE_MODE_READ, cacheStreamInfo);
  665.     delete [] urlKey;
  666.     if (rc != VXIcache_RESULT_SUCCESS)
  667.       break;
  668.     // The document is in cache.
  669.     Diag(MODULE_SBINET_CACHE_TAGID, L"SBinetHttpCacheStream",
  670.          L"Found in cache: %s", absoluteURL);
  671.     // Read the size of the validator info.
  672.     rc = _cache->Read(_cache, (VXIbyte *) &dataSize,
  673.                       sizeof(dataSize), &bytesRead, _cacheStream);
  674.     if (rc != VXIcache_RESULT_SUCCESS || bytesRead != sizeof(dataSize))
  675.     {
  676.       Error(231, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  677.             L"read", bytesRead, L"expected", sizeof(dataSize));
  678.       rc = VXIcache_RESULT_FAILURE;
  679.       break;
  680.     }
  681.     if (dataSize > maxDataSize)
  682.     {
  683.       delete [] validatorData;
  684.       validatorData = new VXIbyte[dataSize];
  685.       maxDataSize = dataSize;
  686.     }
  687.     if (validatorData == NULL)
  688.     {
  689.       Error(103, NULL);
  690.       rc = VXIcache_RESULT_FAILURE;
  691.       break;
  692.     }
  693.     rc = _cache->Read(_cache, validatorData, dataSize, &bytesRead, _cacheStream);
  694.     if (rc != VXIcache_RESULT_SUCCESS || bytesRead != dataSize)
  695.     {
  696.       Error(231, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  697.             L"read", bytesRead, L"expected", dataSize);
  698.       rc = VXIcache_RESULT_FAILURE;
  699.       break;
  700.     }
  701.     if (validator.Create(validatorData, dataSize) != VXIinet_RESULT_SUCCESS)
  702.     {
  703.       Error(215, L"%s%s", NULL);
  704.       rc = VXIcache_RESULT_FAILURE;
  705.       break;
  706.     }
  707.     if (validator.isExpired(_maxAge, _maxStale))
  708.     {
  709.       expired = true;
  710.       Diag(MODULE_SBINET_CACHE_TAGID, L"SBinetHttpCacheStream",
  711.            L"Validator expired: %s", absoluteURL);
  712.       rc = VXIcache_RESULT_FAILURE;      
  713.       break;
  714.     }
  715.     // If the validator's URL is not equals to the current ultimate URL, then
  716.     // this is a redirect.
  717.     absoluteURL = validator.getURL();
  718.     if (tmpURL == NULL)
  719.     {
  720.       if (SBinetURL::create(absoluteURL, NULL, tmpURL) != VXIinet_RESULT_SUCCESS)
  721.         rc = VXIcache_RESULT_FAILURE;
  722.     }
  723.     else
  724.     {
  725.       if (tmpURL->parse(absoluteURL, NULL) != VXIinet_RESULT_SUCCESS)
  726.         rc = VXIcache_RESULT_FAILURE;
  727.     }
  728.     if (rc != VXIcache_RESULT_SUCCESS)
  729.     {
  730.       Diag(MODULE_SBINET_CACHE_TAGID,
  731.            L"SBinetHttpCacheStream::OpenCacheRead",
  732.            L"Invalid URL: <%s>", absoluteURL);
  733.       break;
  734.     }
  735.     // Compare URLs.
  736.     if (*ultimateURL == *tmpURL)
  737.     {
  738.       // No redirection.
  739.       break;
  740.     }
  741.     // Redirection: continue.
  742.     Diag(MODULE_SBINET_CACHE_TAGID, L"SBinetHttpCacheStream::OpenCacheRead",
  743.          L"Redirection detected, from %s to %s", ultimateURL->getAbsolute(), absoluteURL);
  744.     *ultimateURL = *tmpURL;
  745.     // Close the current cache entry and continue with the redirection.
  746.     VXIcacheResult rcc = _cache->CloseEx(_cache, TRUE, &_cacheStream);
  747.     if (rcc != VXIcache_RESULT_SUCCESS)
  748.       Error(239, L"%s%s%s%i", L"URL", absoluteURL, L"rc", rcc);
  749.     _cacheStream = NULL;
  750.   }
  751.   delete [] validatorData;
  752.   delete tmpURL;
  753.   // Close the cache entry no matter what.  It will not be reused.
  754.   if (_cacheStream != NULL)
  755.   {
  756.     VXIcacheResult rcc = _cache->CloseEx(_cache, TRUE, &_cacheStream);
  757.     if (rcc != VXIcache_RESULT_SUCCESS)
  758.       Error(239, L"%s%s%s%i", L"URL", absoluteURL, L"rc", rcc);
  759.     _cacheStream = NULL;
  760.   }
  761.   if (cacheStreamInfo)
  762.     VXIMapDestroy(&cacheStreamInfo);
  763.   if (rc != VXIcache_RESULT_SUCCESS && !expired)
  764.   {
  765.     delete ultimateURL;
  766.     ultimateURL = NULL;
  767.   }
  768.   return rc;
  769. }
  770. // Write the document to cache. This method only stores
  771. // MIME type in the cache. The real document (message body) is
  772. // written later in Read().
  773. VXIinetResult
  774. SBinetHttpCacheStream::openCacheWrite(const VXIchar *absoluteURL,
  775.                                       const VXIMap *streamInfo)
  776. {
  777.   if (_cache == NULL)
  778.     return VXIinet_RESULT_SUCCESS;
  779.   // Check whether we already cached this URL.
  780.   VXIcacheResult rc = openCacheEntry(absoluteURL, CACHE_MODE_WRITE, NULL);
  781.   if (rc != VXIcache_RESULT_SUCCESS)
  782.     return VXIinet_RESULT_SUCCESS;
  783.   const VXIchar* mimeType = SBinetUtils::getString(streamInfo, INET_INFO_MIME_TYPE);
  784.   VXIulong dataSize = (mimeType == NULL)? 0 : ::wcslen(mimeType);
  785.   VXIulong dataSizeBytes = 0;
  786.   VXIulong bytesWritten = 0;
  787.   // Write the size of the of the mime-type (number of VXIchar).
  788.   rc = _cache->Write(_cache, (VXIbyte *) &dataSize, sizeof(dataSize), &bytesWritten, _cacheStream);
  789.   if ((rc != VXIcache_RESULT_SUCCESS) || (bytesWritten != sizeof(dataSize)))
  790.   {
  791.     Error(232, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  792.           L"written", bytesWritten, L"expected", sizeof(dataSize));
  793.     goto failure;
  794.   }
  795.   // Now write the mime-type.
  796.   bytesWritten = 0;
  797.   dataSizeBytes = dataSize * sizeof(VXIchar);
  798.   rc = _cache->Write(_cache, (const VXIbyte *) mimeType, dataSizeBytes,
  799.      &bytesWritten, _cacheStream);
  800.   if ((rc != VXIcache_RESULT_SUCCESS) || (bytesWritten != dataSizeBytes))
  801.   {
  802.     Error(232, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  803.           L"written", bytesWritten, L"expected", dataSizeBytes);
  804.     goto failure;
  805.   }
  806.   goto end;
  807.  failure:
  808.   if (_cacheStream)
  809.   {
  810.     VXIcacheResult rcc = _cache->CloseEx(_cache, FALSE, &_cacheStream);
  811.     if (rcc != VXIcache_RESULT_SUCCESS)
  812.       Error(239, L"%s%s%s%i", L"URL", absoluteURL, L"rc", rcc);
  813.   }
  814.   _cacheStream = NULL;
  815.  end:
  816.   if (rc == VXIcache_RESULT_ENTRY_LOCKED)
  817.   {
  818.     // This is because of a timeout on trying to lock the cache entry.  We just
  819.     // return a a fetch timeout to cause our calling function to fail.
  820.     Error(235, L"%s%s", L"URL", absoluteURL);
  821.     return VXIinet_RESULT_FETCH_TIMEOUT;
  822.   }
  823.   else
  824.   {
  825.     // Something wrong occured while trying to write data to the cache entry.
  826.     // We will assume success, but there will be no caching.
  827.     return VXIinet_RESULT_SUCCESS;
  828.   }
  829. }
  830. // This method writes the validator to the cache.
  831. VXIcacheResult
  832. SBinetHttpCacheStream::writeValidatorToCache(const SBinetURL *ultimateURL,
  833.                                              const SBinetValidator& validator)
  834. {
  835.   if (_cache == NULL)
  836.     return VXIcache_RESULT_SUCCESS;
  837.   VXIcacheResult rc = VXIcache_RESULT_SUCCESS;
  838.   const VXIchar* absoluteURL = NULL;
  839.   // Take care of redirection.
  840.   if (*_url != *ultimateURL)
  841.   {
  842.     Diag(MODULE_SBINET_CACHE_TAGID, L"SBinetHttpCacheStream::OpenCacheWrite",
  843.          L"Redirection detected, from %s to %s", absoluteURL, ultimateURL->getAbsolute());
  844.     absoluteURL = ultimateURL->getAbsolute();
  845.   }
  846.   else
  847.   {
  848.     absoluteURL = _url->getAbsolute();
  849.   }
  850.   VXIbyte *validatorData = NULL;
  851.   VXIulong bytesWritten = 0;
  852.   VXIulong dataSize = 0;
  853.   // Construct the key for this validator cache entry.
  854.   VXIchar* urlKey = new VXIchar [wcslen(absoluteURL) + 12];
  855.   wcscpy(urlKey, absoluteURL);
  856.   wcscat(urlKey, L"_validator");
  857.   // Check whether we already cached the validator for this URL.
  858.   rc = openCacheEntry(urlKey, CACHE_MODE_WRITE, NULL);
  859.   delete [] urlKey;
  860.   if (rc != VXIcache_RESULT_SUCCESS)
  861.     goto failure;
  862.   if (!validator.serialize(validatorData, dataSize))
  863.   {
  864.     Error(215, L"%s%s", L"URL", absoluteURL);
  865.     rc = VXIcache_RESULT_FAILURE;
  866.     goto failure;
  867.   }
  868.   // Write the size of the validator.
  869.   rc = _cache->Write(_cache, (VXIbyte *) &dataSize, sizeof(dataSize), &bytesWritten, _cacheStream);
  870.   if (rc != VXIcache_RESULT_SUCCESS || (bytesWritten != sizeof(dataSize)))
  871.   {
  872.     if (rc == VXIcache_RESULT_EXCEED_MAXSIZE)
  873.       Error(305, L"%s%s", L"URL", absoluteURL);
  874.     else
  875.       Error(232, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  876.             L"written", bytesWritten, L"expected", sizeof(dataSize));
  877.     rc = VXIcache_RESULT_FAILURE;
  878.     goto failure;
  879.   }
  880.   // Write the validator.
  881.   bytesWritten = 0;
  882.   rc = _cache->Write(_cache, validatorData, dataSize, &bytesWritten, _cacheStream);
  883.   if (rc != VXIcache_RESULT_SUCCESS || bytesWritten != dataSize)
  884.   {
  885.     Error(232, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
  886.           L"written", bytesWritten, L"expected", dataSize);
  887.     rc = VXIcache_RESULT_FAILURE;
  888.     goto failure;
  889.   }
  890.  failure:
  891.   delete [] validatorData;
  892.   // Close the validator cache stream once done.
  893.   if (_cacheStream)
  894.   {
  895.     VXIcacheResult rcc = _cache->CloseEx(_cache, TRUE, &_cacheStream);
  896.     if (rcc != VXIcache_RESULT_SUCCESS)
  897.       Error(239, L"%s%s%s%i", L"URL", absoluteURL, L"rc", rcc);
  898.   }
  899.   _cacheStream = NULL;
  900.   return rc;
  901. }