Websocket connection with Poco libraries - c++

I have a problem with websocket connection to wss://www.bitmex.com/realtime.
I found an axample in this question: Connect Websocket with Poco libraries , but I can't do the same with my wss:// address.
HTTPClientSession cs("wss://www.bitmex.com", 443);
HTTPRequest request(HTTPRequest::HTTP_CONNECT, "/realtime", HTTPMessage::HTTP_1_1);
request.set("origin", "wss://www.bitmex.com");
HTTPResponse response;
try {
WebSocket* m_psock = new WebSocket(cs, request, response);
//some code
}
catch (std::exception &e) {
std::cout << "Exception " << e.what();
}
I'm always receiving the exception: "Host not found" after string
WebSocket* m_psock = new WebSocket(cs, request, response);

HTTPClientSession takes a host string as the first param but you have given a host string with a protocol on the front.
The samples have a WebSocketServer in Net but sometimes you need to look at the test suite to find more details and it does require a little more work.
See WebSocketTest.cpp for a basic test that uses a WebSocket.

Related

How to assign JSON body to Boost Library 1.70 http::request as POST request?

I am new to the Boost library. I try to create an Rest HTTP request using the Boost::http library.
My question is how can i simply assign the JSON payload to the http request.
the following code snippet shows my current try which connects successfully but the payload is not assigned.
http::request<http::string_body> req{ http::verb::post, LOGIN_PATH, 10 };
req.set(beast::http::field::content_type, "application/json");
req.body() = std::move(serviceUser);
// Send the HTTP request to the remote host
http::write(stream, req);
// This buffer is used for reading and must be persisted
beast::flat_buffer buffer;
// Declare a container to hold the response
http::response<http::dynamic_body> res;
// Receive the HTTP response
http::read(stream, buffer, res);
// Write the message to standard out
std::cout << res << std::endl;
return "OK";
The following snippet shows the JSON message.
std::stringstream strStream;
strStream << "{\"userName\" : lena, \"password\" : liebe }";
serviceUser = strStream.str();
Can you give me a simple example please. Importent to mention is that i use the Boost library version 1.70.

Poco HTTPClientSession.recieveResponse skips next lines in program C++

I am using Poco to send HTTP requests, as the name implies. Right now, I'm just trying to send a GET request to google.com and store the resulting HTML in a string to test out Poco and see if it fits what I need. However, I'm having a little trouble with this. Here's my code:
try
{
Poco::URI uri("https://www.google.com");
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort());
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
request.add("Content-Length", "0");
Poco::Net::HTTPResponse response;
doRequest(session, request, response);
}
catch (Poco::Exception& exc)
{
OutputDebugStringA(exc.displayText().c_str());
}
void doRequest(Poco::Net::HTTPSClientSession& session, Poco::Net::HTTPRequest& request, Poco::Net::HTTPResponse& response)
{
session.sendRequest(request);
std::istream& is = session.receiveResponse(response);
std::string body(std::istreambuf_iterator<char>(is), { });
message = (LPCWSTR)response.getStatus();
}
I have put breakpoints on every line of doRequest, but the only ones that are triggered are the first two. After clicking continue on the second, the program simply continues as normal. I'm not getting any exceptions or anything. I am adding Content-Length: 0 to avoid a NoMessageException from Poco.

sending a GET command to an ssl server to get result

I am trying to send a get request to acounts.google.com to be able to implement a library for C++ OAuth to learn it.
I get the following code from this post: Creating a HTTPS request using Boost Asio and OpenSSL and modified it as follow:
int main()
{
try
{
std::string request = "/o/oauth2/v2/auth";
boost::system::error_code ec;
using namespace boost::asio;
// what we need
io_service svc;
ssl::context ctx(svc, ssl::context::method::sslv23_client);
ssl::stream<ip::tcp::socket> ssock(svc, ctx);
ip::tcp::resolver resolver(svc);
auto it = resolver.resolve({ "accounts.google.com", "443" }); // https://accouts.google.com:443
boost::asio::connect(ssock.lowest_layer(), it);
ssock.handshake(ssl::stream_base::handshake_type::client);
// send request
std::string fullResuest = "GET " + request + " HTTP/1.1\r\n\r\n";
boost::asio::write(ssock, buffer(fullResuest));
// read response
std::string response;
do
{
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
std::cout << "Response received: '" << response << "'\n"; // I add this to see what I am getting from the server, so it should not be here.
} while (!ec);
// print and exit
std::cout << "Response received: '" << response << "'\n";
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
if (std::string const * extra = boost::get_error_info<my_tag_error_info>(e))
{
std::cout << *extra << std::endl;
}
}
}
The problem that I have is as follow:
1- The results that I am getting is not what I am getting when I visit https://accounts.google.com/o/oauth2/v2/auth using a web browser. I essentially getting a message that they can not find the requested URL /o/oauth2/v2/auth
<p>The requested URL <code>/o/oauth2/v2/auth</code> was not found on this server. <ins>ThatÔÇÖs all we know.</ins>
How should I setup the GET commend so I can get the same result that I am getting with a browser?
2- The application hangs getting data from server, apparently the following loop is not right:
do
{
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
} while (!ec);
What is the correct way of reading responce from the web server which is fast and read all data?
Edit 1
For reference based on accepted answer, I fixed the problem using the correct GET header as shown below:
// send request
std::string fullResuest = "GET " + request + " HTTP/1.1\r\n";
fullResuest+= "Host: " + server + "\r\n";
fullResuest += "Accept: */*\r\n";
fullResuest += "Connection: close\r\n\r\n";
boost::asio::write(ssock, buffer(fullResuest));
A HTTP/1.1 request must have a Host header. A simple experiment with OpenSSL will show the problem, i.e. the missing header:
$ openssl s_client -connect accounts.google.com:443
...
GET /o/oauth2/v2/auth HTTP/1.1
... The requested URL <code>/o/oauth2/v2/auth</code> was not found on this server. <ins>That’s all we know.</ins>
When adding the Host header instead we get a different response:
$ openssl s_client -connect accounts.google.com:443
...
GET /o/oauth2/v2/auth HTTP/1.1
Host: accounts.google.com
... >Required parameter is missing: response_type<
Apart from that HTTP/1.1 implicitly uses HTTP keep-alive, i.e. server and client might keep the connection open after the response is done. This means you should not read until the end of connection but should instead properly parse the HTTP header, extract the Content-length header and/or Transfer-Encoding header and behave according to their values. Or if you want it simpler use HTTP/1.0 instead.
For more information see the HTTP/1.1 standard.

Send Receive using casablanca c++ rest sdk

I'm just starting with RESTful programming and trying to make a program in c++ using the Casablanca sdk (https://github.com/Microsoft/cpprestsdk). I know that I need to use GET, POST, PUT and DEL methods to do data transfer etc. But I cant seem to find any examples on how to do this. I currently need to send an integer value to the server from the client and get a Boolean response from the server. I cant find any good examples in Casablanca's documentation or the web. Any help regarding how to do this simple transfer would be appreciated.
Spending more time to explore the documentation and various examples on the internet would probably have got you the answer.
Basically, you have to set up a http listener, as the server, that will listen to client request at a particular url.
Then a client can send data on that url, to communicate with it.
Nevertheless, if you want to exchange data in json format,
Server would look something like this
void handle_post(http_request request)
{
json::value temp;
request.extract_json() //extracts the request content into a json
.then([&temp](pplx::task<json::value> task)
{
temp = task.get();
})
.wait();
//do whatever you want with 'temp' here
request.reply(status_codes::OK, temp); //send the reply as a json.
}
int main()
{
http_listener listener(L"http://localhost/restdemo"); //define a listener on this url.
listener.support(methods::POST, handle_post); //'handle_post' is the function this listener will go to when it receives a POST request.
try
{
listener
.open() //start listening
.then([&listener](){TRACE(L"\nstarting to listen\n");})
.wait();
while (true);
}
catch (exception const & e)
{
wcout << e.what() << endl;
}
}
Client would be,
int main()
{
json::value client_temp;
http_client client(L"http://localhost");
//insert data into the json e.g : json::value(54)
client.request(methods::POST, L"/restdemo", object)
.then([](http_response response)
{
if (response.status_code() == status_codes::OK)
{
return response.extract_json();
}
return pplx::task_from_result(json::value());
})
.then([&client_temp ](pplx::task<json::value> previousTask)
{
client_temp = previousTask.get();
})
.wait();
}
Your server reply will be stored into 'client_temp'

resolve: No such host is known?

I am facing a strange issue while trying to resolve endpoints using boost resolver in c++.
Case:
I am trying to connect to a website http://localhostIpAddress/test/ using boost.
where local address of server is "172.34.22.11"(say).
I am facing the error saying "resolve: No such host is known"
But when I am connecting to say website like google.com its able to resolve and connect successfully.
Also,even when I try to open "http:://localhostIpAddress/test/" in a browser, it opens successfully.
below is my code:
int main()
{
std::cout << "\nWebClient is starting... \n";
boost::asio::io_service IO_Servicehttp;
boost::asio::ip::tcp::resolver Resolverhttp(IO_Servicehttp);
std::string porthttp = "http";
boost::asio::ip::tcp::resolver::query Queryhttp("172.34.22.11/test/", porthttp);
boost::asio::ip::tcp::resolver::iterator EndPointIteratorhttp = Resolverhttp.resolve(Queryhttp);
g_ClientHttp = new HTTPClient(IO_Servicehttp, EndPointIteratorhttp);
}
catch (std::exception& e)
{
std::cerr << e.what();
}
}
In HTTPClient.cpp
HTTPClient::HTTPClient(boost::asio::io_service& IO_Servicehttp, boost::asio::ip::tcp::resolver::iterator EndPointIterhttp)
: m_IOServicehttp(IO_Servicehttp), m_Sockethttp(IO_Servicehttp),m_EndPointhttp(*EndPointIterhttp)
{
std::cout << "\n Entered: HTTPClient ctor \n";
boost::asio::ip::tcp::resolver::iterator endhttp;
boost::system::error_code error= boost::asio::error::host_not_found;
try
{
while (error && EndPointIterhttp != endhttp) //if error go to next endpoint
{
m_Sockethttp.async_connect(m_EndPointhttp,boost::bind(&HTTPClient::OnConnect_http, this, boost::asio::placeholders::error, ++EndPointIterhttp));
}
if(error)
throw boost::system::system_error(error);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
m_IOServicehttp.run();
}
I have gone through a lot of website directed by google but haven't found anything related to this issue.
Any help or tip will be much appreciated
The hostname being resolved is invalid. Try changing the resolver's query host to "172.34.22.11". In the URL, "http://172.34.22.11/test/":
"http" is the protocol
"172.34.22.11" is the host which needs resolved
"/test/" is the path
At a high level, network communication occurs between the client and the server (host) over TCP. The client will create an HTTP request, include the path as part of the request, and write the complete request to a TCP socket. The server will read the HTTP request from a TCP socket, process the request based on the path, then write an HTTP response to the client over TCP.
Hostnames are concatenated with dots and specified to only allow:
ASCII letters 'a' through 'z'
digits
hyphen
Hence, "172.34.22.11/test/" contains invalid characters, and will likely not resolve. See RFC952 and RFC1123 for more details.