📄 session.cpp
字号:
//
// Get the next chunk size. The format of this string is as follows:
// "chunk-size [chunk-extension]\r\n"
// We want to return chunk_size and the total length of this string.
//
while (dwReadAttempts < MAX_CHUNKED_READ_ATTEMPTS) {
CHAR* pszStopString = NULL;
CHAR* pszEndChunk = NULL;
PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
ASSERT(pBuffer);
// Read to end of chunk-extension
pszEndChunk = strstr((char*)pBuffer, "\r\n");
if (NULL == pszEndChunk) {
// Need to read more data to read past chunk-extension
dwRetVal = ProxyRecv(recvSock, buffer, pcbRecved, -1, NULL);
if (ERROR_SUCCESS != dwRetVal) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Could not recv data for rest of chunk size.\n")));
goto exit;
}
dwReadAttempts++;
continue;
}
// Read chunk-size
*pdwChunkSize = strtol((char*)pBuffer, &pszStopString, 16);
if ((0 == *pdwChunkSize) && (pszStopString == (char*)pBuffer)) {
dwRetVal = ERROR_INVALID_DATA;
goto exit;
}
// Calculate total chunk header size (Add two for \r\n)
*pdwChunkHeaderSize = (pszEndChunk - (char*)pBuffer) + 2;
break;
}
if (0 == *pdwChunkHeaderSize) {
dwRetVal = ERROR_INVALID_DATA;
}
exit:
return dwRetVal;
}
DWORD CHttpSession::HandleChunked(CBuffer& buffer, int* pcchBuffer, int* pcchSent, BOOL fRequest)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD dwChunkSize = 0; // Size of chunk
DWORD dwChunkHeaderSize = 0; // Size of chunk header
DWORD dwReadAttempts = 0; // Number of attempts to read chunk header before giving up
int cbChunkRemain = 0; // Amount of data left to read in chunk
int cbSend = 0; // Size of buffer to send to Client
int cchBuffer; // Total Amount of data in buffer
SOCKET recvSock, sendSock;
recvSock = fRequest ? m_sockClient : m_sockServer;
sendSock = fRequest ? m_sockServer : m_sockClient;
ASSERT(pcchBuffer);
ASSERT(pcchSent);
PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
ASSERT(pBuffer);
cchBuffer = *pcchBuffer;
while (m_fChunked) {
if (0 == cchBuffer) {
// Read some more data if the buffer is empty
dwRetVal = ProxyRecv(recvSock, buffer, &cchBuffer, -1, NULL);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
}
if (cbChunkRemain != 0) {
// We still have data left in the chunk to forward to client
cbSend = (cbChunkRemain < cchBuffer) ? cbChunkRemain : cchBuffer;
cbChunkRemain -= cbSend;
}
else {
// We are at the start of the next chunk
DWORD dwTotalChunkSize;
int cbDeltaRecv = cchBuffer;
dwRetVal = ReadChunkSize(recvSock, buffer, &cchBuffer, &dwChunkSize, &dwChunkHeaderSize);
if (ERROR_SUCCESS != dwRetVal) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Invalid chunk syntax.\n")));
goto exit;
}
pBuffer = buffer.GetBuffer(0, FALSE);
ASSERT(pBuffer);
*pcchBuffer += (cchBuffer - cbDeltaRecv);
dwTotalChunkSize = dwChunkSize + dwChunkHeaderSize + 2;
IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Received chunk of size %d. Forwarding to %s.\n"), dwChunkSize, (fRequest?L"server":L"client")));
if (0 == dwChunkSize) {
m_fChunked = FALSE; // We are done
do {
cbSend = GetHeadersLength(pBuffer);
if (0 == cbSend) {
// Need to recv more data
dwRetVal = ProxyRecv(recvSock, buffer, &cchBuffer, -1, NULL);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
pBuffer = buffer.GetBuffer(0, FALSE);
ASSERT(pBuffer);
}
} while (0 == cbSend);
}
else if (cchBuffer < dwTotalChunkSize) {
cbChunkRemain = dwTotalChunkSize - cchBuffer;
cbSend = cchBuffer;
}
else {
cbSend = dwTotalChunkSize;
}
}
dwRetVal = SendData(sendSock, (char *)pBuffer, cbSend);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
*pcchSent += cbSend;
// If we did not send all data in the buffer, move the rest of the
// data to the front of the buffer.
if (cchBuffer > cbSend) {
memmove(pBuffer, pBuffer + cbSend, cchBuffer - cbSend);
pBuffer[cchBuffer-cbSend] = '\0';
}
cchBuffer -= cbSend;
}
exit:
return dwRetVal;
}
DWORD CHttpSession::HandleFilterRequest(const CHttpHeaders& headers, CBuffer& buffer, BOOL* pfContinue, BOOL* pfCloseConnection)
{
DWORD dwRetVal = ERROR_SUCCESS;
char szNewURLBuf[128];
int cbNewURL = sizeof(szNewURLBuf);
char* pszNewURL = szNewURLBuf;
int cResizeBuf = 0;
ASSERT(pfContinue);
ASSERT(pfCloseConnection);
// If no filter is provided then just return success and leave
// the request unchanged.
if (g_pProxyFilter->GetFilterCount() == 0) {
*pfContinue = TRUE;
return ERROR_SUCCESS;
}
*pfContinue = FALSE;
*pfCloseConnection = FALSE;
stringi strCanonicalizedURL;
strCanonicalizedURL.reserve(headers.strURL.capacity()); // Canonicalized string is no bigger than original
svsutil_HttpCanonicalizeUrlA(headers.strURL, strCanonicalizedURL.get_buffer());
while(1) {
SOCKADDR_IN saPrivate;
saPrivate.sin_family = AF_INET;
g_pSettings->Lock();
saPrivate.sin_addr.S_un.S_addr = inet_addr(g_pSettings->strPrivateAddrV4);
g_pSettings->Unlock();
PROXY_HTTP_REQUEST request;
request.dwSize = sizeof(request);
request.psaClient = (SOCKADDR_STORAGE*)&m_saClient;
request.cbsaClient = sizeof(m_saClient);
request.szUser = m_strUser;
request.cchUser = m_strUser.length();
request.szURL = strCanonicalizedURL;
request.cchURL = strCanonicalizedURL.length();
request.szURLOut = pszNewURL;
request.cbURLOut = cbNewURL;
request.psaProxy = (SOCKADDR_STORAGE*)&saPrivate;
request.cbsaProxy = sizeof(saPrivate);
pszNewURL[0] = '\0';
dwRetVal = g_pProxyFilter->FilterRequest(&request);
if (ERROR_INSUFFICIENT_BUFFER == dwRetVal) {
//
// Only give filter two chances to resize buffer then close session.
//
cResizeBuf++;
if (cResizeBuf > 1) {
dwRetVal = ERROR_INTERNAL_ERROR;
goto exit;
}
//
// Alloc larger buffer if necessary
//
cbNewURL = request.cbURLOut;
pszNewURL = new char[cbNewURL];
if (! pszNewURL) {
dwRetVal = ERROR_OUTOFMEMORY;
goto exit;
}
}
else if (ERROR_NOT_AUTHENTICATED == dwRetVal) {
//
// Filter requires user to be authenticated
//
goto exit;
}
else if (ERROR_SUCCESS != dwRetVal) {
//
// Internal error in ProxyFilterHttpRequest
//
goto exit;
}
else {
//
// Function succeeded. If URLs are the same afterwards then just continue with
// the request. Otherwise, handle the denied request.
//
if (strCanonicalizedURL == request.szURLOut) {
*pfContinue = TRUE;
break;
}
else if ((0 == request.cbURLOut) || (0 == strcmp(request.szURLOut, ""))) {
*pfCloseConnection = TRUE;
dwRetVal = SendMessage(m_sockClient, "403", gc_Reason403, NULL, 0);
goto exit;
}
else {
ClearRecvBuf(buffer);
dwRetVal = SendDeniedRequest(m_sockClient, request.szURLOut);
goto exit;
}
}
}
exit:
if (szNewURLBuf != pszNewURL) {
delete[] pszNewURL;
}
return dwRetVal;
}
//
// Miscellaneous functions used by session objects
//
DWORD GetHeadersLength(const PBYTE pBuffer)
{
DWORD dwLenEnd = 4;
ASSERT(pBuffer);
// Read until CRLF x2
char* chEnd = strstr((char*)pBuffer, "\r\n\r\n");
if (chEnd == NULL) {
// Or LFx2
dwLenEnd = 2;
chEnd = strstr((char*)pBuffer, "\n\n");
if (chEnd == NULL) {
return 0;
}
}
return (chEnd - (char*)pBuffer) + dwLenEnd;
}
DWORD NonBlockingRecv(SOCKET sock, PBYTE pBuffer, int cbBuffer, int* piBytesRecved)
{
DWORD dwRetVal = ERROR_SUCCESS;
FD_SET sockSet;
ASSERT(piBytesRecved);
ASSERT(INVALID_SOCKET != sock);
timeval timeout = {0};
timeout.tv_sec = 10;
FD_ZERO(&sockSet);
FD_SET(sock, &sockSet);
int iSockets = select(0,&sockSet,NULL,NULL,&timeout);
if ((SOCKET_ERROR == iSockets) || (0 == iSockets)) {
dwRetVal = ERROR_TIMEOUT;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: NonBlockingRecv timed out trying to recv data\n")));
goto exit;
}
*piBytesRecved = recv(sock, (char *)pBuffer, cbBuffer, 0);
if ((SOCKET_ERROR == *piBytesRecved)) {
dwRetVal = WSAGetLastError();
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Recv on sock %d, buf 0x%08X, len %d, failed with error %d.\n"), sock, pBuffer, cbBuffer, dwRetVal));
goto exit;
}
if (0 == *piBytesRecved) {
dwRetVal = ERROR_NO_DATA;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Recv on sock %d, buf 0x%08X, len %d, cannot receive anymore data.\n"), sock, pBuffer, cbBuffer));
goto exit;
}
exit:
return dwRetVal;
}
DWORD SendDeniedRequest(SOCKET sock, const char* pszURL)
{
CHttpHeaders response;
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: HTTP request has been denied. A new URL is being substituted.\n")));
response.strStatusCode = "302";
response.strReason = gc_Reason302;
response.strContentLength = "0";
response.strContentType = "text/html";
response.strLocation = pszURL;
response.UpdateResponse();
// Send "Found" message with new URL
return SendCustomPacket(sock, response);
}
DWORD SendMessage(SOCKET sock, const char* szCode, const char* szReason, const char* szContent, int cchContent)
{
DWORD dwRetVal = ERROR_SUCCESS;
CHttpHeaders response;
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Sending response with code %hs.\n"), szCode));
response.strStatusCode = szCode;
response.strReason = szReason;
char szBuf[5];
response.strContentLength = _itoa(cchContent, szBuf, 10);
response.UpdateResponse();
dwRetVal = SendCustomPacket(sock, response);
if (cchContent && (ERROR_SUCCESS == dwRetVal)) {
dwRetVal = SendData(sock, szContent, cchContent);
}
return dwRetVal;
}
DWORD SendCustomPacket(SOCKET sock, CHttpHeaders& headers)
{
DWORD dwRetVal = ERROR_SUCCESS;
CBuffer buffer;
PBYTE pBuffer;
int cbSize = headers.GetBufferSize();
pBuffer = buffer.GetBuffer(cbSize + 1); // Add one for terminating null char
if (! pBuffer) {
dwRetVal = ERROR_OUTOFMEMORY;
goto exit;
}
headers.GetResponseBuffer(pBuffer);
dwRetVal = SendData(sock, (char *)pBuffer, cbSize);
#ifdef DEBUG
if (ERROR_SUCCESS != dwRetVal) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Send returned error on sock %d (error:%d) with %d bytes.\n"), sock, dwRetVal, cbSize));
}
#endif //DEBUG
exit:
return dwRetVal;
}
DWORD SendData(SOCKET sock, const char* szData, int cbData)
{
int cbSent = send(sock, szData, cbData, 0);
if (SOCKET_ERROR == cbSent) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Send returned error %d with %d bytes.\n"), WSAGetLastError(), cbSent));
return WSAGetLastError();
}
else {
#ifdef DEBUG
if (cbSent != cbData) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Tried to send %d bytes but actually sent %d bytes.\n"), cbData, cbSent));
ASSERT(0);
}
#endif // DEBUG
return ERROR_SUCCESS;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -