5.3 Using the HTTP Classes
This section describes how to connect to a server, create a request, send a request, retrieve a reply, and interpret a reply.
5.3.1 Connecting to the Server
Example 4 connects an application to a server using an RWHttpClient. It initializes the RWHttpClient object and specifies the HTTP server to connect to.
Servers and files shown in the code might not exist and are included as examples only.
Example 4 – Connecting to the server
RWHttpClient client = RWHttpSocketClient::make(); //1
try {
client.connect("www.roguewave.com"); //2
} catch (const RWxmsg& msg) {
// error...
}
//1 Initializes the client object by assigning an initialized RWHttpSocketClient object created from the static make function. The RWHttpSocketClient uses an RWSocketPortal internally to communicate with the server. You can create other clients to communicate with the server through another channel (such as over a secure socket).
//2 The client attempts to establish a connection to the server (www.roguewave.com). If any errors occur that prevent the client from establishing a connection to the server, an exception is thrown.
RWHttpClient defaults to port 80 on the server specified. If you want to connect to the HTTP server on an alternate port, you can pass an optional argument to the connect method, as shown below.
 
client.connect("www.roguewave.com", 8001);
This invocation connects to the HTTP server running on port 8001 of the www.roguewave.com server.
RWHttpAgent does not have an explicit connection mechanism because connections to HTTP servers are established automatically as they are needed to fill requests. All RWHttpAgent instances are automatically valid on construction.
 
RWHttpAgent agent;
5.3.2 Creating a Request
The RWHttpClient classes encapsulate HTTP requests within the helper class RWHttpRequest. All HTTP requests must specify:
*The method to execute on the server
*The path to the document that the method will act on
*The version of the HTTP protocol that the request conforms to
*Any HTTP headers that are required by the type of request
Example 5 constructs an HTTP GET request to the root document of the HTTP server. The request does not include any user-defined HTTP headers, however an HTTP Host header is automatically added to the request before sending the request to the server. For more information about adding additional HTTP headers or modifying the default headers, see Section 5.4.4, “Adding and Removing Headers.”
Example 5 – Creating a request
RWHttpRequest request(RWHttpRequest::Get, "/");
RWHttpRequest objects default to HTTP/1.1 formatted request, however the major and minor versions of the request can be set through member functions:
 
request.setVersion(1, 0);
This example converts the RWHttpRequest into an HTTP/1.0 request with all of the restrictions associated with HTTP/1.0 requests. Unless a server specifically cannot accept HTTP/1.1 formatted requests, use the default.
5.3.3 Sending a Request
After an RWHttpClient is connected to an HTTP server and an RWHttpRequest object is constructed, your application can submit the request to the client so that it can be sent to the server.
Example 6 – Submitting a request to the client
try {
client.submit(request);
} catch(const RWxmsg& msg) {
// error...
}
The submit method evaluates the request object to ensure that it is complete. If it is, it is sent to the associated HTTP server. Based on the client and request constructed before, the submit method in Example 6 sends the following request to the server:
 
GET / HTTP/1.1
Host: www.roguewave.com
The RWHttpAgent class uses member functions in order to submit requests to a server. Because RWHttpAgents are not explicitly connected to any servers, additional information must be passed to the request so that it can determine where the request must be sent. An RWURL object encapsulates the information required by the RWHttpAgent class.
Example 7 – Using RWURL
RWURL url("http://www.roguewave.com/");
RWTIOUResult<RWHttpReply> replyIOU = agent.executeGet(url);
All RWHttpAgent execute methods return an RWTIOUResult that contains the response from the server after the request has completed. For more information on the RWTIOUResult class, see the following:
*Section 2.4, “Multithreading and IOUs,” of this user’s guide
*Threads Module User’s Guide
*SourcePro C++ API Reference Guide
5.3.4 Retrieving a Reply
After an HTTP request is submitted, the server processes it and sends a response back to the client. Your application can retrieve the reply from the RWHttpClient object using the getReply() method:
 
RWHttpReply reply = client.getReply();
The getReply() method returns an RWHttpReply object. The getReply() method blocks until the complete reply from the server is read.
RWHttpAgent combines the request and retrieval steps of RWHttpClient into a single request as mentioned in Section 5.3.3, “Sending a Request.” Because the RWHttpAgent request returns immediately with an RWTIOUResult object, your application must ensure that the request is complete before attempting to access the results of the request:
 
RWHttpReply reply = replyIOU.redeem();
The redeem() method of an RWTIOUResult object blocks until the request is complete and the result is fully retrieved from the server. After the reply object is redeemed, the resulting reply is no different than one retrieved through an RWHttpClient request.
5.3.5 Interpreting the Reply
An RWHttpReply object has several member functions that access the information returned from the HTTP server. These functions can retrieve:
*Headers
*Status code and status message
*Version of the HTTP response
*Body of the message
Example 8 shows how to check the status of the reply, and how to retrieve the body of the message. It checks the status of the reply to ensure that the request is successful.
Example 8 – Checking the status and retrieving the body of the message
if(reply.is2XX()) {
cout << reply.getBody() << endl;
}
A status code in the 200 range usually indicates success. For more information about status codes, see RFC 2616, which defines the HTTP protocol.
If the reply is successful, the body of the message is retrieved as an RWCString, and the message body is streamed to stdout.
5.3.6 Bringing it All Together
Example 9 is a complete document request using an RWHttpClient.
Example 9 – Requesting a document using an RWHttpClient
RWHttpClient client; // 1
RWHttpRequest request(RWHttpRequest::Get, "/"); // 2
client = RWHttpSocketClient::make(); // 3
try {
client.connect("www.roguewave.com"); // 4
client.submit(request); // 5
RWHttpReply reply = client.getReply(); // 6
 
cout << reply.asString() << endl; // 7
 
if(reply.is2XX()) { // 8
cout << reply.getBody() << endl; // 9
}
} catch(const RWxmsg& msg) { // 10
// error...
}
//1 Creates an uninitialized RWHttpClient. The client object needs to be initialized before it can be used.
//2 Constructs an RWHttpRequest object to get the root document on the server.
//3 Initializes the RWHttpClient as an RWHttpSocketClient. The RWHttpSocketClient uses an RWSocketPortal to communicate with the server.
//4 Attempts to connect the RWHttpClient to an HTTP server running on www.roguewave.com. The client assumes that the server is running on port 80.
//5 Submits a request to the HTTP server associated with the RWHttpClient. If problems with the RWHttpRequest are detected, the client does not send any data to the server and instead throws an exception describing the problem.
//6 Retrieves the HTTP response from the client and stores it in an RWHttpReply object. This function blocks until a complete reply is read from the server.
//7 Prints the basic information associated with the server's reply. This function formats and prints the status code and status message, the HTTP version of the response, and any headers that were associated with the reply.
//8 Checks the status of the RWHttpReply object, and ensures that it was successful (in the 200 range).
//9 Retrieves the body of the message from the reply. The body is generally the HTML document stored at the location specified, but any type of data may be returned by the server and stored in this string.
//10 Catches any errors that are thrown while attempting to process the HTTP request.
Example 10 shows the same request to an HTTP server using RWHttpAgent. It is a simple HTTP request-response interaction using only a single HTTP method (GET).
Example 10 – Requesting a document using an RWHttpAgent
RWHttpAgent agent; // 1
RWURL url("http://www.roguewave.com/"); // 2
RWTIOUResult<RWHttpReply> replyIOU; // 3
 
try {
replyIOU = agent.executeGet(url); // 4
RWHttpReply reply = replyIOU.redeem(); // 5
 
cout << reply.asString() << endl;
 
if (reply.is2XX()) {
cout << reply.getBody() << endl;
}
} catch(const RWxmsg& msg) {
// error...
}
//1 Constructs an RWHttpAgent. No initialization is necessary for this class.
//2 Constructs an RWURL for the root document on the www.roguewave.com server.
//3 Constructs an RWTIOUResult<> object to hold the return value from the execute command.
//4 Executes a GET request on the document located at url.
//5 Redeems the RWTIOUResult<> for an RWHttpReply object. This method blocks until the request executed in //4 completes.
For more advanced examples, see the examples in the next section and the sample programs distributed with the HTTP package. Sample programs are located in the examples directory created for your installation. For more information, see the Installing and Building Your SourcePro C++ Products and Building Your Applications.