📄 sbinethttpcachestream.cpp
字号:
/****************License************************************************
*
* Copyright 2000-2003. ScanSoft, Inc.
*
* Use of this software is subject to notices and obligations set forth
* in the SpeechWorks Public License - Software Version 1.2 which is
* included with this software.
*
* ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech,
* SpeechWorks and the SpeechWorks logo are registered trademarks or
* trademarks of SpeechWorks International, Inc. in the United States
* and other countries.
*
***********************************************************************/
#include <vxibuildopts.h>
#if P_VXI
#if _MSC_VER >= 1100 // Visual C++ 5.x
#pragma warning( disable : 4786 4503 )
#endif
#include "vxi/VXIinet.h"
#include "SBinetHttpCacheStream.hpp"
#include "SBinetURL.h"
#include "SBinetValidator.h"
#include "SBinetChannel.h"
#include "SBinetUtils.hpp"
#include "SBinetString.hpp"
#include "HttpUtils.hpp"
#if defined(_MSC_VER)
#pragma warning(disable:4061)
#endif
VXIinetResult
SBinetHttpCacheStream::cache2inetRc(VXIcacheResult result)
{
switch (result)
{
case VXIcache_RESULT_FATAL_ERROR:
return VXIinet_RESULT_FATAL_ERROR;
case VXIcache_RESULT_IO_ERROR:
return VXIinet_RESULT_IO_ERROR;
case VXIcache_RESULT_OUT_OF_MEMORY:
return VXIinet_RESULT_OUT_OF_MEMORY;
case VXIcache_RESULT_SYSTEM_ERROR:
return VXIinet_RESULT_SYSTEM_ERROR;
case VXIcache_RESULT_PLATFORM_ERROR:
return VXIinet_RESULT_PLATFORM_ERROR;
case VXIcache_RESULT_BUFFER_TOO_SMALL:
return VXIinet_RESULT_BUFFER_TOO_SMALL;
case VXIcache_RESULT_INVALID_PROP_NAME:
return VXIinet_RESULT_INVALID_PROP_NAME;
case VXIcache_RESULT_INVALID_PROP_VALUE:
return VXIinet_RESULT_INVALID_PROP_VALUE;
case VXIcache_RESULT_INVALID_ARGUMENT:
return VXIinet_RESULT_INVALID_ARGUMENT;
case VXIcache_RESULT_SUCCESS:
return VXIinet_RESULT_SUCCESS;
case VXIcache_RESULT_FAILURE:
return VXIinet_RESULT_FAILURE;
case VXIcache_RESULT_NON_FATAL_ERROR:
return VXIinet_RESULT_NON_FATAL_ERROR;
case VXIcache_RESULT_NOT_FOUND:
return VXIinet_RESULT_NOT_FOUND;
case VXIcache_RESULT_WOULD_BLOCK:
return VXIinet_RESULT_WOULD_BLOCK;
case VXIcache_RESULT_END_OF_STREAM:
return VXIinet_RESULT_END_OF_STREAM;
case VXIcache_RESULT_EXCEED_MAXSIZE:
return VXIinet_RESULT_OUT_OF_MEMORY;
case VXIcache_RESULT_ENTRY_LOCKED:
return VXIinet_RESULT_FETCH_TIMEOUT;
case VXIcache_RESULT_UNSUPPORTED:
return VXIinet_RESULT_UNSUPPORTED;
default: {
Error(299, L"%s%i", L"VXIcacheResult", result);
return VXIinet_RESULT_NON_FATAL_ERROR;
}
}
}
// Refer to SBinetHttpCacheStream.hpp for doc.
SBinetHttpCacheStream::
SBinetHttpCacheStream(SBinetURL* url,
SBinetHttpStream::SubmitMethod method,
SBinetChannel* ch,
VXIcacheInterface *cache,
VXIlogInterface *log,
VXIunsigned diagLogBase):
SBinetStoppableStream(url, log, diagLogBase),
_httpStream(NULL),
_channel(ch),
_cache(cache),
_cacheStream(NULL),
_method(method),
_maxAge(-1),
_maxStale(-1),
_httpReadCompleted(false)
{}
// SBinetHttpCacheStream::~SBinetHttpCacheStream
// Refer to SBinetHttpCacheStream.hpp for doc.
SBinetHttpCacheStream::~SBinetHttpCacheStream()
{
Close();
}
VXIinetResult SBinetHttpCacheStream::Open(VXIint flags,
const VXIMap* properties,
VXIMap* streamInfo)
{
getCacheInfo(properties, _maxAge, _maxStale);
// Determine if this is a conditional open with a validator,
// irrelevant if caching is disabled
const VXIValue* validatorVal =
VXIMapGetProperty(properties, INET_OPEN_IF_MODIFIED);;
SBinetValidator validator(GetLog(), GetDiagBase());
if (validatorVal != NULL)
validator.Create(validatorVal);
if (!validator.isExpired(_maxAge, _maxStale))
{
if (streamInfo && !SBinetUtils::setValidatorInfo(streamInfo, &validator))
{
Error(103, NULL);
return VXIinet_RESULT_OUT_OF_MEMORY;
}
return VXIinet_RESULT_NOT_MODIFIED;
}
// Check whether we can read this document from the cache.
if (_maxAge != 0)
{
switch (openCacheRead(streamInfo))
{
case VXIcache_RESULT_SUCCESS:
return VXIinet_RESULT_SUCCESS;
case VXIcache_RESULT_ENTRY_LOCKED:
Error(234, L"%s%s", L"URL", _url->getAbsolute());
return VXIinet_RESULT_FETCH_TIMEOUT;
default:
break;
}
}
SBinetURL *url = new SBinetURL(*_url);
_httpStream =
new SBinetHttpStream(url, _method, _channel, GetLog(), GetDiagBase());
_httpReadCompleted = false;
SWITimeStamp timeout;
getTimeOut(&timeout);
_httpStream->setTimeOut(&timeout);
VXIinetResult rc = _httpStream->Open(flags, properties, streamInfo);
const SBinetValidator *cacheValidator = _httpStream->getValidator();
switch (rc)
{
case VXIinet_RESULT_SUCCESS:
if (cacheValidator != NULL && !cacheValidator->isExpired())
openCacheWrite(streamInfo, *cacheValidator, url);
break;
case VXIinet_RESULT_NOT_MODIFIED:
// The remote server returned a NOT-MODIFIED, we have to return not
// modified as well. Also, if the validator returned by the HttpStream is
// not strong or does not provide an expiration hint, we have to replace
// it by a clone of the original one.
if (streamInfo != NULL)
{
if (cacheValidator == NULL ||
((!cacheValidator->isStrong() &&
cacheValidator->getExpiresTime() <= 0) &&
(validator.isStrong() || validator.getExpiresTime() > 0)))
{
if (!SBinetUtils::setValidatorInfo(streamInfo, &validator))
{
Error(103, NULL);
rc = VXIinet_RESULT_OUT_OF_MEMORY;
}
}
}
// no break: intentional
default:
Close();
break;
}
return rc;
}
// This method writes the message body to the cache.
VXIinetResult SBinetHttpCacheStream::Read(/* [OUT] */ VXIbyte* pBuffer,
/* [IN] */ VXIulong nBuflen,
/* [OUT] */ VXIulong* pnRead )
{
VXIinetResult rc = VXIinet_RESULT_NON_FATAL_ERROR;
bool cleanCache = false;
if (_httpStream != NULL)
{
VXIulong nbRead;
rc = _httpStream->Read(pBuffer, nBuflen, &nbRead);
if (pnRead != NULL) *pnRead = nbRead;
if (_cacheStream != NULL)
{
switch (rc)
{
case VXIinet_RESULT_END_OF_STREAM:
_httpReadCompleted = true;
// no break: intentional
case VXIinet_RESULT_SUCCESS:
if (nbRead > 0)
{
VXIulong nbWritten = 0;
// Now write the read data (message body) to the cache
VXIcacheResult rcc = _cache->Write(_cache, pBuffer, nbRead,
&nbWritten, _cacheStream);
if ((rcc != VXIcache_RESULT_SUCCESS) || (nbWritten != nbRead))
{
if (rcc == VXIcache_RESULT_EXCEED_MAXSIZE)
{
Error(305, L"%s%s", L"URL", _url->getAbsolute());
rc = VXIinet_RESULT_SUCCESS;
}
else
{
Error(232, L"%s%s%s%i%s%i%s%i", L"URL", _url->getAbsolute(),
L"rc", rcc, L"written", nbWritten, L"expected", nbRead);
rc = VXIinet_RESULT_NON_FATAL_ERROR;
}
cleanCache = true;
}
}
break;
default:
cleanCache = true;
break;
}
}
}
else if (_cacheStream != NULL)
{
if (hasTimedOut())
{
Error(251, L"%s%s", L"URL", _url->getAbsolute());
rc = VXIinet_RESULT_FETCH_TIMEOUT;
cleanCache = true;
}
else
{
VXIcacheResult rcc = _cache->Read(_cache, pBuffer, nBuflen, pnRead, _cacheStream);
if ((rcc != VXIcache_RESULT_SUCCESS) && (rcc != VXIcache_RESULT_END_OF_STREAM))
{
Error(231, L"%s%s%s%i%s%i%s%i", L"URL", _url->getAbsolute(),
L"rc", rcc, L"read", *pnRead, L"expected", nBuflen);
cleanCache = true;
}
rc = cache2inetRc(rcc);
}
}
else
{
Error(218, L"%s%s", L"URL", _url->getAbsolute());
}
if (cleanCache)
{
VXIcacheResult rcc = _cache->CloseEx(_cache, FALSE, &_cacheStream);
if (rcc != VXIcache_RESULT_SUCCESS)
Error(239, L"%s%s%s%i", L"URL", _url->getAbsolute(), L"rc", rcc);
_cacheStream = NULL;
}
return rc;
}
VXIinetResult SBinetHttpCacheStream::Write(/* [IN] */ const VXIbyte* pBuffer,
/* [IN] */ VXIulong nBuflen,
/* [OUT] */ VXIulong* pnWritten)
{
if (_httpStream != NULL)
{
return _httpStream->Write(pBuffer, nBuflen, pnWritten);
}
return VXIinet_RESULT_PLATFORM_ERROR;
}
VXIinetResult SBinetHttpCacheStream::Close()
{
VXIinetResult rc1 = VXIinet_RESULT_SUCCESS;
VXIinetResult rc2 = VXIinet_RESULT_SUCCESS;
VXIbool keepEntry = TRUE;
if (_httpStream != NULL)
{
rc1 = _httpStream->Close();
delete _httpStream;
_httpStream = NULL;
keepEntry = _httpReadCompleted;
}
if (_cacheStream != NULL)
{
VXIcacheResult rcc = _cache->CloseEx(_cache, keepEntry, &_cacheStream);
if (rcc != VXIcache_RESULT_SUCCESS)
{
Error(239, L"%s%s%s%i", L"URL", _url->getAbsolute(), L"rc", rcc);
rc2 = VXIinet_RESULT_FAILURE;
}
_cacheStream = NULL;
}
// If any of the close fails, return that one.
return rc1 != VXIinet_RESULT_SUCCESS ? rc1 : rc2;
}
VXIcacheResult SBinetHttpCacheStream::openCacheRead(VXIMap *streamInfo)
{
if (_cache == NULL) return VXIcache_RESULT_FAILURE;
// We need to put all the global variables at the beginning of the block
// because of the goto for clean-up.
const VXIchar* absoluteURL = NULL;
VXIulong bytesRead = 0;
VXIulong dataSize = 0;
VXIulong dataSizeBytes = 0;
VXIchar* mimeType = NULL;
SBinetValidator validator(GetLog(), GetDiagBase());
VXIbool keepEntry = TRUE;
SBinetURL *ultimateURL = NULL;
//time_t expiresTimeStamp = (time_t) 0;
VXIcacheResult rc = openCacheRead(validator, keepEntry, ultimateURL);
if (rc != VXIcache_RESULT_SUCCESS)
goto failure;
absoluteURL = ultimateURL->getAbsolute();
// Read the MIME type size (number of VXIchar), followed by the actual MIME
// type
bytesRead = 0;
rc = _cache->Read(_cache, (VXIbyte *) &dataSize, sizeof(dataSize), &bytesRead, _cacheStream);
if ((rc != VXIcache_RESULT_SUCCESS) || (bytesRead != sizeof(dataSize)))
{
Error(231, L"%s%s%s%i%s%i%s%i", "URL", absoluteURL, L"rc", rc,
L"read", bytesRead, L"expected", sizeof(dataSize));
rc = VXIcache_RESULT_FAILURE;
goto failure;
}
// Now read mime type.
mimeType = new VXIchar[dataSize + 1];
dataSizeBytes = dataSize * sizeof(VXIchar);
rc = _cache->Read(_cache, (VXIbyte *) mimeType, dataSizeBytes, &bytesRead, _cacheStream);
if ((rc != VXIcache_RESULT_SUCCESS) || (bytesRead != dataSizeBytes))
{
Error(231, L"%s%s%s%i%s%i%s%i", L"URL", absoluteURL, L"rc", rc,
L"read", bytesRead, L"expected", dataSizeBytes);
rc = VXIcache_RESULT_FAILURE;
goto failure;
}
mimeType[dataSize] = L'\0';
VXIMapSetProperty(streamInfo, INET_INFO_HTTP_STATUS,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -