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.
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;
}