📄 session.cpp
字号:
}
IFDBG(DebugOut(ZONE_REQUEST, _T("WebProxy: Request data remaining to be read in session %d. Now there are %d bytes left.\n"), m_dwSessionId, m_cbRequestRemain));
*pcchSent = *pcchBuffer;
}
else {
//
// Now that we have all the headers, parse them.
//
BOOL fContinue = TRUE;
BOOL fAdditionalContent = FALSE;
PBYTE pContent = NULL;
CBuffer buffContent;
int cbNewHeaders = 0; // size of the headers after modification
int cbContent = 0; // size of the content in this packet
int cbTotalContent = 0; // total amount of content that has to be recved
dwRetVal = g_pParser->ParseRequest(pBuffer, *pcchBuffer, headers);
if (ERROR_SUCCESS != dwRetVal) {
// If hit this assert then we have encountered an HTTP request that we could not parse
ASSERT(0);
goto exit;
}
ASSERT(headers.strReason == "");
ASSERT(headers.strStatusCode == "");
// The following must be in request headers
if ((headers.strMethod == "") || (headers.strURL == "") || (headers.strVersion == "")) {
dwRetVal = ERROR_INVALID_DATA;
goto exit;
}
IFDBG(DebugOut(ZONE_REQUEST, _T("WebProxy: Request Headers:\n")));
IFDBG(DebugOut(ZONE_REQUEST, _T("WebProxy: -- Method: %hs\n"), (LPCSTR)headers.strMethod));
IFDBG(DebugOut(ZONE_REQUEST, _T("WebProxy: -- Host: %hs\n"), (LPCSTR)headers.strHost));
IFDBG(DebugOut(ZONE_REQUEST, _T("WebProxy: -- Version: %hs\n"), (LPCSTR)headers.strVersion));
if ((headers.strHost == "") && (headers.strVersion == gc_HTTP11)) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: No host header was present, returning Bad Request.\n")));
dwRetVal = SendMessage(m_sockClient, "400", gc_Reason400, NULL, 0);
*pfCloseConnection = TRUE;
goto exit;
}
g_pSettings->Lock();
if (0 == strncmp(headers.strURL, g_pSettings->strProxyPacURL, g_pSettings->strProxyPacURL.length())) {
g_pSettings->Unlock();
dwRetVal = HandleProxyPacRequest();
*pfCloseConnection = TRUE;
goto exit;
}
g_pSettings->Unlock();
m_strCurrMethod = headers.strMethod;
if (headers.strTransferEncoding == gc_TEChunked) {
m_fChunked = TRUE;
}
//
// Determine how much data is left to be read in this request
//
cbTotalContent = atoi(headers.strContentLength);
cbContent = *pcchBuffer - cchHeaders;
m_cbRequestRemain = cbTotalContent - cbContent;
//
// IE and Netscape both append a CRLF to POST data but do not count it as part of the
// content length. If we have read 2 bytes too many then check if these last two bytes
// are CRLF on a POST request and reset the remaining bytes to zero if so.
//
if ((m_strCurrMethod == gc_MethodPost) && (m_cbRequestRemain == -2)) {
if ((*pcchBuffer >= 2) && (pBuffer[*pcchBuffer - 2] == '\r') && (pBuffer[*pcchBuffer - 1] == '\n')) {
cbTotalContent += 2;
m_cbRequestRemain = 0;
}
}
// Only send headers if chunked or if we detected a pipelined request
if (m_fChunked || (m_cbRequestRemain < 0)) {
m_cbRequestRemain = 0;
fAdditionalContent = TRUE;
}
// If this is not a CONNECT request then make sure the protocol is http
if (m_strCurrMethod != gc_MethodConnect) {
if (0 != strncmp(headers.strURL, "http://", 7)) {
ClearRecvBuf(buffer);
dwRetVal = SendMessage(m_sockClient, "502", gc_Reason502, g_pErrors->szProtocolNotSupported, g_pErrors->cchProtocolNotSupported);
goto exit;
}
}
//
// If authentication is in progress, then finish before calling into filter
//
if ((m_strUser == "") && (headers.strProxyAuthorization != "")) {
IFDBG(DebugOut(ZONE_AUTH, _T("WebProxy: Authenticating session %d.\n"), m_dwSessionId));
dwRetVal = HandleAuthentication(headers, buffer, pfCloseConnection);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
// If HandleAuthentication does not return a user then the client
// could not be authenticated in this pass.
if (m_strUser == "") {
goto exit;
}
IFDBG(DebugOut(ZONE_AUTH, _T("WebProxy: Successfully authenticated user %hs.\n"), (LPCSTR)m_strUser));
}
//
// Call into proxy filter
//
dwRetVal = HandleFilterRequest(headers, buffer, &fContinue, pfCloseConnection);
if ((ERROR_NOT_AUTHENTICATED == dwRetVal) && (m_strUser == "")) {
// Need to authenticate before calling filter
IFDBG(DebugOut(ZONE_AUTH, _T("WebProxy: Filter requires authentication in session %d.\n"), m_dwSessionId));
dwRetVal = HandleAuthentication(headers, buffer, pfCloseConnection);
goto exit;
}
else if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
if (! fContinue) {
goto exit;
}
//
// Do not forward the following headers
//
headers.strProxyAuthorization = "";
//
// Handle a CONNECT request
//
if (m_strCurrMethod == gc_MethodConnect) {
//
// Handle the CONNECT request. A connect request can be used to tunnel SSL
// traffic through the HTTP proxy.
//
if (g_pSettings->strSecondProxyHost == "") {
dwRetVal = HandleConnectRequest(headers.strHost, headers.strPort);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
goto exit;
}
else {
m_fSSLTunnelThruSecondProxy = TRUE;
}
}
//
// Handle an OPTIONS request
//
if (m_strCurrMethod == gc_MethodOptions) {
DWORD dwMaxForwards = atoi(headers.strMaxForwards);
if ((headers.strMaxForwards == "") || (0 == dwMaxForwards)) {
dwRetVal = SendMessage(m_sockClient, "200", gc_Reason200, NULL, 0);
goto exit;
}
else if (headers.strMaxForwards != "") {
_itoa(dwMaxForwards-1, headers.strMaxForwards.get_buffer(), 10);
}
}
//
// Check if server socket has been opened yet. If not, open it. If it has been
// opened then verify that we are connected to the correct server for this request.
// If a secondary proxy has been specified, connect to this proxy rather than the
// origin server.
//
if (g_pSettings->strSecondProxyHost != "") {
if ((! m_sockServer.valid()) || (m_strServerName != g_pSettings->strSecondProxyHost)) {
dwRetVal = ConnectServer(g_pSettings->strSecondProxyHost, g_pSettings->iSecondProxyPort);
if (ERROR_SUCCESS != dwRetVal) {
ClearRecvBuf(buffer);
dwRetVal = SendMessage(m_sockClient, "502", "Proxy Error (Invalid data)", g_pErrors->szURLNotFound, g_pErrors->cchURLNotFound);
goto exit;
}
}
}
else if ((! m_sockServer.valid()) || (m_strServerName != headers.strHost)) {
dwRetVal = ConnectServer(headers.strHost);
if (ERROR_SUCCESS != dwRetVal) {
ClearRecvBuf(buffer);
dwRetVal = SendMessage(m_sockClient, "502", "Proxy Error (Invalid data)", g_pErrors->szURLNotFound, g_pErrors->cchURLNotFound);
goto exit;
}
}
//
// Copy the content to a temporary buffer while the new headers are copied back
// to the request buffer. If no content is present in this packet, we do not
// have to worry about copying content around.
//
if (cbContent) {
pContent = buffContent.GetBuffer(cbContent);
if (! pContent) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
memcpy(pContent, &pBuffer[cchHeaders], cbContent);
}
//
// Update the request headers and copy them along with the content into the final
// buffer to be sent to the server
//
headers.UpdateRequest((g_pSettings->strSecondProxyHost != ""));
cbNewHeaders = headers.GetBufferSize();
*pcchBuffer += (cbNewHeaders - cchHeaders);
*pcchSent = fAdditionalContent ? (cbNewHeaders + cbTotalContent) : *pcchBuffer;
pBuffer = buffer.GetBuffer(*pcchBuffer); // add one for a null terminating char
if(! pBuffer) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Insufficient memory to allocate send buffer.\n")));
goto exit;
}
// Fill pBuffer with new headers.
headers.GetRequestBuffer(pBuffer);
// Copy the content back after new headers
if (cbContent) {
memcpy(&pBuffer[cbNewHeaders], pContent, cbContent);
}
}
//
// Send the buffer along to the server
//
dwRetVal = SendData(m_sockServer, (char *)pBuffer, *pcchSent);
exit:
return dwRetVal;
}
DWORD CHttpSession::HandleServerMessage(CBuffer& buffer, int* pcchBuffer, int cchHeaders, int* pcchSent, BOOL* pfCloseConnection)
{
DWORD dwRetVal = ERROR_SUCCESS;
CHttpHeaders headers;
ASSERT(pcchBuffer);
ASSERT(pfCloseConnection);
ASSERT(pcchSent);
*pcchSent = 0;
PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
ASSERT(pBuffer);
if (m_fSSLTunnel) {
//
// If the current connection is just tunnelling SSL data then we do not parse the
// data, simply send it on to the server.
//
*pcchSent = *pcchBuffer;
}
else if (0 != m_cbResponseRemain) {
//
// If we have already parsed the headers and just need to read remaining content
// continuing over on a new packet, then just keep reading.
//
if (m_cbResponseRemain >= 0) {
m_cbResponseRemain -= *pcchBuffer;
}
else {
*pfCloseConnection = TRUE;
}
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Response data remaining to be read. Now there are %d bytes left.\n"), m_cbResponseRemain));
*pcchSent = *pcchBuffer;
}
else if (*pfCloseConnection) {
//
// If pfCloseConnection is true then the proxy should assume the data does not have any
// headers and is just content that has to be read and forwarded to the server. When
// the data is completely read, the server will close the connection.
//
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Reading response data until the connection is closed.\n")));
*pcchSent = *pcchBuffer;
}
else {
//
// Time to parse headers...
//
BOOL fAdditionalContent = FALSE;
PBYTE pContent = NULL;
CBuffer buffContent;
int cbNewHeaders = 0; // size of the headers after modification
int cbContent = 0; // size of the content in this packet
int cbTotalContent = 0; // total amount of content that has to be recved
dwRetVal = g_pParser->ParseResponse(pBuffer, *pcchBuffer, headers);
if (ERROR_SUCCESS != dwRetVal) {
// If hit this assert then we have encountered an HTTP request that we could not parse
ASSERT(0);
goto exit;
}
ASSERT(headers.strMethod == "");
ASSERT(headers.strURL == "");
// The following must be in response headers
if ((headers.strVersion == "") || (headers.strStatusCode == "")) {
dwRetVal = ERROR_INVALID_DATA;
goto exit;
}
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Response Headers:\n")));
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: -- Version: %hs\n"), (LPCSTR)headers.strVersion));
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: -- Status: %hs\n"), (LPCSTR)headers.strStatusCode));
if (headers.strTransferEncoding == gc_TEChunked) {
m_fChunked = TRUE;
}
m_fAuthInProgress = (headers.strStatusCode == "401");
cbContent = *pcchBuffer - cchHeaders;
if (m_fSSLTunnelThruSecondProxy) {
// We need to set up tunnel after response from secondary proxy
if (headers.strStatusCode == "200") {
m_fSSLTunnel = TRUE;
}
else {
*pfCloseConnection = TRUE;
}
}
//
// Determine how much response data needs to still be read in this session.
//
if (m_fChunked) {
m_cbResponseRemain = 0;
cbTotalContent = 0;
fAdditionalContent = TRUE;
}
else if (m_fSSLTunnel) {
m_cbResponseRemain = 0;
}
else if (headers.strContentLength == "" &&
(headers.strStatusCode != "204") &&
(headers.strStatusCode != "304") &&
(strncmp(headers.strStatusCode, "1", 1))) {
IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Content-Length was not specified. Reading response data until server closes connection in session %d.\n"), m_dwSessionId));
cbTotalContent = cbContent;
m_cbResponseRemain = -1; // Signals object that there is an unknown amount of data left to read
*pfCloseConnection = TRUE;
}
else {
cbTotalContent = atoi(headers.strContentLength);
m_cbResponseRemain = cbTotalContent - cbContent;
if (m_cbResponseRemain < 0) {
m_cbResponseRemain = 0;
fAdditionalContent = TRUE;
}
}
//
// Server signalled proxy to close connection
//
if (headers.strConnection == gc_ConnClose) {
headers.strConnection = "";
*pfCloseConnection = TRUE;
}
//
// Copy the content to a temporary buffer while the new headers are copied back
// to the response buffer. If no content is present in this packet, we do not
// have to worry about copying content around.
//
if (cbContent) {
pContent = buffContent.GetBuffer(cbContent);
if (! pContent) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
memcpy(pContent, &pBuffer[cchHeaders], cbContent);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -