📄 httpfileobj.cpp
字号:
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()), "\r\nContent-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, "\r\n", 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] = '\0';
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] = '\0'; // 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] = '\0';
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, '\0'};
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] = '\0';
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 = "\r\n";
char* CRLFCRLF = "\r\n\r\n";
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()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -