www.pudn.com > NETINFO.rar > http.cpp
#include "http.h"
//some tool function
BOOL SplitHttpHeader(const char line[], char name[MAX_HTTP_HEADER_LINE], char value[MAX_HTTP_HEADER_LINE])
{
const char *pColon = strchr(line, ':');
if( !pColon ) //because I have found some cases that is using '=' as seperator
pColon = strchr(line, '=');
if( !pColon ) return FALSE;
const char *pStart, *pEnd;
//extract name
for(pStart = line; pStart=pStart && isspace(*pEnd); pEnd--)NULL; //skip end space
if(pEnd>=pStart && pEnd - pStart + 2 < MAX_HTTP_HEADER_LINE )
{
memcpy(name, pStart, pEnd-pStart+1);
name[pEnd-pStart+1] = 0;
}
else
strcpy(name, "");
//extract value
const char* pZero = pColon + strlen(pColon);
for(pStart = pColon+1; pStart=pStart && isspace(*pEnd); pEnd--)NULL; //skip end space
if(pEnd>=pStart && pEnd - pStart + 2 < MAX_HTTP_HEADER_LINE )
{
memcpy(value, pStart, pEnd-pStart+1);
value[pEnd-pStart+1] = 0;
}
else
strcpy(value, "");
return TRUE;
}
//if successfully analyse a header field, return TRUE, else return FALSE
BOOL HttpAnalyseHeader(const char*fullLine, HTTP_HEADER_INFO* pHeader, enum HTTP_ANALYSE_HEADER_TYPE type)
{
if( strcmp(fullLine, "") == 0 )
return FALSE;
if( type == HEADER_TYPE_REQUEST_LINE )
{
sscanf(fullLine, "%s %s %s", pHeader->method, pHeader->url, pHeader->http_Version);
//check validation
strlwr(pHeader->http_Version);
if( memicmp(pHeader->http_Version, "http/1.", 7) )
{
printf("invalidate http_version: %s\n", pHeader->http_Version);
return FALSE;
}
}
else if( type == HEADER_TYPE_STATUS_LINE )
{
sscanf(fullLine, "%s %s", pHeader->http_Version, pHeader->status_Code);
//check validation
if( memicmp(pHeader->http_Version, "http/1.", 7) )
{
printf("invalidate http_version: %s\n", pHeader->http_Version);
return FALSE;
}
}
else if( type == HEADER_TYPE_NORMAL_HEADER )
{
char name[MAX_HTTP_HEADER_LINE], value[MAX_HTTP_HEADER_LINE];
if( !SplitHttpHeader(fullLine, name, value) )
return FALSE;
if( stricmp(name, "Content-Location") == 0 )
{
if( strlen(value)content_Location) )
strcpy(pHeader->content_Location, value);
}
else if( stricmp(name, "Location") == 0 )
{
if( strlen(value)location) )
strcpy(pHeader->location, value);
}
else if( stricmp(name, "Host") == 0 )
{
if( strlen(value)host) )
strcpy(pHeader->host, value);
}
else if( stricmp(name, "Connection") == 0 )
{
if( strlen(value)connection) )
strcpy(pHeader->connection, value);
}
else if( stricmp(name, "Content-Encoding") == 0 )
{
if( strlen(value)content_Encoding) )
strcpy(pHeader->content_Encoding, value);
}
else if( stricmp(name, "Content-Length") == 0 )
{
if( strlen(value)content_Length) )
strcpy(pHeader->content_Length, value);
}
else if( stricmp(name, "Content-Type") == 0 )
{
char *pSlash = strchr(value, '/');
if( pSlash )
{
memcpy(pHeader->content_MainType, value, pSlash - value);
pHeader->content_MainType[pSlash-value] = 0;
char *pEnd;
if( (pEnd = strchr(pSlash, ';'))==NULL )
pEnd = pSlash+strlen(pSlash);
memcpy(pHeader->content_SubType, pSlash+1, pEnd - pSlash - 1);
pHeader->content_SubType[pEnd-pSlash-1] = 0;
}
}
else if( stricmp(name, "Content-Range") == 0 )
{
if( strlen(value)content_Range) )
strcpy(pHeader->content_Range, value);
}
else if( stricmp(name, "Referer") == 0 )
{
if( strlen(value)referer) )
strcpy(pHeader->referer, value);
}
else if( stricmp(name, "Transfer-Encoding") == 0 )
{
if( strlen(value)transfer_Encoding) )
strcpy(pHeader->transfer_Encoding, value);
}
}
return TRUE;
}
BOOL GetHostFromUrl(const char url[], char host[MAX_HOST_LENGTH])
{
BOOL retVal = FALSE;
const char *p1, *p2;
p1 = strstr(url, "://");
p2 = strstr(url, "/");
if( p1!=NULL && p1 < p2 )
{
const char *pStart, *pEnd, *pChar;
pStart = p1 + 3;
pEnd = strchr(pStart, '/');
if( pEnd )
{
//look for '@' to check if it's a url such as
// http://123:123@www.test.com:88/index.htm
for(pChar = pStart; pCharOnHttpClientBegin )
m_pFuncs->OnHttpClientBegin(m_pNi, this);
}
CHttpConnection::~CHttpConnection()
{
if( m_status == HTTP_REQUEST_BODY )
{
if( m_pFuncs && m_pFuncs->OnHttpClientEnd )
m_pFuncs->OnHttpClientEnd(m_pNi, this);
}
else if( m_status == HTTP_RESPONSE_BODY )
{
if( m_pFuncs && m_pFuncs->OnHttpServerEnd )
m_pFuncs->OnHttpServerEnd(m_pNi, this);
}
}
BOOL CHttpConnection::OnData(int sender, int receiver, const BYTE* pData, DWORD length)
{
if( m_status == HTTP_REQUEST_LINE || m_status == HTTP_REQUEST_HEADER
|| m_status == HTTP_STATUS_LINE || m_status == HTTP_RESPONSE_HEADER )
{
if( ( (m_status == HTTP_REQUEST_LINE || m_status == HTTP_REQUEST_HEADER) && sender==m_listener )
|| ( (m_status == HTTP_STATUS_LINE || m_status == HTTP_RESPONSE_HEADER) && sender==m_connecter ) )
{
printf("invalid direction data when decoding headers\n");
return FALSE;
}
if( !m_lineBuf.PutData((const char*)pData, length) ) return FALSE;
char line[MAX_HTTP_HEADER_LINE];
int writeLen;
while( m_lineBuf.GetLine(line, sizeof(line), &writeLen, FALSE) )
{
//add this LWSP line to current line
if( line[0] == ' ' || line[0] == '\t' )
{
if( strlen(line) + strlen(m_szLastLine) + 1 > sizeof(m_szLastLine) )
{
printf("CHttpConnection::OnData(): m_szLastLine is too small\n");
return FALSE;
}
strcat(m_szLastLine, line);
}
else
{
//analyse m_szLastLine
if( strcmp(m_szLastLine,"")!=0 )
{
enum HTTP_ANALYSE_HEADER_TYPE headerType;
HTTP_HEADER_INFO *pHeader = (sender==m_connecter) ? &m_request : &m_response;
if( m_status == HTTP_REQUEST_LINE )
{
headerType = HEADER_TYPE_REQUEST_LINE;
m_status = HTTP_REQUEST_HEADER;
}
else if( m_status == HTTP_STATUS_LINE )
{
headerType = HEADER_TYPE_STATUS_LINE;
m_status = HTTP_RESPONSE_HEADER;
}
else
headerType = HEADER_TYPE_NORMAL_HEADER;
if( !HttpAnalyseHeader(m_szLastLine, pHeader, headerType) )
{
printf("CHttpConnection::OnData(): error occured when decoding header\n");
return FALSE;
}
}
//store current line to m_szLastLine
strcpy(m_szLastLine, line);
//check whether encounter ending CRLF line of headers
if( strcmp(line, "") == 0 )
{
if( m_status == HTTP_REQUEST_HEADER )
{
if( m_pFuncs && m_pFuncs->OnHttpClientHeader )
m_pFuncs->OnHttpClientHeader(m_pNi, this, &m_request);
m_status = HTTP_REQUEST_BODY;
if( m_lineBuf.GetCount() != 0 )
{
if( m_pFuncs && m_pFuncs->OnHttpClientBody )
m_pFuncs->OnHttpClientBody(m_pNi, this, (const BYTE*)m_lineBuf.GetRemainStart(), m_lineBuf.GetCount() );
}
}
else if( m_status == HTTP_RESPONSE_HEADER )
{
if( m_pFuncs && m_pFuncs->OnHttpServerHeader )
m_pFuncs->OnHttpServerHeader(m_pNi, this, &m_request, &m_response);
m_status = HTTP_RESPONSE_BODY;
if( m_lineBuf.GetCount() != 0 )
{
if( m_pFuncs && m_pFuncs->OnHttpServerBody )
m_pFuncs->OnHttpServerBody(m_pNi, this, (const BYTE*)m_lineBuf.GetRemainStart(), m_lineBuf.GetCount() );
}
}
m_lineBuf.ResetContent();
strcpy(m_szLastLine, "");
}
}
}
}
else if( m_status == HTTP_REQUEST_BODY )
{
if( sender == m_connecter )
{
if( m_pFuncs && m_pFuncs->OnHttpClientBody )
m_pFuncs->OnHttpClientBody(m_pNi, this, pData, length);
}
else
{
if( m_pFuncs && m_pFuncs->OnHttpClientEnd )
m_pFuncs->OnHttpClientEnd(m_pNi, this);
m_status = HTTP_STATUS_LINE;
if( m_pFuncs && m_pFuncs->OnHttpServerBegin )
m_pFuncs->OnHttpServerBegin(m_pNi, this);
m_lineBuf.ResetContent();
strcpy(m_szLastLine, "");
return OnData(sender, receiver, pData, length);
}
}
else if( m_status == HTTP_RESPONSE_BODY )
{
if( sender == m_listener )
{
if( m_pFuncs && m_pFuncs->OnHttpServerBody )
m_pFuncs->OnHttpServerBody(m_pNi, this, pData, length);
}
else
{
if( m_pFuncs && m_pFuncs->OnHttpServerEnd )
m_pFuncs->OnHttpServerEnd(m_pNi, this);
m_lineBuf.ResetContent();
strcpy(m_szLastLine, "");
memset(&m_request, 0, sizeof(m_request));
memset(&m_response, 0, sizeof(m_response));
m_status = HTTP_REQUEST_LINE;
if( m_pFuncs && m_pFuncs->OnHttpClientBegin )
m_pFuncs->OnHttpClientBegin(m_pNi, this);
return OnData(sender, receiver, pData, length);
}
}
return TRUE;
}
void GetHttpHeader(HHTTPCONNECT hHttpConnect, const HTTP_HEADER_INFO **ppRequest, const HTTP_HEADER_INFO **ppResponse)
{
*ppRequest = &hHttpConnect->m_request;
*ppResponse = &hHttpConnect->m_response;
}