📄 httpfileobj.cpp
字号:
// 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 OK\r\n"; // HTTP success code
// Is the starting line "HTTP/1.x 200 OK\r\n" ?
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()), "\r\n\r\n",
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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -