📄 httpfileobj.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/****************************************************************************
* Includes
*/
#include "hlxclib/stdio.h" /* FILE */
#include "hlxclib/string.h" /* strcpy, etc. */
#include "hlxclib/sys/stat.h" /* stat, etc. */
#include "hxtypes.h" /* UINT32, BOOL, etc */
#include "hxcom.h" /* IUnknown */
#include "hxcomm.h" /* IHXCommonClassFactory */
#include "ihxpckts.h" /* IHXValues, IHXBuffers */
#include "hxbuffer.h" /* CHXBuffer */
#include "hxurl.h" /* CHXURL */
#include "chxpckts.h" /* CHXHeader */
#include "hxcache2.h" /* IHXCache2, IHXCacheObject,
IHXCacheObjectResponse */
#include "httpfilesys.h" /* FILE_SYS_PROTOCOL */
#include "httpfileobj.h" /* CHXHTTPFileObject */
#include "debug.h" /* DPRINTF */
#include "chxcache2.h" /* CHXCache2 */
#include "hxprefs.h" /* IHXPreferences */
#include "multilog.h" /* INIT_MULTILOG_GROUP_NO_COREDEBUG(...) */
#include "mlog_http.h" /* MLOG_HTTP(...) */
#ifdef _SYMBIAN
#include "symbhxdir.h" /* OS_SEPARATOE_CHAR */
#else
#include "hxdir.h"
#endif
#define D_HTTP_FO 0x1000000
// The capacity of the Cache in bytes. IMPORTANT >> See the comment for CHUNK_SIZE.
#define CACHE_CAPACITY (12 * 1024)
// The amount of data requested through the TCP socket read operation.
// IMPORTANT !!! The chunk_size should be <= (1 - THRESHOLD/100)*CACHE_CAPACITY
// Otherwise we may get into a position wherein the cache has less than
// THRESHOLD read-data but it won't ever be able to accept any new data as the
// new data buffer size (CHUNK_SIZE) will overflow the cache. Also, since
// read-data is below threshold, the cache will never discard any more data.
#define CHUNK_SIZE (2 * 1024)
// 70% -> The percentage of read data we would like the cache
// to hold. It is made high because when a request for old data can't
// be satisfied, then the whole connection has to be teared down
// everything has to be restrated. So, it's better to have this value high.
// Note that some fileformat objects start seeking from start whatever be
// the direction of the User Interface seek. In such cases, threshold doesn't
// matter.
#define THRESHOLD 70
#define DEFAULT_HTTP_PORT 80
#define DEFAULT_CALLBACK_INTERVAL 10 // ms
// A utility function which does searches for a *string* in a
// *character buffer* of size haystacksize. strnstr() wouldn't work since
// it requires both the parameters to be strings.
char* bufnstr(char *haystackBuffer, char* needleString, int haystackSize);
// CHXHTTPFileObject Class Methods
/****************************************************************************
* CHXHTTPFileObject::CHXHTTPFileObject
*
* Constructor
*/
CHXHTTPFileObject::CHXHTTPFileObject(IUnknown* pContext, IHXValues* pOptions)
: m_RefCount (0), // See header file for the
m_pContext (NULL), // purpose of these variables.
m_pOptions (NULL),
m_pClassFactory (NULL),
m_pFileResponse (NULL),
m_pRequest (NULL),
m_pCache (NULL),
m_pSocket (NULL),
m_pCHXURL (NULL),
m_ulCurrentReadOffset (0),
m_lNewReadOffset (-1),
m_bInSeekDone (FALSE),
m_bInReadDone (FALSE),
m_bReadPending (FALSE),
m_bIncompleteReadPending (FALSE),
m_ulFileLength (0),
m_pHdrListRoot (NULL),
m_bHeaderCompletelyRead (FALSE),
m_pHeader (NULL),
m_bStartAllOverAgain (FALSE),
m_pScheduler (NULL),
m_ulCallbackHandle (0),
m_ulCallBackInterval (DEFAULT_CALLBACK_INTERVAL), // 10 ms
m_bFirstChunk (TRUE),
m_bInitResponsePending (FALSE),
m_bInitialized (FALSE),
m_ulFileDataRead (0),
m_bAddBlockPending (FALSE),
m_pPendingAddBlock (NULL),
m_bDisconnected (FALSE)
{
MLOG_HTTP("CHXHTTPFileObject::CHXHTTPFileObject()\n");
m_pContext = pContext;
m_pOptions = pOptions;
// Signify that we need to keep a reference to this object
if (m_pOptions != NULL)
{
m_pOptions->AddRef();
}
if (m_pContext != NULL)
{
m_pContext->AddRef();
m_pContext->QueryInterface(IID_IHXScheduler,
(void**) &m_pScheduler);
m_pContext->QueryInterface(IID_IHXCommonClassFactory,
(void**)&m_pClassFactory);
}
} // CHXHTTPFileObject()
/****************************************************************************
* CHXHTTPFileObject::~CHXHTTPFileObject
*
* Destructor.
*/
CHXHTTPFileObject::~CHXHTTPFileObject(void)
{
MLOG_HTTP("CHXHTTPFileObject::~CHXHTTPFileObject()\n");
_CleanUp();
} // ~CHXHTTPFileObject()
/****************************************************************************
* IHXFileObject::_CleanUp()
*
* Cleans up the object by relesing all member objects. This is a helper
* function used by the Close() and the destructor.
*
*/
STDMETHODIMP
CHXHTTPFileObject::_CleanUp(void)
{
MLOG_HTTP("CHXHTTPFileObject::_CleanUp()\n");
m_bAddBlockPending = FALSE;
HX_RELEASE(m_pPendingAddBlock);
if (m_ulCallbackHandle)
{
m_pScheduler->Remove(m_ulCallbackHandle);
m_ulCallbackHandle = 0;
}
m_bInitialized = FALSE;
HX_RELEASE(m_pContext);
HX_RELEASE(m_pOptions);
HX_RELEASE(m_pClassFactory);
HX_RELEASE(m_pFileResponse);
HX_RELEASE(m_pRequest);
HX_RELEASE(m_pCache);
HX_RELEASE(m_pSocket);
HX_DELETE(m_pCHXURL);
HX_RELEASE(m_pPendingReadInfo.pPendingReadBuff);
HX_RELEASE(m_pHeader);
HX_RELEASE(m_pScheduler);
HX_RELEASE(m_pPendingAddBlock);
return HXR_OK;
} // _CleanUp()
// IHXFileObject Interface Methods
/****************************************************************************
* IHXFileObject::Init
*
* This routine associates this File Object with a File Response object
* which is notified when file operations (read, write, seek, etc.) are
* complete. This method also checks the validity of the file by actually
* opening it.
*/
STDMETHODIMP
CHXHTTPFileObject::Init(UINT32 fileAccessMode, // We ignore access mode here
IHXFileResponse* pFileResponse)
{
MLOG_HTTP("CHXHTTPFileObject::Init()\n");
HX_RESULT res = HXR_OK;
if (pFileResponse != NULL)
{
// Release any previous File Response objects
if (m_pFileResponse != NULL)
{
m_pFileResponse->Release();
}
m_pFileResponse = pFileResponse;
m_pFileResponse->AddRef();
}
else
{
return HXR_INVALID_PARAMETER;
}
if(m_bInitialized) // Init() was previously called atleast once
{
// There is no point continuing with a pending read as
// the caller has changed.
m_bReadPending = FALSE;
m_bIncompleteReadPending = FALSE;
HX_RELEASE(m_pPendingReadInfo.pPendingReadBuff);
/* If we have already opened a file, then seek back
* to zero during re-initialization
*/
m_ulCurrentReadOffset = 0;
m_pFileResponse->InitDone(HXR_OK);
return HXR_OK;
}
m_pPendingReadInfo.pPendingReadBuff = NULL;
// Else, this is the first time Init() is being called
if(m_pCHXURL == NULL) // Init() being called before calling SetRequest()
{
return HXR_INVALID_OPERATION;
}
/*
* We have to check the validity of the file. What we do is we
* contact the HTTP server and request for the HTTP file header.
* This lets us do two things:
* (1) It lets us know if the file really exists on the server.
* (2) If file exists, the response contains the stats of the file.
*/
res = _Start(); // Commence the action - connect to server, send GET req, etc
return res;
} // Init()
// Assumes the state of the network related state variables is
// as it would be if this method is called for the first time
// (for eg., from the constructor). So, m_pSocket, etc should all
// be NULL
STDMETHODIMP
CHXHTTPFileObject::_Start()
{
MLOG_HTTP("CHXHTTPFileObject::_Start()\n");
IHXNetworkServices* pNetworkServices = NULL;
if (HXR_OK != m_pContext->QueryInterface( IID_IHXNetworkServices,
(void **)&pNetworkServices))
{
return HXR_FAIL;
}
HX_RESULT res = HXR_OK;
res = pNetworkServices->CreateTCPSocket(&m_pSocket);
pNetworkServices->Release();
if( (res != HXR_OK) || (m_pSocket == NULL) )
{
return HXR_FAIL;
}
// Identify yourself as the object to whom the results of all
// socket related operations should be reported.
res = m_pSocket->Init( (IHXTCPResponse *)this );
if( ( res != HXR_OK) || (m_pCHXURL == NULL) )
{
HX_RELEASE(m_pSocket);
return HXR_FAIL;
}
// Parse the URL to get server address and port
IHXValues* pHeader = m_pCHXURL->GetProperties();
IHXBuffer* pBuffer = NULL;
char *serverAddress = NULL;
pHeader->GetPropertyBuffer(PROPERTY_HOST, pBuffer);
if(pBuffer != NULL)
{
serverAddress = (char*)(pBuffer->GetBuffer());
}
ULONG32 serverPort = 0;
pHeader->GetPropertyULONG32(PROPERTY_PORT, serverPort);
// Connect to the HTTP server
res = m_pSocket->Connect(serverAddress, (UINT16)serverPort);
if(res != HXR_OK)
{
HX_RELEASE(m_pSocket);
return HXR_FAIL;
}
return HXR_OK;
} // _Start()
/****************************************************************************
* IHXFileObject::GetFilename
*
* This routine returns the name of the requested file (without any path
* information). This method may be called by the File Format plug-in if the
* short name of the file is required.
*/
STDMETHODIMP
CHXHTTPFileObject::GetFilename(REF(const char*) pFileName)
{
MLOG_HTTP("CHXHTTPFileObject::GetFilename()\n");
pFileName = NULL;
HX_RESULT res = HXR_OK;
// From the File path, extract the file name and return it.
if(m_pCHXURL != NULL)
{
IHXBuffer* pBuffer = NULL;
IHXValues* pHeader = m_pCHXURL->GetProperties();
pHeader->GetPropertyBuffer(PROPERTY_RESOURCE, pBuffer);
if(pBuffer != NULL)
{
pFileName = (char*)(pBuffer->GetBuffer());
}
}
else
{
res = HXR_FAIL;
}
return res;
}
/****************************************************************************
* IHXFileObject::Read
*
* This routine reads a block of data of the specified length from the file.
* When reading has completed, the caller is asynchronously notified via the
* File Response object associated with this File Object. This method is
* called by the File Format plug-in when it needs to read from the file.
*/
STDMETHODIMP
CHXHTTPFileObject::Read(UINT32 byteCount)
{
MLOG_HTTP("CHXHTTPFileObject::Read(%u)\n", byteCount);
// The whole file has already been read
if(m_ulCurrentReadOffset == m_ulFileLength)
{
HX_RESULT res = HXR_FAIL;
if (m_pFileResponse)
{
m_pFileResponse->ReadDone(HXR_FAIL, 0);
res = HXR_OK;
}
return res;
}
// Can't have a read when a previous read is outstanding
if(m_bReadPending)
{
return HXR_INVALID_OPERATION;
}
m_bIncompleteReadPending = FALSE;
// Can't read more than the (remaining) file length
int actualLen = m_ulFileLength - m_ulCurrentReadOffset;
if(actualLen > byteCount)
actualLen = byteCount;
m_bReadPending = TRUE;
m_pPendingReadInfo.pPendingReadBuff = NULL;
m_pPendingReadInfo.ulWriteOffset = 0;
m_pPendingReadInfo.ulReadOffset = m_ulCurrentReadOffset;
m_pPendingReadInfo.ulSize = (UINT32)actualLen;
HX_RESULT r = m_pCache->ReadBlock(m_ulCurrentReadOffset, (UINT32)actualLen);
return r;
} // Read()
/****************************************************************************
* IHXFileObject::Write
*
* This routine writes a block of data to the file. When writing has
* completed, the caller is asynchronously notified via the File Response
* object associated with this File Object. This method called by the File
* Format plug-in when it needs to write to the file.
*/
STDMETHODIMP
CHXHTTPFileObject::Write(IHXBuffer* pDataToWrite)
{
MLOG_HTTP("CHXHTTPFileObject::Write()\n");
return HXR_NOTIMPL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -