8.2 Using the HTTP CONNECT Method with the HTTPS Package
The HTTP CONNECT method creates an end-to-end tunnel between two machines through a proxy/firewall machine.
The HTTP CONNECT method can be used only with the client class (in our case RWHttpsSecureSocketClient).
If you want to access secure content on a machine behind a proxy, your application must:
1. Connect to the proxy insecurely.
Normally, when using RWHttpsSecureSocketClient, the connection is secure from the time of connection. To start out as a nonsecure HTTP client so that the application can connect to the proxy, pass the enumeration RW_HTTPS_START_INSECURE as the second parameter to the static make() function of RWHttpsSecureSocketClient. At this point, the class behaves like class RWHttpSocketClient in the HTTP package.
For more information about connecting to proxies, see the chapter on the HTTP protocol in the Internet Protocols Module User’s Guide.
2. Ask the proxy to create a tunnel to the secure machine.
After step 1, your application can use standard HTTP commands to connect to the proxy and send the CONNECT request for a tunnel to the remote (secure) server.
3. Direct the HTTPS package to begin using security. Do this by calling the secureUpgrade() member function on RWHttpsSecureSocketClient. The function returns true if a secure connection is established.
After the CONNECT request returns from the proxy successfully, your channel to the secure server is established, as if you had connected to the server directly.
From this point on, you can use standard HTTP client commands to write your application.
Example 14 – HTTPS CONNECT Example
// File: examples/https/SecureProxyRequestDocument.cpp
 
#include <stdlib.h>
 
#include <rw/network/RWWinSockInfo.h>
#include <rw/internet/RWURL.h>
#include <rw/http/RWHttpRequest.h>
 
#include <rw/secsock/RWSecureSocketPackageInit.h>
#include <rw/https/RWHttpsSecureSocketClient.h>
 
# include <iostream>
using std::cout;
using std::cerr;
using std::endl;
 
// wait at most 5 seconds for each call to connect, submit, or
// getReplay on RWHttpClient to complete.
const int networkMaxWait = 5000;
 
// This data is used to seed the RNG. Extremely insecure!
const unsigned char seed[] = “123456789012345678901234567890”
“123456789012345678901234567890”
“123456789012345678901234567890”
“123456789012345678901234567890”
“123456789012345678901234567890”;
 
int main(int argc, char** argv)
{
RWWinSockInfo winsock;
RWSecureSocketPackageInit secsock;
 
RWSecureSocketPackageInit::seedRGNFromMemory(seed, sizeof(seed));
 
if (argc < 4)
{
cerr << "Usage: " << argv[0]
<< " <proxy host> <proxy port> <URL>" << endl;
return 1;
}
 
RWSecureSocketContext context;
context.prepareToAuthenticate(“../manual/certs/TrustedCerts.pem”);
 
RWCString proxyHost = argv[1];
int proxyPort = atoi(argv[2]);
 
RWURL url(argv[3]);
 
RWHttpsSecureSocketClient client
client = RWHttpsSecureSocketClient::make(context,
RW_HTTPS_START_INSECURE); //1
RWCString actualServer(url.getHost() + ":" + url.getPort());
 
RWHttpRequest makeTunnelRequest(RWHttpRequest::Connect,
actualServer); //2
try {
client.connect(proxyHost, proxyPort, networkMaxWait); //3
client.submit(makeTunnelRequest, RW_HTTP_FORBID_PIPELINING,
networkMaxWait); //4
 
RWHttpReply reply = client.getReply(networkMaxWait);
if(!reply.is2XX()) { //5
cerr << "Failed to establish tunnel through proxy" << endl;
return 1;
}
 
if(!client.secureUpgrade()) { //6
cerr << "Failed to upgrade to secure client" << endl;
return 1;
}
 
// Create and submit the request (securely) to the server behind the proxy
RWHttpRequest actualRequest(RWHttpRequest::Get, RWCString("/")
+ url.getPath());
client.submit(actualRequest, RW_HTTP_FORBID_PIPELINING,
networkMaxWait); //7
 
reply = client.getReply(networkMaxWait);
cout << reply.asString() << endl;
 
if(!reply.is2XX()) { //8
cerr << “Invalid server reply code” << endl;
return 1;
}
 
cout << reply.getBody() << endl;
}
catch(const RWxmsg& msg)
{
cerr << "Error: " << msg.why() << endl;
return 1;
}
catch(...)
{
cerr << “Error: Unexpected exception.” << endl;
return 1;
}
 
return 0;
}
//1 Starts the HTTPS client insecurely (using a standard TCP/IP socket) by passing RW_HTTPS_START_INSECURE as the second parameter to make().
//2 Creates the CONNECT request with the name of the “real” server (the server behind the proxy).
//3 Connects our client to the proxy machine.
//4 Submits our CONNECT request, which asks the proxy to set up a tunnel to the real machine.
//5 If a successful (200 series) reply is returned from the server, the tunnel has been established.
//6 Calls secureUpgrade() to start using SSL.
//7 Constructs and submits our request to the actual server (behind the proxy).
//8 Finally, on success, displays the page received from the server.