📄 davutil.cpp
字号:
if (!m_pszBuf) {
m_iSize = GetNextBufSize(dwAlloc);
if (NULL == (m_pszBuf = MyRgAllocNZ(char,m_iSize)))
return FALSE;
m_iNextIn = CHUNK_PREAMBLE;
}
else if (((DWORD)(m_iSize - m_iNextIn) <= cbSize) && (m_iSize != MAX_CHUNK_BUFFER_SIZE)) {
dwAlloc = GetNextBufSize(dwAlloc);
PSTR szTempBuf = (PSTR) g_funcRealloc(m_pszBuf,dwAlloc,g_pvAllocData);
if (!szTempBuf)
return FALSE;
m_iSize = dwAlloc;
m_pszBuf = szTempBuf;
}
BufferConsistencyChecks();
return TRUE;
}
// GetEndOfFileWithNoSlashes returns the last portion of URL between last '/'
// and optionally trailing '/' (or '\').
// Given the URL foobar/myfile.txt, this function will set szStart=myfile.txt
// and not modify ppszSave or pcSave.
// Given URL foobar/dirName/, this function will set *ppszStart=dirName, set
// *ppszSave=0 (will be closing '/') and *pcSave=/.
void GetEndOfFileWithNoSlashes(PSTR *ppszStart, PSTR *ppszSave, CHAR *pcSave) {
DEBUGCHK((*ppszSave) == NULL);
DEBUGCHK(*pcSave == 0);
PSTR pszTrav = *ppszStart;
PSTR pszLastSlash = NULL;
PSTR pszSecondToLastSlash = NULL;
if (strlen(pszTrav) == 1) // special case, len 1
return;
while (*pszTrav) {
if (*pszTrav == '/' || *pszTrav == '\\') {
pszSecondToLastSlash = pszLastSlash;
pszLastSlash = pszTrav;
}
pszTrav++;
}
DEBUGCHK(pszLastSlash);
// A slash was last char before NULL
if ((pszTrav - pszLastSlash) == 1) {
PREFAST_SUPPRESS(11,"Calling function will not call into this unless pszLastSlash will be found");
*pcSave = *pszLastSlash;
*ppszSave = pszLastSlash;
*pszLastSlash = 0;
DEBUGCHK(pszSecondToLastSlash);
if (pszSecondToLastSlash)
*ppszStart = pszSecondToLastSlash+1;
}
else {
if (pszLastSlash)
*ppszStart = pszLastSlash+1;
}
}
//
// Response buffer implementation routines.
//
const CHAR rg_XmlCharacters[] = {'<', '>', '\'', '"', '&'};
const CHAR *rgsz_EntityReferences[] = {"<", ">", "'", """, "&"};
const DWORD dwNumReferences = SVSUTIL_ARRLEN(rg_XmlCharacters);
BOOL CXMLBuffer::Encode(PCSTR pszData) {
// Translate pszData into encoded XML. We have to call
// CChunkedBuffer::Append every bit individually because we may
// have to send across a chunked response at any time.
PSTR pszTrav = (PSTR)pszData;
DWORD i;
while (*pszTrav) {
for (i = 0; i < dwNumReferences; i++) {
if (rg_XmlCharacters[i] == *pszTrav) {
if (! Append(rgsz_EntityReferences[i],strlen(rgsz_EntityReferences[i])))
return FALSE;
break;
}
}
if ((*pszTrav == '\r') && (*(pszTrav+1) == '\n')) {
if (! Append(pszTrav,2))
return FALSE;
pszTrav++; // skip past '\n'
}
if (*pszTrav == '\n') {
if (! Append("\r\n",2))
return FALSE;
}
else if (i == dwNumReferences) {
if (! Append(pszTrav,1))
return FALSE;
}
pszTrav++;
}
return TRUE;
}
/*
// This is original table used to determine whether or not we need to encode, from httplite.
// There is no need for 1 bit worth of information to take up a byte of ROM, so this
// table is further compressed in isAcceptable array below, where 2 rows take up one entry.
// Note below that we reverse order of bits for least significant bit.
const CHAR isAcceptableExpanded[] =
{0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2x !"#$%&'()*+,-./
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, // 3x 0123151189:;<=>?
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4x @ABCDEFGHIJKLMNO
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, // 5X PQRSTUVWXYZ[\]^_
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6x `abcdefghijklmno
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0}; // 7X pqrstuvwxyz{|}~ DEL
*/
const DWORD isAcceptable[] = {
0x2FFFFF92, // 00101111111111111111111110010010
0xAFFFFFFF, // 10101111111111111111111111111111
0x47FFFFFE, // 01000111111111111111111111111110
};
BOOL RequiresEncode(CHAR c) {
if ((c >= 32) && (c <128)) {
int i = (c & 0x60) >> 6; // rip out 6th and 7th bits
int m = c & 0x1F;
DEBUGCHK((i >= 0) && (i <= SVSUTIL_ARRLEN(isAcceptable)));
return ! (isAcceptable[i] & (1 << m));
}
return TRUE;
}
BOOL CBuffer::EncodeURL(PCSTR pszData) {
PSTR pszTrav;
CHAR szBuf[3];
szBuf[0] = HEX_ESCAPE;
for (pszTrav = (PSTR)pszData; *pszTrav; pszTrav++) {
CHAR c = *pszTrav;
if (RequiresEncode(c)) {
szBuf[1] = g_szHexDigits[c >> 4];
szBuf[2] = g_szHexDigits[c & 15];
if (! AppendData(szBuf,3))
return FALSE;
}
else if (! AppendCHAR(*pszTrav))
return FALSE;
}
return TRUE;
}
BOOL CXMLBuffer::EncodeURL(PCSTR pszData) {
PSTR pszTrav;
CHAR szBuf[3];
szBuf[0] = HEX_ESCAPE;
for (pszTrav = (PSTR)pszData; *pszTrav; pszTrav++) {
CHAR c = *pszTrav;
if (RequiresEncode(c)) {
szBuf[1] = g_szHexDigits[c >> 4];
szBuf[2] = g_szHexDigits[c & 15];
if (! Append(szBuf,3))
return FALSE;
}
else if (! AppendCHAR(*pszTrav))
return FALSE;
}
return TRUE;
}
BOOL CChunkedBuffer::Append(PCSTR pszData, DWORD ccData) {
DEBUGCHK(!m_fFinalDataSent);
if (!AllocMem(ccData))
return FALSE;
while ((m_iNextIn+ccData) >= MAX_CHUNK_BODY_SIZE) {
DWORD ccCopy = MAX_CHUNK_BODY_SIZE-m_iNextIn;
memcpy(m_pszBuf+m_iNextIn,pszData,ccCopy);
ccData -= ccCopy;
pszData += ccCopy;
m_iNextIn += ccCopy;
if (!FlushBuffer())
return FALSE;
}
memcpy(m_pszBuf+m_iNextIn,pszData,ccData);
m_iNextIn += ccData;
BufferConsistencyChecks();
return TRUE;
}
// FlushBuffer sends data across to client, does appropriate munging with chunk
// lengths. If fFinalChunk=TRUE, then it will close off buffer as far as client knows.
BOOL CChunkedBuffer::FlushBuffer(BOOL fFinalChunk) {
BufferConsistencyChecks();
if (! AllocMem(CHUNK_RESERVE_SPACE))
return FALSE;
// Where to position start of send buffer depends on number of
// bytes required to encode the content-length.
DWORD ccBodyLen = m_iNextIn - CHUNK_PREAMBLE;
DWORD ccOffset;
DWORD cbSend;
BOOL fRet;
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: WebDav FlushBuffer called for chunked buffer send\r\n"));
DEBUGMSG(ZONE_WEBDAV_VERBOSE,(L"HTTPD: FlushBuffer fFinalChunk=%d,ccBodyLen=%d\r\n",fFinalChunk,ccBodyLen));
DEBUGCHK(ccBodyLen <= MAX_CHUNK_BODY_SIZE);
DEBUGCHK(m_pszBuf);
DEBUGCHK(!m_fFinalDataSent);
if (m_pRequest->m_fResponseHTTP11) {
// Calculate offsets for chunked encoding
if (ccBodyLen <= 0xF)
ccOffset = CHUNK_PREAMBLE - 3; // -2 for CRLF, -1 to store number
else if (ccBodyLen <= 0xFF)
ccOffset= CHUNK_PREAMBLE - 4; // -2 for CRLF, -2 to store number
else if (ccBodyLen <= 0xFFF)
ccOffset = CHUNK_PREAMBLE - 5; // -2 for CRLF, -3 to store number
else
ccOffset = 0; // need all 4 bytes to store the number
DWORD dwSprintf = sprintf(m_pszBuf+ccOffset,"%x",ccBodyLen);
DEBUGCHK(dwSprintf == (CHUNK_PREAMBLE-2-ccOffset));
// Last two bytes before body will always be CRLF
m_pszBuf[CHUNK_PREAMBLE-2] = '\r';
m_pszBuf[CHUNK_PREAMBLE-1] = '\n';
cbSend = ccBodyLen + (CHUNK_PREAMBLE-ccOffset);
// Last two bytes after body will always be CRLF
m_pszBuf[m_iNextIn++] = '\r';
m_pszBuf[m_iNextIn++] = '\n';
cbSend += 2;
if (fFinalChunk) {
WriteCloseChunk(m_pszBuf,m_iNextIn);
cbSend += CHUNK_CLOSE_LEN;
}
}
else {
// In HTTP 1.0 case, assume client doesn't know about chunked-encoding so send back regular.
ccOffset = CHUNK_PREAMBLE;
cbSend = ccBodyLen;
if (m_pRequest->m_fKeepAlive && fFinalChunk && !m_fSentFirstChunk) {
// If 1.0 client wants keep-alives and this is our last chunk, then
// we know length of body and can do a keep-alive
CHttpResponse resp(m_pRequest, m_pRequest->GetStatus());
resp.SetLength(cbSend);
resp.SendHeadersAndDefaultBodyIfAvailable(NULL,NULL);
}
else if (!m_fSentFirstChunk) {
// We haven't sent body back yet, and either no keep-alives by client request
// and/or this isn't final chunk, then no keepalives.
CHttpResponse resp(m_pRequest, m_pRequest->GetStatus(),CONN_CLOSE);
m_pRequest->m_fKeepAlive = FALSE;
resp.SendHeadersAndDefaultBodyIfAvailable(NULL,NULL);
}
else {
// We've already sent first part of data in no-keepalive case.
DEBUGCHK(m_fSentFirstChunk);
DEBUGCHK(m_pRequest->m_fKeepAlive == FALSE);
}
m_fSentFirstChunk = TRUE;
}
DEBUGCHK(cbSend < MAX_CHUNK_BUFFER_SIZE);
DEBUGCHK(cbSend < m_iSize);
fRet = m_pRequest->SendData(m_pszBuf+ccOffset,cbSend);
m_iNextIn = CHUNK_PREAMBLE;
BufferConsistencyChecks();
return fRet;
}
// Called when an error has occured. Ignore any data in buffer already, send back
// code to indicate we're done sending.
BOOL CChunkedBuffer::AbortiveError(void) {
CHAR szBuf[CHUNK_POSTAMBLE];
BufferConsistencyChecks();
DEBUGCHK(!m_fFinalDataSent);
m_iNextIn = CHUNK_PREAMBLE;
WriteCloseChunk(szBuf,0);
return m_pRequest->SendData(szBuf,CHUNK_CLOSE_LEN);
}
void CChunkedBuffer::WriteCloseChunk(PSTR szBuf, DWORD dwOffset) {
#if defined (DEBUG)
m_fFinalDataSent = TRUE;
#endif
m_pszBuf[dwOffset++] = '0';
m_pszBuf[dwOffset++] = '\r';
m_pszBuf[dwOffset++] = '\n';
m_pszBuf[dwOffset++] = '\r';
m_pszBuf[dwOffset++] = '\n';
}
const char cszPrefixBraceOpenD[] = "<d:";
const DWORD ccPrefixBraceOpenD = SVSUTIL_CONSTSTRLEN(cszPrefixBraceOpenD);
BOOL SetEmptyTagWin32NS(CXMLBuffer *pBuffer, PCSTR pszElement, DWORD ccElement) {
return (pBuffer->Append(cszPrefixBraceOpenD,ccPrefixBraceOpenD) &&
pBuffer->Append(pszElement,ccElement) &&
pBuffer->Append("/>",2));
}
BOOL SetTagWin32NS(CXMLBuffer *pBuffer, PCSTR pszName, DWORD ccName, PCSTR szValue) {
return (pBuffer->Append(cszPrefixBraceOpenD,ccPrefixBraceOpenD) &&
pBuffer->Append(pszName,ccName) &&
pBuffer->AppendCHAR('>') &&
pBuffer->Append(szValue,strlen(szValue)) &&
pBuffer->Append("</d:",4) &&
pBuffer->Append(pszName,ccName) &&
pBuffer->CloseBrace());
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -