📄 sbinetchannel.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
#ifndef _SB_USE_STD_NAMESPACE
#define _SB_USE_STD_NAMESPACE
#endif
#define SBINET_EXPORTS
#include "vxi/VXItypes.h"
#include "vxi/VXIvalue.h"
#include "vxi/VXIinet.h"
#include "vxi/VXItrd.h"
#include "vxi/VXIlog.h"
#include <vxi/SBinet.h>
#include "SBinetLog.h"
#include "SBinetHttpCacheStream.hpp"
#include "SBinetTimedStream.hpp"
#include "SBinetFileStream.hpp"
#include "SBinetChannel.h"
#include "SBinetURL.h"
#include "SBinetCookie.h"
#include "SBinetProxyMatcher.hpp"
#include "SBinetUtils.hpp"
#include "SBinetHttpConnection.hpp"
#include "SBinetSSLsocket.hpp"
#include <vxi/SWIList.hpp>
#include <vxi/SWIinputStream.hpp>
#include <vxi/SWIoutputStream.hpp>
#include <vxi/SWIdataOutputStream.hpp>
#include <vxi/SWIipAddress.hpp>
/*****************************************************************************
*****************************************************************************
* SBinetChannel Implementation
*****************************************************************************
*****************************************************************************
*/
#if defined(_MSC_VER)
#pragma warning(disable:4061)
#endif
//Static data members
VXItrdMutex *SBinetChannel::_extensionRulesMutex = NULL;
VXIMap *SBinetChannel::_extensionRules = NULL;
SBinetNString *SBinetChannel::_userAgent = NULL;
double SBinetChannel::_freshnessFraction = SBINET_FRESHNESS_FRACTION_DEFAULT;
time_t SBinetChannel::_freshnessLifetime = (time_t) SBINET_FRESHNESS_LIFETIME_DEFAULT;
time_t SBinetChannel::_maxLifetime = (time_t) SBINET_MAX_LIFETIME_DEFAULT;
VXIint32 SBinetChannel::_pageLoadTimeout = SBINET_PAGE_LOADING_TIMEOUT_DEFAULT;
VXIint32 SBinetChannel::_postContinueTimeout = SBINET_POST_CONTINUE_TIMEOUT_DEFAULT;
SWIList SBinetChannel::_proxyMatcherList;
bool SBinetChannel::_usePersistentConnections = true;
SBinetString *SBinetChannel::_defaultMimeType = NULL;
SBinetChannel::SBinetChannel( VXIlogInterface* pVXILog,
VXIunsigned diagLogBase,
VXIcacheInterface *pVXIcache):
SWIutilLogger(MODULE_SBINET, pVXILog, diagLogBase), _cookieList(),
_jarChanged(true), _cookiesEnabled(false),
_connectionCount(0), _pVXILog(pVXILog), _pVXICache(pVXIcache),
_echoStream(NULL)
{
Diag (MODULE_SBINET_CHANNEL_TAGID, L"SBinetChannel::SBinetChannel",
L"0x%p", pVXILog);
// Init interface
VXIinetInterface::GetVersion = SBinetChannel::GetVersion;
VXIinetInterface::GetImplementationName =
SBinetChannel::GetImplementationName;
VXIinetInterface::Prefetch = staticPrefetch;
VXIinetInterface::Open = staticOpen;
VXIinetInterface::Read = staticRead;
VXIinetInterface::Write = staticWrite;
VXIinetInterface::Close = staticClose;
VXIinetInterface::SetCookieJar = staticSetCookieJar;
VXIinetInterface::GetCookieJar = staticGetCookieJar;
if ((DiagIsEnabled(MODULE_SBINET_DUMP_HTTP_MSGS)) &&
(LOG_CONTENT_METHODS_SUPPORTED(_pVXILog)))
{
VXIString *logKey = NULL, *logValue = NULL;
if (_pVXILog->ContentOpen(_pVXILog, MODULE_SBINET, VXI_MIME_TEXT, &logKey,
&logValue, &_echoStream) ==
VXIlog_RESULT_SUCCESS)
{
Diag(MODULE_SBINET_DUMP_HTTP_MSGS, NULL,
L"Dumping HTTP messages, %s=%s", VXIStringCStr(logKey),
VXIStringCStr(logValue));
VXIStringDestroy(&logKey);
VXIStringDestroy(&logValue);
}
}
}
SBinetChannel::~SBinetChannel( )
{
Diag (MODULE_SBINET_CHANNEL_TAGID, L"SBinetChannel::~SBinetChannel", NULL);
closeHttpConnections();
closeAllStreams();
deleteAllCookies();
if (_echoStream)
{
_pVXILog->ContentClose(_pVXILog, &_echoStream);
}
// NOP // // NOP // // NOP //
}
/*
* Prefetch: For now punt, eventually spawn thread to call Open() into /dev/null
*/
VXIinetResult
SBinetChannel::prefetch(const VXIchar* pszModuleName,
const VXIchar* pszName,
VXIinetOpenMode eMode,
VXIint32 nFlags,
const VXIMap* pProperties )
{
#if 0 // NOT YET IMPLEMENTED
/*
* Add prefetch request to prefetch queue. These requests are
* processed when the fetch engine is idle, and the fetched
* documents are stored in the Inet cache until retrieved by
* a subsequent Open call. Note that in order for prefetching
* to work, caching must be enabled, the fetched document must
* be cachable (server must not return a 'no-cache' directive)
* and the caching mode must not be SAFE.
*/
Diag( MODULE_SBINET_CHANNEL_TAGID, L"SBinetChannel::Prefetch",
L"(%s)", pszName );
#endif
return VXIinet_RESULT_SUCCESS;
}
VXIinetResult
SBinetChannel::closeAllStreams()
{
// should interate over open stream and close gracefully
return(VXIinet_RESULT_SUCCESS);
}
static VXIinetResult parseURL(const VXIchar *pszName,
const VXIMap *properties,
SWIutilLogger *logger,
SBinetURL *& url)
{
const VXIchar *pszUrlBase = SBinetUtils::getString(properties,
INET_URL_BASE);
VXIinetResult rc = SBinetURL::create(pszName,pszUrlBase,url);
if (rc == VXIinet_RESULT_OUT_OF_MEMORY)
{
logger->Error(103, NULL);
}
else if (rc != VXIinet_RESULT_SUCCESS)
{
logger->Error(200, L"%s%s%s%s", L"Operation", L"Open",
L"URL", (pszName != NULL) ? pszName : L"NULL");
}
return rc;
}
VXIinetStream* SBinetChannel::createHttpStream(SBinetURL *url,
const VXIMap *properties)
{
SBinetHttpStream::SubmitMethod method = SBinetHttpStream::GET_METHOD;
const VXIchar *methodStr = SBinetUtils::getString(properties,
INET_SUBMIT_METHOD);
if (methodStr == NULL)
methodStr = INET_SUBMIT_METHOD_DEFAULT;
if (!::wcscmp(methodStr, INET_SUBMIT_METHOD_POST))
method = SBinetHttpStream::POST_METHOD;
SBinetStoppableStream *stream = NULL;
if (method == SBinetHttpStream::GET_METHOD)
{
// Get method, append the query arguments to the URL and create a cache
// stream.
const VXIMap *queryArgs =
(const VXIMap *)VXIMapGetProperty(properties, INET_URL_QUERY_ARGS);
url->appendQueryArgsToURL(queryArgs);
stream = new SBinetHttpCacheStream(url, method, this, getCache(),
GetLog(), GetDiagBase());
}
else
{
// No caching for POST operations.
stream = new SBinetHttpStream(url, method, this, GetLog(), GetDiagBase());
}
if (stream != NULL)
return new SBinetTimedStream(stream, GetLog(), GetDiagBase());
else
return NULL;
}
VXIinetResult SBinetChannel::createStream(SBinetURL *url,
const VXIMap *properties,
VXIinetStream* &stream)
{
/*
* Note: Stream now owns url and must delete on cleanup
*/
switch (url->getProtocol())
{
case SBinetURL::HTTP_PROTOCOL:
case SBinetURL::HTTPS_PROTOCOL:
stream = createHttpStream(url, properties);
break;
case SBinetURL::FILE_PROTOCOL:
stream = new SBinetFileStream(url, this, GetLog(), GetDiagBase());
break;
default:
// Can't really happen.
stream = NULL;
break;
}
if (!stream)
{
Error(103, NULL);
delete url;
return VXIinet_RESULT_OUT_OF_MEMORY;
}
return VXIinet_RESULT_SUCCESS;
}
/*
* Open: Serious work here.
* Parse URL and combine with base
* Collect properties and query args
* Call appropriate Stream constructor base on URL scheme (http or file)
* Call Open() on stream
*/
VXIinetResult
SBinetChannel::open(const VXIchar* pszModuleName,
const VXIchar* pszName,
VXIinetOpenMode eMode,
VXIint32 nFlags,
const VXIMap* pProperties,
VXIMap* pmapStreamInfo,
VXIinetStream** ppStream)
{
if (eMode != INET_MODE_READ)
return(VXIinet_RESULT_UNSUPPORTED);
if(!ppStream)
{
Error(200, L"%s%s%s%s", L"Operation", L"Open",
L"URL", (pszName != NULL) ? pszName : L"NULL");
return(VXIinet_RESULT_INVALID_ARGUMENT);
}
Diag (MODULE_SBINET_CHANNEL_TAGID, L"SBinetChannel::Open",
L"(%s)", pszName != NULL ? pszName : L"NULL");
SBinetURL *url;
VXIinetResult rc = ::parseURL(pszName, pProperties, this, url);
if (rc != VXIinet_RESULT_SUCCESS)
return rc;
rc = createStream(url, pProperties, *ppStream);
if (rc != VXIinet_RESULT_SUCCESS)
return rc;
rc = (*ppStream)->Open(nFlags, pProperties, pmapStreamInfo);
switch (rc)
{
case VXIinet_RESULT_SUCCESS:
return VXIinet_RESULT_SUCCESS;
break;
case VXIinet_RESULT_NOT_MODIFIED:
case VXIinet_RESULT_LOCAL_FILE:
// no logging to perform.
break;
case VXIinet_RESULT_FETCH_TIMEOUT:
Error(228, L"%s%s", L"URL", url->getAbsolute());
// no break: intentional
default:
Error(204, L"%s%s%s%d",
L"URL", url->getAbsolute(),
L"rc",rc);
break;
}
delete (*ppStream);
*ppStream = NULL;
return rc;
}
VXIinetResult
SBinetChannel::close(VXIinetStream** ppStream)
{
if (ppStream == NULL)
{
Error(200, L"%s%s", L"Operation", L"Close");
return(VXIinet_RESULT_INVALID_ARGUMENT);
}
VXIinetStream* st = *ppStream;
VXIinetResult err;
if(st != NULL)
{
err = st->Close();
delete st;
st = NULL;
}
else
{
Error(200, L"%s%s", L"Operation", L"Close");
err = VXIinet_RESULT_INVALID_ARGUMENT;
}
*ppStream = NULL;
return(err);
}
VXIinetResult SBinetChannel::setCookieJar( const VXIVector* pJar )
{
deleteAllCookies();
if (pJar == NULL)
{
// NULL jar means 'disable cookie usage'
_jarChanged = false;
_cookiesEnabled = false;
return VXIinet_RESULT_SUCCESS;
}
_cookiesEnabled = true; // Enable cookie usage
VXIunsigned numElements = VXIVectorLength(pJar);
for (VXIunsigned i = 0; i < numElements; i++)
{
const VXIMap *cookie_map = (const VXIMap *) VXIVectorGetElement(pJar, i);
if (cookie_map == NULL)
{
Error (212, NULL);
continue;
}
if (VXIValueGetType((const VXIValue *) cookie_map) != VALUE_MAP)
{
Error (213, L"%s%d", L"VXIValueType",
VXIValueGetType((const VXIValue *) cookie_map));
continue;
}
VXIint32 tempInt = 0;
SBinetUtils::getInteger(cookie_map, INET_COOKIE_EXPIRES, tempInt);
time_t expires = (time_t) tempInt;
// Check if the cookie is expired, if so don't add it, zero
// expiration time means the cookie is not persistent and should not be added.
if(expires < time(0))
continue;
// Get the name
const VXIchar *tempStr = SBinetUtils::getString(cookie_map, INET_COOKIE_NAME);
if (tempStr == NULL)
{
Error(106, NULL);
continue;
}
// convert to narrow string.
SBinetNString name = tempStr;
// Get the domain
tempStr = SBinetUtils::getString(cookie_map, INET_COOKIE_DOMAIN);
SBinetNString domain;
if(tempStr != NULL)
{
domain = tempStr;
}
// Get the path
tempStr = SBinetUtils::getString(cookie_map, INET_COOKIE_PATH);
SBinetNString path;
if(tempStr != NULL)
{
path = tempStr;
}
// Get the secure flag
bool secure = SBinetUtils::getInteger(cookie_map, INET_COOKIE_SECURE, tempInt) && tempInt;
// AC: Why would it be an error to have a cookie withouth the secure attribute?
// if(tempInt == NULL)
// {
// Error(200, NULL);
// continue;
// }
// Get the value
tempStr = SBinetUtils::getString(cookie_map,INET_COOKIE_VALUE);
SBinetNString value;
if(tempStr != NULL)
{
value = tempStr;
}
// Create the cookie
SBinetCookie* pSBinetCookie = new SBinetCookie(domain.c_str(), path.c_str(), name.c_str(),
value.c_str(), expires, secure);
// Add the cookie to the channel's list
if (pSBinetCookie && !addCookie(pSBinetCookie))
delete pSBinetCookie; // Could not add
}
_jarChanged = false;
return VXIinet_RESULT_SUCCESS;
}
VXIinetResult SBinetChannel::getCookieJar( VXIVector** ppJar,
VXIbool* ppfChanged )
{
time_t now = time(NULL);
if (ppJar == NULL)
{
Error(200, L"%s%s", L"Operation", L"GetCookieJar");
return VXIinet_RESULT_INVALID_ARGUMENT;
}
*ppJar = VXIVectorCreate();
if(*ppJar == NULL)
{
Error(103, NULL);
return VXIinet_RESULT_OUT_OF_MEMORY;
}
// Parse the channel's cookie list
SWIList::Iterator iter(_cookieList);
while (iter.hasNext())
{
SBinetCookie *cookie = (SBinetCookie *) iter.next();
if (cookie->getExpires() < now)
continue;
VXIMap *cookie_map = VXIMapCreate();
if(cookie_map == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -