httpfileobj.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:54k
- /* ***** 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;
- }
- /****************************************************************************
- * IHXFileObject::Seek
- *
- * This routine moves to a given position in the file. The move can be
- * either from the beginning of the file (absolute), or relative to the
- * current file position. When seeking 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 seek to a location within the file.
- */
- STDMETHODIMP
- CHXHTTPFileObject::Seek(UINT32 offset, BOOL bIsRelative)
- {
- const char *seekType = NULL;
- seekType = (bIsRelative == TRUE)? "REL": "ABS";
- MLOG_HTTP("CHXHTTPFileObject::Seek(%u, %s)n", offset, seekType);
- m_lNewReadOffset = offset;
- if(bIsRelative)
- {
- m_lNewReadOffset += m_ulCurrentReadOffset;
- }
- // Can't seek to outside the file
- if( (m_lNewReadOffset < 0) || (m_lNewReadOffset > m_ulFileLength) )
- {
- m_lNewReadOffset = -1;
- return HXR_FAIL;
- }
- if(!m_bInSeekDone)
- {
- while(m_lNewReadOffset >= 0)
- {
- // Cancel any pending reads
- m_bReadPending = FALSE;
- m_bIncompleteReadPending = FALSE;
- HX_RELEASE(m_pPendingReadInfo.pPendingReadBuff);
- m_ulCurrentReadOffset = m_lNewReadOffset;
- m_lNewReadOffset = -1;
- m_bInSeekDone = TRUE;
- if (m_pFileResponse)
- {
- m_pFileResponse->SeekDone(HXR_OK);
- }
- m_bInSeekDone = FALSE;
- }
- }
- return HXR_OK;
- }
- /****************************************************************************
- * IHXFileObject::Advise
- *
- * This routine is passed information about the intended usage of this
- * object. The useage will indicate whether sequential or random requests
- * for information will be made. This may be useful, for example, in
- * developing a caching scheme.
- */
- STDMETHODIMP
- CHXHTTPFileObject::Advise(UINT32 usage)
- {
- MLOG_HTTP("CHXHTTPFileObject::Advice(%u)n", usage);
- HX_RESULT res = HXR_FAILED;
- // Because of the simple cache, only
- // linear useage is allowed.
- if(HX_FILEADVISE_RANDOMACCESS == usage)
- {
- res = HXR_ADVISE_PREFER_LINEAR;
- }
- return res;
- } // Advise()
- /****************************************************************************
- * IHXFileObject::Close
- *
- * This routine closes the file resource and releases all resources
- * associated with the object. This routine is crucial and must be called
- * before the File Object is destroyed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::Close(void)
- {
- MLOG_HTTP("CHXHTTPFileObject::Close()n");
- /*
- * Store this in temp since calling _CleanUp()
- * causes m_pFileResponse to get released. We will
- * have pCallCloseDone on the stack to call
- * CloseDone() and then to safely release.
- */
- IHXFileResponse* pCallCloseDone = m_pFileResponse;
- if(pCallCloseDone)
- pCallCloseDone->AddRef();
- HX_RELEASE(m_pFileResponse);
- if(pCallCloseDone)
- {
- pCallCloseDone->CloseDone(HXR_OK);
- pCallCloseDone->Release();
- }
-
- return HXR_OK;
- } // Close()
- // IHXRequestHandler Interface Methods
- /****************************************************************************
- * IHXRequestHandler::SetRequest
- *
- * This routine associates this File Object with the file Request object
- * passed to it from the Helix core. This Request object is primarily used to
- * obtain the requested URL. This method is called just after the File
- * Object is created.
- */
- STDMETHODIMP
- CHXHTTPFileObject::SetRequest(IHXRequest* pRequest)
- {
- MLOG_HTTP("CHXHTTPFileObject::SetRequest()n");
- HX_RESULT res = HXR_OK;
- if(pRequest == NULL)
- {
- res = HXR_INVALID_PARAMETER;
- }
- else
- {
- // Release any previous request object, URL
- HX_RELEASE(m_pRequest);
- if(m_pCHXURL != NULL)
- {
- delete m_pCHXURL;
- m_pCHXURL = NULL;
- }
- // Store a reference to the object
- m_pRequest = pRequest;
- m_pRequest->AddRef();
- const char *pURL = NULL;
- if(m_pRequest->GetURL(pURL) != HXR_OK)
- {
- HX_RELEASE(m_pRequest);
- return HXR_FAIL;
- }
- // Store the URL in a CHXURL object for parsing.
- m_pCHXURL = new CHXURL(pURL);
- if(m_pCHXURL == NULL)
- {
- HX_RELEASE(m_pRequest);
- return HXR_FAIL;
- //return HXR_OUTOFMEMORY;
- }
- }
- return res;
- } // SetRequest()
- /****************************************************************************
- * IHXRequestHandler::GetRequest
- *
- * This routine retrieves the Request object associated with this File
- * Object. It is called just after the SetRequest() method.
- */
- STDMETHODIMP
- CHXHTTPFileObject::GetRequest(REF(IHXRequest*) pRequest)
- {
- MLOG_HTTP("CHXHTTPFileObject::GetRequest()n");
- pRequest = m_pRequest;
- if (pRequest != NULL)
- {
- pRequest->AddRef();
- }
- return HXR_OK;
- }
- // IUnknown COM Interface Methods
- /****************************************************************************
- * IUnknown::AddRef
- *
- * This routine increases the object reference count in a thread safe
- * manner. The reference count is used to manage the lifetime of an object.
- * This method must be explicitly called by the user whenever a new
- * reference to an object is used.
- */
- STDMETHODIMP_(UINT32) CHXHTTPFileObject::AddRef(void)
- {
- MLOG_HTTP("CHXHTTPFileObject::AddRef()n");
- return InterlockedIncrement(&m_RefCount);
- }
- /****************************************************************************
- * IUnknown::Release
- *
- * This routine decreases the object reference count in a thread safe
- * manner, and deletes the object if no more references to it exist. It must
- * be called explicitly by the user whenever an object is no longer needed.
- */
- STDMETHODIMP_(UINT32) CHXHTTPFileObject::Release(void)
- {
- MLOG_HTTP("CHXHTTPFileObject::Release()n");
- if (InterlockedDecrement(&m_RefCount) > 0)
- {
- return m_RefCount;
- }
- delete this;
- return 0;
- }
- /****************************************************************************
- * IUnknown::QueryInterface
- *
- * This routine indicates which interfaces this object supports. If a given
- * interface is supported, the object's reference count is incremented, and
- * a reference to that interface is returned. Otherwise a NULL object and
- * error code are returned. This method is called by other objects to
- * discover the functionality of this object.
- */
- STDMETHODIMP CHXHTTPFileObject::QueryInterface(REFIID interfaceID,
- void** ppInterfaceObj)
- {
- MLOG_HTTP("CHXHTTPFileObject::QueryInterface()n");
- // Initially assume no interfaces are supported
- HX_RESULT res = HXR_NOINTERFACE;
- *ppInterfaceObj = NULL;
- // By definition all COM objects support the IUnknown interface
- if (IsEqualIID(interfaceID, IID_IUnknown))
- {
- *ppInterfaceObj = (IUnknown*)(IHXFileObject*)this;
- }
- // IHXFileObject interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXFileObject))
- {
- *ppInterfaceObj = (IHXFileObject*)this;
- }
- // IHXRequestHandler interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXRequestHandler))
- {
- *ppInterfaceObj = (IHXRequestHandler*)this;
- }
- // IHXFileStat interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXFileStat))
- {
- *ppInterfaceObj = (IHXFileStat*)this;
- }
- // IHXCacheObjectResponse interface is supported
- else if(IsEqualIID(interfaceID, IID_IHXCacheObjectResponse))
- {
- *ppInterfaceObj = (IHXCacheObjectResponse*)this;
- }
- // IHXTCPResponse interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXTCPResponse))
- {
- *ppInterfaceObj = (IHXTCPResponse*)this;
- }
- // IHXCallback interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXCallback))
- {
- *ppInterfaceObj = (IHXCallback*)this;
- }
- if (*ppInterfaceObj)
- {
- AddRef();
- res = HXR_OK;
- }
- return res;
- }
- /************************************************************************
- * Method:
- * IHXFileStat::Stat
- * Purpose:
- * Collects information about the file that is returned to the
- * caller in an IHXStat object
- */
- STDMETHODIMP
- CHXHTTPFileObject::Stat(IHXFileStatResponse* pFileStatResponse)
- {
- MLOG_HTTP("CHXHTTPFileObject::Stat()n");
- if(pFileStatResponse == NULL)
- {
- return HXR_INVALID_PARAMETER;
- }
- // It shouldn't call this function before it gets a InitDone() (by which time
- // header would have been completely read).
- // >>> Later, give proper values for last four parameters too...
- if(m_ulFileLength > 0)
- {
- pFileStatResponse->StatDone(HXR_OK, m_ulFileLength, 0, 0, 0, HX_S_IFREG);
- }
- else
- {
- return HXR_FAIL;
- }
- return HXR_OK;
- }
- /*
- * IHXCacheObjectResponse methods
- */
- /************************************************************************
- * Method:
- *
- * IHXCacheObjectResponse::InitDone
- *
- * Purpose:
- *
- * Notification that IHXCacheObject::Init call has completed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::InitDone(HX_RESULT /*IN*/ status)
- {
- MLOG_HTTP("CHXHTTPFileObject::InitDone(%s)n", StrRep(status));
- return HXR_OK;
- } // InitDone()
- /************************************************************************
- * Method:
- *
- * IHXCacheObjectResponse::ChangeCapacityDone
- *
- * Purpose:
- *
- * Notification that IHXCacheObject::ChangeCapacity call has completed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::ChangeCapacityDone(HX_RESULT /*IN*/ status)
- {
- MLOG_HTTP("CHXHTTPFileObject::ChangeCapacityDone(%s)n", StrRep(status));
- return HXR_NOTIMPL;
- } // ChangeCapacityDone()
- /************************************************************************
- * Method:
- *
- * IHXCacheObjectResponse::AddBlockDone
- *
- * Purpose:
- *
- * Notification that IHXCacheObject::AddBlock operation has completed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::AddBlockDone(HX_RESULT /*IN*/ status)
- {
- MLOG_HTTP("CHXHTTPFileObject::AddBlockDone(%s)n", StrRep(status));
- // Can the Cache accomodate more data that might arrive
- // should we request the network for some.
- UINT32 uReadSize = m_ulFileLength - m_ulFileDataRead;
- if(uReadSize > CHUNK_SIZE)
- uReadSize = CHUNK_SIZE;
- if(status == HXR_OUTOFMEMORY)
- {
- // Try to add this block again when you read
- // something of the cache (i.e., in ReadBlockDone()
- m_bAddBlockPending = TRUE;
- }
- else
- {
- HX_RELEASE(m_pPendingAddBlock);
- // Ask the network services to get more data.
- m_pSocket->Read((UINT16)uReadSize);
- }
- return HXR_OK;
- } // AddBlockDone()
- /************************************************************************
- * Method:
- *
- * IHXCacheObjectResponse::VerifyBlockDone
- *
- * Purpose:
- *
- * Notification that IHXCacheObject::VerifyBlock operation has
- * completed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::VerifyBlockDone(BOOL /*IN*/ bExist)
- {
- MLOG_HTTP("CHXHTTPFileObject::VerifyBlockDone(%d)n", bExist);
- return HXR_NOTIMPL;
- } // VerifyBlockDone()
- /************************************************************************
- * Method:
- *
- * IHXCacheObjectResponse::ReadBlockDone
- *
- * Purpose:
- *
- * Notification that IHXCacheObject::ReadBlock operation has
- * completed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::ReadBlockDone(HX_RESULT /*IN*/ status,
- IHXBuffer* /*IN*/ pBuffer)
- {
- MLOG_HTTP("CHXHTTPFileObject::ReadBlockDone(%s)n", StrRep(status));
- // If the cache has failed to give us anydata and it will not do
- // so in the future and at the same time we notice that the server
- // has disconnected, then raise alarm. Note that we need to check
- // for all these conditions because if the server disconnected after
- // serving all data and if it is stored in the cache, then we shouldn't
- // be worried.
- if(
- (status == HXR_INCOMPLETE) && (pBuffer == NULL) &&
- (m_bDisconnected == TRUE) && (m_pCache->IsEmpty())
- )
- {
- if (m_pFileResponse)
- {
- m_pFileResponse->ReadDone(HXR_SERVER_DISCONNECTED, NULL);
- }
- return HXR_OK;
- }
- if(pBuffer != NULL)
- pBuffer->AddRef();
- HX_RESULT res = HXR_OK;
- // This is a response to a ReadBlock() called from Func(). Func() does this
- // only when there is an incomplete Read.
- if(m_bIncompleteReadPending)
- {
- if( ((status == HXR_OK) || (status == HXR_INCOMPLETE)) && (pBuffer != NULL) )
- {
- // Copy data into the buffer set aside for the incomplete read.
- memcpy((void*)(m_pPendingReadInfo.pPendingReadBuff->GetBuffer() + m_pPendingReadInfo.ulWriteOffset),
- (void*)(pBuffer->GetBuffer()), pBuffer->GetSize());
- // Update offsets and sizes for the next read installment
- m_pPendingReadInfo.ulWriteOffset += pBuffer->GetSize(); // Next installment buffer-write offset
- m_pPendingReadInfo.ulReadOffset += pBuffer->GetSize(); // Next installment cache-read offset
- m_pPendingReadInfo.ulSize -= pBuffer->GetSize(); // Next installment max-size
- }
- if(HXR_OK == status)
- {
- // This installment finally fills up the incomplete read buffer.
- m_ulCurrentReadOffset = m_pPendingReadInfo.ulReadOffset;
- m_bIncompleteReadPending = FALSE;
- m_bReadPending = FALSE;
- // Get a handle since there is a possibilily of m_pPendingReadInfo
- // being modified in some method called from ReadDone().
- IHXBuffer* pBuff = m_pPendingReadInfo.pPendingReadBuff;
- m_pPendingReadInfo.pPendingReadBuff = NULL;
- if (m_pFileResponse)
- {
- m_pFileResponse->ReadDone(HXR_OK, pBuff);
- }
- HX_RELEASE(pBuff);
- pBuff = NULL;
- }
- else if(status == HXR_INCOMPLETE) // Need to get more installments to fill up ReadBuffer
- {
- m_ulCallbackHandle = m_pScheduler->RelativeEnter(this, m_ulCallBackInterval);
- }
- else
- {
- // Can't happen
- }
- }
- else // !m_bIncompleteReadPending
- {
- if(status == HXR_OK) // Cool, hand data over to the FF object
- {
- m_ulCurrentReadOffset = m_pPendingReadInfo.ulReadOffset + m_pPendingReadInfo.ulSize;
- m_bReadPending = FALSE;
- if (m_pFileResponse)
- {
- m_pFileResponse->ReadDone(HXR_OK, pBuffer);
- }
- }
- // This means that the Cache has only partial data. Create a buffer to store this partial data.
- // Mark this read as incomplete and try to read from the cache in installments.
- // Request scheduler to signal you after some time. When the scheduler signals
- // you (via Func()), check to see if Cache has recieved anymore data.
- else if(status == HXR_INCOMPLETE)
- {
- if(m_pClassFactory != NULL)
- {
- // Create a buffer to fill it in installments.
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&m_pPendingReadInfo.pPendingReadBuff);
- if (m_pPendingReadInfo.pPendingReadBuff != NULL)
- {
- res = m_pPendingReadInfo.pPendingReadBuff->SetSize(m_pPendingReadInfo.ulSize);
- if(HXR_OK == res)
- {
- if(pBuffer != NULL)
- {
- // Copy the partial data into the pending read buffer.
- memcpy((void*)(m_pPendingReadInfo.pPendingReadBuff->GetBuffer()),
- (void*)(pBuffer->GetBuffer()), pBuffer->GetSize());
- m_pPendingReadInfo.ulWriteOffset = pBuffer->GetSize(); // Next installment buffer-write offset
- m_pPendingReadInfo.ulReadOffset += pBuffer->GetSize(); // Next installment cache-read offset
- m_pPendingReadInfo.ulSize -= pBuffer->GetSize(); // Next installment max-size
- }
- }
- else
- {
- HX_RELEASE(m_pPendingReadInfo.pPendingReadBuff);
- res = HXR_OUTOFMEMORY;
- }
- }
- else
- {
- res = HXR_OUTOFMEMORY;
- }
- }
- else
- {
- res = HXR_UNEXPECTED;
- }
- // Not enough memory to create buffers.
- // Let's do the best we can do! Return the incomplete data.
- if(HXR_OK != res)
- {
- m_bReadPending = FALSE;
- m_ulCurrentReadOffset = m_pPendingReadInfo.ulReadOffset;
- if (m_pFileResponse)
- {
- m_pFileResponse->ReadDone(HXR_INCOMPLETE, pBuffer);
- }
- }
- else
- {
- // We will try to fill the remaining data in the buffer after waiting for some
- // time. We ask the scheduler to call us back after some time and then we check if the
- // Cache has recieved any new data.
- m_bIncompleteReadPending = TRUE;
- m_ulCallbackHandle = m_pScheduler->RelativeEnter(this, m_ulCallBackInterval);
- }
- }
- // status = HXR_FAIL, i.e, the Cache had discarded some part of the data
- // we requeted. The cache has already discarded the data and so there is no hope
- // of getting that data. The only way to satisfy the Read request
- // is to tear down the connection and start-all-over-again.
- else //status = HXR_FAIL and the reason is request for past data
- {
- // Set this flag so that other activities are all paralysed
- m_bStartAllOverAgain = TRUE;
- m_bAddBlockPending = FALSE;
- HX_RELEASE(m_pPendingAddBlock);
- m_pPendingAddBlock = NULL;
- // Close the socket
- HX_RELEASE(m_pSocket);
- m_bIncompleteReadPending = TRUE;
- if(m_pClassFactory != NULL)
- {
- // Create a buffer and fill it in installments.
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&m_pPendingReadInfo.pPendingReadBuff);
- m_pPendingReadInfo.pPendingReadBuff->SetSize(m_pPendingReadInfo.ulSize);
- }
- // Flush the cache so that we can freshly start
- // storing the new info into it.
- m_pCache->Flush();
- // Rest of the the "start-all-over-again" continues in FlushDone()
- }
- } // !m_bIncompleteReadPending
- if(m_bAddBlockPending)
- {
- // Now that we have read some data out of cache, maybe the cache would accept
- // the previously rejected data.
- if( (pBuffer != NULL) && (pBuffer->GetSize() > 0) )
- {
- if(m_pCache->GetUnusedCapacity() >= m_pPendingAddBlock->GetSize())
- {
- m_ulCallbackHandle = m_pScheduler->RelativeEnter(this, 0);
- }
- }
- }
- HX_RELEASE(pBuffer);
- pBuffer = NULL;
- return HXR_OK;
- } // ReadBlockDone()
- /************************************************************************
- * Method:
- *
- * IHXCacheObjectResponse::FlushDone
- *
- * Purpose:
- *
- * Notification that IHXCacheObject::Flush operation has completed.
- */
- STDMETHODIMP
- CHXHTTPFileObject::FlushDone(HX_RESULT /*IN*/ status)
- {
- MLOG_HTTP("CHXHTTPFileObject::FlushDone(%s)n", StrRep(status));
- // Discard the old header so that the incoming new
- // hdr is not confused for data.
- HX_RELEASE(m_pHeader);
- m_pHeader = NULL;
- m_bHeaderCompletelyRead = FALSE;
- m_ulFileDataRead = 0;
- m_bFirstChunk = TRUE; // The TCP chunk that will be recived later
- // will be the first one from the new connection.
- m_bStartAllOverAgain = FALSE;
- // Start the whole process (viz., connecting, GET request, etc) all over again.
- _Start();
- return HXR_OK;
- } // FlushDone()
- /*
- * IHXTCPResponse methods
- */
- /************************************************************************
- * Method:
- * IHXTCPResponse::ConnectDone
- * Purpose:
- * A Connect operation has been completed or an error has occurred.
- */
- STDMETHODIMP
- CHXHTTPFileObject::ConnectDone(HX_RESULT status)
- {
- MLOG_HTTP("CHXHTTPFileObject::ConnectDone(%s)n", StrRep(status));
- if(status != HXR_OK)
- {
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(status);
- }
- return HXR_OK;
- }
- // OK, the connection has been established. Now send a GET request to
- // start getting the file.
- char* HttpGetReq = NULL;
- UINT32 ulReqLen = 0;
- HX_RESULT res = HXR_OK;
- res = _PrepareHTTP10GetMessage(HttpGetReq, ulReqLen);
- if(res != HXR_OK)
- {
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_OUTOFMEMORY);
- }
- return HXR_OK;
- }
- CHXBuffer* pSendBuffer = new CHXBuffer((UCHAR*)HttpGetReq, ulReqLen);
- if(pSendBuffer == NULL)
- {
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_OUTOFMEMORY);
- }
- return HXR_OK;
- }
- pSendBuffer->AddRef();
- // Now write the HTTP/1.0 GET request into the socket
- res = m_pSocket->Write( (IHXBuffer *)pSendBuffer );
- // Ask for the response
- res = m_pSocket->Read((UINT16)CHUNK_SIZE);
- HX_RELEASE(pSendBuffer);
- return res;
- } // ConnectDone()
- /************************************************************************
- * Method:
- * IHXTCPResponse::ReadDone
- * Purpose:
- * A Read operation has been completed or an error has occurred.
- * The data is returned in the IHXBuffer.
- */
- STDMETHODIMP
- CHXHTTPFileObject::ReadDone(HX_RESULT status,
- IHXBuffer* pBuffer)
- {
- MLOG_HTTP("CHXHTTPFileObject::ReadDone(%s)n", StrRep(status));
- if(pBuffer != NULL)
- pBuffer->AddRef();
- // A backward seek had failed. Which means the Cache is going
- // to be flushed, connection tore down and everythings going to
- // start all over again. So, no point storing this in the cache.
- if(m_bStartAllOverAgain)
- {
- HX_RELEASE(pBuffer);
- return HXR_OK;
- }
- if(!m_bHeaderCompletelyRead) // The TCP data we recvd is a chunk of HTTP header
- {
- if( (status != HXR_OK) || (pBuffer == NULL) )
- {
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_FAIL);
- }
- return HXR_OK;
- }
- // Check if response indicates success
- if(m_bFirstChunk) // If it is the first chunk from the server
- {
- m_bFirstChunk = FALSE;
- const char pSuccess[] = "200 OKrn"; // HTTP success code
- // Is the starting line "HTTP/1.x 200 OKrn" ?
- if( memcmp((void*)(pBuffer->GetBuffer() + 9), (void*)pSuccess, strlen(pSuccess)) != 0 )
- {
- if(!m_bInitialized)
- {
- m_bFirstChunk = TRUE;
- // The requested file is not present on the web server
- if (m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_DOC_MISSING);
- }
- }
- return HXR_OK;
- }
- }
- // Append this header chunk to the list of such chunks being maintained.
- HdrChunk *hi = new HdrChunk;
- hi->pPartOfHdr = pBuffer;
- hi->next = NULL;
- if(m_pHdrListRoot == NULL)
- {
- m_pHdrListRoot = hi;
- }
- else
- {
- HdrChunk *temp = NULL;
- for(temp = m_pHdrListRoot; temp->next != NULL; temp = temp->next);
- temp->next = hi;
- }
- // Is this the last header chunk? If so, does this chunk
- // also contain some non-header data? If true, store this
- // non-hdr data in the Cache and consolidate all the previous
- // header chunks into a single buffer. Then destroy the
- // header-chunks list.
- // Note!!!! GetBuffer() doesn't return a NULL terminated string. So,
- // shouldn't use strstr(). That's why I used my utility function bufnstr()!
- char *marker = bufnstr((char*)(hi->pPartOfHdr->GetBuffer()), "rnrn",
- hi->pPartOfHdr->GetSize());
- if(marker == NULL) // End of hdr not found in this chunk
- {
- return m_pSocket->Read((UINT16)CHUNK_SIZE); // Read more data
- }
- else
- {
- m_bHeaderCompletelyRead = TRUE;
- }
- // This chunk has the end-of-header marker.
- // Consolidate all the header chunks
- marker += 4; // Move the pointer just after the header end-marker.
- int hdrLen = 0;
- int dataLen = 0;
- char *hdr = NULL;
- char *data = NULL;
- CHXBuffer* dataBuff = NULL;
- int len = 0;
- for(HdrChunk *temp = m_pHdrListRoot; temp != hi; temp = temp->next)
- len += temp->pPartOfHdr->GetSize();
- int lastPktHdrLen = marker - (char *)(hi->pPartOfHdr->GetBuffer());
- hdrLen = len + lastPktHdrLen;
- dataLen = hi->pPartOfHdr->GetSize() - lastPktHdrLen;
- hdr = new char[hdrLen];
- data = new char[dataLen];
- if( (hdr == NULL) || (data == NULL) )
- {
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_OUTOFMEMORY);
- }
- return HXR_OK;
- }
- int i = 0;
- for(HdrChunk *temp2 = m_pHdrListRoot; temp2 != hi; temp2 = temp2->next)
- {
- int buffLen = temp2->pPartOfHdr->GetSize();
- memcpy((void*)(hdr + i), (void*)(temp2->pPartOfHdr->GetBuffer()),buffLen);
- i += buffLen;
- }
- // m_ulFileDataRead is the amount of file data that has been read
- // so far.
- m_ulFileDataRead = dataLen;
- memcpy((void*)hdr, (void*)(hi->pPartOfHdr->GetBuffer()), lastPktHdrLen);
- memcpy((void*)data, (void*)(hi->pPartOfHdr->GetBuffer() + lastPktHdrLen), dataLen);
- m_pHeader = new CHXBuffer((UCHAR*)hdr, hdrLen);
- m_pHeader->AddRef();
- dataBuff = new CHXBuffer((UCHAR*)data, dataLen);
- dataBuff->AddRef();
- if( (!m_pHeader) || (!dataBuff) )
- {
- delete hdr;
- delete data;
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_OUTOFMEMORY);
- }
- return HXR_OK;
- }
- // Destroy the header-chunks list
- HdrChunk *temp3 = m_pHdrListRoot;
- HdrChunk *temp4 = NULL;
- while(temp3 != NULL)
- {
- temp4 = temp3;
- temp3 = temp3->next;
- temp4->pPartOfHdr->Release();
- delete temp4;
- }
- m_pHdrListRoot = NULL;
- // Parse the header for file statistics
- marker = bufnstr((char*)(m_pHeader->GetBuffer()), "rnContent-Length: ",
- m_pHeader->GetSize());
- if(marker == NULL)
- {
- m_ulFileLength = 0;
- HX_RELEASE(m_pHeader);
- m_pHeader = NULL;
- HX_RELEASE(dataBuff);
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_INVALID_FILE);
- }
- return HXR_OK;
- }
- marker += 18;
- int remLen = m_pHeader->GetSize() - (marker - (char*)(m_pHeader->GetBuffer()));
- char *marker2 = bufnstr(marker, "rn", remLen);
- if(marker2 == NULL)
- {
- m_ulFileLength = 0;
- HX_RELEASE(m_pHeader);
- m_pHeader = NULL;
- HX_RELEASE(dataBuff);
- if(!m_bInitialized && m_pFileResponse)
- {
- m_pFileResponse->InitDone(HXR_INVALID_FILE);
- }
- return HXR_OK;
- }
- int l = marker2 - marker;
- char *flen = new char[l + 1];
- memcpy((void*)flen, (void*)marker, l);
- flen[l] = ' ';
- m_ulFileLength = atol(flen);
- delete flen;
- if(m_pCache == NULL)
- {
- CHXCache2 *pObj = new CHXCache2();
- pObj->AddRef();
- #ifdef HELIX_FEATURE_HTTP_FILECACHE
- BOOL bCacheEnabled = FALSE;
- char *pCacheFile = NULL;
- _GetCachePreferences(bCacheEnabled, pCacheFile);
- if(bCacheEnabled)
- {
- pObj->CreateFileCacheObject(&m_pCache, m_pClassFactory,
- m_ulFileLength, pCacheFile);
- }
- #endif
- if(m_pCache == NULL)
- {
- pObj->CreateMemCacheObject(&m_pCache, m_pClassFactory);
- }
- pObj->Release();
- m_pCache->Init((IHXCacheObjectResponse*)this, CACHE_CAPACITY,
- THRESHOLD);
- }
- // You are on the network thread, so you can't call InitDone(). Let the
- // scheduler do it.
- if(!m_bInitialized)
- {
- m_bInitResponsePending = TRUE;
- m_ulCallbackHandle = m_pScheduler->RelativeEnter(this, 0);
- }
- // Store the non-header portion of the latest chunk in cache.
- m_pPendingAddBlock = (IHXBuffer*)dataBuff;
- m_pCache->AddBlock((IHXBuffer*)dataBuff);
- if(m_bIncompleteReadPending)
- {
- // Now that we have got the data for which we had to "startAllOverAgain",
- // let Func() take over and satisfy the "failed" Read().
- m_ulCallbackHandle = m_pScheduler->RelativeEnter(this, 0);
- }
- }
- else // The TCP data we recvd is applications data (i.e., not part of HTTP header)
- {
- if( (status == HXR_OK) && (pBuffer != NULL) )
- {
- m_ulFileDataRead += pBuffer->GetSize();
- m_pPendingAddBlock = pBuffer;
- m_pCache->AddBlock(pBuffer);
- }
- }
- return HXR_OK;
- } // ReadDone()
- /************************************************************************
- * Method:
- * IHXTCPResponse::WriteReady
- * Purpose:
- * This is the response method for WantWrite.
- * If HX_RESULT is ok, then the TCP channel is ok to Write to.
- */
- STDMETHODIMP
- CHXHTTPFileObject::WriteReady(HX_RESULT status)
- {
- MLOG_HTTP("CHXHTTPFileObject::WriteReady(%s)n", StrRep(status));
- return HXR_NOTIMPL;
- } // WriteReady()
- /************************************************************************
- * Method:
- * IHXTCPResponse::Closed
- * Purpose:
- * This method is called to inform you that the TCP channel has
- * been closed by the peer or closed due to error.
- */
- STDMETHODIMP
- CHXHTTPFileObject::Closed(HX_RESULT status)
- {
- MLOG_HTTP("CHXHTTPFileObject::Closed(%s)n", StrRep(status));
- m_bDisconnected = TRUE;
- return HXR_OK;
- } // Closed()
- /************************************************************************
- * IHXCallback::Func()
- */
- STDMETHODIMP
- CHXHTTPFileObject::Func()
- {
- MLOG_HTTP("CHXHTTPFileObject::Func()n");
- if(m_bInitResponsePending && m_pFileResponse)
- {
- m_bInitResponsePending = FALSE;
- m_bInitialized = TRUE;
- m_pFileResponse->InitDone(HXR_OK);
- }
- // Is there any incomplete read pending?
- if(m_bIncompleteReadPending && m_pCache && m_pFileResponse)
- {
- // Ask the cache if it can supply the next installment for the
- // incomplete read.
- HX_RESULT res = m_pCache->ReadBlock(m_pPendingReadInfo.ulReadOffset,
- m_pPendingReadInfo.ulSize);
- if(res != HXR_OK)
- {
- m_bIncompleteReadPending = FALSE;
- IHXBuffer* pBuff = m_pPendingReadInfo.pPendingReadBuff;
- m_pPendingReadInfo.pPendingReadBuff = NULL;
- if (m_pFileResponse)
- {
- m_pFileResponse->ReadDone(HXR_INCOMPLETE, pBuff);
- }
- HX_RELEASE(pBuff);
- pBuff = NULL;
- }
- }
- // Is there any block which was rejected by the cache earlier because it
- // was full? If so, let's try inserting into the cache again. Maybe, the
- // cache has since freed some space.
- if(m_bAddBlockPending && m_pCache)
- {
- m_bAddBlockPending = FALSE;
- m_pCache->AddBlock(m_pPendingAddBlock);
- }
- return HXR_OK;
- } // Func()
- // 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)
- {
- char lastchar = haystackBuffer[haystackSize];
- haystackBuffer[haystackSize] = ' '; // Now, it's a string
- char* marker = strstr(haystackBuffer, needleString);
- if(marker != NULL)
- {
- haystackBuffer[haystackSize] = lastchar;
- return marker;
- }
- // Perhaps the pattern occurs at the very end?
- haystackBuffer[haystackSize] = lastchar;
- int needleSize = strlen(needleString);
- marker = haystackBuffer + haystackSize - needleSize;
- char *tailPiece = new char[needleSize + 1];
- if(tailPiece == NULL)
- return NULL;
- memcpy((void*)tailPiece, (void*)marker, needleSize);
- tailPiece[needleSize] = ' ';
- if( strcmp(tailPiece, needleString) != 0 )
- marker = NULL;
- delete tailPiece;
- return marker;
- } // bufnstr()
- // From the preferences, get the directory and file where the
- // contents should be cached.
- STDMETHODIMP
- CHXHTTPFileObject::_GetCachePreferences(BOOL& bCacheEnabled, char* &pCacheFile )
- {
- IHXPreferences* pPreferences;
- m_pContext->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);
- HX_ASSERT(pPreferences);
- // Get cache directory, if not set and available
- IHXBuffer* pBuffer = NULL;
- // Check to see if the cache is enabled
- bCacheEnabled = TRUE;
- if (pPreferences->ReadPref("CacheEnabled", pBuffer) == HXR_OK)
- {
- // Cache enabled entry exists
- if (atoi((const char*)pBuffer->GetBuffer()))
- {
- // Cache enabled
- bCacheEnabled = TRUE;
- }
- else
- {
- // Cache disabled
- bCacheEnabled = FALSE;
- }
- }
- else
- {
- bCacheEnabled = FALSE;
- }
- if(bCacheEnabled == FALSE)
- {
- HX_RELEASE(pBuffer);
- return HXR_OK;
- }
- char separator[2] = {OS_SEPARATOR_CHAR, ' '};
- BOOL bCacheDirSpecified = FALSE;
- if (pPreferences->ReadPref("CacheFolder", pBuffer) == HXR_OK)
- {
- // Make sure that the given filename belongs to a directory
- struct stat statbuf = { 0 };
- // If cache database filename does not refer to a file, drop the filename part
- if (!stat ((const char*)pBuffer->GetBuffer(), &statbuf))
- {
- if (statbuf.st_mode & S_IFDIR)
- {
- // Valid cache directory specified
- bCacheDirSpecified = TRUE;
- }
- }
- }
- if( bCacheDirSpecified == FALSE )
- {
- return HXR_FAIL;
- }
- char *cacheDir = (char*)(pBuffer->GetBuffer());
- // Now append the file name
- HX_ASSERT(m_pCHXURL);
- IHXValues* pHeader = m_pCHXURL->GetProperties();
- HX_ASSERT(pHeader);
- IHXBuffer* pPath = NULL;
- char *path = NULL;
- IHXBuffer* pFullPath = NULL;
- char* fullPath = NULL;
- pHeader->GetPropertyBuffer(PROPERTY_PATH, pPath);
- if(pPath != NULL)
- {
- path = (char*)(pPath->GetBuffer());
- }
- pHeader->GetPropertyBuffer(PROPERTY_FULLPATH, pFullPath);
- if(pFullPath!= NULL)
- {
- fullPath = (char*)(pFullPath->GetBuffer());
- }
- char *justFileName = &fullPath[strlen(path)];
- UINT32 l1 = strlen(cacheDir);
- UINT32 l2 = strlen(separator);
- UINT32 l3 = strlen(justFileName);
- pCacheFile = new char[l1 + l2 + l3 + 1];
- HX_ASSERT(pCacheFile);
- memcpy( (void*)pCacheFile, (void*)cacheDir, l1);
- memcpy( (void*)(pCacheFile + l1), (void*)separator, l2);
- memcpy( (void*)(pCacheFile + l1 + l2), (void*)justFileName, l3);
- pCacheFile[l1 + l2 + l3] = ' ';
- HX_RELEASE(pBuffer);
- HX_RELEASE(pPath);
- HX_RELEASE(pFullPath);
- return HXR_OK;
- } // _GetCachePreferences()
- // Prepare a HTTP/1.0 GET Request Message with the appropriate headers.
- STDMETHODIMP
- CHXHTTPFileObject::_PrepareHTTP10GetMessage(char* &pGetMsg,
- UINT32 &ulMsgLen)
- {
- char* SP = " "; // space
- char* CRLF = "rn";
- char* CRLFCRLF = "rnrn";
- char* resource = NULL;
- IHXBuffer* pBuffer = NULL;
- IHXValues* pHeader = m_pCHXURL->GetProperties();
- pHeader->GetPropertyBuffer(PROPERTY_RESOURCE, pBuffer);
- if(pBuffer != NULL)
- {
- resource = (char*)(pBuffer->GetBuffer());
- }
- if(resource == NULL)
- {
- return HXR_UNEXPECTED;
- }
- CHXString ReqStr;
- ReqStr += (const char*)"GET /";
- ReqStr += (const char*)resource;
- ReqStr += (const char*)SP;
- ReqStr += (const char*)"HTTP/1.0";
- IHXValues* pHeaders = NULL;
- m_pRequest->GetRequestHeaders(pHeaders);
- const char* pKey = NULL;
- IHXBuffer* pStr = NULL;
- IHXKeyValueList* pKeyVals = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXKeyValueList,
- (void**)&pKeyVals);
- pKeyVals->ImportValues(pHeaders);
- IHXKeyValueListIter* pIter;
- pKeyVals->GetIter(pIter);
- // Attach the appropriate HTTP Request headers
- HX_RESULT retVal = pIter->GetNextPair(pKey, pStr);
- while(retVal == HXR_OK)
- {
- ReqStr += (const char*)CRLF;
- ReqStr += (const char*)pKey;
- ReqStr += (const char*)": ";
- ReqStr += (const char*)pStr->GetBuffer();
- retVal = pIter->GetNextPair(pKey, pStr);
- }
- ReqStr += (const char*)CRLFCRLF;
- // Set the function's out parameters
- ulMsgLen = ReqStr.GetLength();
- pGetMsg = NULL;
- pGetMsg = new char[ulMsgLen];
- if(pGetMsg == NULL)
- {
- return HXR_OUTOFMEMORY;
- }
- memcpy(pGetMsg, ReqStr.GetBuffer(ulMsgLen), ulMsgLen);
- return HXR_OK;
- } // _PrepareHTTP10GetMessage()