[ 
https://issues.apache.org/jira/browse/AXISCPP-899?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12671290#action_12671290
 ] 

Ryan McCullough commented on AXISCPP-899:
-----------------------------------------

I think I have a solution for this incident.

I had to change 4 files, all under axis/transport/axis3/:
HTTPTransport.cpp:
cut all of the #define ASCII_* stuff

IChannel.hpp:
Paste all of the #define ASCII_* stuff from HTTPTransport.cpp. I needed to do 
this so that they were available to the SSL channel.

HTTPSSLChannel\HTTPSSLChannel.hpp:
add the following to the protected section:
    bool                proxyConnect();
    int                 writeProxyConnect();
    int                 readProxyConnect(char* pRxBuffer);

HTTPSSLChannel\HTTPSSLChannel.cpp:
add the following:
/**
 * HTTPSSLChannel::writeProxyConnect()
 *
 * This method writes the CONNECT method unencrypted to the open channel.
 *
 * 02/04/2009 rmccullough
 *
 * Based off the "CONNECT" method 
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.9),
 * part of "Hypertext Transfer Protocol -- HTTP/1.1" 
(http://www.w3.org/Protocols/rfc2616/rfc2616.html)
 *
 * "Tunneling SSL Through a WWW Proxy"
 * by Ari Luotonen, December 14, 1995
 * http://muffin.doit.org/docs/rfc/tunneling_ssl.html
 *
 * "Tunneling TCP based protocols through Web proxy servers"
 * by Ari Luotonen, August 1998
 * 
http://www.web-cache.com/Writings/Internet-Drafts/draft-luotonen-web-proxy-tunneling-01.txt
 *
 * SSL tunneling patch for CERN httpd
 * http://www.w3.org/Daemon/User/Patch/SSL.patch
 *
 *
 * @param buf Character pointer pointing to the array of character containing 
the message to be transmitted.
 * @param numBytes The number of bytes in the message to be transmitted.
 * @return The number of bytes sent.
 */
bool HTTPSSLChannel::
proxyConnect()
{
    // return value, default to failure
    bool bSuccess = (bool)AXIS_FAIL;

    // request a CONNECT to the server
    int nBytesSent = writeProxyConnect();
    
    // variables needed for recieving data
    int iHTTPStatus = 100;
    int iBytesReceived = 0;
    int iBytesLeft = 0;
    char* pRxBuffer = new char [BUF_SIZE];
    string strBytesReceived;
    string strResponseHTTPHeaders;
    
    // loop while the response is valid
    do
    {
        while (strBytesReceived.find(ASCII_S_HTTP) == std::string::npos 
            || strBytesReceived.find(ASCII_S_CRLFCRLF) == std::string::npos)
        {
            iBytesReceived = readProxyConnect(pRxBuffer);
    
            if (iBytesReceived > 0)
            {
                strBytesReceived += pRxBuffer;
                iBytesLeft = strBytesReceived.length();
            }
            else
            {
                throw 
HTTPTransportException(SERVER_TRANSPORT_INPUT_STREAMING_ERROR,
                                              "Socket connection has been 
closed.");
            }
        }
    
        // At this point the HTTP header has been found. Seperate the response 
headers
        // from the payload (i.e. SOAP message). 
        string::size_type iHTTPStart = strBytesReceived.find(ASCII_S_HTTP);
        string::size_type iHTTPEnd   = strBytesReceived.find(ASCII_S_CRLFCRLF, 
iHTTPStart);
    
        strResponseHTTPHeaders = strBytesReceived.substr(iHTTPStart, iHTTPEnd + 
4 - iHTTPStart);
        
        // Process the HTTP header
        PLATFORM_ASCTOSTR(strBytesReceived.c_str());
        string strHTTPStatus = strBytesReceived.substr(strlen("HTTP/1.x "), 3);
        iHTTPStatus = atoi(strHTTPStatus.c_str());
    }
    while(iHTTPStatus == 100);
    
    // delete the Rx buffer
    delete[] pRxBuffer;
    
    // Now have a valid HTTP header that is not 100. Throw an exception if some 
unexpected error.
    // Note that error 500 are for for SOAP faults.
    if (iHTTPStatus != 500 && (iHTTPStatus < 200 || iHTTPStatus >= 300))
    {
        throw HTTPTransportException(SERVER_TRANSPORT_HTTP_EXCEPTION, "Server 
sent HTTP error: \n");
    }
    if (iHTTPStatus == 200)
    {
        bSuccess = (bool)AXIS_SUCCESS;
    }
    return bSuccess;
}

int HTTPSSLChannel::
writeProxyConnect()
{
    // send buffer
    char buf[1024];
    
    // server port, not proxy port
    unsigned int uiPort = m_URL.getPort();

    // the header should look liks this:
    // CONNECT home1.netscape.com:443 HTTP/1.0
    sprintf(buf, "CONNECT %s:%u HTTP/1.1\r\n\r\n", m_URL.getHostName(), uiPort);

    // get the number of bytes, needed for send()
    int numBytes = strlen(buf);

    //
    // SEND THE CONNECT
    //
    if (INVALID_SOCKET == m_Sock)
    {
        m_LastError = "No valid socket to perform write operation.";
        throw HTTPTransportException( SERVER_TRANSPORT_INVALID_SOCKET, 
m_LastError.c_str());
    }

    int nByteSent = 0;

#ifdef __OS400__
    if ((nByteSent = send( m_Sock, (char *)buf, numBytes, 0)) == SOCKET_ERROR) 
#else
    if ((nByteSent = send( m_Sock, buf, numBytes, 0)) == SOCKET_ERROR) #endif
    {
        // This must be done first before closing channel in order to get 
actual error.
        m_LastError = "Error sending data.";

        // Close the channel and throw an exception.
        CloseChannel();

        throw HTTPTransportException( SERVER_TRANSPORT_OUTPUT_STREAMING_ERROR, 
m_LastError.c_str());
    }
    return nByteSent;
}

int HTTPSSLChannel::
readProxyConnect(char* buf)
{
    //
    // RECEIVE THE CONNECT
    //
    if (INVALID_SOCKET == m_Sock)
    {
        m_LastError = "Unable to perform read operation.";
        throw HTTPTransportException( SERVER_TRANSPORT_INVALID_SOCKET, 
m_LastError.c_str());
    }

    int nByteRecv = 0;
    int iBufSize = BUF_SIZE - 10;

    // If timeout set then wait for maximum amount of time for data
    if (m_lTimeoutSeconds)
    {
        int iTimeoutStatus = applyTimeout();

        // Handle timeout outcome
        if (iTimeoutStatus < 0)
        {
            throw HTTPTransportException( SERVER_TRANSPORT_TIMEOUT_EXCEPTION, 
m_LastError.c_str());
        }
    
        if (iTimeoutStatus == 0)
        {
            m_LastError = "Read operation timed-out while waiting for data.";
            throw HTTPTransportException( SERVER_TRANSPORT_TIMEOUT_EXPIRED, 
m_LastError.c_str() );
        }
    }

    // Either timeout was not set or data available before timeout; so read
    nByteRecv = recv( m_Sock, buf, iBufSize, 0);
    if (nByteRecv == SOCKET_ERROR)
    {
        // This must be done first before closing channel in order to get 
actual error.
        m_LastError = "Error receiving data.";

        // Close the channel and throw an exception.
        CloseChannel();

        if(!bNoExceptionOnForceClose)
        {
            throw HTTPTransportException( 
SERVER_TRANSPORT_INPUT_STREAMING_ERROR, m_LastError.c_str());
        }
    }
    else if ( 0 == nByteRecv )
    {
        // read-side of socket is closed.
    }
    else if (nByteRecv)
    {
        buf[nByteRecv] = '\0';
    }
    return nByteRecv;
}

My source files are somewhat out of date with what is in subversion, but I 
attached them.



> tunnel https connections over http proxies
> ------------------------------------------
>
>                 Key: AXISCPP-899
>                 URL: https://issues.apache.org/jira/browse/AXISCPP-899
>             Project: Axis-C++
>          Issue Type: New Feature
>          Components: Transport (Client)
>    Affects Versions:  1.6 Beta
>            Reporter: Franz Fehringer
>
> The necessary steps for this scheme would be (to my best knowledge)
> 1) connect normally to proxy
> 2) send http CONNECT request (with remote address as argument)
> 3) now we have a connection to the remote host (descriptor from step 1)
> 4) do SSL handshake
> 5) ready for normal SSL/HTTPS communication

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to