📄 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. * ***********************************************************************/ #if _MSC_VER >= 1100 // Visual C++ 5.x #pragma warning( disable : 4786 4503 ) #endif #include "VXIinet.h" #include "SBinetHttpCacheStream.hpp" #include "SBinetURL.h" #include "SBinetValidator.h" #include "SBinetChannel.h" #include "SBinetUtils.hpp" #include "SBinetString.hpp" #include "HttpUtils.hpp" 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, (VXIValue*)VXIIntegerCreate(SBinetHttpUtils::HTTP_NOT_MODIFIED));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -