⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 session.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//

#include "session.h"
#include "proxydbg.h"
#include "filter.h"
#include <ws2tcpip.h>

const char gc_szProxyPac[] =
"function FindProxyForURL(url, host)\n"
"{\n"
"if (isInNet(host, \"%s\", \"%s\"))\n"
"{\n"
"return \"DIRECT\";\n"
"}\n"
"if (isPlainHostName(host))\n"
"{\n"
"return \"DIRECT\";\n"
"}\n"
"if (host == \"127.0.0.1\")\n"
"{\n"
"return \"DIRECT\";\n"
"}\n"
"if (url.substring(0, 6) == \"https:\" ||\n"
"url.substring(0, 5) == \"http:\")\n"
"{\n"
"return \"PROXY %s:%d\";\n"
"}\n"
"return \"DIRECT\";\n"
"}\n";


CHttpSession::CHttpSession(void) :
    m_fRunning(FALSE),
    m_fSSLTunnel(FALSE),
    m_fSSLTunnelThruSecondProxy(FALSE),
    m_fAuthInProgress(FALSE),
    m_fChunked(FALSE),
    m_dwSessionId(0),
    m_cbResponseRemain(0),
    m_cbRequestRemain(0)
{
}

CHttpSession::~CHttpSession(void)
{
}

void CHttpSession::SetId(DWORD dwSessionId)
{
    SessionLock();
    m_dwSessionId = dwSessionId;
    SessionUnlock();
}

DWORD CHttpSession::GetId(void)
{
    DWORD dwId;
    
    SessionLock();
    dwId = m_dwSessionId;
    SessionUnlock();

    return dwId;
}

DWORD CHttpSession::Start(SessionSettings* pSettings)
{
    DWORD dwRetVal = ERROR_SUCCESS;

    ASSERT(pSettings);
    
    SessionLock();

    ASSERT(! m_fRunning);

    // Set session data
    m_sockClient = pSettings->sockClient;
    m_saClient = pSettings->saClient;

    m_fRunning = TRUE;

    memset(&m_auth, 0, sizeof(AUTH_NTLM));
    m_auth.m_Conversation = NTLM_NO_INIT_CONTEXT;

    // Create a thread to handle the session
    g_pThreadPool->ScheduleEvent(SessionThread, this);

    SessionUnlock();
    return ERROR_SUCCESS;
}

DWORD CHttpSession::Shutdown(void)
{
    DWORD dwRetVal = ERROR_SUCCESS;

    SessionLock();

    ASSERT(m_fRunning);

    // Change thread status to signal shutdown
    m_fRunning = FALSE;

    IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Closing client socket in session %d, sock=%d\n"), m_dwSessionId, m_sockClient));
    IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: If valid, we will also close server socket in session %d, sock=%d\n"), m_dwSessionId, m_sockServer));
    
    // Delete socket data (unblock any blocking socket calls)
    if (SOCKET_ERROR == closesocket(m_sockClient)) {
        IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error closing client socket in session %d, error: %d\n"), m_dwSessionId, WSAGetLastError()));
    }    
    if (m_sockServer.valid() && (SOCKET_ERROR == closesocket(m_sockServer))) {
        IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error closing server socket in session %d, error: %d\n"), m_dwSessionId, WSAGetLastError()));
    }

    SessionUnlock();
    return dwRetVal;
}

DWORD WINAPI CHttpSession::SessionThread(LPVOID pv)
{
    CHttpSession* pInst = (CHttpSession*) pv;
    pInst->Run();
    return 0;
}

void CHttpSession::Run(void)
{
    DWORD dwErr;
    FD_SET sockSet;
    CBuffer buffer;
    BOOL fCloseSessionReq = FALSE;
    BOOL fCloseSessionResp = FALSE;

    IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Session %d has been started.\n"), m_dwSessionId));

    timeval timeout = {0};
    timeout.tv_sec = g_pSettings->iSessionTimeout;

    SessionLock();
    
    while (1) {
        //
        // Loop for the lifetime of the session
        //

        BOOL fServerConnected = FALSE;
        FD_ZERO(&sockSet);

        FD_SET(m_sockClient, &sockSet);
        if (m_sockServer.valid()) {
            fServerConnected = TRUE;
            FD_SET(m_sockServer, &sockSet);
        }

        SessionUnlock();
        int iSockets = select(0,&sockSet,NULL,NULL,&timeout);
        SessionLock();
    
        // Check if session was closed while blocking on select
        if (! m_fRunning) {
            IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Session %d has been signalled to shutdown.\n"), m_dwSessionId));
            break;
        }

        if (SOCKET_ERROR == iSockets) {
            IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Select call failed in session %d, error: %d.\n"), m_dwSessionId, WSAGetLastError()));
            break;
        }

        if (0 == iSockets) {
            IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Session %d has expired\n"), m_dwSessionId));
            break;
        }

        //
        // Make sure the connections are not being closed
        //

        if (FD_ISSET(m_sockClient, &sockSet)) {
            DWORD dwAvailable = 0;
            if (SOCKET_ERROR == ioctlsocket(m_sockClient, FIONREAD, &dwAvailable)) {
                IFDBG(DebugOut(ZONE_WARN, _T("WebProxy: Failed to query how much data is available on socket %d\n"), WSAGetLastError()));
                dwAvailable = 0;
            }

            // If no data is available on client socket then close the session
            if (0 == dwAvailable) {                
                IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: The client socket has been signalled to close.  Closing session %d.\n"), m_dwSessionId));
                break;
            }
        }

        if (fServerConnected && FD_ISSET(m_sockServer, &sockSet)) {
            DWORD dwAvailable = 0;
            if (SOCKET_ERROR == ioctlsocket(m_sockServer, FIONREAD, &dwAvailable)) {
                IFDBG(DebugOut(ZONE_WARN, _T("WebProxy: Failed to query how much data is available on socket %d\n"), WSAGetLastError()));
                dwAvailable = 0;
            }

            // If no data is available on server socket close the session unless auth is in progress in which case we should
            // just close the server socket.
            if (0 == dwAvailable) {
                if (m_fAuthInProgress) {
                    m_sockServer.close();
                    m_strServerName = "";
                    continue;
                }
                break;
            }
        }

        //
        // Check for data on the sockets
        //
        
        if (FD_ISSET(m_sockClient, &sockSet)) {
            //
            // Packet arrived from client
            //

            dwErr = ProcessMessage(buffer, &fCloseSessionReq, TRUE);
            if (ERROR_SUCCESS != dwErr) {
                IFDBG(DebugOut(ZONE_WARN, _T("WebProxy: Due to an internal error when processing a request, session %d is being aborted: %d.\n"), m_dwSessionId, dwErr));
                break;
            }

            if (fCloseSessionReq && (0 == m_cbRequestRemain)) {
                IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Proxy was signalled to close session by a request, session %d is being closed.\n"), m_dwSessionId));
                shutdown(m_sockClient, SD_SEND);
                continue;
            }
        }
        
        if (fServerConnected && FD_ISSET(m_sockServer, &sockSet)) {
            //
            // Packet arrived from server
            //

            dwErr = ProcessMessage(buffer, &fCloseSessionResp, FALSE);
            if (ERROR_SUCCESS != dwErr) {
                IFDBG(DebugOut(ZONE_WARN, _T("WebProxy: Proxy was signalled to close session by a response or an internal error occured, session %d is being closed: %d.\n"), m_dwSessionId, dwErr));
                break;
            }

            if (fCloseSessionResp && (0 == m_cbResponseRemain)) {
                IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Proxy was signalled to close session by a response, session %d is being closed.\n"), m_dwSessionId));
                shutdown(m_sockServer, SD_SEND);
                continue;
            }
        }
    }

    // If we aborted not due to stopping service then we have to clean up the session
    if (m_fRunning) {
        Shutdown();
    }

    SessionUnlock();

    dwErr = g_pSessionMgr->RemoveSession(m_dwSessionId);

#ifdef DEBUG
    if (ERROR_SUCCESS != dwErr) {
        IFDBG(DebugOut(ZONE_WARN, _T("WebProxy: Could not delete session %d, error: %d - potential memory leak\n"), m_dwSessionId, dwErr));
    }
#endif // DEBUG

}

DWORD CHttpSession::ProcessMessage(CBuffer& buffer, BOOL* pfCloseConnection, BOOL fRequest)
{
    DWORD dwRetVal = ERROR_SUCCESS;
    int cchBuffer = 0;
    int cchSent = 0;
    int cchHeaders = 0;        // size of the recved headers 

    IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: %s(s) arrived from server in session %d.\n"), (fRequest?L"Request":L"Response"), m_dwSessionId));

    // This method is generic for both requests and responses.  Need to set the following
    // variables based on fRequest parameter.
    int* pcbRemain = fRequest ? &m_cbRequestRemain : &m_cbResponseRemain;
    SOCKET sock = fRequest ? m_sockClient : m_sockServer;

    //
    // Receive data until at least all the headers have been read.
    //

    dwRetVal = ProxyRecv(sock, buffer, &cchBuffer, *pcbRemain, &cchHeaders);
    if (ERROR_SUCCESS != dwRetVal) {
        goto exit;
    }
        
    IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Received buffer.  Total: %d, Headers: %d, Remaining: %d.  Session %d.\n"), cchBuffer, cchHeaders, m_cbResponseRemain, m_dwSessionId));
    
    //
    // We may have read more than one request since multiple requests can be pipelined.
    //
    while(1) {
        // The proxy will only handle one request/response.  If more than one message is in the buffer, this
        // is determined by the fact that we sent out less data than we received.
        if (fRequest) {
            dwRetVal = HandleClientMessage(buffer, &cchBuffer, cchHeaders, &cchSent, pfCloseConnection);
        }
        else {
            dwRetVal = HandleServerMessage(buffer, &cchBuffer, cchHeaders, &cchSent, pfCloseConnection);
        }

        if (ERROR_SUCCESS != dwRetVal) {
            goto exit;
        }  

        if (m_fChunked) {
            PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
            ASSERT(pBuffer);

            IFDBG(DebugOut(ZONE_SESSION, _T("WebProxy: Detected chunked transfer in session %d.\n"), m_dwSessionId));
            
            // Copy remaining data to beginning of buffer, reset sizes, and keep going
            if (cchBuffer > cchSent) {
                memmove(pBuffer, pBuffer + cchSent, cchBuffer - cchSent);
            }            
            cchBuffer -= cchSent;
            cchSent = 0;
            pBuffer[cchBuffer] = '\0';
            
            // Receive all chunks and forward it to the client
            dwRetVal = HandleChunked(buffer, &cchBuffer, &cchSent, fRequest);
            if (ERROR_SUCCESS != dwRetVal) {
                goto exit;
            }
        }

        if (*pfCloseConnection) {
            break;
        }

        if ((cchSent > 0) && (cchSent < cchBuffer)) {
            PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
            ASSERT(pBuffer);

            IFDBG(DebugOut(ZONE_RESPONSE, _T("WebProxy: Detected pipelined %s.\n"), (fRequest?L"request":L"response")));

            // Copy remaining data to beginning of buffer, reset sizes, and keep going
            memmove(pBuffer, pBuffer + cchSent, cchBuffer - cchSent);
            cchBuffer -= cchSent;
            cchSent = 0;
            pBuffer[cchBuffer] = '\0';
            
            cchHeaders = GetHeadersLength(pBuffer);
            if (0 == cchHeaders) {
                dwRetVal = ProxyRecv(sock, buffer, &cchBuffer, *pcbRemain, &cchHeaders);
                if (ERROR_SUCCESS != dwRetVal) {
                    goto exit;
                }
            }
        }
        else {
            break;
        }
    }

exit:
    return dwRetVal;
}

DWORD CHttpSession::HandleClientMessage(CBuffer& buffer, int* pcchBuffer, int cchHeaders, int* pcchSent, BOOL* pfCloseConnection)
{
    DWORD dwRetVal = ERROR_SUCCESS;
    CHttpHeaders headers;

    *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_cbRequestRemain) {
        //
        // 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_cbRequestRemain >= 0) {
            m_cbRequestRemain -= *pcchBuffer;

            // 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')) {
                    m_cbRequestRemain = 0;
                }
            }
        }
        else {
            *pfCloseConnection = TRUE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -