Reputation: 1029
I'm trying to send a http GET request using the REST API of some domain. Basically what I'm trying to do is to replace following curl request:
curl -k -H "Content-Type: application/json" -X GET
--data '{"username":"[email protected]", "password":"test"}' https:/domain.name/api/login/
with some c++ code using boost::asio
.
I do not what to find all c++ code here , but some checkpoints would be great.
Upvotes: 7
Views: 33022
Reputation: 3690
I found myself also working with boost
in order to send some "customized" HTTP GET request - I ran the server locally on my Ubuntu machine (16.04).
In my case the request was of some proprietary API my server implemented (related to words it kept in its data base), but you can modify the queryStr
variable to hold whatever query string you wish for.
Also, change the argv[1]
and argv[2]
when you ran the program to hold your required values (IP address, query, and port if needed - default is 80).
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using namespace std;
int main(int argc, char* argv[])
{
cout << "main -start" << endl;
try
{
boost::asio::io_service io_service;
string ipAddress = argv[1]; //"localhost" for loop back or ip address otherwise, i.e.- www.boost.org;
string portNum = argv[2]; //"8000" for instance;
string hostAddress;
if (portNum.compare("80") != 0) // add the ":" only if the port number is not 80 (proprietary port number).
{
hostAddress = ipAddress + ":" + portNum;
}
else
{
hostAddress = ipAddress;
}
string wordToQuery = "aha";
string queryStr = argv[3]; //"/api/v1/similar?word=" + wordToQuery;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query(ipAddress, portNum);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << queryStr << " HTTP/1.1\r\n"; // note that you can change it if you wish to HTTP/1.0
request_stream << "Host: " << hostAddress << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout << "Invalid response\n";
return 1;
}
if (status_code != 200)
{
std::cout << "Response returned with status code " << status_code << "\n";
return 1;
}
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
{
std::cout << header << "\n";
}
std::cout << "\n";
// Write whatever content we already have to output.
if (response.size() > 0)
{
std::cout << &response;
}
// Read until EOF, writing data to output as we go.
boost::system::error_code error;
while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error))
{
std::cout << &response;
}
if (error != boost::asio::error::eof)
{
throw boost::system::system_error(error);
}
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << "\n";
}
return 0;
}
The original example I followed is here: Boost-simple-http-get-request-sync-client
Upvotes: 8
Reputation: 7357
boost::asio
is not an application level library. So you can open a connection with it, do an SSL handshake and so on. But you cannot construct HTTP requests via boost::asio
since it's designed to just send/receive data.
But, you can try to experiment with this asio HTTP client example. Probably this can be a good thing to start with.
Upvotes: 7
Reputation: 1556
There is an Urdl library, created by Christopher M. Kohlhoff, the author of Boost.Asio:
Urdl is a cross-platform C++ library for downloading web content using a URL. It provides an easy-to-use extension to standard C++ iostreams and an asynchronous interface for use with Boost.Asio.
Your request sample would be like following:
#include <urdl/http.hpp>
urdl::istream is;
// Set request options: method, content type, content
is.set_option(urdl::http::request_method("GET"));
is.set_option(urdl::http::request_content_type("application/json"));
is.set_option(urdl::http::request_content("{\"username\":\"[email protected]\", \"password\":\"test\"}"));
// open HTTP stream at URL
is.open("https:/domain.name/api/login/");
Upvotes: 4