📄 httpcore.cpp
字号:
--- */
int i = 0;
for( ; i<iLineLen && !(isspace(pLine[i])); i++);
*ppProtocol = pLine;
if ( i==iLineLen ) { return ST_BADREQUEST; };
pLine[i]='\0'; i++;
for(; i<iLineLen && (isspace(pLine[i])); i++);
pLine = &( pLine[i] ); iLineLen -= i; i=0;
/* ---
pLine now points at the statuscode following the protocol
--- */
/* --- Statuscode must exist --- */
if ( i==iLineLen ) { return ST_BADREQUEST; };
for(; i<iLineLen && !(isspace(pLine[i])); i++);
const char *pStatusCode = pLine;
pLine[i]='\0'; i++;
*piStatusCode = atoi(pStatusCode);
/* ---
We ignore the status text and the whole rest
--- */
/* -- OK --- */
return INT_CONTINUE;
}
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
Verify the HTTP request line and divide it into components. Returns
INT_CONTINUE on success or an HTTP error status code on error.
Assumes pLine is NULL terminated at pLine[iLineLen].
On success instantiates all values to at least an empty string with the
exception of the proxy values which will all be instantiated if
ppProxyProtocol is instantiated.
\*____________________________________________________________________________*/
static int Internal_SplitRequestLine(
char *pLine,
int iLineLen,
const char **ppMethod,
const char **ppProxyProtocol,
const char **ppProxyHost,
int *piProxyHostLen,
const char **ppProxyPort,
int *piProxyPortLen,
const char **ppPath,
const char **ppQueryString,
const char **ppProtocol
)
{
assert( pLine );
assert( iLineLen );
assert( ppMethod );
assert( ppProxyProtocol );
assert( ppProxyHost );
assert( piProxyHostLen );
assert( ppProxyPort );
assert( piProxyPortLen );
assert( ppPath );
assert( ppProtocol );
*ppProtocol = ""; /* --- this is done because protcol is optional, i.e.
HTTP/0.9 doesn't send one
--- */
/*
** check URI for exluded characters acc. to RFC2396 2.4.3
** (silently checking the whole request line instead of URI only
** and intentional omitting \x00, \x20, '#' and '%' from this check)
*/
#define deniedchars "\
\x7F\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\
\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\
<>\"{}|\\^[]`"
if ( strcspn( pLine, deniedchars ) < strlen( pLine ))
{ return ST_BADREQUEST; };
/* ---
method
--- */
int i = 0;
for( ; i<iLineLen && !(isspace(pLine[i])); i++);
*ppMethod = pLine;
if ( i==iLineLen ) { return ST_BADREQUEST; };
pLine[i]='\0'; i++;
for(; i<iLineLen && (isspace(pLine[i])); i++);
pLine = &( pLine[i] ); iLineLen -= i; i=0;
/* ---
pLine now points at the component following the method
--- */
/* --- URL path must exist --- */
if ( i==iLineLen )
{ return ST_BADREQUEST; };
/* ---
proxy host and port
--- */
if ( (*pLine!='/') && (*pLine!='*'))
{
/* --- assume proxy host and port specification --- */
for(;
(i+2)<iLineLen &&
strncmp(&(pLine[i]), "://", 3) && !(isspace(pLine[i])); i++)
{ pLine[i] = tolower( pLine[i] ); };
if ( !strncmp( &(pLine[i]), "://", 3 ) )
{
*ppProxyProtocol = pLine; pLine[i] = '\0';
i += 3;
pLine = &( pLine[i] ); iLineLen -= i; i=0;
/* --- pLine now points at proxy host --- */
*ppProxyHost = pLine;
for(; i<iLineLen &&
pLine[i]!=':' &&
pLine[i]!='/' &&
!(isspace(pLine[i])); i++);
*piProxyHostLen = i;
if ( pLine[i]==':' )
{
i++;
pLine = &( pLine[i] ); iLineLen -= i; i=0;
/* --- pLine now points at proxy port --- */
*ppProxyPort = pLine;
for(; i<iLineLen && pLine[i]!='/' && !(isspace(pLine[i])); i++);
*piProxyPortLen = i;
}
else
{
*ppProxyPort = "";
*piProxyPortLen = 0;
};
pLine = &( pLine[i] ); iLineLen -= i; i=0;
}
else
{
/* ---
The URL path didn't start with '/' but it wasn't a proxy request
NOTE: Maybe this should raise a gateway error instead of the
generic bad request error.
--- */
return ST_BADREQUEST;
};
};
/* ---
pLine now points at first character of URL path
--- */
/* ---
path and query string.
--- */
for(; i<iLineLen && pLine[i]!='?' && !(isspace(pLine[i])); i++);
*ppPath = pLine;
if ( pLine[i]=='?' )
{
pLine[i++] = '\0';
*ppQueryString = &(pLine[i]);
for(; i<iLineLen && !(isspace(pLine[i])); i++);
}
else
{ *ppQueryString = ""; };
// decode long file names with spaces
char *pdest = strchr( *ppPath, '+' );
while (pdest != NULL) {
if (strlen(*ppQueryString) && (pdest > *ppQueryString)) break;
pdest[0] = ' ';
pdest = strchr( *ppPath, '+' );
};
if ( i==iLineLen ) { return INT_CONTINUE; };
pLine[i++]='\0';
for(; i<iLineLen && (isspace(pLine[i])); i++);
pLine = &( pLine[i] ); iLineLen -= i; i=0;
/* ---
pLine now points at the component following the URL path and
query string.
--- */
/* ---
protocol is last component on the line, skip components until the last
--- */
for(;;)
{
for(; i<iLineLen && !(isspace(pLine[i])); i++);
*ppProtocol = pLine;
for(; i<iLineLen && (isspace(pLine[i])); i++);
if ( i==iLineLen ) { return INT_CONTINUE; }; /* this should be true */
/* --- I guess not --- */
pLine = &( pLine[i] ); iLineLen -= i; i=0;
};
/* -- OK --- */
return INT_CONTINUE;
}
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
Returns INT_CONTINUE on success, otherwise HTTPCore_readHeaders() returns
an HTTP error status code.
\*____________________________________________________________________________*/
int HTTPCore_readHeaders(
PIIOBuffer *pB, /* Buffer */
PIDB *pDB, /* Request DB */
int iFlags )
{
assert( pB );
PIIOBuffer &tB = *pB;
char szLocalBuffer[ LOCAL_BUFFER_LEN+1 ];
szLocalBuffer[ LOCAL_BUFFER_LEN ]='\0';
int iLen = tB.GetLine( szLocalBuffer, LOCAL_BUFFER_LEN );
if ( iLen<0 )
{ return ST_INTERNALERROR; }
else if ( iLen==0 )
{ return ST_BADREQUEST; }
if ( iLen==LOCAL_BUFFER_LEN )
/* --- HTTP/1.1 status code --- */
{ return ST_REQUESTURITOOLONG; }
szLocalBuffer[iLen]='\0';
/* ---
Get status line
--- */
const char *pMethod = 0;
const char *pProxyProtocol = 0;
const char *pProxyHost = 0;
int iProxyHostLen = 0;
const char *pProxyPort = 0;
int iProxyPortLen = 0;
const char *pURI = 0;
const char *pQueryString = 0;
const char *pProtocol = 0;
int iStatus;
if ( iFlags==RH_CLIENTREQUEST )
{
/* ---
Save the raw request line in the CLF header field
--- */
PIDB_add( pDB, PIDBTYPE_STRING, pFKCLF, szLocalBuffer,
PIDBFLAG_FASTKEY );
/* --- parse the line --- */
iStatus = Internal_SplitRequestLine(
szLocalBuffer,
iLen,
&pMethod,
&pProxyProtocol,
&pProxyHost,
&iProxyHostLen,
&pProxyPort,
&iProxyPortLen,
&pURI,
&pQueryString,
&pProtocol
);
if ( iStatus )
{ return iStatus; };
if ( !pMethod || !pURI || !pQueryString || !pProtocol )
{ return ST_BADREQUEST; };
/* --- store these headers --- */
PIDB_add( pDB, PIDBTYPE_STRING, pFKMethod, (void *)pMethod,
PIDBFLAG_FASTKEY );
PIDB_add( pDB, PIDBTYPE_STRING, pFKURI, (void *)pURI,
PIDBFLAG_FASTKEY );
PIDB_add( pDB, PIDBTYPE_STRING, pFKQueryString, (void *)pQueryString,
PIDBFLAG_FASTKEY );
PIDB_add( pDB, PIDBTYPE_STRING, pFKProtocol, (void *)pProtocol,
PIDBFLAG_FASTKEY );
/* --- Is this a proxy request? --- */
if ( pProxyProtocol )
{
PIDB_add( pDB, PIDBTYPE_STRING, pFKProxyProtocol,
(void *)pProxyProtocol, PIDBFLAG_FASTKEY );
PIString sProxyHost( pProxyHost, iProxyHostLen );
PIDB_add( pDB, PIDBTYPE_STRING, pFKProxyHost,
(void *)(const char *)sProxyHost, PIDBFLAG_FASTKEY );
PIString sProxyPort( pProxyPort, iProxyPortLen );
PIDB_add( pDB, PIDBTYPE_STRING, pFKProxyPort,
(void *)(const char *)sProxyPort, PIDBFLAG_FASTKEY );
};
/* ---
Convert method and protocol into internal numeric form
--- */
int iMethod = MD_UNKNOWN;
int iProtocol = PR_UNKNOWN;
if ( !PIUtil_stricmp( pMethod, MD_NAME_GET ) )
{ iMethod = MD_GET; }
else if ( !PIUtil_stricmp( pMethod, MD_NAME_POST ) )
{ iMethod = MD_POST; }
else if ( !PIUtil_stricmp( pMethod, MD_NAME_HEAD ) )
{ iMethod = MD_HEAD; }
else if ( !PIUtil_stricmp( pMethod, MD_NAME_PUT ) )
{ iMethod = MD_PUT; }
else if ( !PIUtil_stricmp( pMethod, MD_NAME_DELETE ) )
{ iMethod = MD_DELETE; }
else if ( !PIUtil_stricmp( pMethod, MD_NAME_OPTIONS ) )
{ iMethod = MD_OPTIONS; }
else if ( !PIUtil_stricmp( pMethod, MD_NAME_TRACE ) )
{ iMethod = MD_TRACE; };
if ( *pProtocol )
{
/* --- any protocol is not HTTP/0.9 --- */
if ( !PIUtil_stricmp( pProtocol, PR_NAME_HTTP10 ) )
{ iProtocol = PR_HTTP10; }
else if ( !PIUtil_stricmp( pProtocol, PR_NAME_HTTP11 ) )
{ iProtocol = PR_HTTP11; };
}
else
{ iProtocol = PR_HTTP09; };
/* --- Do we support this method and protocol ? --- */
if ( iMethod == MD_UNKNOWN )
{ return ST_NOTIMPLEMENTED; };
if ( iProtocol == PR_UNKNOWN )
{ iProtocol = PR_HTTP10; };
/* --- Do we support the method for version < HTTP/1.1 ? --- */
// Removed because to strict, e.g. for uploads with Netscape
#if 0
if ((iProtocol != PR_HTTP11) && (iMethod > MD_HEAD))
{ return ST_BADREQUEST; }; // maybe better ST_NOTIMPLEMENTED?
#endif
/* --- set the numeric method and protocol --- */
PIDB_replace( pDB, PIDBTYPE_OPAQUE, pFKMethodNumber, (void *)iMethod,
PIDBFLAG_FASTKEY );
PIDB_replace( pDB, PIDBTYPE_OPAQUE, pFKProtocolNumber,
(void *)iProtocol, PIDBFLAG_FASTKEY );
/* ---
Don't get the rest of the RFC822 headers if the protocol
is HTTP/0.9
--- */
if ( iProtocol==PR_HTTP09 )
{ return INT_CONTINUE; };
iLen = tB.GetLine( szLocalBuffer, LOCAL_BUFFER_LEN );
}
else if ( iFlags==RH_RESPONSE )
{
/* ---
determine if this is a full response:
This is considered true if both the following are true
- The line starts with 'HTTP/' or 'http/'
- The line does not contain the ':' character
--- */
if ( !PIUtil_strncmpi( szLocalBuffer, "HTTP/", 5 ) )
{
int i=0;
for(; i<iLen && szLocalBuffer[i]!=':'; i++);
if ( i==iLen )
{
/* ---
this is a full response, add this line to the DB as CLF
and get the next line
--- */
PIDB_add( pDB, PIDBTYPE_STRING, pFKCLF, szLocalBuffer,
PIDBFLAG_FASTKEY );
int iStatusCode = 0;
iStatus = Internal_SplitResponseLine(
szLocalBuffer,
iLen,
&pProtocol,
&iStatusCode
);
if ( iStatus )
{ return iStatus; };
if ( !pProtocol || iStatusCode < 100 || iStatusCode > 599 )
{ return ST_BADREQUEST; };
/* ---
Convert protocol into internal numeric form
--- */
int iProtocol = PR_UNKNOWN;
if ( *pProtocol )
{
/* --- any protocol is not HTTP/0.9 --- */
if ( !PIUtil_stricmp( pProtocol, PR_NAME_HTTP10 ) )
{ iProtocol = PR_HTTP10; }
else if ( !PIUtil_stricmp( pProtocol, PR_NAME_HTTP11 ) )
{ iProtocol = PR_HTTP11; };
}
else
{ iProtocol = PR_HTTP09; };
if ( iProtocol == PR_UNKNOWN )
{ iProtocol = PR_HTTP10; };
/* --- store the protocol name --- */
PIDB_add( pDB, PIDBTYPE_STRING, pFKProtocol, (void *)pProtocol,
PIDBFLAG_FASTKEY );
/* --- set the numeric protocol and statuscode --- */
PIDB_add( pDB, PIDBTYPE_OPAQUE, pFKProtocolNumber,
(void *)iProtocol, PIDBFLAG_FASTKEY );
PIDB_add( pDB, PIDBTYPE_OPAQUE, pFKStatusCode,
(void *)iStatusCode, PIDBFLAG_FASTKEY );
iLen = tB.GetLine( szLocalBuffer, LOCAL_BUFFER_LEN );
};
};
};
while( iLen>0 )
{
int i=0;
for(; i<iLen && szLocalBuffer[i]!=':'; i++);
szLocalBuffer[i++]='\0';
for(; i<iLen && (isspace(szLocalBuffer[i])); i++);
PIDB_add( pDB,
PIDBTYPE_RFC822,
szLocalBuffer,
(void *)&(szLocalBuffer[i]),
0
);
iLen = tB.GetLine( szLocalBuffer, LOCAL_BUFFER_LEN );
};
/* --- The 'Host' Header is mandatory for HTTP/1.1 --- */
if ((iFlags==RH_CLIENTREQUEST) && ((const int)PIDB_lookup(pDB,
PIDBTYPE_OPAQUE, pFKProtocolNumber, PIDBFLAG_FASTKEY) == PR_HTTP11)
&& !PIDB_lookup(pDB, PIDBTYPE_RFC822, KEY_HTTP_HOST, 0)) {
return ST_BADREQUEST;
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -